From 4f93f071ca9e7f85f976c805142d33f6cffd2745 Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Thu, 6 Oct 2022 17:06:49 -0300 Subject: target/ppc: fix msgclr/msgsnd insns flags On Power ISA v2.07, the category for these instructions became "Embedded.Processor Control" or "Book S". Signed-off-by: Matheus Ferst Reviewed-by: Fabiano Rosas Message-Id: <20221006200654.725390-2-matheus.ferst@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/translate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'target') diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 7228857..b5d80fd 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -6902,9 +6902,9 @@ GEN_HANDLER2_E(tlbivax_booke206, "tlbivax", 0x1F, 0x12, 0x18, 0x00000001, GEN_HANDLER2_E(tlbilx_booke206, "tlbilx", 0x1F, 0x12, 0x00, 0x03800001, PPC_NONE, PPC2_BOOKE206), GEN_HANDLER2_E(msgsnd, "msgsnd", 0x1F, 0x0E, 0x06, 0x03ff0001, - PPC_NONE, PPC2_PRCNTL), + PPC_NONE, (PPC2_PRCNTL | PPC2_ISA207S)), GEN_HANDLER2_E(msgclr, "msgclr", 0x1F, 0x0E, 0x07, 0x03ff0001, - PPC_NONE, PPC2_PRCNTL), + PPC_NONE, (PPC2_PRCNTL | PPC2_ISA207S)), GEN_HANDLER2_E(msgsync, "msgsync", 0x1F, 0x16, 0x1B, 0x00000000, PPC_NONE, PPC2_PRCNTL), GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_WRTEE), -- cgit v1.1 From 9d950c724144770d9d092f70716da0da022926de Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Thu, 6 Oct 2022 17:06:50 -0300 Subject: target/ppc: fix msgsync insns flags This instruction was added by Power ISA 3.0, using PPC2_PRCNTL makes it available for older processors, like de e5500 and e6500. Fixes: 7af1e7b02264 ("target/ppc: add support for hypervisor doorbells on book3s CPUs") Signed-off-by: Matheus Ferst Reviewed-by: Fabiano Rosas Message-Id: <20221006200654.725390-3-matheus.ferst@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'target') diff --git a/target/ppc/translate.c b/target/ppc/translate.c index b5d80fd..ccf2ffd 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -6906,7 +6906,7 @@ GEN_HANDLER2_E(msgsnd, "msgsnd", 0x1F, 0x0E, 0x06, 0x03ff0001, GEN_HANDLER2_E(msgclr, "msgclr", 0x1F, 0x0E, 0x07, 0x03ff0001, PPC_NONE, (PPC2_PRCNTL | PPC2_ISA207S)), GEN_HANDLER2_E(msgsync, "msgsync", 0x1F, 0x16, 0x1B, 0x00000000, - PPC_NONE, PPC2_PRCNTL), + PPC_NONE, PPC2_ISA300), GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_WRTEE), GEN_HANDLER(wrteei, 0x1F, 0x03, 0x05, 0x000E7C01, PPC_WRTEE), GEN_HANDLER(dlmzb, 0x1F, 0x0E, 0x02, 0x00000000, PPC_440_SPEC), -- cgit v1.1 From e8db3cc76e9555c482ee92743bcf3560e25b1424 Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Thu, 6 Oct 2022 17:06:51 -0300 Subject: target/ppc: fix REQUIRE_HV macro definition The macro is missing a '{' after the if condition. Any use of REQUIRE_HV would cause a compilation error. Fixes: fc34e81acd51 ("target/ppc: add macros to check privilege level") Signed-off-by: Matheus Ferst Reviewed-by: Fabiano Rosas Message-Id: <20221006200654.725390-4-matheus.ferst@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/translate.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'target') diff --git a/target/ppc/translate.c b/target/ppc/translate.c index ccf2ffd..f73ff2d 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -6545,12 +6545,12 @@ static int64_t dw_compose_ea(DisasContext *ctx, int x) } \ } while (0) -#define REQUIRE_HV(CTX) \ - do { \ - if (unlikely((CTX)->pr || !(CTX)->hv)) \ - gen_priv_opc(CTX); \ - return true; \ - } \ +#define REQUIRE_HV(CTX) \ + do { \ + if (unlikely((CTX)->pr || !(CTX)->hv)) { \ + gen_priv_opc(CTX); \ + return true; \ + } \ } while (0) #else #define REQUIRE_SV(CTX) do { gen_priv_opc(CTX); return true; } while (0) -- cgit v1.1 From 98f43417b66457eb9c207a2a09e0eef984dadc41 Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Thu, 6 Oct 2022 17:06:52 -0300 Subject: target/ppc: move msgclr/msgsnd to decodetree Signed-off-by: Matheus Ferst Reviewed-by: Daniel Henrique Barboza Message-Id: <20221006200654.725390-5-matheus.ferst@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/insn32.decode | 5 ++ target/ppc/translate.c | 34 +------------ target/ppc/translate/processor-ctrl-impl.c.inc | 70 ++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 32 deletions(-) create mode 100644 target/ppc/translate/processor-ctrl-impl.c.inc (limited to 'target') diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode index a5249ee..bba49de 100644 --- a/target/ppc/insn32.decode +++ b/target/ppc/insn32.decode @@ -908,3 +908,8 @@ SLBSYNC 011111 ----- ----- ----- 0101010010 - TLBIE 011111 ..... - .. . . ..... 0100110010 - @X_tlbie TLBIEL 011111 ..... - .. . . ..... 0100010010 - @X_tlbie + +# Processor Control Instructions + +MSGCLR 011111 ----- ----- ..... 0011101110 - @X_rb +MSGSND 011111 ----- ----- ..... 0011001110 - @X_rb diff --git a/target/ppc/translate.c b/target/ppc/translate.c index f73ff2d..231bc95 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -6241,34 +6241,6 @@ static void gen_icbt_440(DisasContext *ctx) /* Embedded.Processor Control */ -static void gen_msgclr(DisasContext *ctx) -{ -#if defined(CONFIG_USER_ONLY) - GEN_PRIV(ctx); -#else - CHK_HV(ctx); - if (is_book3s_arch2x(ctx)) { - gen_helper_book3s_msgclr(cpu_env, cpu_gpr[rB(ctx->opcode)]); - } else { - gen_helper_msgclr(cpu_env, cpu_gpr[rB(ctx->opcode)]); - } -#endif /* defined(CONFIG_USER_ONLY) */ -} - -static void gen_msgsnd(DisasContext *ctx) -{ -#if defined(CONFIG_USER_ONLY) - GEN_PRIV(ctx); -#else - CHK_HV(ctx); - if (is_book3s_arch2x(ctx)) { - gen_helper_book3s_msgsnd(cpu_gpr[rB(ctx->opcode)]); - } else { - gen_helper_msgsnd(cpu_gpr[rB(ctx->opcode)]); - } -#endif /* defined(CONFIG_USER_ONLY) */ -} - #if defined(TARGET_PPC64) static void gen_msgclrp(DisasContext *ctx) { @@ -6628,6 +6600,8 @@ static bool resolve_PLS_D(DisasContext *ctx, arg_D *d, arg_PLS_D *a) #include "translate/branch-impl.c.inc" +#include "translate/processor-ctrl-impl.c.inc" + #include "translate/storage-ctrl-impl.c.inc" /* Handles lfdp */ @@ -6901,10 +6875,6 @@ GEN_HANDLER2_E(tlbivax_booke206, "tlbivax", 0x1F, 0x12, 0x18, 0x00000001, PPC_NONE, PPC2_BOOKE206), GEN_HANDLER2_E(tlbilx_booke206, "tlbilx", 0x1F, 0x12, 0x00, 0x03800001, PPC_NONE, PPC2_BOOKE206), -GEN_HANDLER2_E(msgsnd, "msgsnd", 0x1F, 0x0E, 0x06, 0x03ff0001, - PPC_NONE, (PPC2_PRCNTL | PPC2_ISA207S)), -GEN_HANDLER2_E(msgclr, "msgclr", 0x1F, 0x0E, 0x07, 0x03ff0001, - PPC_NONE, (PPC2_PRCNTL | PPC2_ISA207S)), GEN_HANDLER2_E(msgsync, "msgsync", 0x1F, 0x16, 0x1B, 0x00000000, PPC_NONE, PPC2_ISA300), GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_WRTEE), diff --git a/target/ppc/translate/processor-ctrl-impl.c.inc b/target/ppc/translate/processor-ctrl-impl.c.inc new file mode 100644 index 0000000..208f2c2 --- /dev/null +++ b/target/ppc/translate/processor-ctrl-impl.c.inc @@ -0,0 +1,70 @@ +/* + * Power ISA decode for Storage Control instructions + * + * Copyright (c) 2022 Instituto de Pesquisas Eldorado (eldorado.org.br) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +/* + * Processor Control Instructions + */ + +static bool trans_MSGCLR(DisasContext *ctx, arg_X_rb *a) +{ + if (!(ctx->insns_flags2 & PPC2_ISA207S)) { + /* + * Before Power ISA 2.07, processor control instructions were only + * implemented in the "Embedded.Processor Control" category. + */ + REQUIRE_INSNS_FLAGS2(ctx, PRCNTL); + } + + REQUIRE_HV(ctx); + +#if !defined(CONFIG_USER_ONLY) + if (is_book3s_arch2x(ctx)) { + gen_helper_book3s_msgclr(cpu_env, cpu_gpr[a->rb]); + } else { + gen_helper_msgclr(cpu_env, cpu_gpr[a->rb]); + } +#else + qemu_build_not_reached(); +#endif + return true; +} + +static bool trans_MSGSND(DisasContext *ctx, arg_X_rb *a) +{ + if (!(ctx->insns_flags2 & PPC2_ISA207S)) { + /* + * Before Power ISA 2.07, processor control instructions were only + * implemented in the "Embedded.Processor Control" category. + */ + REQUIRE_INSNS_FLAGS2(ctx, PRCNTL); + } + + REQUIRE_HV(ctx); + +#if !defined(CONFIG_USER_ONLY) + if (is_book3s_arch2x(ctx)) { + gen_helper_book3s_msgsnd(cpu_gpr[a->rb]); + } else { + gen_helper_msgsnd(cpu_gpr[a->rb]); + } +#else + qemu_build_not_reached(); +#endif + return true; +} -- cgit v1.1 From e8e09d7da7dd572e6cf62b2f12b65fb9833cf7ba Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Thu, 6 Oct 2022 17:06:53 -0300 Subject: target/ppc: move msgclrp/msgsndp to decodetree Signed-off-by: Matheus Ferst Reviewed-by: Daniel Henrique Barboza Message-Id: <20221006200654.725390-6-matheus.ferst@eldorado.org.br> [danielhb: ppc32 build fix in trans_(MSGCLRP|MSGSNDP)] Signed-off-by: Daniel Henrique Barboza --- target/ppc/insn32.decode | 2 ++ target/ppc/translate.c | 26 -------------------------- target/ppc/translate/processor-ctrl-impl.c.inc | 26 ++++++++++++++++++++++++++ 3 files changed, 28 insertions(+), 26 deletions(-) (limited to 'target') diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode index bba49de..5ba4a68 100644 --- a/target/ppc/insn32.decode +++ b/target/ppc/insn32.decode @@ -913,3 +913,5 @@ TLBIEL 011111 ..... - .. . . ..... 0100010010 - @X_tlbie MSGCLR 011111 ----- ----- ..... 0011101110 - @X_rb MSGSND 011111 ----- ----- ..... 0011001110 - @X_rb +MSGCLRP 011111 ----- ----- ..... 0010101110 - @X_rb +MSGSNDP 011111 ----- ----- ..... 0010001110 - @X_rb diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 231bc95..9e200ce 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -6241,28 +6241,6 @@ static void gen_icbt_440(DisasContext *ctx) /* Embedded.Processor Control */ -#if defined(TARGET_PPC64) -static void gen_msgclrp(DisasContext *ctx) -{ -#if defined(CONFIG_USER_ONLY) - GEN_PRIV(ctx); -#else - CHK_SV(ctx); - gen_helper_book3s_msgclrp(cpu_env, cpu_gpr[rB(ctx->opcode)]); -#endif /* defined(CONFIG_USER_ONLY) */ -} - -static void gen_msgsndp(DisasContext *ctx) -{ -#if defined(CONFIG_USER_ONLY) - GEN_PRIV(ctx); -#else - CHK_SV(ctx); - gen_helper_book3s_msgsndp(cpu_env, cpu_gpr[rB(ctx->opcode)]); -#endif /* defined(CONFIG_USER_ONLY) */ -} -#endif - static void gen_msgsync(DisasContext *ctx) { #if defined(CONFIG_USER_ONLY) @@ -6896,10 +6874,6 @@ GEN_HANDLER(vmladduhm, 0x04, 0x11, 0xFF, 0x00000000, PPC_ALTIVEC), GEN_HANDLER_E(maddhd_maddhdu, 0x04, 0x18, 0xFF, 0x00000000, PPC_NONE, PPC2_ISA300), GEN_HANDLER_E(maddld, 0x04, 0x19, 0xFF, 0x00000000, PPC_NONE, PPC2_ISA300), -GEN_HANDLER2_E(msgsndp, "msgsndp", 0x1F, 0x0E, 0x04, 0x03ff0001, - PPC_NONE, PPC2_ISA207S), -GEN_HANDLER2_E(msgclrp, "msgclrp", 0x1F, 0x0E, 0x05, 0x03ff0001, - PPC_NONE, PPC2_ISA207S), #endif #undef GEN_INT_ARITH_ADD diff --git a/target/ppc/translate/processor-ctrl-impl.c.inc b/target/ppc/translate/processor-ctrl-impl.c.inc index 208f2c2..d704a32 100644 --- a/target/ppc/translate/processor-ctrl-impl.c.inc +++ b/target/ppc/translate/processor-ctrl-impl.c.inc @@ -68,3 +68,29 @@ static bool trans_MSGSND(DisasContext *ctx, arg_X_rb *a) #endif return true; } + +static bool trans_MSGCLRP(DisasContext *ctx, arg_X_rb *a) +{ + REQUIRE_64BIT(ctx); + REQUIRE_INSNS_FLAGS2(ctx, ISA207S); + REQUIRE_SV(ctx); +#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) + gen_helper_book3s_msgclrp(cpu_env, cpu_gpr[a->rb]); +#else + qemu_build_not_reached(); +#endif + return true; +} + +static bool trans_MSGSNDP(DisasContext *ctx, arg_X_rb *a) +{ + REQUIRE_64BIT(ctx); + REQUIRE_INSNS_FLAGS2(ctx, ISA207S); + REQUIRE_SV(ctx); +#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) + gen_helper_book3s_msgsndp(cpu_env, cpu_gpr[a->rb]); +#else + qemu_build_not_reached(); +#endif + return true; +} -- cgit v1.1 From b35bf5f2d759d97652b4acd96e62329a1657f3cb Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Thu, 6 Oct 2022 17:06:54 -0300 Subject: target/ppc: move msgsync to decodetree Signed-off-by: Matheus Ferst Reviewed-by: Daniel Henrique Barboza Message-Id: <20221006200654.725390-7-matheus.ferst@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/insn32.decode | 1 + target/ppc/translate.c | 14 -------------- target/ppc/translate/processor-ctrl-impl.c.inc | 9 +++++++++ 3 files changed, 10 insertions(+), 14 deletions(-) (limited to 'target') diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode index 5ba4a68..70a3b4d 100644 --- a/target/ppc/insn32.decode +++ b/target/ppc/insn32.decode @@ -915,3 +915,4 @@ MSGCLR 011111 ----- ----- ..... 0011101110 - @X_rb MSGSND 011111 ----- ----- ..... 0011001110 - @X_rb MSGCLRP 011111 ----- ----- ..... 0010101110 - @X_rb MSGSNDP 011111 ----- ----- ..... 0010001110 - @X_rb +MSGSYNC 011111 ----- ----- ----- 1101110110 - diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 9e200ce..959e7e3 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -6239,18 +6239,6 @@ static void gen_icbt_440(DisasContext *ctx) */ } -/* Embedded.Processor Control */ - -static void gen_msgsync(DisasContext *ctx) -{ -#if defined(CONFIG_USER_ONLY) - GEN_PRIV(ctx); -#else - CHK_HV(ctx); -#endif /* defined(CONFIG_USER_ONLY) */ - /* interpreted as no-op */ -} - #if defined(TARGET_PPC64) static void gen_maddld(DisasContext *ctx) { @@ -6853,8 +6841,6 @@ GEN_HANDLER2_E(tlbivax_booke206, "tlbivax", 0x1F, 0x12, 0x18, 0x00000001, PPC_NONE, PPC2_BOOKE206), GEN_HANDLER2_E(tlbilx_booke206, "tlbilx", 0x1F, 0x12, 0x00, 0x03800001, PPC_NONE, PPC2_BOOKE206), -GEN_HANDLER2_E(msgsync, "msgsync", 0x1F, 0x16, 0x1B, 0x00000000, - PPC_NONE, PPC2_ISA300), GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_WRTEE), GEN_HANDLER(wrteei, 0x1F, 0x03, 0x05, 0x000E7C01, PPC_WRTEE), GEN_HANDLER(dlmzb, 0x1F, 0x0E, 0x02, 0x00000000, PPC_440_SPEC), diff --git a/target/ppc/translate/processor-ctrl-impl.c.inc b/target/ppc/translate/processor-ctrl-impl.c.inc index d704a32..cc7a50d 100644 --- a/target/ppc/translate/processor-ctrl-impl.c.inc +++ b/target/ppc/translate/processor-ctrl-impl.c.inc @@ -94,3 +94,12 @@ static bool trans_MSGSNDP(DisasContext *ctx, arg_X_rb *a) #endif return true; } + +static bool trans_MSGSYNC(DisasContext *ctx, arg_MSGSYNC *a) +{ + REQUIRE_INSNS_FLAGS2(ctx, ISA300); + REQUIRE_HV(ctx); + + /* interpreted as no-op */ + return true; +} -- cgit v1.1 From dc46167a2225d3c0861cd4fcbc350e3e0e89bc61 Mon Sep 17 00:00:00 2001 From: "Lucas Mateus Castro (alqotel)" Date: Wed, 19 Oct 2022 09:50:29 -0300 Subject: target/ppc: Moved VMLADDUHM to decodetree and use gvec This patch moves VMLADDUHM to decodetree a creates a gvec implementation using mul_vec and add_vec. rept loop master patch 8 12500 0,01810500 0,00903100 (-50.1%) 25 4000 0,01739400 0,00747700 (-57.0%) 100 1000 0,01843600 0,00901400 (-51.1%) 500 200 0,02574600 0,01971000 (-23.4%) 2500 40 0,05921600 0,07121800 (+20.3%) 8000 12 0,15326700 0,21725200 (+41.7%) The significant difference in performance when REPT is low and LOOP is high I think is due to the fact that the new implementation has a higher translation time, as when using a helper only 5 TCGop are used but with the patch a total of 10 TCGop are needed (Power lacks a direct mul_vec equivalent so this instruction is implemented with the help of 5 others, vmuleu, vmulou, vmrgh, vmrgl and vpkum). Signed-off-by: Lucas Mateus Castro (alqotel) Reviewed-by: Richard Henderson Message-Id: <20221019125040.48028-2-lucas.araujo@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/helper.h | 2 +- target/ppc/insn32.decode | 2 ++ target/ppc/int_helper.c | 3 ++- target/ppc/translate.c | 1 - target/ppc/translate/vmx-impl.c.inc | 48 +++++++++++++++++++++++-------------- 5 files changed, 35 insertions(+), 21 deletions(-) (limited to 'target') diff --git a/target/ppc/helper.h b/target/ppc/helper.h index 57eee07..9c562ab 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -264,7 +264,7 @@ DEF_HELPER_FLAGS_4(VMSUMUHM, TCG_CALL_NO_RWG, void, avr, avr, avr, avr) DEF_HELPER_5(VMSUMUHS, void, env, avr, avr, avr, avr) DEF_HELPER_FLAGS_4(VMSUMSHM, TCG_CALL_NO_RWG, void, avr, avr, avr, avr) DEF_HELPER_5(VMSUMSHS, void, env, avr, avr, avr, avr) -DEF_HELPER_FLAGS_4(vmladduhm, TCG_CALL_NO_RWG, void, avr, avr, avr, avr) +DEF_HELPER_FLAGS_5(VMLADDUHM, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32) DEF_HELPER_FLAGS_2(mtvscr, TCG_CALL_NO_RWG, void, env, i32) DEF_HELPER_FLAGS_1(mfvscr, TCG_CALL_NO_RWG, i32, env) DEF_HELPER_3(lvebx, void, env, avr, tl) diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode index 70a3b4d..9ba1689 100644 --- a/target/ppc/insn32.decode +++ b/target/ppc/insn32.decode @@ -693,6 +693,8 @@ VMSUMUHS 000100 ..... ..... ..... ..... 100111 @VA VMSUMCUD 000100 ..... ..... ..... ..... 010111 @VA VMSUMUDM 000100 ..... ..... ..... ..... 100011 @VA +VMLADDUHM 000100 ..... ..... ..... ..... 100010 @VA + ## Vector String Instructions VSTRIBL 000100 ..... 00000 ..... . 0000001101 @VX_tb_rc diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c index 6960961..0d25000 100644 --- a/target/ppc/int_helper.c +++ b/target/ppc/int_helper.c @@ -974,7 +974,8 @@ void helper_vmhraddshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, } } -void helper_vmladduhm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) +void helper_VMLADDUHM(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c, + uint32_t v) { int i; diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 959e7e3..58fbc15 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -6855,7 +6855,6 @@ GEN_HANDLER(lvsl, 0x1f, 0x06, 0x00, 0x00000001, PPC_ALTIVEC), GEN_HANDLER(lvsr, 0x1f, 0x06, 0x01, 0x00000001, PPC_ALTIVEC), GEN_HANDLER(mfvscr, 0x04, 0x2, 0x18, 0x001ff800, PPC_ALTIVEC), GEN_HANDLER(mtvscr, 0x04, 0x2, 0x19, 0x03ff0000, PPC_ALTIVEC), -GEN_HANDLER(vmladduhm, 0x04, 0x11, 0xFF, 0x00000000, PPC_ALTIVEC), #if defined(TARGET_PPC64) GEN_HANDLER_E(maddhd_maddhdu, 0x04, 0x18, 0xFF, 0x00000000, PPC_NONE, PPC2_ISA300), diff --git a/target/ppc/translate/vmx-impl.c.inc b/target/ppc/translate/vmx-impl.c.inc index e644ad3..9f18c6d 100644 --- a/target/ppc/translate/vmx-impl.c.inc +++ b/target/ppc/translate/vmx-impl.c.inc @@ -2523,24 +2523,6 @@ static void glue(gen_, name0##_##name1)(DisasContext *ctx) \ GEN_VAFORM_PAIRED(vmhaddshs, vmhraddshs, 16) -static void gen_vmladduhm(DisasContext *ctx) -{ - TCGv_ptr ra, rb, rc, rd; - if (unlikely(!ctx->altivec_enabled)) { - gen_exception(ctx, POWERPC_EXCP_VPU); - return; - } - ra = gen_avr_ptr(rA(ctx->opcode)); - rb = gen_avr_ptr(rB(ctx->opcode)); - rc = gen_avr_ptr(rC(ctx->opcode)); - rd = gen_avr_ptr(rD(ctx->opcode)); - gen_helper_vmladduhm(rd, ra, rb, rc); - tcg_temp_free_ptr(ra); - tcg_temp_free_ptr(rb); - tcg_temp_free_ptr(rc); - tcg_temp_free_ptr(rd); -} - static bool do_va_helper(DisasContext *ctx, arg_VA *a, void (*gen_helper)(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_ptr)) { @@ -2569,6 +2551,36 @@ TRANS_FLAGS2(ALTIVEC_207, VSUBECUQ, do_va_helper, gen_helper_VSUBECUQ) TRANS_FLAGS(ALTIVEC, VPERM, do_va_helper, gen_helper_VPERM) TRANS_FLAGS2(ISA300, VPERMR, do_va_helper, gen_helper_VPERMR) +static void gen_vmladduhm_vec(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b, + TCGv_vec c) +{ + tcg_gen_mul_vec(vece, t, a, b); + tcg_gen_add_vec(vece, t, t, c); +} + +static bool trans_VMLADDUHM(DisasContext *ctx, arg_VA *a) +{ + static const TCGOpcode vecop_list[] = { + INDEX_op_add_vec, INDEX_op_mul_vec, 0 + }; + + static const GVecGen4 op = { + .fno = gen_helper_VMLADDUHM, + .fniv = gen_vmladduhm_vec, + .opt_opc = vecop_list, + .vece = MO_16 + }; + + REQUIRE_INSNS_FLAGS(ctx, ALTIVEC); + REQUIRE_VECTOR(ctx); + + tcg_gen_gvec_4(avr_full_offset(a->vrt), avr_full_offset(a->vra), + avr_full_offset(a->vrb), avr_full_offset(a->rc), + 16, 16, &op); + + return true; +} + static bool trans_VSEL(DisasContext *ctx, arg_VA *a) { REQUIRE_INSNS_FLAGS(ctx, ALTIVEC); -- cgit v1.1 From 306e4753354378213eddf6f4e6335ffc68186d1f Mon Sep 17 00:00:00 2001 From: "Lucas Mateus Castro (alqotel)" Date: Wed, 19 Oct 2022 09:50:30 -0300 Subject: target/ppc: Move VMH[R]ADDSHS instruction to decodetree This patch moves VMHADDSHS and VMHRADDSHS to decodetree I couldn't find a satisfactory implementation with TCG inline. vmhaddshs: rept loop master patch 8 12500 0,02983400 0,02648500 (-11.2%) 25 4000 0,02946000 0,02518000 (-14.5%) 100 1000 0,03104300 0,02638000 (-15.0%) 500 200 0,04002000 0,03502500 (-12.5%) 2500 40 0,08090100 0,07562200 (-6.5%) 8000 12 0,19242600 0,18626800 (-3.2%) vmhraddshs: rept loop master patch 8 12500 0,03078600 0,02851000 (-7.4%) 25 4000 0,02793200 0,02746900 (-1.7%) 100 1000 0,02886000 0,02839900 (-1.6%) 500 200 0,03714700 0,03799200 (+2.3%) 2500 40 0,07948000 0,07852200 (-1.2%) 8000 12 0,19049800 0,18813900 (-1.2%) Signed-off-by: Lucas Mateus Castro (alqotel) Reviewed-by: Richard Henderson Message-Id: <20221019125040.48028-3-lucas.araujo@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/helper.h | 4 ++-- target/ppc/insn32.decode | 2 ++ target/ppc/int_helper.c | 4 ++-- target/ppc/translate/vmx-impl.c.inc | 5 +++-- target/ppc/translate/vmx-ops.c.inc | 1 - 5 files changed, 9 insertions(+), 7 deletions(-) (limited to 'target') diff --git a/target/ppc/helper.h b/target/ppc/helper.h index 9c562ab..f02a949 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -258,8 +258,8 @@ DEF_HELPER_4(vpkuhum, void, env, avr, avr, avr) DEF_HELPER_4(vpkuwum, void, env, avr, avr, avr) DEF_HELPER_4(vpkudum, void, env, avr, avr, avr) DEF_HELPER_FLAGS_3(vpkpx, TCG_CALL_NO_RWG, void, avr, avr, avr) -DEF_HELPER_5(vmhaddshs, void, env, avr, avr, avr, avr) -DEF_HELPER_5(vmhraddshs, void, env, avr, avr, avr, avr) +DEF_HELPER_5(VMHADDSHS, void, env, avr, avr, avr, avr) +DEF_HELPER_5(VMHRADDSHS, void, env, avr, avr, avr, avr) DEF_HELPER_FLAGS_4(VMSUMUHM, TCG_CALL_NO_RWG, void, avr, avr, avr, avr) DEF_HELPER_5(VMSUMUHS, void, env, avr, avr, avr, avr) DEF_HELPER_FLAGS_4(VMSUMSHM, TCG_CALL_NO_RWG, void, avr, avr, avr, avr) diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode index 9ba1689..4e142d5 100644 --- a/target/ppc/insn32.decode +++ b/target/ppc/insn32.decode @@ -694,6 +694,8 @@ VMSUMCUD 000100 ..... ..... ..... ..... 010111 @VA VMSUMUDM 000100 ..... ..... ..... ..... 100011 @VA VMLADDUHM 000100 ..... ..... ..... ..... 100010 @VA +VMHADDSHS 000100 ..... ..... ..... ..... 100000 @VA +VMHRADDSHS 000100 ..... ..... ..... ..... 100001 @VA ## Vector String Instructions diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c index 0d25000..ae1ba80 100644 --- a/target/ppc/int_helper.c +++ b/target/ppc/int_helper.c @@ -939,7 +939,7 @@ target_ulong helper_vctzlsbb(ppc_avr_t *r) return count; } -void helper_vmhaddshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, +void helper_VMHADDSHS(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) { int sat = 0; @@ -957,7 +957,7 @@ void helper_vmhaddshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, } } -void helper_vmhraddshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, +void helper_VMHRADDSHS(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c) { int sat = 0; diff --git a/target/ppc/translate/vmx-impl.c.inc b/target/ppc/translate/vmx-impl.c.inc index 9f18c6d..3acd585 100644 --- a/target/ppc/translate/vmx-impl.c.inc +++ b/target/ppc/translate/vmx-impl.c.inc @@ -2521,7 +2521,7 @@ static void glue(gen_, name0##_##name1)(DisasContext *ctx) \ tcg_temp_free_ptr(rd); \ } -GEN_VAFORM_PAIRED(vmhaddshs, vmhraddshs, 16) +GEN_VAFORM_PAIRED(vmaddfp, vnmsubfp, 23) static bool do_va_helper(DisasContext *ctx, arg_VA *a, void (*gen_helper)(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_ptr)) @@ -2620,7 +2620,8 @@ static bool do_va_env_helper(DisasContext *ctx, arg_VA *a, TRANS_FLAGS(ALTIVEC, VMSUMUHS, do_va_env_helper, gen_helper_VMSUMUHS) TRANS_FLAGS(ALTIVEC, VMSUMSHS, do_va_env_helper, gen_helper_VMSUMSHS) -GEN_VAFORM_PAIRED(vmaddfp, vnmsubfp, 23) +TRANS_FLAGS(ALTIVEC, VMHADDSHS, do_va_env_helper, gen_helper_VMHADDSHS) +TRANS_FLAGS(ALTIVEC, VMHRADDSHS, do_va_env_helper, gen_helper_VMHRADDSHS) GEN_VXFORM_NOA(vclzb, 1, 28) GEN_VXFORM_NOA(vclzh, 1, 29) diff --git a/target/ppc/translate/vmx-ops.c.inc b/target/ppc/translate/vmx-ops.c.inc index a3a0fd0..7cd9d40 100644 --- a/target/ppc/translate/vmx-ops.c.inc +++ b/target/ppc/translate/vmx-ops.c.inc @@ -219,7 +219,6 @@ GEN_VXFORM_UIMM(vctsxs, 5, 15), #define GEN_VAFORM_PAIRED(name0, name1, opc2) \ GEN_HANDLER(name0##_##name1, 0x04, opc2, 0xFF, 0x00000000, PPC_ALTIVEC) -GEN_VAFORM_PAIRED(vmhaddshs, vmhraddshs, 16), GEN_VAFORM_PAIRED(vmaddfp, vnmsubfp, 23), GEN_VXFORM_DUAL(vclzb, vpopcntb, 1, 28, PPC_NONE, PPC2_ALTIVEC_207), -- cgit v1.1 From 611bc69bf6bc6b23e91e4798c036b941c9958b40 Mon Sep 17 00:00:00 2001 From: "Lucas Mateus Castro (alqotel)" Date: Wed, 19 Oct 2022 09:50:31 -0300 Subject: target/ppc: Move V(ADD|SUB)CUW to decodetree and use gvec This patch moves VADDCUW and VSUBCUW to decodtree with gvec using an implementation based on the helper, with the main difference being changing the -1 (aka all bits set to 1) result returned by cmp when true to +1. It also implemented a .fni4 version of those instructions and dropped the helper. vaddcuw: rept loop master patch 8 12500 0,01008200 0,00612400 (-39.3%) 25 4000 0,01091500 0,00471600 (-56.8%) 100 1000 0,01332500 0,00593700 (-55.4%) 500 200 0,01998500 0,01275700 (-36.2%) 2500 40 0,04704300 0,04364300 (-7.2%) 8000 12 0,10748200 0,11241000 (+4.6%) vsubcuw: rept loop master patch 8 12500 0,01226200 0,00571600 (-53.4%) 25 4000 0,01493500 0,00462100 (-69.1%) 100 1000 0,01522700 0,00455100 (-70.1%) 500 200 0,02384600 0,01133500 (-52.5%) 2500 40 0,04935200 0,03178100 (-35.6%) 8000 12 0,09039900 0,09440600 (+4.4%) Overall there was a gain in performance, but the TCGop code was still slightly bigger in the new version (it went from 4 to 5). Signed-off-by: Lucas Mateus Castro (alqotel) Reviewed-by: Richard Henderson Message-Id: <20221019125040.48028-4-lucas.araujo@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/helper.h | 2 -- target/ppc/insn32.decode | 2 ++ target/ppc/int_helper.c | 18 ----------- target/ppc/translate/vmx-impl.c.inc | 61 ++++++++++++++++++++++++++++++++++--- target/ppc/translate/vmx-ops.c.inc | 3 +- 5 files changed, 60 insertions(+), 26 deletions(-) (limited to 'target') diff --git a/target/ppc/helper.h b/target/ppc/helper.h index f02a949..f7047ed 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -193,11 +193,9 @@ DEF_HELPER_FLAGS_3(vslo, TCG_CALL_NO_RWG, void, avr, avr, avr) DEF_HELPER_FLAGS_3(vsro, TCG_CALL_NO_RWG, void, avr, avr, avr) DEF_HELPER_FLAGS_3(vsrv, TCG_CALL_NO_RWG, void, avr, avr, avr) DEF_HELPER_FLAGS_3(vslv, TCG_CALL_NO_RWG, void, avr, avr, avr) -DEF_HELPER_FLAGS_3(vaddcuw, TCG_CALL_NO_RWG, void, avr, avr, avr) DEF_HELPER_FLAGS_2(vprtybw, TCG_CALL_NO_RWG, void, avr, avr) DEF_HELPER_FLAGS_2(vprtybd, TCG_CALL_NO_RWG, void, avr, avr) DEF_HELPER_FLAGS_2(vprtybq, TCG_CALL_NO_RWG, void, avr, avr) -DEF_HELPER_FLAGS_3(vsubcuw, TCG_CALL_NO_RWG, void, avr, avr, avr) DEF_HELPER_FLAGS_5(vaddsbs, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32) DEF_HELPER_FLAGS_5(vaddshs, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32) DEF_HELPER_FLAGS_5(vaddsws, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32) diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode index 4e142d5..c985f8f 100644 --- a/target/ppc/insn32.decode +++ b/target/ppc/insn32.decode @@ -608,12 +608,14 @@ VRLQNM 000100 ..... ..... ..... 00101000101 @VX ## Vector Integer Arithmetic Instructions +VADDCUW 000100 ..... ..... ..... 00110000000 @VX VADDCUQ 000100 ..... ..... ..... 00101000000 @VX VADDUQM 000100 ..... ..... ..... 00100000000 @VX VADDEUQM 000100 ..... ..... ..... ..... 111100 @VA VADDECUQ 000100 ..... ..... ..... ..... 111101 @VA +VSUBCUW 000100 ..... ..... ..... 10110000000 @VX VSUBCUQ 000100 ..... ..... ..... 10101000000 @VX VSUBUQM 000100 ..... ..... ..... 10100000000 @VX diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c index ae1ba80..f8dd12e 100644 --- a/target/ppc/int_helper.c +++ b/target/ppc/int_helper.c @@ -492,15 +492,6 @@ static inline void set_vscr_sat(CPUPPCState *env) env->vscr_sat.u32[0] = 1; } -void helper_vaddcuw(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(r->u32); i++) { - r->u32[i] = ~a->u32[i] < b->u32[i]; - } -} - /* vprtybw */ void helper_vprtybw(ppc_avr_t *r, ppc_avr_t *b) { @@ -1962,15 +1953,6 @@ void helper_vsro(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) #endif } -void helper_vsubcuw(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(r->u32); i++) { - r->u32[i] = a->u32[i] >= b->u32[i]; - } -} - void helper_vsumsws(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) { int64_t t; diff --git a/target/ppc/translate/vmx-impl.c.inc b/target/ppc/translate/vmx-impl.c.inc index 3acd585..f52485a 100644 --- a/target/ppc/translate/vmx-impl.c.inc +++ b/target/ppc/translate/vmx-impl.c.inc @@ -803,8 +803,6 @@ GEN_VXFORM(vsrv, 2, 28); GEN_VXFORM(vslv, 2, 29); GEN_VXFORM(vslo, 6, 16); GEN_VXFORM(vsro, 6, 17); -GEN_VXFORM(vaddcuw, 0, 6); -GEN_VXFORM(vsubcuw, 0, 22); static bool do_vector_gvec3_VX(DisasContext *ctx, arg_VX *a, int vece, void (*gen_gvec)(unsigned, uint32_t, uint32_t, @@ -2847,8 +2845,6 @@ static void gen_xpnd04_2(DisasContext *ctx) } -GEN_VXFORM_DUAL(vsubcuw, PPC_ALTIVEC, PPC_NONE, \ - xpnd04_1, PPC_NONE, PPC2_ISA300) GEN_VXFORM_DUAL(vsubsws, PPC_ALTIVEC, PPC_NONE, \ xpnd04_2, PPC_NONE, PPC2_ISA300) @@ -3110,6 +3106,63 @@ TRANS_FLAGS2(ALTIVEC_207, VPMSUMD, do_vx_helper, gen_helper_VPMSUMD) TRANS_FLAGS2(ALTIVEC_207, VSUBCUQ, do_vx_helper, gen_helper_VSUBCUQ) TRANS_FLAGS2(ALTIVEC_207, VSUBUQM, do_vx_helper, gen_helper_VSUBUQM) +static void gen_VADDCUW_vec(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +{ + tcg_gen_not_vec(vece, a, a); + tcg_gen_cmp_vec(TCG_COND_LTU, vece, t, a, b); + tcg_gen_and_vec(vece, t, t, tcg_constant_vec_matching(t, vece, 1)); +} + +static void gen_VADDCUW_i32(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) +{ + tcg_gen_not_i32(a, a); + tcg_gen_setcond_i32(TCG_COND_LTU, t, a, b); +} + +static void gen_VSUBCUW_vec(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +{ + tcg_gen_cmp_vec(TCG_COND_GEU, vece, t, a, b); + tcg_gen_and_vec(vece, t, t, tcg_constant_vec_matching(t, vece, 1)); +} + +static void gen_VSUBCUW_i32(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b) +{ + tcg_gen_setcond_i32(TCG_COND_GEU, t, a, b); +} + +static bool do_vx_vaddsubcuw(DisasContext *ctx, arg_VX *a, int add) +{ + static const TCGOpcode vecop_list[] = { + INDEX_op_cmp_vec, 0 + }; + + static const GVecGen3 op[] = { + { + .fniv = gen_VSUBCUW_vec, + .fni4 = gen_VSUBCUW_i32, + .opt_opc = vecop_list, + .vece = MO_32 + }, + { + .fniv = gen_VADDCUW_vec, + .fni4 = gen_VADDCUW_i32, + .opt_opc = vecop_list, + .vece = MO_32 + }, + }; + + REQUIRE_INSNS_FLAGS(ctx, ALTIVEC); + REQUIRE_VECTOR(ctx); + + tcg_gen_gvec_3(avr_full_offset(a->vrt), avr_full_offset(a->vra), + avr_full_offset(a->vrb), 16, 16, &op[add]); + + return true; +} + +TRANS(VSUBCUW, do_vx_vaddsubcuw, 0) +TRANS(VADDCUW, do_vx_vaddsubcuw, 1) + static bool do_vx_vmuleo(DisasContext *ctx, arg_VX *a, bool even, void (*gen_mul)(TCGv_i64, TCGv_i64, TCGv_i64, TCGv_i64)) { diff --git a/target/ppc/translate/vmx-ops.c.inc b/target/ppc/translate/vmx-ops.c.inc index 7cd9d40..ded0234 100644 --- a/target/ppc/translate/vmx-ops.c.inc +++ b/target/ppc/translate/vmx-ops.c.inc @@ -106,12 +106,11 @@ GEN_VXFORM_300(vsrv, 2, 28), GEN_VXFORM_300(vslv, 2, 29), GEN_VXFORM(vslo, 6, 16), GEN_VXFORM(vsro, 6, 17), -GEN_VXFORM(vaddcuw, 0, 6), GEN_HANDLER_E_2(vprtybw, 0x4, 0x1, 0x18, 8, 0, PPC_NONE, PPC2_ISA300), GEN_HANDLER_E_2(vprtybd, 0x4, 0x1, 0x18, 9, 0, PPC_NONE, PPC2_ISA300), GEN_HANDLER_E_2(vprtybq, 0x4, 0x1, 0x18, 10, 0, PPC_NONE, PPC2_ISA300), -GEN_VXFORM_DUAL(vsubcuw, xpnd04_1, 0, 22, PPC_ALTIVEC, PPC_NONE), +GEN_VXFORM(xpnd04_1, 0, 22), GEN_VXFORM_300(bcdsr, 0, 23), GEN_VXFORM_300(bcdsr, 0, 31), GEN_VXFORM_DUAL(vaddubs, vmul10uq, 0, 8, PPC_ALTIVEC, PPC_NONE), -- cgit v1.1 From 90b5aadb09b1063dfc34636efe212c6862cbe32f Mon Sep 17 00:00:00 2001 From: "Lucas Mateus Castro (alqotel)" Date: Wed, 19 Oct 2022 09:50:32 -0300 Subject: target/ppc: Move VNEG[WD] to decodtree and use gvec Moved the instructions VNEGW and VNEGD to decodetree and used gvec to decode it. vnegw: rept loop master patch 8 12500 0,01053200 0,00548400 (-47.9%) 25 4000 0,01030500 0,00390000 (-62.2%) 100 1000 0,01096300 0,00395400 (-63.9%) 500 200 0,01472000 0,00712300 (-51.6%) 2500 40 0,03809000 0,02147700 (-43.6%) 8000 12 0,09957100 0,06202100 (-37.7%) vnegd: rept loop master patch 8 12500 0,00594600 0,00543800 (-8.5%) 25 4000 0,00575200 0,00396400 (-31.1%) 100 1000 0,00676100 0,00394800 (-41.6%) 500 200 0,01149300 0,00709400 (-38.3%) 2500 40 0,03441500 0,02169600 (-37.0%) 8000 12 0,09516900 0,06337000 (-33.4%) Signed-off-by: Lucas Mateus Castro (alqotel) Reviewed-by: Richard Henderson Message-Id: <20221019125040.48028-5-lucas.araujo@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/helper.h | 2 -- target/ppc/insn32.decode | 3 +++ target/ppc/int_helper.c | 12 ------------ target/ppc/translate/vmx-impl.c.inc | 15 +++++++++++++-- target/ppc/translate/vmx-ops.c.inc | 2 -- 5 files changed, 16 insertions(+), 18 deletions(-) (limited to 'target') diff --git a/target/ppc/helper.h b/target/ppc/helper.h index f7047ed..b2e910b 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -229,8 +229,6 @@ DEF_HELPER_FLAGS_2(VSTRIBL, TCG_CALL_NO_RWG, i32, avr, avr) DEF_HELPER_FLAGS_2(VSTRIBR, TCG_CALL_NO_RWG, i32, avr, avr) DEF_HELPER_FLAGS_2(VSTRIHL, TCG_CALL_NO_RWG, i32, avr, avr) DEF_HELPER_FLAGS_2(VSTRIHR, TCG_CALL_NO_RWG, i32, avr, avr) -DEF_HELPER_FLAGS_2(vnegw, TCG_CALL_NO_RWG, void, avr, avr) -DEF_HELPER_FLAGS_2(vnegd, TCG_CALL_NO_RWG, void, avr, avr) DEF_HELPER_FLAGS_2(vupkhpx, TCG_CALL_NO_RWG, void, avr, avr) DEF_HELPER_FLAGS_2(vupklpx, TCG_CALL_NO_RWG, void, avr, avr) DEF_HELPER_FLAGS_2(vupkhsb, TCG_CALL_NO_RWG, void, avr, avr) diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode index c985f8f..2fafde0 100644 --- a/target/ppc/insn32.decode +++ b/target/ppc/insn32.decode @@ -629,6 +629,9 @@ VEXTSH2D 000100 ..... 11001 ..... 11000000010 @VX_tb VEXTSW2D 000100 ..... 11010 ..... 11000000010 @VX_tb VEXTSD2Q 000100 ..... 11011 ..... 11000000010 @VX_tb +VNEGD 000100 ..... 00111 ..... 11000000010 @VX_tb +VNEGW 000100 ..... 00110 ..... 11000000010 @VX_tb + ## Vector Mask Manipulation Instructions MTVSRBM 000100 ..... 10000 ..... 11001000010 @VX_tb diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c index f8dd12e..c7fd0d1 100644 --- a/target/ppc/int_helper.c +++ b/target/ppc/int_helper.c @@ -1928,18 +1928,6 @@ XXBLEND(W, 32) XXBLEND(D, 64) #undef XXBLEND -#define VNEG(name, element) \ -void helper_##name(ppc_avr_t *r, ppc_avr_t *b) \ -{ \ - int i; \ - for (i = 0; i < ARRAY_SIZE(r->element); i++) { \ - r->element[i] = -b->element[i]; \ - } \ -} -VNEG(vnegw, s32) -VNEG(vnegd, s64) -#undef VNEG - void helper_vsro(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) { int sh = (b->VsrB(0xf) >> 3) & 0xf; diff --git a/target/ppc/translate/vmx-impl.c.inc b/target/ppc/translate/vmx-impl.c.inc index f52485a..b9a9e83 100644 --- a/target/ppc/translate/vmx-impl.c.inc +++ b/target/ppc/translate/vmx-impl.c.inc @@ -2625,8 +2625,19 @@ GEN_VXFORM_NOA(vclzb, 1, 28) GEN_VXFORM_NOA(vclzh, 1, 29) GEN_VXFORM_TRANS(vclzw, 1, 30) GEN_VXFORM_TRANS(vclzd, 1, 31) -GEN_VXFORM_NOA_2(vnegw, 1, 24, 6) -GEN_VXFORM_NOA_2(vnegd, 1, 24, 7) + +static bool do_vneg(DisasContext *ctx, arg_VX_tb *a, unsigned vece) +{ + REQUIRE_INSNS_FLAGS2(ctx, ISA300); + REQUIRE_VECTOR(ctx); + + tcg_gen_gvec_neg(vece, avr_full_offset(a->vrt), avr_full_offset(a->vrb), + 16, 16); + return true; +} + +TRANS(VNEGW, do_vneg, MO_32) +TRANS(VNEGD, do_vneg, MO_64) static void gen_vexts_i64(TCGv_i64 t, TCGv_i64 b, int64_t s) { diff --git a/target/ppc/translate/vmx-ops.c.inc b/target/ppc/translate/vmx-ops.c.inc index ded0234..2790853 100644 --- a/target/ppc/translate/vmx-ops.c.inc +++ b/target/ppc/translate/vmx-ops.c.inc @@ -181,8 +181,6 @@ GEN_VXFORM_300_EXT(vextractd, 6, 11, 0x100000), GEN_VXFORM(vspltisb, 6, 12), GEN_VXFORM(vspltish, 6, 13), GEN_VXFORM(vspltisw, 6, 14), -GEN_VXFORM_300_EO(vnegw, 0x01, 0x18, 0x06), -GEN_VXFORM_300_EO(vnegd, 0x01, 0x18, 0x07), GEN_VXFORM_300_EO(vctzb, 0x01, 0x18, 0x1C), GEN_VXFORM_300_EO(vctzh, 0x01, 0x18, 0x1D), GEN_VXFORM_300_EO(vctzw, 0x01, 0x18, 0x1E), -- cgit v1.1 From d57fbd8fd9ea4f559cf4ed6c8fb6f064b73d6882 Mon Sep 17 00:00:00 2001 From: "Lucas Mateus Castro (alqotel)" Date: Wed, 19 Oct 2022 09:50:33 -0300 Subject: target/ppc: Move VPRTYB[WDQ] to decodetree and use gvec Moved VPRTYBW and VPRTYBD to use gvec and both of them and VPRTYBQ to decodetree. VPRTYBW and VPRTYBD now also use .fni4 and .fni8, respectively. vprtybw: rept loop master patch 8 12500 0,01198900 0,00703100 (-41.4%) 25 4000 0,01070100 0,00571400 (-46.6%) 100 1000 0,01123300 0,00678200 (-39.6%) 500 200 0,01601500 0,01535600 (-4.1%) 2500 40 0,03872900 0,05562100 (43.6%) 8000 12 0,10047000 0,16643000 (65.7%) vprtybd: rept loop master patch 8 12500 0,00757700 0,00788100 (4.0%) 25 4000 0,00652500 0,00669600 (2.6%) 100 1000 0,00714400 0,00825400 (15.5%) 500 200 0,01211000 0,01903700 (57.2%) 2500 40 0,03483800 0,07021200 (101.5%) 8000 12 0,09591800 0,21036200 (119.3%) vprtybq: rept loop master patch 8 12500 0,00675600 0,00667200 (-1.2%) 25 4000 0,00619400 0,00643200 (3.8%) 100 1000 0,00707100 0,00751100 (6.2%) 500 200 0,01199300 0,01342000 (11.9%) 2500 40 0,03490900 0,04092900 (17.2%) 8000 12 0,09588200 0,11465100 (19.6%) I wasn't expecting such a performance lost in both VPRTYBD and VPRTYBQ, I'm not sure if it's worth to move those instructions. Comparing the assembly of the helper with the TCGop they are pretty similar, so I'm not sure why vprtybd took so much more time. Signed-off-by: Lucas Mateus Castro (alqotel) Reviewed-by: Richard Henderson Message-Id: <20221019125040.48028-6-lucas.araujo@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/helper.h | 4 +-- target/ppc/insn32.decode | 4 +++ target/ppc/int_helper.c | 25 +------------- target/ppc/translate/vmx-impl.c.inc | 68 +++++++++++++++++++++++++++++++++++-- target/ppc/translate/vmx-ops.c.inc | 3 -- 5 files changed, 71 insertions(+), 33 deletions(-) (limited to 'target') diff --git a/target/ppc/helper.h b/target/ppc/helper.h index b2e910b..a06193b 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -193,9 +193,7 @@ DEF_HELPER_FLAGS_3(vslo, TCG_CALL_NO_RWG, void, avr, avr, avr) DEF_HELPER_FLAGS_3(vsro, TCG_CALL_NO_RWG, void, avr, avr, avr) DEF_HELPER_FLAGS_3(vsrv, TCG_CALL_NO_RWG, void, avr, avr, avr) DEF_HELPER_FLAGS_3(vslv, TCG_CALL_NO_RWG, void, avr, avr, avr) -DEF_HELPER_FLAGS_2(vprtybw, TCG_CALL_NO_RWG, void, avr, avr) -DEF_HELPER_FLAGS_2(vprtybd, TCG_CALL_NO_RWG, void, avr, avr) -DEF_HELPER_FLAGS_2(vprtybq, TCG_CALL_NO_RWG, void, avr, avr) +DEF_HELPER_FLAGS_3(VPRTYBQ, TCG_CALL_NO_RWG, void, avr, avr, i32) DEF_HELPER_FLAGS_5(vaddsbs, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32) DEF_HELPER_FLAGS_5(vaddshs, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32) DEF_HELPER_FLAGS_5(vaddsws, TCG_CALL_NO_RWG, void, avr, avr, avr, avr, i32) diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode index 2fafde0..b05c89e 100644 --- a/target/ppc/insn32.decode +++ b/target/ppc/insn32.decode @@ -529,6 +529,10 @@ VCTZDM 000100 ..... ..... ..... 11111000100 @VX VPDEPD 000100 ..... ..... ..... 10111001101 @VX VPEXTD 000100 ..... ..... ..... 10110001101 @VX +VPRTYBD 000100 ..... 01001 ..... 11000000010 @VX_tb +VPRTYBQ 000100 ..... 01010 ..... 11000000010 @VX_tb +VPRTYBW 000100 ..... 01000 ..... 11000000010 @VX_tb + ## Vector Permute and Formatting Instruction VEXTDUBVLX 000100 ..... ..... ..... ..... 011000 @VA diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c index c7fd0d1..c6ce466 100644 --- a/target/ppc/int_helper.c +++ b/target/ppc/int_helper.c @@ -492,31 +492,8 @@ static inline void set_vscr_sat(CPUPPCState *env) env->vscr_sat.u32[0] = 1; } -/* vprtybw */ -void helper_vprtybw(ppc_avr_t *r, ppc_avr_t *b) -{ - int i; - for (i = 0; i < ARRAY_SIZE(r->u32); i++) { - uint64_t res = b->u32[i] ^ (b->u32[i] >> 16); - res ^= res >> 8; - r->u32[i] = res & 1; - } -} - -/* vprtybd */ -void helper_vprtybd(ppc_avr_t *r, ppc_avr_t *b) -{ - int i; - for (i = 0; i < ARRAY_SIZE(r->u64); i++) { - uint64_t res = b->u64[i] ^ (b->u64[i] >> 32); - res ^= res >> 16; - res ^= res >> 8; - r->u64[i] = res & 1; - } -} - /* vprtybq */ -void helper_vprtybq(ppc_avr_t *r, ppc_avr_t *b) +void helper_VPRTYBQ(ppc_avr_t *r, ppc_avr_t *b, uint32_t v) { uint64_t res = b->u64[0] ^ b->u64[1]; res ^= res >> 32; diff --git a/target/ppc/translate/vmx-impl.c.inc b/target/ppc/translate/vmx-impl.c.inc index b9a9e83..cbb2a3e 100644 --- a/target/ppc/translate/vmx-impl.c.inc +++ b/target/ppc/translate/vmx-impl.c.inc @@ -1659,9 +1659,71 @@ GEN_VXFORM_NOA_ENV(vrfim, 5, 11); GEN_VXFORM_NOA_ENV(vrfin, 5, 8); GEN_VXFORM_NOA_ENV(vrfip, 5, 10); GEN_VXFORM_NOA_ENV(vrfiz, 5, 9); -GEN_VXFORM_NOA(vprtybw, 1, 24); -GEN_VXFORM_NOA(vprtybd, 1, 24); -GEN_VXFORM_NOA(vprtybq, 1, 24); + +static void gen_vprtyb_vec(unsigned vece, TCGv_vec t, TCGv_vec b) +{ + int i; + TCGv_vec tmp = tcg_temp_new_vec_matching(b); + /* MO_32 is 2, so 2 iteractions for MO_32 and 3 for MO_64 */ + for (i = 0; i < vece; i++) { + tcg_gen_shri_vec(vece, tmp, b, (4 << (vece - i))); + tcg_gen_xor_vec(vece, b, tmp, b); + } + tcg_gen_and_vec(vece, t, b, tcg_constant_vec_matching(t, vece, 1)); + tcg_temp_free_vec(tmp); +} + +/* vprtybw */ +static void gen_vprtyb_i32(TCGv_i32 t, TCGv_i32 b) +{ + tcg_gen_ctpop_i32(t, b); + tcg_gen_and_i32(t, t, tcg_constant_i32(1)); +} + +/* vprtybd */ +static void gen_vprtyb_i64(TCGv_i64 t, TCGv_i64 b) +{ + tcg_gen_ctpop_i64(t, b); + tcg_gen_and_i64(t, t, tcg_constant_i64(1)); +} + +static bool do_vx_vprtyb(DisasContext *ctx, arg_VX_tb *a, unsigned vece) +{ + static const TCGOpcode vecop_list[] = { + INDEX_op_shri_vec, 0 + }; + + static const GVecGen2 op[] = { + { + .fniv = gen_vprtyb_vec, + .fni4 = gen_vprtyb_i32, + .opt_opc = vecop_list, + .vece = MO_32 + }, + { + .fniv = gen_vprtyb_vec, + .fni8 = gen_vprtyb_i64, + .opt_opc = vecop_list, + .vece = MO_64 + }, + { + .fno = gen_helper_VPRTYBQ, + .vece = MO_128 + }, + }; + + REQUIRE_INSNS_FLAGS2(ctx, ISA300); + REQUIRE_VECTOR(ctx); + + tcg_gen_gvec_2(avr_full_offset(a->vrt), avr_full_offset(a->vrb), + 16, 16, &op[vece - MO_32]); + + return true; +} + +TRANS(VPRTYBW, do_vx_vprtyb, MO_32) +TRANS(VPRTYBD, do_vx_vprtyb, MO_64) +TRANS(VPRTYBQ, do_vx_vprtyb, MO_128) static void gen_vsplt(DisasContext *ctx, int vece) { diff --git a/target/ppc/translate/vmx-ops.c.inc b/target/ppc/translate/vmx-ops.c.inc index 2790853..46a620a 100644 --- a/target/ppc/translate/vmx-ops.c.inc +++ b/target/ppc/translate/vmx-ops.c.inc @@ -106,9 +106,6 @@ GEN_VXFORM_300(vsrv, 2, 28), GEN_VXFORM_300(vslv, 2, 29), GEN_VXFORM(vslo, 6, 16), GEN_VXFORM(vsro, 6, 17), -GEN_HANDLER_E_2(vprtybw, 0x4, 0x1, 0x18, 8, 0, PPC_NONE, PPC2_ISA300), -GEN_HANDLER_E_2(vprtybd, 0x4, 0x1, 0x18, 9, 0, PPC_NONE, PPC2_ISA300), -GEN_HANDLER_E_2(vprtybq, 0x4, 0x1, 0x18, 10, 0, PPC_NONE, PPC2_ISA300), GEN_VXFORM(xpnd04_1, 0, 22), GEN_VXFORM_300(bcdsr, 0, 23), -- cgit v1.1 From c85929b2ddf6bbad737635c9b85213007ec043af Mon Sep 17 00:00:00 2001 From: "Lucas Mateus Castro (alqotel)" Date: Wed, 19 Oct 2022 09:50:34 -0300 Subject: target/ppc: Move VAVG[SU][BHW] to decodetree and use gvec Moved the instructions VAVGUB, VAVGUH, VAVGUW, VAVGSB, VAVGSH, VAVGSW, to decodetree and use gvec with them. For these one the right shift had to be made before the sum as to avoid an overflow, so add 1 at the end if any of the entries had 1 in its LSB as to replicate the "+ 1" before the shift described by the ISA. vavgub: rept loop master patch 8 12500 0,02616600 0,00754200 (-71.2%) 25 4000 0,02530000 0,00637700 (-74.8%) 100 1000 0,02604600 0,00790100 (-69.7%) 500 200 0,03189300 0,01838400 (-42.4%) 2500 40 0,06006900 0,06851000 (+14.1%) 8000 12 0,13941000 0,20548500 (+47.4%) vavguh: rept loop master patch 8 12500 0,01818200 0,00780600 (-57.1%) 25 4000 0,01789300 0,00641600 (-64.1%) 100 1000 0,01899100 0,00787200 (-58.5%) 500 200 0,02527200 0,01828400 (-27.7%) 2500 40 0,05361800 0,06773000 (+26.3%) 8000 12 0,12886600 0,20291400 (+57.5%) vavguw: rept loop master patch 8 12500 0,01423100 0,00776600 (-45.4%) 25 4000 0,01780800 0,00638600 (-64.1%) 100 1000 0,02085500 0,00787000 (-62.3%) 500 200 0,02737100 0,01828800 (-33.2%) 2500 40 0,05572600 0,06774200 (+21.6%) 8000 12 0,13101700 0,20311600 (+55.0%) vavgsb: rept loop master patch 8 12500 0,03006000 0,00788600 (-73.8%) 25 4000 0,02882200 0,00637800 (-77.9%) 100 1000 0,02958000 0,00791400 (-73.2%) 500 200 0,03548800 0,01860400 (-47.6%) 2500 40 0,06360000 0,06850800 (+7.7%) 8000 12 0,13816500 0,20550300 (+48.7%) vavgsh: rept loop master patch 8 12500 0,01965900 0,00776600 (-60.5%) 25 4000 0,01875400 0,00638700 (-65.9%) 100 1000 0,01952200 0,00786900 (-59.7%) 500 200 0,02562000 0,01760300 (-31.3%) 2500 40 0,05384300 0,06742800 (+25.2%) 8000 12 0,13240800 0,20330000 (+53.5%) vavgsw: rept loop master patch 8 12500 0,01407700 0,00775600 (-44.9%) 25 4000 0,01762300 0,00640000 (-63.7%) 100 1000 0,02046500 0,00788500 (-61.5%) 500 200 0,02745600 0,01843000 (-32.9%) 2500 40 0,05375500 0,06820500 (+26.9%) 8000 12 0,13068300 0,20304900 (+55.4%) These results to me seems to indicate that with gvec the results have a slower translation but faster execution. Signed-off-by: Lucas Mateus Castro (alqotel) Reviewed-by: Richard Henderson Message-Id: <20221019125040.48028-7-lucas.araujo@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/helper.h | 12 ++-- target/ppc/insn32.decode | 9 +++ target/ppc/int_helper.c | 32 +++++------ target/ppc/translate/vmx-impl.c.inc | 106 ++++++++++++++++++++++++++++++++---- target/ppc/translate/vmx-ops.c.inc | 9 +-- 5 files changed, 127 insertions(+), 41 deletions(-) (limited to 'target') diff --git a/target/ppc/helper.h b/target/ppc/helper.h index a06193b..71c22ef 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -143,15 +143,15 @@ DEF_HELPER_FLAGS_1(ftsqrt, TCG_CALL_NO_RWG_SE, i32, i64) #define dh_ctype_acc ppc_acc_t * #define dh_typecode_acc dh_typecode_ptr -DEF_HELPER_FLAGS_3(vavgub, TCG_CALL_NO_RWG, void, avr, avr, avr) -DEF_HELPER_FLAGS_3(vavguh, TCG_CALL_NO_RWG, void, avr, avr, avr) -DEF_HELPER_FLAGS_3(vavguw, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_4(VAVGUB, TCG_CALL_NO_RWG, void, avr, avr, avr, i32) +DEF_HELPER_FLAGS_4(VAVGUH, TCG_CALL_NO_RWG, void, avr, avr, avr, i32) +DEF_HELPER_FLAGS_4(VAVGUW, TCG_CALL_NO_RWG, void, avr, avr, avr, i32) DEF_HELPER_FLAGS_3(vabsdub, TCG_CALL_NO_RWG, void, avr, avr, avr) DEF_HELPER_FLAGS_3(vabsduh, TCG_CALL_NO_RWG, void, avr, avr, avr) DEF_HELPER_FLAGS_3(vabsduw, TCG_CALL_NO_RWG, void, avr, avr, avr) -DEF_HELPER_FLAGS_3(vavgsb, TCG_CALL_NO_RWG, void, avr, avr, avr) -DEF_HELPER_FLAGS_3(vavgsh, TCG_CALL_NO_RWG, void, avr, avr, avr) -DEF_HELPER_FLAGS_3(vavgsw, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_4(VAVGSB, TCG_CALL_NO_RWG, void, avr, avr, avr, i32) +DEF_HELPER_FLAGS_4(VAVGSH, TCG_CALL_NO_RWG, void, avr, avr, avr, i32) +DEF_HELPER_FLAGS_4(VAVGSW, TCG_CALL_NO_RWG, void, avr, avr, avr, i32) DEF_HELPER_4(vcmpeqfp, void, env, avr, avr, avr) DEF_HELPER_4(vcmpgefp, void, env, avr, avr, avr) DEF_HELPER_4(vcmpgtfp, void, env, avr, avr, avr) diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode index b05c89e..53dd45b 100644 --- a/target/ppc/insn32.decode +++ b/target/ppc/insn32.decode @@ -519,6 +519,15 @@ VCMPNEZW 000100 ..... ..... ..... . 0110000111 @VC VCMPSQ 000100 ... -- ..... ..... 00101000001 @VX_bf VCMPUQ 000100 ... -- ..... ..... 00100000001 @VX_bf +## Vector Integer Average Instructions + +VAVGSB 000100 ..... ..... ..... 10100000010 @VX +VAVGSH 000100 ..... ..... ..... 10101000010 @VX +VAVGSW 000100 ..... ..... ..... 10110000010 @VX +VAVGUB 000100 ..... ..... ..... 10000000010 @VX +VAVGUH 000100 ..... ..... ..... 10001000010 @VX +VAVGUW 000100 ..... ..... ..... 10010000010 @VX + ## Vector Bit Manipulation Instruction VGNB 000100 ..... -- ... ..... 10011001100 @VX_n diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c index c6ce466..bda76e5 100644 --- a/target/ppc/int_helper.c +++ b/target/ppc/int_helper.c @@ -570,25 +570,23 @@ VARITHSAT_UNSIGNED(w, u32, uint64_t, cvtsduw) #undef VARITHSAT_SIGNED #undef VARITHSAT_UNSIGNED -#define VAVG_DO(name, element, etype) \ - void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ - { \ - int i; \ - \ - for (i = 0; i < ARRAY_SIZE(r->element); i++) { \ - etype x = (etype)a->element[i] + (etype)b->element[i] + 1; \ - r->element[i] = x >> 1; \ - } \ +#define VAVG(name, element, etype) \ + void helper_##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t v)\ + { \ + int i; \ + \ + for (i = 0; i < ARRAY_SIZE(r->element); i++) { \ + etype x = (etype)a->element[i] + (etype)b->element[i] + 1; \ + r->element[i] = x >> 1; \ + } \ } -#define VAVG(type, signed_element, signed_type, unsigned_element, \ - unsigned_type) \ - VAVG_DO(avgs##type, signed_element, signed_type) \ - VAVG_DO(avgu##type, unsigned_element, unsigned_type) -VAVG(b, s8, int16_t, u8, uint16_t) -VAVG(h, s16, int32_t, u16, uint32_t) -VAVG(w, s32, int64_t, u32, uint64_t) -#undef VAVG_DO +VAVG(VAVGSB, s8, int16_t) +VAVG(VAVGUB, u8, uint16_t) +VAVG(VAVGSH, s16, int32_t) +VAVG(VAVGUH, u16, uint32_t) +VAVG(VAVGSW, s32, int64_t) +VAVG(VAVGUW, u32, uint64_t) #undef VAVG #define VABSDU_DO(name, element) \ diff --git a/target/ppc/translate/vmx-impl.c.inc b/target/ppc/translate/vmx-impl.c.inc index cbb2a3e..195c601 100644 --- a/target/ppc/translate/vmx-impl.c.inc +++ b/target/ppc/translate/vmx-impl.c.inc @@ -431,21 +431,9 @@ GEN_VXFORM_V(vminsb, MO_8, tcg_gen_gvec_smin, 1, 12); GEN_VXFORM_V(vminsh, MO_16, tcg_gen_gvec_smin, 1, 13); GEN_VXFORM_V(vminsw, MO_32, tcg_gen_gvec_smin, 1, 14); GEN_VXFORM_V(vminsd, MO_64, tcg_gen_gvec_smin, 1, 15); -GEN_VXFORM(vavgub, 1, 16); GEN_VXFORM(vabsdub, 1, 16); -GEN_VXFORM_DUAL(vavgub, PPC_ALTIVEC, PPC_NONE, \ - vabsdub, PPC_NONE, PPC2_ISA300) -GEN_VXFORM(vavguh, 1, 17); GEN_VXFORM(vabsduh, 1, 17); -GEN_VXFORM_DUAL(vavguh, PPC_ALTIVEC, PPC_NONE, \ - vabsduh, PPC_NONE, PPC2_ISA300) -GEN_VXFORM(vavguw, 1, 18); GEN_VXFORM(vabsduw, 1, 18); -GEN_VXFORM_DUAL(vavguw, PPC_ALTIVEC, PPC_NONE, \ - vabsduw, PPC_NONE, PPC2_ISA300) -GEN_VXFORM(vavgsb, 1, 20); -GEN_VXFORM(vavgsh, 1, 21); -GEN_VXFORM(vavgsw, 1, 22); GEN_VXFORM(vmrghb, 6, 0); GEN_VXFORM(vmrghh, 6, 1); GEN_VXFORM(vmrghw, 6, 2); @@ -3373,6 +3361,100 @@ TRANS(VMULHSD, do_vx_mulh, true , do_vx_vmulhd_i64) TRANS(VMULHUW, do_vx_mulh, false, do_vx_vmulhw_i64) TRANS(VMULHUD, do_vx_mulh, false, do_vx_vmulhd_i64) +static void do_vavg(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b, + void (*gen_shr_vec)(unsigned, TCGv_vec, TCGv_vec, int64_t)) +{ + TCGv_vec tmp = tcg_temp_new_vec_matching(t); + tcg_gen_or_vec(vece, tmp, a, b); + tcg_gen_and_vec(vece, tmp, tmp, tcg_constant_vec_matching(t, vece, 1)); + gen_shr_vec(vece, a, a, 1); + gen_shr_vec(vece, b, b, 1); + tcg_gen_add_vec(vece, t, a, b); + tcg_gen_add_vec(vece, t, t, tmp); + tcg_temp_free_vec(tmp); +} + +QEMU_FLATTEN +static void gen_vavgu(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +{ + do_vavg(vece, t, a, b, tcg_gen_shri_vec); +} + +QEMU_FLATTEN +static void gen_vavgs(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +{ + do_vavg(vece, t, a, b, tcg_gen_sari_vec); +} + +static bool do_vx_vavg(DisasContext *ctx, arg_VX *a, int sign, int vece) +{ + static const TCGOpcode vecop_list_s[] = { + INDEX_op_add_vec, INDEX_op_sari_vec, 0 + }; + static const TCGOpcode vecop_list_u[] = { + INDEX_op_add_vec, INDEX_op_shri_vec, 0 + }; + + static const GVecGen3 op[2][3] = { + { + { + .fniv = gen_vavgu, + .fno = gen_helper_VAVGUB, + .opt_opc = vecop_list_u, + .vece = MO_8 + }, + { + .fniv = gen_vavgu, + .fno = gen_helper_VAVGUH, + .opt_opc = vecop_list_u, + .vece = MO_16 + }, + { + .fniv = gen_vavgu, + .fno = gen_helper_VAVGUW, + .opt_opc = vecop_list_u, + .vece = MO_32 + }, + }, + { + { + .fniv = gen_vavgs, + .fno = gen_helper_VAVGSB, + .opt_opc = vecop_list_s, + .vece = MO_8 + }, + { + .fniv = gen_vavgs, + .fno = gen_helper_VAVGSH, + .opt_opc = vecop_list_s, + .vece = MO_16 + }, + { + .fniv = gen_vavgs, + .fno = gen_helper_VAVGSW, + .opt_opc = vecop_list_s, + .vece = MO_32 + }, + }, + }; + + REQUIRE_VECTOR(ctx); + + tcg_gen_gvec_3(avr_full_offset(a->vrt), avr_full_offset(a->vra), + avr_full_offset(a->vrb), 16, 16, &op[sign][vece]); + + + return true; +} + + +TRANS_FLAGS(ALTIVEC, VAVGSB, do_vx_vavg, 1, MO_8) +TRANS_FLAGS(ALTIVEC, VAVGSH, do_vx_vavg, 1, MO_16) +TRANS_FLAGS(ALTIVEC, VAVGSW, do_vx_vavg, 1, MO_32) +TRANS_FLAGS(ALTIVEC, VAVGUB, do_vx_vavg, 0, MO_8) +TRANS_FLAGS(ALTIVEC, VAVGUH, do_vx_vavg, 0, MO_16) +TRANS_FLAGS(ALTIVEC, VAVGUW, do_vx_vavg, 0, MO_32) + static bool do_vdiv_vmod(DisasContext *ctx, arg_VX *a, const int vece, void (*func_32)(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b), void (*func_64)(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b)) diff --git a/target/ppc/translate/vmx-ops.c.inc b/target/ppc/translate/vmx-ops.c.inc index 46a620a..02db51d 100644 --- a/target/ppc/translate/vmx-ops.c.inc +++ b/target/ppc/translate/vmx-ops.c.inc @@ -83,12 +83,9 @@ GEN_VXFORM(vminsb, 1, 12), GEN_VXFORM(vminsh, 1, 13), GEN_VXFORM(vminsw, 1, 14), GEN_VXFORM_207(vminsd, 1, 15), -GEN_VXFORM_DUAL(vavgub, vabsdub, 1, 16, PPC_ALTIVEC, PPC_NONE), -GEN_VXFORM_DUAL(vavguh, vabsduh, 1, 17, PPC_ALTIVEC, PPC_NONE), -GEN_VXFORM_DUAL(vavguw, vabsduw, 1, 18, PPC_ALTIVEC, PPC_NONE), -GEN_VXFORM(vavgsb, 1, 20), -GEN_VXFORM(vavgsh, 1, 21), -GEN_VXFORM(vavgsw, 1, 22), +GEN_VXFORM(vabsdub, 1, 16), +GEN_VXFORM(vabsduh, 1, 17), +GEN_VXFORM(vabsduw, 1, 18), GEN_VXFORM(vmrghb, 6, 0), GEN_VXFORM(vmrghh, 6, 1), GEN_VXFORM(vmrghw, 6, 2), -- cgit v1.1 From 26c964f85159c78f6ecf132de8f2f0093d3f2e89 Mon Sep 17 00:00:00 2001 From: "Lucas Mateus Castro (alqotel)" Date: Wed, 19 Oct 2022 09:50:35 -0300 Subject: target/ppc: Move VABSDU[BHW] to decodetree and use gvec Moved VABSDUB, VABSDUH and VABSDUW to decodetree and use gvec to translate them. vabsdub: rept loop master patch 8 12500 0,03601600 0,00688500 (-80.9%) 25 4000 0,03651000 0,00532100 (-85.4%) 100 1000 0,03666900 0,00595300 (-83.8%) 500 200 0,04305800 0,01244600 (-71.1%) 2500 40 0,06893300 0,04273700 (-38.0%) 8000 12 0,14633200 0,12660300 (-13.5%) vabsduh: rept loop master patch 8 12500 0,02172400 0,00687500 (-68.4%) 25 4000 0,02154100 0,00531500 (-75.3%) 100 1000 0,02235400 0,00596300 (-73.3%) 500 200 0,02827500 0,01245100 (-56.0%) 2500 40 0,05638400 0,04285500 (-24.0%) 8000 12 0,13166000 0,12641400 (-4.0%) vabsduw: rept loop master patch 8 12500 0,01646400 0,00688300 (-58.2%) 25 4000 0,01454500 0,00475500 (-67.3%) 100 1000 0,01545800 0,00511800 (-66.9%) 500 200 0,02168200 0,01114300 (-48.6%) 2500 40 0,04571300 0,04138800 (-9.5%) 8000 12 0,12209500 0,12178500 (-0.3%) Same as VADDCUW and VSUBCUW, overall performance gain but it uses more TCGop (4 before the patch, 6 after). Signed-off-by: Lucas Mateus Castro (alqotel) Reviewed-by: Richard Henderson Message-Id: <20221019125040.48028-8-lucas.araujo@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/helper.h | 6 ++--- target/ppc/insn32.decode | 6 +++++ target/ppc/int_helper.c | 13 ++++------ target/ppc/translate/vmx-impl.c.inc | 49 ++++++++++++++++++++++++++++++++++--- target/ppc/translate/vmx-ops.c.inc | 3 --- 5 files changed, 60 insertions(+), 17 deletions(-) (limited to 'target') diff --git a/target/ppc/helper.h b/target/ppc/helper.h index 71c22ef..fd8280d 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -146,9 +146,9 @@ DEF_HELPER_FLAGS_1(ftsqrt, TCG_CALL_NO_RWG_SE, i32, i64) DEF_HELPER_FLAGS_4(VAVGUB, TCG_CALL_NO_RWG, void, avr, avr, avr, i32) DEF_HELPER_FLAGS_4(VAVGUH, TCG_CALL_NO_RWG, void, avr, avr, avr, i32) DEF_HELPER_FLAGS_4(VAVGUW, TCG_CALL_NO_RWG, void, avr, avr, avr, i32) -DEF_HELPER_FLAGS_3(vabsdub, TCG_CALL_NO_RWG, void, avr, avr, avr) -DEF_HELPER_FLAGS_3(vabsduh, TCG_CALL_NO_RWG, void, avr, avr, avr) -DEF_HELPER_FLAGS_3(vabsduw, TCG_CALL_NO_RWG, void, avr, avr, avr) +DEF_HELPER_FLAGS_4(VABSDUB, TCG_CALL_NO_RWG, void, avr, avr, avr, i32) +DEF_HELPER_FLAGS_4(VABSDUH, TCG_CALL_NO_RWG, void, avr, avr, avr, i32) +DEF_HELPER_FLAGS_4(VABSDUW, TCG_CALL_NO_RWG, void, avr, avr, avr, i32) DEF_HELPER_FLAGS_4(VAVGSB, TCG_CALL_NO_RWG, void, avr, avr, avr, i32) DEF_HELPER_FLAGS_4(VAVGSH, TCG_CALL_NO_RWG, void, avr, avr, avr, i32) DEF_HELPER_FLAGS_4(VAVGSW, TCG_CALL_NO_RWG, void, avr, avr, avr, i32) diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode index 53dd45b..1214af7 100644 --- a/target/ppc/insn32.decode +++ b/target/ppc/insn32.decode @@ -528,6 +528,12 @@ VAVGUB 000100 ..... ..... ..... 10000000010 @VX VAVGUH 000100 ..... ..... ..... 10001000010 @VX VAVGUW 000100 ..... ..... ..... 10010000010 @VX +## Vector Integer Absolute Difference Instructions + +VABSDUB 000100 ..... ..... ..... 10000000011 @VX +VABSDUH 000100 ..... ..... ..... 10001000011 @VX +VABSDUW 000100 ..... ..... ..... 10010000011 @VX + ## Vector Bit Manipulation Instruction VGNB 000100 ..... -- ... ..... 10011001100 @VX_n diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c index bda76e5..d97a7f1 100644 --- a/target/ppc/int_helper.c +++ b/target/ppc/int_helper.c @@ -589,8 +589,8 @@ VAVG(VAVGSW, s32, int64_t) VAVG(VAVGUW, u32, uint64_t) #undef VAVG -#define VABSDU_DO(name, element) \ -void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ +#define VABSDU(name, element) \ +void helper_##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t v)\ { \ int i; \ \ @@ -606,12 +606,9 @@ void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \ * name - instruction mnemonic suffix (b: byte, h: halfword, w: word) * element - element type to access from vector */ -#define VABSDU(type, element) \ - VABSDU_DO(absdu##type, element) -VABSDU(b, u8) -VABSDU(h, u16) -VABSDU(w, u32) -#undef VABSDU_DO +VABSDU(VABSDUB, u8) +VABSDU(VABSDUH, u16) +VABSDU(VABSDUW, u32) #undef VABSDU #define VCF(suffix, cvt, element) \ diff --git a/target/ppc/translate/vmx-impl.c.inc b/target/ppc/translate/vmx-impl.c.inc index 195c601..7741f2e 100644 --- a/target/ppc/translate/vmx-impl.c.inc +++ b/target/ppc/translate/vmx-impl.c.inc @@ -431,9 +431,6 @@ GEN_VXFORM_V(vminsb, MO_8, tcg_gen_gvec_smin, 1, 12); GEN_VXFORM_V(vminsh, MO_16, tcg_gen_gvec_smin, 1, 13); GEN_VXFORM_V(vminsw, MO_32, tcg_gen_gvec_smin, 1, 14); GEN_VXFORM_V(vminsd, MO_64, tcg_gen_gvec_smin, 1, 15); -GEN_VXFORM(vabsdub, 1, 16); -GEN_VXFORM(vabsduh, 1, 17); -GEN_VXFORM(vabsduw, 1, 18); GEN_VXFORM(vmrghb, 6, 0); GEN_VXFORM(vmrghh, 6, 1); GEN_VXFORM(vmrghw, 6, 2); @@ -3455,6 +3452,52 @@ TRANS_FLAGS(ALTIVEC, VAVGUB, do_vx_vavg, 0, MO_8) TRANS_FLAGS(ALTIVEC, VAVGUH, do_vx_vavg, 0, MO_16) TRANS_FLAGS(ALTIVEC, VAVGUW, do_vx_vavg, 0, MO_32) +static void gen_vabsdu(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +{ + tcg_gen_umax_vec(vece, t, a, b); + tcg_gen_umin_vec(vece, a, a, b); + tcg_gen_sub_vec(vece, t, t, a); +} + +static bool do_vabsdu(DisasContext *ctx, arg_VX *a, const int vece) +{ + static const TCGOpcode vecop_list[] = { + INDEX_op_umax_vec, INDEX_op_umin_vec, INDEX_op_sub_vec, 0 + }; + + static const GVecGen3 op[] = { + { + .fniv = gen_vabsdu, + .fno = gen_helper_VABSDUB, + .opt_opc = vecop_list, + .vece = MO_8 + }, + { + .fniv = gen_vabsdu, + .fno = gen_helper_VABSDUH, + .opt_opc = vecop_list, + .vece = MO_16 + }, + { + .fniv = gen_vabsdu, + .fno = gen_helper_VABSDUW, + .opt_opc = vecop_list, + .vece = MO_32 + }, + }; + + REQUIRE_VECTOR(ctx); + + tcg_gen_gvec_3(avr_full_offset(a->vrt), avr_full_offset(a->vra), + avr_full_offset(a->vrb), 16, 16, &op[vece]); + + return true; +} + +TRANS_FLAGS2(ISA300, VABSDUB, do_vabsdu, MO_8) +TRANS_FLAGS2(ISA300, VABSDUH, do_vabsdu, MO_16) +TRANS_FLAGS2(ISA300, VABSDUW, do_vabsdu, MO_32) + static bool do_vdiv_vmod(DisasContext *ctx, arg_VX *a, const int vece, void (*func_32)(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b), void (*func_64)(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b)) diff --git a/target/ppc/translate/vmx-ops.c.inc b/target/ppc/translate/vmx-ops.c.inc index 02db51d..33fec8a 100644 --- a/target/ppc/translate/vmx-ops.c.inc +++ b/target/ppc/translate/vmx-ops.c.inc @@ -83,9 +83,6 @@ GEN_VXFORM(vminsb, 1, 12), GEN_VXFORM(vminsh, 1, 13), GEN_VXFORM(vminsw, 1, 14), GEN_VXFORM_207(vminsd, 1, 15), -GEN_VXFORM(vabsdub, 1, 16), -GEN_VXFORM(vabsduh, 1, 17), -GEN_VXFORM(vabsduw, 1, 18), GEN_VXFORM(vmrghb, 6, 0), GEN_VXFORM(vmrghh, 6, 1), GEN_VXFORM(vmrghw, 6, 2), -- cgit v1.1 From a5b36805192ac12f114c45e9c8ccbe4ce9ba1cf9 Mon Sep 17 00:00:00 2001 From: "Lucas Mateus Castro (alqotel)" Date: Wed, 19 Oct 2022 09:50:36 -0300 Subject: target/ppc: Use gvec to decode XV[N]ABS[DS]P/XVNEG[DS]P Moved XVABSSP, XVABSDP, XVNABSSP,XVNABSDP, XVNEGSP and XVNEGDP to decodetree and used gvec to translate them. xvabssp: rept loop master patch 8 12500 0,00477900 0,00476000 (-0.4%) 25 4000 0,00442800 0,00353300 (-20.2%) 100 1000 0,00478700 0,00366100 (-23.5%) 500 200 0,00973200 0,00649400 (-33.3%) 2500 40 0,03165200 0,02226700 (-29.7%) 8000 12 0,09315900 0,06674900 (-28.3%) xvabsdp: rept loop master patch 8 12500 0,00475000 0,00474400 (-0.1%) 25 4000 0,00355600 0,00367500 (+3.3%) 100 1000 0,00444200 0,00366000 (-17.6%) 500 200 0,00942700 0,00732400 (-22.3%) 2500 40 0,02990000 0,02308500 (-22.8%) 8000 12 0,08770300 0,06683800 (-23.8%) xvnabssp: rept loop master patch 8 12500 0,00494500 0,00492900 (-0.3%) 25 4000 0,00397700 0,00338600 (-14.9%) 100 1000 0,00421400 0,00353500 (-16.1%) 500 200 0,01048000 0,00707100 (-32.5%) 2500 40 0,03251500 0,02238300 (-31.2%) 8000 12 0,08889100 0,06469800 (-27.2%) xvnabsdp: rept loop master patch 8 12500 0,00511000 0,00492700 (-3.6%) 25 4000 0,00398800 0,00381500 (-4.3%) 100 1000 0,00390500 0,00365900 (-6.3%) 500 200 0,00924800 0,00784600 (-15.2%) 2500 40 0,03138900 0,02391600 (-23.8%) 8000 12 0,09654200 0,05684600 (-41.1%) xvnegsp: rept loop master patch 8 12500 0,00493900 0,00452800 (-8.3%) 25 4000 0,00369100 0,00366800 (-0.6%) 100 1000 0,00371100 0,00380000 (+2.4%) 500 200 0,00991100 0,00652300 (-34.2%) 2500 40 0,03025800 0,02422300 (-19.9%) 8000 12 0,09251100 0,06457600 (-30.2%) xvnegdp: rept loop master patch 8 12500 0,00474900 0,00454400 (-4.3%) 25 4000 0,00353100 0,00325600 (-7.8%) 100 1000 0,00398600 0,00366800 (-8.0%) 500 200 0,01032300 0,00702400 (-32.0%) 2500 40 0,03125000 0,02422400 (-22.5%) 8000 12 0,09475100 0,06173000 (-34.9%) This one to me seemed the opposite of the previous instructions, as it looks like there was an improvement in the translation time (itself not a surprise as operations were done twice before so there was the need to translate twice as many TCGop) Signed-off-by: Lucas Mateus Castro (alqotel) Reviewed-by: Richard Henderson Message-Id: <20221019125040.48028-9-lucas.araujo@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/insn32.decode | 9 +++++ target/ppc/translate/vsx-impl.c.inc | 73 ++++++++++++++++++++++++++++++++++--- target/ppc/translate/vsx-ops.c.inc | 6 --- 3 files changed, 76 insertions(+), 12 deletions(-) (limited to 'target') diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode index 1214af7..395339c 100644 --- a/target/ppc/insn32.decode +++ b/target/ppc/insn32.decode @@ -754,6 +754,15 @@ STXVRHX 011111 ..... ..... ..... 0010101101 . @X_TSX STXVRWX 011111 ..... ..... ..... 0011001101 . @X_TSX STXVRDX 011111 ..... ..... ..... 0011101101 . @X_TSX +## VSX Vector Binary Floating-Point Sign Manipulation Instructions + +XVABSDP 111100 ..... 00000 ..... 111011001 .. @XX2 +XVABSSP 111100 ..... 00000 ..... 110011001 .. @XX2 +XVNABSDP 111100 ..... 00000 ..... 111101001 .. @XX2 +XVNABSSP 111100 ..... 00000 ..... 110101001 .. @XX2 +XVNEGDP 111100 ..... 00000 ..... 111111001 .. @XX2 +XVNEGSP 111100 ..... 00000 ..... 110111001 .. @XX2 + ## VSX Scalar Multiply-Add Instructions XSMADDADP 111100 ..... ..... ..... 00100001 . . . @XX3 diff --git a/target/ppc/translate/vsx-impl.c.inc b/target/ppc/translate/vsx-impl.c.inc index e6e5c45..8717e20 100644 --- a/target/ppc/translate/vsx-impl.c.inc +++ b/target/ppc/translate/vsx-impl.c.inc @@ -782,15 +782,76 @@ static void glue(gen_, name)(DisasContext *ctx) \ tcg_temp_free_i64(sgm); \ } -VSX_VECTOR_MOVE(xvabsdp, OP_ABS, SGN_MASK_DP) -VSX_VECTOR_MOVE(xvnabsdp, OP_NABS, SGN_MASK_DP) -VSX_VECTOR_MOVE(xvnegdp, OP_NEG, SGN_MASK_DP) VSX_VECTOR_MOVE(xvcpsgndp, OP_CPSGN, SGN_MASK_DP) -VSX_VECTOR_MOVE(xvabssp, OP_ABS, SGN_MASK_SP) -VSX_VECTOR_MOVE(xvnabssp, OP_NABS, SGN_MASK_SP) -VSX_VECTOR_MOVE(xvnegsp, OP_NEG, SGN_MASK_SP) VSX_VECTOR_MOVE(xvcpsgnsp, OP_CPSGN, SGN_MASK_SP) +#define TCG_OP_IMM_i64(FUNC, OP, IMM) \ + static void FUNC(TCGv_i64 t, TCGv_i64 b) \ + { \ + OP(t, b, IMM); \ + } + +TCG_OP_IMM_i64(do_xvabssp_i64, tcg_gen_andi_i64, ~SGN_MASK_SP) +TCG_OP_IMM_i64(do_xvnabssp_i64, tcg_gen_ori_i64, SGN_MASK_SP) +TCG_OP_IMM_i64(do_xvnegsp_i64, tcg_gen_xori_i64, SGN_MASK_SP) +TCG_OP_IMM_i64(do_xvabsdp_i64, tcg_gen_andi_i64, ~SGN_MASK_DP) +TCG_OP_IMM_i64(do_xvnabsdp_i64, tcg_gen_ori_i64, SGN_MASK_DP) +TCG_OP_IMM_i64(do_xvnegdp_i64, tcg_gen_xori_i64, SGN_MASK_DP) +#undef TCG_OP_IMM_i64 + +static void xv_msb_op1(unsigned vece, TCGv_vec t, TCGv_vec b, + void (*tcg_gen_op_vec)(unsigned, TCGv_vec, TCGv_vec, TCGv_vec)) +{ + uint64_t msb = (vece == MO_32) ? SGN_MASK_SP : SGN_MASK_DP; + tcg_gen_op_vec(vece, t, b, tcg_constant_vec_matching(t, vece, msb)); +} + +static void do_xvabs_vec(unsigned vece, TCGv_vec t, TCGv_vec b) +{ + xv_msb_op1(vece, t, b, tcg_gen_andc_vec); +} + +static void do_xvnabs_vec(unsigned vece, TCGv_vec t, TCGv_vec b) +{ + xv_msb_op1(vece, t, b, tcg_gen_or_vec); +} + +static void do_xvneg_vec(unsigned vece, TCGv_vec t, TCGv_vec b) +{ + xv_msb_op1(vece, t, b, tcg_gen_xor_vec); +} + +static bool do_vsx_msb_op(DisasContext *ctx, arg_XX2 *a, unsigned vece, + void (*vec)(unsigned, TCGv_vec, TCGv_vec), + void (*i64)(TCGv_i64, TCGv_i64)) +{ + static const TCGOpcode vecop_list[] = { + 0 + }; + + const GVecGen2 op = { + .fni8 = i64, + .fniv = vec, + .opt_opc = vecop_list, + .vece = vece + }; + + REQUIRE_INSNS_FLAGS2(ctx, VSX); + REQUIRE_VSX(ctx); + + tcg_gen_gvec_2(vsr_full_offset(a->xt), vsr_full_offset(a->xb), + 16, 16, &op); + + return true; +} + +TRANS(XVABSDP, do_vsx_msb_op, MO_64, do_xvabs_vec, do_xvabsdp_i64) +TRANS(XVNABSDP, do_vsx_msb_op, MO_64, do_xvnabs_vec, do_xvnabsdp_i64) +TRANS(XVNEGDP, do_vsx_msb_op, MO_64, do_xvneg_vec, do_xvnegdp_i64) +TRANS(XVABSSP, do_vsx_msb_op, MO_32, do_xvabs_vec, do_xvabssp_i64) +TRANS(XVNABSSP, do_vsx_msb_op, MO_32, do_xvnabs_vec, do_xvnabssp_i64) +TRANS(XVNEGSP, do_vsx_msb_op, MO_32, do_xvneg_vec, do_xvnegsp_i64) + #define VSX_CMP(name, op1, op2, inval, type) \ static void gen_##name(DisasContext *ctx) \ { \ diff --git a/target/ppc/translate/vsx-ops.c.inc b/target/ppc/translate/vsx-ops.c.inc index bff14bb..b77324e 100644 --- a/target/ppc/translate/vsx-ops.c.inc +++ b/target/ppc/translate/vsx-ops.c.inc @@ -165,13 +165,7 @@ GEN_XX3FORM(name, opc2, opc3 | 1, fl2) GEN_XX2FORM_DCMX(xvtstdcdp, 0x14, 0x1E, PPC2_ISA300), GEN_XX2FORM_DCMX(xvtstdcsp, 0x14, 0x1A, PPC2_ISA300), -GEN_XX2FORM(xvabsdp, 0x12, 0x1D, PPC2_VSX), -GEN_XX2FORM(xvnabsdp, 0x12, 0x1E, PPC2_VSX), -GEN_XX2FORM(xvnegdp, 0x12, 0x1F, PPC2_VSX), GEN_XX3FORM(xvcpsgndp, 0x00, 0x1E, PPC2_VSX), -GEN_XX2FORM(xvabssp, 0x12, 0x19, PPC2_VSX), -GEN_XX2FORM(xvnabssp, 0x12, 0x1A, PPC2_VSX), -GEN_XX2FORM(xvnegsp, 0x12, 0x1B, PPC2_VSX), GEN_XX3FORM(xvcpsgnsp, 0x00, 0x1A, PPC2_VSX), GEN_XX3FORM(xsadddp, 0x00, 0x04, PPC2_VSX), -- cgit v1.1 From 95a89d3118590aaed3a56b52e08246cdb51a108e Mon Sep 17 00:00:00 2001 From: "Lucas Mateus Castro (alqotel)" Date: Wed, 19 Oct 2022 09:50:37 -0300 Subject: target/ppc: Use gvec to decode XVCPSGN[SD]P Moved XVCPSGNSP and XVCPSGNDP to decodetree and used gvec to translate them. xvcpsgnsp: rept loop master patch 8 12500 0,00561400 0,00537900 (-4.2%) 25 4000 0,00562100 0,00400000 (-28.8%) 100 1000 0,00696900 0,00416300 (-40.3%) 500 200 0,02211900 0,00840700 (-62.0%) 2500 40 0,09328600 0,02728300 (-70.8%) 8000 12 0,27295300 0,06867800 (-74.8%) xvcpsgndp: rept loop master patch 8 12500 0,00556300 0,00584200 (+5.0%) 25 4000 0,00482700 0,00431700 (-10.6%) 100 1000 0,00585800 0,00464400 (-20.7%) 500 200 0,01565300 0,00839700 (-46.4%) 2500 40 0,05766500 0,02430600 (-57.8%) 8000 12 0,19875300 0,07947100 (-60.0%) Like the previous instructions there seemed to be a improvement on translation time. Signed-off-by: Lucas Mateus Castro (alqotel) Reviewed-by: Richard Henderson Message-Id: <20221019125040.48028-10-lucas.araujo@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/insn32.decode | 2 + target/ppc/translate/vsx-impl.c.inc | 109 ++++++++++++++++++------------------ target/ppc/translate/vsx-ops.c.inc | 3 - 3 files changed, 55 insertions(+), 59 deletions(-) (limited to 'target') diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode index 395339c..3594c0c 100644 --- a/target/ppc/insn32.decode +++ b/target/ppc/insn32.decode @@ -762,6 +762,8 @@ XVNABSDP 111100 ..... 00000 ..... 111101001 .. @XX2 XVNABSSP 111100 ..... 00000 ..... 110101001 .. @XX2 XVNEGDP 111100 ..... 00000 ..... 111111001 .. @XX2 XVNEGSP 111100 ..... 00000 ..... 110111001 .. @XX2 +XVCPSGNDP 111100 ..... ..... ..... 11110000 ... @XX3 +XVCPSGNSP 111100 ..... ..... ..... 11010000 ... @XX3 ## VSX Scalar Multiply-Add Instructions diff --git a/target/ppc/translate/vsx-impl.c.inc b/target/ppc/translate/vsx-impl.c.inc index 8717e20..1c28923 100644 --- a/target/ppc/translate/vsx-impl.c.inc +++ b/target/ppc/translate/vsx-impl.c.inc @@ -729,62 +729,6 @@ VSX_SCALAR_MOVE_QP(xsnabsqp, OP_NABS, SGN_MASK_DP) VSX_SCALAR_MOVE_QP(xsnegqp, OP_NEG, SGN_MASK_DP) VSX_SCALAR_MOVE_QP(xscpsgnqp, OP_CPSGN, SGN_MASK_DP) -#define VSX_VECTOR_MOVE(name, op, sgn_mask) \ -static void glue(gen_, name)(DisasContext *ctx) \ - { \ - TCGv_i64 xbh, xbl, sgm; \ - if (unlikely(!ctx->vsx_enabled)) { \ - gen_exception(ctx, POWERPC_EXCP_VSXU); \ - return; \ - } \ - xbh = tcg_temp_new_i64(); \ - xbl = tcg_temp_new_i64(); \ - sgm = tcg_temp_new_i64(); \ - get_cpu_vsr(xbh, xB(ctx->opcode), true); \ - get_cpu_vsr(xbl, xB(ctx->opcode), false); \ - tcg_gen_movi_i64(sgm, sgn_mask); \ - switch (op) { \ - case OP_ABS: { \ - tcg_gen_andc_i64(xbh, xbh, sgm); \ - tcg_gen_andc_i64(xbl, xbl, sgm); \ - break; \ - } \ - case OP_NABS: { \ - tcg_gen_or_i64(xbh, xbh, sgm); \ - tcg_gen_or_i64(xbl, xbl, sgm); \ - break; \ - } \ - case OP_NEG: { \ - tcg_gen_xor_i64(xbh, xbh, sgm); \ - tcg_gen_xor_i64(xbl, xbl, sgm); \ - break; \ - } \ - case OP_CPSGN: { \ - TCGv_i64 xah = tcg_temp_new_i64(); \ - TCGv_i64 xal = tcg_temp_new_i64(); \ - get_cpu_vsr(xah, xA(ctx->opcode), true); \ - get_cpu_vsr(xal, xA(ctx->opcode), false); \ - tcg_gen_and_i64(xah, xah, sgm); \ - tcg_gen_and_i64(xal, xal, sgm); \ - tcg_gen_andc_i64(xbh, xbh, sgm); \ - tcg_gen_andc_i64(xbl, xbl, sgm); \ - tcg_gen_or_i64(xbh, xbh, xah); \ - tcg_gen_or_i64(xbl, xbl, xal); \ - tcg_temp_free_i64(xah); \ - tcg_temp_free_i64(xal); \ - break; \ - } \ - } \ - set_cpu_vsr(xT(ctx->opcode), xbh, true); \ - set_cpu_vsr(xT(ctx->opcode), xbl, false); \ - tcg_temp_free_i64(xbh); \ - tcg_temp_free_i64(xbl); \ - tcg_temp_free_i64(sgm); \ - } - -VSX_VECTOR_MOVE(xvcpsgndp, OP_CPSGN, SGN_MASK_DP) -VSX_VECTOR_MOVE(xvcpsgnsp, OP_CPSGN, SGN_MASK_SP) - #define TCG_OP_IMM_i64(FUNC, OP, IMM) \ static void FUNC(TCGv_i64 t, TCGv_i64 b) \ { \ @@ -852,6 +796,59 @@ TRANS(XVABSSP, do_vsx_msb_op, MO_32, do_xvabs_vec, do_xvabssp_i64) TRANS(XVNABSSP, do_vsx_msb_op, MO_32, do_xvnabs_vec, do_xvnabssp_i64) TRANS(XVNEGSP, do_vsx_msb_op, MO_32, do_xvneg_vec, do_xvnegsp_i64) +static void do_xvcpsgndp_i64(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) +{ + tcg_gen_andi_i64(a, a, SGN_MASK_DP); + tcg_gen_andi_i64(b, b, ~SGN_MASK_DP); + tcg_gen_or_i64(t, a, b); +} + +static void do_xvcpsgnsp_i64(TCGv_i64 t, TCGv_i64 a, TCGv_i64 b) +{ + tcg_gen_andi_i64(a, a, SGN_MASK_SP); + tcg_gen_andi_i64(b, b, ~SGN_MASK_SP); + tcg_gen_or_i64(t, a, b); +} + +static void do_xvcpsgn_vec(unsigned vece, TCGv_vec t, TCGv_vec a, TCGv_vec b) +{ + uint64_t msb = (vece == MO_32) ? SGN_MASK_SP : SGN_MASK_DP; + tcg_gen_bitsel_vec(vece, t, tcg_constant_vec_matching(t, vece, msb), a, b); +} + +static bool do_xvcpsgn(DisasContext *ctx, arg_XX3 *a, unsigned vece) +{ + static const TCGOpcode vecop_list[] = { + 0 + }; + + static const GVecGen3 op[] = { + { + .fni8 = do_xvcpsgnsp_i64, + .fniv = do_xvcpsgn_vec, + .opt_opc = vecop_list, + .vece = MO_32 + }, + { + .fni8 = do_xvcpsgndp_i64, + .fniv = do_xvcpsgn_vec, + .opt_opc = vecop_list, + .vece = MO_64 + }, + }; + + REQUIRE_INSNS_FLAGS2(ctx, VSX); + REQUIRE_VSX(ctx); + + tcg_gen_gvec_3(vsr_full_offset(a->xt), vsr_full_offset(a->xa), + vsr_full_offset(a->xb), 16, 16, &op[vece - MO_32]); + + return true; +} + +TRANS(XVCPSGNSP, do_xvcpsgn, MO_32) +TRANS(XVCPSGNDP, do_xvcpsgn, MO_64) + #define VSX_CMP(name, op1, op2, inval, type) \ static void gen_##name(DisasContext *ctx) \ { \ diff --git a/target/ppc/translate/vsx-ops.c.inc b/target/ppc/translate/vsx-ops.c.inc index b77324e..f7d7377 100644 --- a/target/ppc/translate/vsx-ops.c.inc +++ b/target/ppc/translate/vsx-ops.c.inc @@ -165,9 +165,6 @@ GEN_XX3FORM(name, opc2, opc3 | 1, fl2) GEN_XX2FORM_DCMX(xvtstdcdp, 0x14, 0x1E, PPC2_ISA300), GEN_XX2FORM_DCMX(xvtstdcsp, 0x14, 0x1A, PPC2_ISA300), -GEN_XX3FORM(xvcpsgndp, 0x00, 0x1E, PPC2_VSX), -GEN_XX3FORM(xvcpsgnsp, 0x00, 0x1A, PPC2_VSX), - GEN_XX3FORM(xsadddp, 0x00, 0x04, PPC2_VSX), GEN_VSX_XFORM_300(xsaddqp, 0x04, 0x00, 0x0), GEN_XX3FORM(xssubdp, 0x00, 0x05, PPC2_VSX), -- cgit v1.1 From a70a5247104d3d7a8cf584f20d73f41bef643a19 Mon Sep 17 00:00:00 2001 From: "Lucas Mateus Castro (alqotel)" Date: Wed, 19 Oct 2022 09:50:38 -0300 Subject: target/ppc: Moved XVTSTDC[DS]P to decodetree Moved XVTSTDCSP and XVTSTDCDP to decodetree an restructured the helper to be simpler and do all decoding in the decodetree (so XB, XT and DCMX are all calculated outside the helper). Obs: The tests in this one are slightly different, these are the sum of these instructions with all possible immediate and those instructions are repeated 10 times. xvtstdcsp: rept loop master patch 8 12500 2,76402100 2,70699100 (-2.1%) 25 4000 2,64867100 2,67884100 (+1.1%) 100 1000 2,73806300 2,78701000 (+1.8%) 500 200 3,44666500 3,61027600 (+4.7%) 2500 40 5,85790200 6,47475500 (+10.5%) 8000 12 15,22102100 17,46062900 (+14.7%) xvtstdcdp: rept loop master patch 8 12500 2,11818000 1,61065300 (-24.0%) 25 4000 2,04573400 1,60132200 (-21.7%) 100 1000 2,13834100 1,69988100 (-20.5%) 500 200 2,73977000 2,48631700 (-9.3%) 2500 40 5,05067000 5,25914100 (+4.1%) 8000 12 14,60507800 15,93704900 (+9.1%) Signed-off-by: Lucas Mateus Castro (alqotel) Reviewed-by: Richard Henderson Message-Id: <20221019125040.48028-11-lucas.araujo@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/fpu_helper.c | 39 +++++++++++++++++++++++++++++++++++-- target/ppc/helper.h | 4 ++-- target/ppc/insn32.decode | 5 +++++ target/ppc/translate/vsx-impl.c.inc | 28 ++++++++++++++++++++++++-- target/ppc/translate/vsx-ops.c.inc | 8 -------- 5 files changed, 70 insertions(+), 14 deletions(-) (limited to 'target') diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c index ae25f32..960a76a 100644 --- a/target/ppc/fpu_helper.c +++ b/target/ppc/fpu_helper.c @@ -3295,11 +3295,46 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \ } \ } -VSX_TEST_DC(xvtstdcdp, 2, xB(opcode), float64, VsrD(i), VsrD(i), UINT64_MAX, 0) -VSX_TEST_DC(xvtstdcsp, 4, xB(opcode), float32, VsrW(i), VsrW(i), UINT32_MAX, 0) VSX_TEST_DC(xststdcdp, 1, xB(opcode), float64, VsrD(0), VsrD(0), 0, 1) VSX_TEST_DC(xststdcqp, 1, (rB(opcode) + 32), float128, f128, VsrD(0), 0, 1) +#define VSX_TSTDC(tp) \ +static int32_t tp##_tstdc(tp b, uint32_t dcmx) \ +{ \ + uint32_t match = 0; \ + uint32_t sign = tp##_is_neg(b); \ + if (tp##_is_any_nan(b)) { \ + match = extract32(dcmx, 6, 1); \ + } else if (tp##_is_infinity(b)) { \ + match = extract32(dcmx, 4 + !sign, 1); \ + } else if (tp##_is_zero(b)) { \ + match = extract32(dcmx, 2 + !sign, 1); \ + } else if (tp##_is_zero_or_denormal(b)) { \ + match = extract32(dcmx, 0 + !sign, 1); \ + } \ + return (match != 0); \ +} + +VSX_TSTDC(float32) +VSX_TSTDC(float64) +#undef VSX_TSTDC + +void helper_XVTSTDCDP(ppc_vsr_t *t, ppc_vsr_t *b, uint64_t dcmx, uint32_t v) +{ + int i; + for (i = 0; i < 2; i++) { + t->s64[i] = (int64_t)-float64_tstdc(b->f64[i], dcmx); + } +} + +void helper_XVTSTDCSP(ppc_vsr_t *t, ppc_vsr_t *b, uint64_t dcmx, uint32_t v) +{ + int i; + for (i = 0; i < 4; i++) { + t->s32[i] = (int32_t)-float32_tstdc(b->f32[i], dcmx); + } +} + void helper_xststdcsp(CPUPPCState *env, uint32_t opcode, ppc_vsr_t *xb) { uint32_t dcmx, sign, exp; diff --git a/target/ppc/helper.h b/target/ppc/helper.h index fd8280d..9e5d119 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -517,8 +517,8 @@ DEF_HELPER_3(xvcvsxdsp, void, env, vsr, vsr) DEF_HELPER_3(xvcvuxdsp, void, env, vsr, vsr) DEF_HELPER_3(xvcvsxwsp, void, env, vsr, vsr) DEF_HELPER_3(xvcvuxwsp, void, env, vsr, vsr) -DEF_HELPER_2(xvtstdcsp, void, env, i32) -DEF_HELPER_2(xvtstdcdp, void, env, i32) +DEF_HELPER_FLAGS_4(XVTSTDCSP, TCG_CALL_NO_RWG, void, vsr, vsr, i64, i32) +DEF_HELPER_FLAGS_4(XVTSTDCDP, TCG_CALL_NO_RWG, void, vsr, vsr, i64, i32) DEF_HELPER_3(xvrspi, void, env, vsr, vsr) DEF_HELPER_3(xvrspic, void, env, vsr, vsr) DEF_HELPER_3(xvrspim, void, env, vsr, vsr) diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode index 3594c0c..44905ed 100644 --- a/target/ppc/insn32.decode +++ b/target/ppc/insn32.decode @@ -199,6 +199,9 @@ @XX2_uim4 ...... ..... . uim:4 ..... ......... .. &XX2_uim xt=%xx_xt xb=%xx_xb +%xx_uim7 6:1 2:1 16:5 +@XX2_uim7 ...... ..... ..... ..... .... . ... . .. &XX2_uim xt=%xx_xt xb=%xx_xb uim=%xx_uim7 + &XX2_bf_xb bf xb @XX2_bf_xb ...... bf:3 .. ..... ..... ......... . . &XX2_bf_xb xb=%xx_xb @@ -848,6 +851,8 @@ XSCVSPDPN 111100 ..... ----- ..... 101001011 .. @XX2 ## VSX Binary Floating-Point Math Support Instructions XVXSIGSP 111100 ..... 01001 ..... 111011011 .. @XX2 +XVTSTDCDP 111100 ..... ..... ..... 1111 . 101 ... @XX2_uim7 +XVTSTDCSP 111100 ..... ..... ..... 1101 . 101 ... @XX2_uim7 ## VSX Vector Test Least-Significant Bit by Byte Instruction diff --git a/target/ppc/translate/vsx-impl.c.inc b/target/ppc/translate/vsx-impl.c.inc index 1c28923..287ea8e 100644 --- a/target/ppc/translate/vsx-impl.c.inc +++ b/target/ppc/translate/vsx-impl.c.inc @@ -630,6 +630,8 @@ static void gen_mtvsrws(DisasContext *ctx) #define OP_CPSGN 4 #define SGN_MASK_DP 0x8000000000000000ull #define SGN_MASK_SP 0x8000000080000000ull +#define EXP_MASK_DP 0x7FF0000000000000ull +#define EXP_MASK_SP 0x7F8000007F800000ull #define VSX_SCALAR_MOVE(name, op, sgn_mask) \ static void glue(gen_, name)(DisasContext *ctx) \ @@ -1110,6 +1112,30 @@ GEN_VSX_HELPER_X2(xscvhpdp, 0x16, 0x15, 0x10, PPC2_ISA300) GEN_VSX_HELPER_R2(xscvsdqp, 0x04, 0x1A, 0x0A, PPC2_ISA300) GEN_VSX_HELPER_X2(xscvspdp, 0x12, 0x14, 0, PPC2_VSX) +static bool do_xvtstdc(DisasContext *ctx, arg_XX2_uim *a, unsigned vece) +{ + static const GVecGen2i op[] = { + { + .fnoi = gen_helper_XVTSTDCSP, + .vece = MO_32 + }, + { + .fnoi = gen_helper_XVTSTDCDP, + .vece = MO_64 + }, + }; + + REQUIRE_VSX(ctx); + + tcg_gen_gvec_2i(vsr_full_offset(a->xt), vsr_full_offset(a->xb), + 16, 16, (int32_t)(a->uim), &op[vece - MO_32]); + + return true; +} + +TRANS_FLAGS2(VSX, XVTSTDCSP, do_xvtstdc, MO_32) +TRANS_FLAGS2(VSX, XVTSTDCDP, do_xvtstdc, MO_64) + bool trans_XSCVSPDPN(DisasContext *ctx, arg_XX2 *a) { TCGv_i64 tmp; @@ -1213,8 +1239,6 @@ GEN_VSX_HELPER_X2(xvrspic, 0x16, 0x0A, 0, PPC2_VSX) GEN_VSX_HELPER_X2(xvrspim, 0x12, 0x0B, 0, PPC2_VSX) GEN_VSX_HELPER_X2(xvrspip, 0x12, 0x0A, 0, PPC2_VSX) GEN_VSX_HELPER_X2(xvrspiz, 0x12, 0x09, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvtstdcsp, 0x14, 0x1A, 0, PPC2_VSX) -GEN_VSX_HELPER_2(xvtstdcdp, 0x14, 0x1E, 0, PPC2_VSX) static bool trans_XXPERM(DisasContext *ctx, arg_XX3 *a) { diff --git a/target/ppc/translate/vsx-ops.c.inc b/target/ppc/translate/vsx-ops.c.inc index f7d7377..4b317d4 100644 --- a/target/ppc/translate/vsx-ops.c.inc +++ b/target/ppc/translate/vsx-ops.c.inc @@ -157,14 +157,6 @@ GEN_XX2FORM_EO(xvxexpdp, 0x16, 0x1D, 0x00, PPC2_ISA300), GEN_XX2FORM_EO(xvxsigdp, 0x16, 0x1D, 0x01, PPC2_ISA300), GEN_XX2FORM_EO(xvxexpsp, 0x16, 0x1D, 0x08, PPC2_ISA300), -/* DCMX = bit[25] << 6 | bit[29] << 5 | bit[11:15] */ -#define GEN_XX2FORM_DCMX(name, opc2, opc3, fl2) \ -GEN_XX3FORM(name, opc2, opc3 | 0, fl2), \ -GEN_XX3FORM(name, opc2, opc3 | 1, fl2) - -GEN_XX2FORM_DCMX(xvtstdcdp, 0x14, 0x1E, PPC2_ISA300), -GEN_XX2FORM_DCMX(xvtstdcsp, 0x14, 0x1A, PPC2_ISA300), - GEN_XX3FORM(xsadddp, 0x00, 0x04, PPC2_VSX), GEN_VSX_XFORM_300(xsaddqp, 0x04, 0x00, 0x0), GEN_XX3FORM(xssubdp, 0x00, 0x05, PPC2_VSX), -- cgit v1.1 From da3c53bac3d8f3040b35ef3d98a64b592bb28a66 Mon Sep 17 00:00:00 2001 From: "Lucas Mateus Castro (alqotel)" Date: Wed, 19 Oct 2022 09:50:39 -0300 Subject: target/ppc: Moved XSTSTDC[QDS]P to decodetree Moved XSTSTDCSP, XSTSTDCDP and XSTSTDCQP to decodetree and moved some of its decoding away from the helper as previously the DCMX, XB and BF were calculated in the helper with the help of cpu_env, now that part was moved to the decodetree with the rest. xvtstdcsp: rept loop master patch 8 12500 1,85393600 1,94683600 (+5.0%) 25 4000 1,78779800 1,92479000 (+7.7%) 100 1000 2,12775000 2,28895500 (+7.6%) 500 200 2,99655300 3,23102900 (+7.8%) 2500 40 6,89082200 7,44827500 (+8.1%) 8000 12 17,50585500 18,95152100 (+8.3%) xvtstdcdp: rept loop master patch 8 12500 1,39043100 1,33539800 (-4.0%) 25 4000 1,35731800 1,37347800 (+1.2%) 100 1000 1,51514800 1,56053000 (+3.0%) 500 200 2,21014400 2,47906000 (+12.2%) 2500 40 5,39488200 6,68766700 (+24.0%) 8000 12 13,98623900 18,17661900 (+30.0%) xvtstdcdp: rept loop master patch 8 12500 1,35123800 1,34455800 (-0.5%) 25 4000 1,36441200 1,36759600 (+0.2%) 100 1000 1,49763500 1,54138400 (+2.9%) 500 200 2,19020200 2,46196400 (+12.4%) 2500 40 5,39265700 6,68147900 (+23.9%) 8000 12 14,04163600 18,19669600 (+29.6%) As some values are now decoded outside the helper and passed to it as an argument the number of arguments of the helper increased, the number of TCGop needed to load the arguments increased. I suspect that's why the slow-down in the tests with a high REPT but low LOOP. Signed-off-by: Lucas Mateus Castro (alqotel) Reviewed-by: Richard Henderson Message-Id: <20221019125040.48028-12-lucas.araujo@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/fpu_helper.c | 114 +++++++++++------------------------- target/ppc/helper.h | 6 +- target/ppc/insn32.decode | 6 ++ target/ppc/translate/vsx-impl.c.inc | 20 ++++++- target/ppc/translate/vsx-ops.c.inc | 4 -- 5 files changed, 60 insertions(+), 90 deletions(-) (limited to 'target') diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c index 960a76a..a66e16c 100644 --- a/target/ppc/fpu_helper.c +++ b/target/ppc/fpu_helper.c @@ -3241,63 +3241,6 @@ void helper_XVXSIGSP(ppc_vsr_t *xt, ppc_vsr_t *xb) *xt = t; } -/* - * VSX_TEST_DC - VSX floating point test data class - * op - instruction mnemonic - * nels - number of elements (1, 2 or 4) - * xbn - VSR register number - * tp - type (float32 or float64) - * fld - vsr_t field (VsrD(*) or VsrW(*)) - * tfld - target vsr_t field (VsrD(*) or VsrW(*)) - * fld_max - target field max - * scrf - set result in CR and FPCC - */ -#define VSX_TEST_DC(op, nels, xbn, tp, fld, tfld, fld_max, scrf) \ -void helper_##op(CPUPPCState *env, uint32_t opcode) \ -{ \ - ppc_vsr_t *xt = &env->vsr[xT(opcode)]; \ - ppc_vsr_t *xb = &env->vsr[xbn]; \ - ppc_vsr_t t = { }; \ - uint32_t i, sign, dcmx; \ - uint32_t cc, match = 0; \ - \ - if (!scrf) { \ - dcmx = DCMX_XV(opcode); \ - } else { \ - t = *xt; \ - dcmx = DCMX(opcode); \ - } \ - \ - for (i = 0; i < nels; i++) { \ - sign = tp##_is_neg(xb->fld); \ - if (tp##_is_any_nan(xb->fld)) { \ - match = extract32(dcmx, 6, 1); \ - } else if (tp##_is_infinity(xb->fld)) { \ - match = extract32(dcmx, 4 + !sign, 1); \ - } else if (tp##_is_zero(xb->fld)) { \ - match = extract32(dcmx, 2 + !sign, 1); \ - } else if (tp##_is_zero_or_denormal(xb->fld)) { \ - match = extract32(dcmx, 0 + !sign, 1); \ - } \ - \ - if (scrf) { \ - cc = sign << CRF_LT_BIT | match << CRF_EQ_BIT; \ - env->fpscr &= ~FP_FPCC; \ - env->fpscr |= cc << FPSCR_FPCC; \ - env->crf[BF(opcode)] = cc; \ - } else { \ - t.tfld = match ? fld_max : 0; \ - } \ - match = 0; \ - } \ - if (!scrf) { \ - *xt = t; \ - } \ -} - -VSX_TEST_DC(xststdcdp, 1, xB(opcode), float64, VsrD(0), VsrD(0), 0, 1) -VSX_TEST_DC(xststdcqp, 1, (rB(opcode) + 32), float128, f128, VsrD(0), 0, 1) - #define VSX_TSTDC(tp) \ static int32_t tp##_tstdc(tp b, uint32_t dcmx) \ { \ @@ -3317,6 +3260,7 @@ static int32_t tp##_tstdc(tp b, uint32_t dcmx) \ VSX_TSTDC(float32) VSX_TSTDC(float64) +VSX_TSTDC(float128) #undef VSX_TSTDC void helper_XVTSTDCDP(ppc_vsr_t *t, ppc_vsr_t *b, uint64_t dcmx, uint32_t v) @@ -3335,34 +3279,44 @@ void helper_XVTSTDCSP(ppc_vsr_t *t, ppc_vsr_t *b, uint64_t dcmx, uint32_t v) } } -void helper_xststdcsp(CPUPPCState *env, uint32_t opcode, ppc_vsr_t *xb) +static bool not_SP_value(float64 val) { - uint32_t dcmx, sign, exp; - uint32_t cc, match = 0, not_sp = 0; - float64 arg = xb->VsrD(0); - float64 arg_sp; - - dcmx = DCMX(opcode); - exp = (arg >> 52) & 0x7FF; - sign = float64_is_neg(arg); - - if (float64_is_any_nan(arg)) { - match = extract32(dcmx, 6, 1); - } else if (float64_is_infinity(arg)) { - match = extract32(dcmx, 4 + !sign, 1); - } else if (float64_is_zero(arg)) { - match = extract32(dcmx, 2 + !sign, 1); - } else if (float64_is_zero_or_denormal(arg) || (exp > 0 && exp < 0x381)) { - match = extract32(dcmx, 0 + !sign, 1); - } - - arg_sp = helper_todouble(helper_tosingle(arg)); - not_sp = arg != arg_sp; + return val != helper_todouble(helper_tosingle(val)); +} +/* + * VSX_XS_TSTDC - VSX Scalar Test Data Class + * NAME - instruction name + * FLD - vsr_t field (VsrD(0) or f128) + * TP - type (float64 or float128) + */ +#define VSX_XS_TSTDC(NAME, FLD, TP) \ + void helper_##NAME(CPUPPCState *env, uint32_t bf, \ + uint32_t dcmx, ppc_vsr_t *b) \ + { \ + uint32_t cc, match, sign = TP##_is_neg(b->FLD); \ + match = TP##_tstdc(b->FLD, dcmx); \ + cc = sign << CRF_LT_BIT | match << CRF_EQ_BIT; \ + env->fpscr &= ~FP_FPCC; \ + env->fpscr |= cc << FPSCR_FPCC; \ + env->crf[bf] = cc; \ + } + +VSX_XS_TSTDC(XSTSTDCDP, VsrD(0), float64) +VSX_XS_TSTDC(XSTSTDCQP, f128, float128) +#undef VSX_XS_TSTDC + +void helper_XSTSTDCSP(CPUPPCState *env, uint32_t bf, + uint32_t dcmx, ppc_vsr_t *b) +{ + uint32_t cc, match, sign = float64_is_neg(b->VsrD(0)); + uint32_t exp = (b->VsrD(0) >> 52) & 0x7FF; + int not_sp = (int)not_SP_value(b->VsrD(0)); + match = float64_tstdc(b->VsrD(0), dcmx) || (exp > 0 && exp < 0x381); cc = sign << CRF_LT_BIT | match << CRF_EQ_BIT | not_sp << CRF_SO_BIT; env->fpscr &= ~FP_FPCC; env->fpscr |= cc << FPSCR_FPCC; - env->crf[BF(opcode)] = cc; + env->crf[bf] = cc; } void helper_xsrqpi(CPUPPCState *env, uint32_t opcode, diff --git a/target/ppc/helper.h b/target/ppc/helper.h index 9e5d119..8344fe3 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -417,9 +417,9 @@ DEF_HELPER_3(xscvuxdsp, void, env, vsr, vsr) DEF_HELPER_3(xscvsxdsp, void, env, vsr, vsr) DEF_HELPER_4(xscvudqp, void, env, i32, vsr, vsr) DEF_HELPER_3(xscvuxddp, void, env, vsr, vsr) -DEF_HELPER_3(xststdcsp, void, env, i32, vsr) -DEF_HELPER_2(xststdcdp, void, env, i32) -DEF_HELPER_2(xststdcqp, void, env, i32) +DEF_HELPER_4(XSTSTDCSP, void, env, i32, i32, vsr) +DEF_HELPER_4(XSTSTDCDP, void, env, i32, i32, vsr) +DEF_HELPER_4(XSTSTDCQP, void, env, i32, i32, vsr) DEF_HELPER_3(xsrdpi, void, env, vsr, vsr) DEF_HELPER_3(xsrdpic, void, env, vsr, vsr) DEF_HELPER_3(xsrdpim, void, env, vsr, vsr) diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode index 44905ed..f8f589e 100644 --- a/target/ppc/insn32.decode +++ b/target/ppc/insn32.decode @@ -202,6 +202,9 @@ %xx_uim7 6:1 2:1 16:5 @XX2_uim7 ...... ..... ..... ..... .... . ... . .. &XX2_uim xt=%xx_xt xb=%xx_xb uim=%xx_uim7 +&XX2_bf_uim bf xb uim +@XX2_bf_uim ...... bf:3 uim:7 ..... ......... . . &XX2_bf_uim + &XX2_bf_xb bf xb @XX2_bf_xb ...... bf:3 .. ..... ..... ......... . . &XX2_bf_xb xb=%xx_xb @@ -853,6 +856,9 @@ XSCVSPDPN 111100 ..... ----- ..... 101001011 .. @XX2 XVXSIGSP 111100 ..... 01001 ..... 111011011 .. @XX2 XVTSTDCDP 111100 ..... ..... ..... 1111 . 101 ... @XX2_uim7 XVTSTDCSP 111100 ..... ..... ..... 1101 . 101 ... @XX2_uim7 +XSTSTDCSP 111100 ... ....... ..... 100101010 . - @XX2_bf_uim xb=%xx_xb +XSTSTDCDP 111100 ... ....... ..... 101101010 . - @XX2_bf_uim xb=%xx_xb +XSTSTDCQP 111111 ... ....... xb:5 1011000100 - @XX2_bf_uim ## VSX Vector Test Least-Significant Bit by Byte Instruction diff --git a/target/ppc/translate/vsx-impl.c.inc b/target/ppc/translate/vsx-impl.c.inc index 287ea8e..af410cb 100644 --- a/target/ppc/translate/vsx-impl.c.inc +++ b/target/ppc/translate/vsx-impl.c.inc @@ -1136,6 +1136,23 @@ static bool do_xvtstdc(DisasContext *ctx, arg_XX2_uim *a, unsigned vece) TRANS_FLAGS2(VSX, XVTSTDCSP, do_xvtstdc, MO_32) TRANS_FLAGS2(VSX, XVTSTDCDP, do_xvtstdc, MO_64) +static bool do_XX2_bf_uim(DisasContext *ctx, arg_XX2_bf_uim *a, bool vsr, + void (*gen_helper)(TCGv_env, TCGv_i32, TCGv_i32, TCGv_ptr)) +{ + TCGv_ptr xb; + + REQUIRE_VSX(ctx); + xb = vsr ? gen_vsr_ptr(a->xb) : gen_avr_ptr(a->xb); + gen_helper(cpu_env, tcg_constant_i32(a->bf), tcg_constant_i32(a->uim), xb); + tcg_temp_free_ptr(xb); + + return true; +} + +TRANS_FLAGS2(ISA300, XSTSTDCSP, do_XX2_bf_uim, true, gen_helper_XSTSTDCSP) +TRANS_FLAGS2(ISA300, XSTSTDCDP, do_XX2_bf_uim, true, gen_helper_XSTSTDCDP) +TRANS_FLAGS2(ISA300, XSTSTDCQP, do_XX2_bf_uim, false, gen_helper_XSTSTDCQP) + bool trans_XSCVSPDPN(DisasContext *ctx, arg_XX2 *a) { TCGv_i64 tmp; @@ -1182,9 +1199,6 @@ GEN_VSX_HELPER_X2(xssqrtsp, 0x16, 0x00, 0, PPC2_VSX207) GEN_VSX_HELPER_X2(xsrsqrtesp, 0x14, 0x00, 0, PPC2_VSX207) GEN_VSX_HELPER_X2(xscvsxdsp, 0x10, 0x13, 0, PPC2_VSX207) GEN_VSX_HELPER_X2(xscvuxdsp, 0x10, 0x12, 0, PPC2_VSX207) -GEN_VSX_HELPER_X1(xststdcsp, 0x14, 0x12, 0, PPC2_ISA300) -GEN_VSX_HELPER_2(xststdcdp, 0x14, 0x16, 0, PPC2_ISA300) -GEN_VSX_HELPER_2(xststdcqp, 0x04, 0x16, 0, PPC2_ISA300) GEN_VSX_HELPER_X3(xvadddp, 0x00, 0x0C, 0, PPC2_VSX) GEN_VSX_HELPER_X3(xvsubdp, 0x00, 0x0D, 0, PPC2_VSX) diff --git a/target/ppc/translate/vsx-ops.c.inc b/target/ppc/translate/vsx-ops.c.inc index 4b317d4..a3ba094 100644 --- a/target/ppc/translate/vsx-ops.c.inc +++ b/target/ppc/translate/vsx-ops.c.inc @@ -147,10 +147,6 @@ GEN_HANDLER_E(xsiexpdp, 0x3C, 0x16, 0x1C, 0, PPC_NONE, PPC2_ISA300), GEN_VSX_XFORM_300(xsiexpqp, 0x4, 0x1B, 0x00000001), #endif -GEN_XX2FORM(xststdcdp, 0x14, 0x16, PPC2_ISA300), -GEN_XX2FORM(xststdcsp, 0x14, 0x12, PPC2_ISA300), -GEN_VSX_XFORM_300(xststdcqp, 0x04, 0x16, 0x00000001), - GEN_XX3FORM(xviexpsp, 0x00, 0x1B, PPC2_ISA300), GEN_XX3FORM(xviexpdp, 0x00, 0x1F, PPC2_ISA300), GEN_XX2FORM_EO(xvxexpdp, 0x16, 0x1D, 0x00, PPC2_ISA300), -- cgit v1.1 From bbd8dd5e45b831ef3fda585cf80d08f45cdaba95 Mon Sep 17 00:00:00 2001 From: "Lucas Mateus Castro (alqotel)" Date: Wed, 19 Oct 2022 09:50:40 -0300 Subject: target/ppc: Use gvec to decode XVTSTDC[DS]P Used gvec to translate XVTSTDCSP and XVTSTDCDP. xvtstdcsp: rept loop imm master version prev version current version 25 4000 0 0,206200 0,040730 (-80.2%) 0,040740 (-80.2%) 25 4000 1 0,205120 0,053650 (-73.8%) 0,053510 (-73.9%) 25 4000 3 0,206160 0,058630 (-71.6%) 0,058570 (-71.6%) 25 4000 51 0,217110 0,191490 (-11.8%) 0,192320 (-11.4%) 25 4000 127 0,206160 0,191490 (-7.1%) 0,192640 (-6.6%) 8000 12 0 1,234719 0,418833 (-66.1%) 0,386365 (-68.7%) 8000 12 1 1,232417 1,435979 (+16.5%) 1,462792 (+18.7%) 8000 12 3 1,232760 1,766073 (+43.3%) 1,743990 (+41.5%) 8000 12 51 1,239281 1,319562 (+6.5%) 1,423479 (+14.9%) 8000 12 127 1,231708 1,315760 (+6.8%) 1,426667 (+15.8%) xvtstdcdp: rept loop imm master version prev version current version 25 4000 0 0,159930 0,040830 (-74.5%) 0,040610 (-74.6%) 25 4000 1 0,160640 0,053670 (-66.6%) 0,053480 (-66.7%) 25 4000 3 0,160020 0,063030 (-60.6%) 0,062960 (-60.7%) 25 4000 51 0,160410 0,128620 (-19.8%) 0,127470 (-20.5%) 25 4000 127 0,160330 0,127670 (-20.4%) 0,128690 (-19.7%) 8000 12 0 1,190365 0,422146 (-64.5%) 0,388417 (-67.4%) 8000 12 1 1,191292 1,445312 (+21.3%) 1,428698 (+19.9%) 8000 12 3 1,188687 1,980656 (+66.6%) 1,975354 (+66.2%) 8000 12 51 1,191250 1,264500 (+6.1%) 1,355083 (+13.8%) 8000 12 127 1,197313 1,266729 (+5.8%) 1,349156 (+12.7%) Overall, these instructions are the hardest ones to measure performance as the gvec implementation is affected by the immediate. Above there are 5 different scenarios when it comes to immediate and 2 when it comes to rept/loop combination. The immediates scenarios are: all bits are 0 therefore the target register should just be changed to 0, with 1 bit set, with 2 bits set in a combination the new implementation can deal with using gvec, 4 bits set and the new implementation can't deal with it using gvec and all bits set. The rept/loop scenarios are high loop and low rept (so it should spend more time executing it than translating it) and high rept low loop (so it should spend more time translating it than executing this code). These comparisons are between the upstream version, a previous similar implementation and a one with a cleaner code(this one). For a comparison with o previous different implementation: <20221010191356.83659-13-lucas.araujo@eldorado.org.br> Signed-off-by: Lucas Mateus Castro (alqotel) Reviewed-by: Richard Henderson Message-Id: <20221019125040.48028-13-lucas.araujo@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/translate/vsx-impl.c.inc | 167 +++++++++++++++++++++++++++++++++--- 1 file changed, 157 insertions(+), 10 deletions(-) (limited to 'target') diff --git a/target/ppc/translate/vsx-impl.c.inc b/target/ppc/translate/vsx-impl.c.inc index af410cb..4deb29e 100644 --- a/target/ppc/translate/vsx-impl.c.inc +++ b/target/ppc/translate/vsx-impl.c.inc @@ -632,6 +632,8 @@ static void gen_mtvsrws(DisasContext *ctx) #define SGN_MASK_SP 0x8000000080000000ull #define EXP_MASK_DP 0x7FF0000000000000ull #define EXP_MASK_SP 0x7F8000007F800000ull +#define FRC_MASK_DP (~(SGN_MASK_DP | EXP_MASK_DP)) +#define FRC_MASK_SP (~(SGN_MASK_SP | EXP_MASK_SP)) #define VSX_SCALAR_MOVE(name, op, sgn_mask) \ static void glue(gen_, name)(DisasContext *ctx) \ @@ -1112,23 +1114,168 @@ GEN_VSX_HELPER_X2(xscvhpdp, 0x16, 0x15, 0x10, PPC2_ISA300) GEN_VSX_HELPER_R2(xscvsdqp, 0x04, 0x1A, 0x0A, PPC2_ISA300) GEN_VSX_HELPER_X2(xscvspdp, 0x12, 0x14, 0, PPC2_VSX) +/* test if +Inf */ +static void gen_is_pos_inf(unsigned vece, TCGv_vec t, TCGv_vec b, int64_t v) +{ + uint64_t exp_msk = (vece == MO_32) ? (uint32_t)EXP_MASK_SP : EXP_MASK_DP; + tcg_gen_cmp_vec(TCG_COND_EQ, vece, t, b, + tcg_constant_vec_matching(t, vece, exp_msk)); +} + +/* test if -Inf */ +static void gen_is_neg_inf(unsigned vece, TCGv_vec t, TCGv_vec b, int64_t v) +{ + uint64_t exp_msk = (vece == MO_32) ? (uint32_t)EXP_MASK_SP : EXP_MASK_DP; + uint64_t sgn_msk = (vece == MO_32) ? (uint32_t)SGN_MASK_SP : SGN_MASK_DP; + tcg_gen_cmp_vec(TCG_COND_EQ, vece, t, b, + tcg_constant_vec_matching(t, vece, sgn_msk | exp_msk)); +} + +/* test if +Inf or -Inf */ +static void gen_is_any_inf(unsigned vece, TCGv_vec t, TCGv_vec b, int64_t v) +{ + uint64_t exp_msk = (vece == MO_32) ? (uint32_t)EXP_MASK_SP : EXP_MASK_DP; + uint64_t sgn_msk = (vece == MO_32) ? (uint32_t)SGN_MASK_SP : SGN_MASK_DP; + tcg_gen_andc_vec(vece, b, b, tcg_constant_vec_matching(t, vece, sgn_msk)); + tcg_gen_cmp_vec(TCG_COND_EQ, vece, t, b, + tcg_constant_vec_matching(t, vece, exp_msk)); +} + +/* test if +0 */ +static void gen_is_pos_zero(unsigned vece, TCGv_vec t, TCGv_vec b, int64_t v) +{ + tcg_gen_cmp_vec(TCG_COND_EQ, vece, t, b, + tcg_constant_vec_matching(t, vece, 0)); +} + +/* test if -0 */ +static void gen_is_neg_zero(unsigned vece, TCGv_vec t, TCGv_vec b, int64_t v) +{ + uint64_t sgn_msk = (vece == MO_32) ? (uint32_t)SGN_MASK_SP : SGN_MASK_DP; + tcg_gen_cmp_vec(TCG_COND_EQ, vece, t, b, + tcg_constant_vec_matching(t, vece, sgn_msk)); +} + +/* test if +0 or -0 */ +static void gen_is_any_zero(unsigned vece, TCGv_vec t, TCGv_vec b, int64_t v) +{ + uint64_t sgn_msk = (vece == MO_32) ? (uint32_t)SGN_MASK_SP : SGN_MASK_DP; + tcg_gen_andc_vec(vece, b, b, tcg_constant_vec_matching(t, vece, sgn_msk)); + tcg_gen_cmp_vec(TCG_COND_EQ, vece, t, b, + tcg_constant_vec_matching(t, vece, 0)); +} + +/* test if +Denormal */ +static void gen_is_pos_denormal(unsigned vece, TCGv_vec t, + TCGv_vec b, int64_t v) +{ + uint64_t frc_msk = (vece == MO_32) ? (uint32_t)FRC_MASK_SP : FRC_MASK_DP; + tcg_gen_cmp_vec(TCG_COND_LEU, vece, t, b, + tcg_constant_vec_matching(t, vece, frc_msk)); + tcg_gen_cmp_vec(TCG_COND_NE, vece, b, b, + tcg_constant_vec_matching(t, vece, 0)); + tcg_gen_and_vec(vece, t, t, b); +} + +/* test if -Denormal */ +static void gen_is_neg_denormal(unsigned vece, TCGv_vec t, + TCGv_vec b, int64_t v) +{ + uint64_t sgn_msk = (vece == MO_32) ? (uint32_t)SGN_MASK_SP : SGN_MASK_DP; + uint64_t frc_msk = (vece == MO_32) ? (uint32_t)FRC_MASK_SP : FRC_MASK_DP; + tcg_gen_cmp_vec(TCG_COND_LEU, vece, t, b, + tcg_constant_vec_matching(t, vece, sgn_msk | frc_msk)); + tcg_gen_cmp_vec(TCG_COND_GTU, vece, b, b, + tcg_constant_vec_matching(t, vece, sgn_msk)); + tcg_gen_and_vec(vece, t, t, b); +} + +/* test if +Denormal or -Denormal */ +static void gen_is_any_denormal(unsigned vece, TCGv_vec t, + TCGv_vec b, int64_t v) +{ + uint64_t sgn_msk = (vece == MO_32) ? (uint32_t)SGN_MASK_SP : SGN_MASK_DP; + uint64_t frc_msk = (vece == MO_32) ? (uint32_t)FRC_MASK_SP : FRC_MASK_DP; + tcg_gen_andc_vec(vece, b, b, tcg_constant_vec_matching(t, vece, sgn_msk)); + tcg_gen_cmp_vec(TCG_COND_LE, vece, t, b, + tcg_constant_vec_matching(t, vece, frc_msk)); + tcg_gen_cmp_vec(TCG_COND_NE, vece, b, b, + tcg_constant_vec_matching(t, vece, 0)); + tcg_gen_and_vec(vece, t, t, b); +} + +/* test if NaN */ +static void gen_is_nan(unsigned vece, TCGv_vec t, TCGv_vec b, int64_t v) +{ + uint64_t exp_msk = (vece == MO_32) ? (uint32_t)EXP_MASK_SP : EXP_MASK_DP; + uint64_t sgn_msk = (vece == MO_32) ? (uint32_t)SGN_MASK_SP : SGN_MASK_DP; + tcg_gen_and_vec(vece, b, b, tcg_constant_vec_matching(t, vece, ~sgn_msk)); + tcg_gen_cmp_vec(TCG_COND_GT, vece, t, b, + tcg_constant_vec_matching(t, vece, exp_msk)); +} + static bool do_xvtstdc(DisasContext *ctx, arg_XX2_uim *a, unsigned vece) { - static const GVecGen2i op[] = { - { - .fnoi = gen_helper_XVTSTDCSP, - .vece = MO_32 - }, - { - .fnoi = gen_helper_XVTSTDCDP, - .vece = MO_64 - }, + static const TCGOpcode vecop_list[] = { + INDEX_op_cmp_vec, 0 + }; + + GVecGen2i op = { + .fnoi = (vece == MO_32) ? gen_helper_XVTSTDCSP : gen_helper_XVTSTDCDP, + .vece = vece, + .opt_opc = vecop_list }; REQUIRE_VSX(ctx); + switch (a->uim) { + case 0: + set_cpu_vsr(a->xt, tcg_constant_i64(0), true); + set_cpu_vsr(a->xt, tcg_constant_i64(0), false); + return true; + case ((1 << 0) | (1 << 1)): + /* test if +Denormal or -Denormal */ + op.fniv = gen_is_any_denormal; + break; + case (1 << 0): + /* test if -Denormal */ + op.fniv = gen_is_neg_denormal; + break; + case (1 << 1): + /* test if +Denormal */ + op.fniv = gen_is_pos_denormal; + break; + case ((1 << 2) | (1 << 3)): + /* test if +0 or -0 */ + op.fniv = gen_is_any_zero; + break; + case (1 << 2): + /* test if -0 */ + op.fniv = gen_is_neg_zero; + break; + case (1 << 3): + /* test if +0 */ + op.fniv = gen_is_pos_zero; + break; + case ((1 << 4) | (1 << 5)): + /* test if +Inf or -Inf */ + op.fniv = gen_is_any_inf; + break; + case (1 << 4): + /* test if -Inf */ + op.fniv = gen_is_neg_inf; + break; + case (1 << 5): + /* test if +Inf */ + op.fniv = gen_is_pos_inf; + break; + case (1 << 6): + /* test if NaN */ + op.fniv = gen_is_nan; + break; + } tcg_gen_gvec_2i(vsr_full_offset(a->xt), vsr_full_offset(a->xb), - 16, 16, (int32_t)(a->uim), &op[vece - MO_32]); + 16, 16, a->uim, &op); return true; } -- cgit v1.1 From f003109f710bb39a78c27ce18aa10579340f5a3f Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Tue, 11 Oct 2022 17:48:01 -0300 Subject: target/ppc: define PPC_INTERRUPT_* values directly This enum defines the bit positions in env->pending_interrupts for each interrupt. However, except for the comparison in kvmppc_set_interrupt, the values are always used as (1 << PPC_INTERRUPT_*). Define them directly like that to save some clutter. No functional change intended. Reviewed-by: David Gibson Signed-off-by: Matheus Ferst Message-Id: <20221011204829.1641124-2-matheus.ferst@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/cpu.h | 40 +++++++++++++------------- target/ppc/cpu_init.c | 56 ++++++++++++++++++------------------ target/ppc/excp_helper.c | 74 ++++++++++++++++++++++++------------------------ target/ppc/misc_helper.c | 6 ++-- 4 files changed, 88 insertions(+), 88 deletions(-) (limited to 'target') diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index cca6c4e..2433756 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -2416,27 +2416,27 @@ enum { /* Hardware exceptions definitions */ enum { /* External hardware exception sources */ - PPC_INTERRUPT_RESET = 0, /* Reset exception */ - PPC_INTERRUPT_WAKEUP, /* Wakeup exception */ - PPC_INTERRUPT_MCK, /* Machine check exception */ - PPC_INTERRUPT_EXT, /* External interrupt */ - PPC_INTERRUPT_SMI, /* System management interrupt */ - PPC_INTERRUPT_CEXT, /* Critical external interrupt */ - PPC_INTERRUPT_DEBUG, /* External debug exception */ - PPC_INTERRUPT_THERM, /* Thermal exception */ + PPC_INTERRUPT_RESET = 0x00001, /* Reset exception */ + PPC_INTERRUPT_WAKEUP = 0x00002, /* Wakeup exception */ + PPC_INTERRUPT_MCK = 0x00004, /* Machine check exception */ + PPC_INTERRUPT_EXT = 0x00008, /* External interrupt */ + PPC_INTERRUPT_SMI = 0x00010, /* System management interrupt */ + PPC_INTERRUPT_CEXT = 0x00020, /* Critical external interrupt */ + PPC_INTERRUPT_DEBUG = 0x00040, /* External debug exception */ + PPC_INTERRUPT_THERM = 0x00080, /* Thermal exception */ /* Internal hardware exception sources */ - PPC_INTERRUPT_DECR, /* Decrementer exception */ - PPC_INTERRUPT_HDECR, /* Hypervisor decrementer exception */ - PPC_INTERRUPT_PIT, /* Programmable interval timer interrupt */ - PPC_INTERRUPT_FIT, /* Fixed interval timer interrupt */ - PPC_INTERRUPT_WDT, /* Watchdog timer interrupt */ - PPC_INTERRUPT_CDOORBELL, /* Critical doorbell interrupt */ - PPC_INTERRUPT_DOORBELL, /* Doorbell interrupt */ - PPC_INTERRUPT_PERFM, /* Performance monitor interrupt */ - PPC_INTERRUPT_HMI, /* Hypervisor Maintenance interrupt */ - PPC_INTERRUPT_HDOORBELL, /* Hypervisor Doorbell interrupt */ - PPC_INTERRUPT_HVIRT, /* Hypervisor virtualization interrupt */ - PPC_INTERRUPT_EBB, /* Event-based Branch exception */ + PPC_INTERRUPT_DECR = 0x00100, /* Decrementer exception */ + PPC_INTERRUPT_HDECR = 0x00200, /* Hypervisor decrementer exception */ + PPC_INTERRUPT_PIT = 0x00400, /* Programmable interval timer int. */ + PPC_INTERRUPT_FIT = 0x00800, /* Fixed interval timer interrupt */ + PPC_INTERRUPT_WDT = 0x01000, /* Watchdog timer interrupt */ + PPC_INTERRUPT_CDOORBELL = 0x02000, /* Critical doorbell interrupt */ + PPC_INTERRUPT_DOORBELL = 0x04000, /* Doorbell interrupt */ + PPC_INTERRUPT_PERFM = 0x08000, /* Performance monitor interrupt */ + PPC_INTERRUPT_HMI = 0x10000, /* Hypervisor Maintenance interrupt */ + PPC_INTERRUPT_HDOORBELL = 0x20000, /* Hypervisor Doorbell interrupt */ + PPC_INTERRUPT_HVIRT = 0x40000, /* Hypervisor virtualization interrupt */ + PPC_INTERRUPT_EBB = 0x80000, /* Event-based Branch exception */ }; /* Processor Compatibility mask (PCR) */ diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index 335351c..07171c6 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -5969,23 +5969,23 @@ static bool cpu_has_work_POWER7(CPUState *cs) if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) { return false; } - if ((env->pending_interrupts & (1u << PPC_INTERRUPT_EXT)) && + if ((env->pending_interrupts & PPC_INTERRUPT_EXT) && (env->spr[SPR_LPCR] & LPCR_P7_PECE0)) { return true; } - if ((env->pending_interrupts & (1u << PPC_INTERRUPT_DECR)) && + if ((env->pending_interrupts & PPC_INTERRUPT_DECR) && (env->spr[SPR_LPCR] & LPCR_P7_PECE1)) { return true; } - if ((env->pending_interrupts & (1u << PPC_INTERRUPT_MCK)) && + if ((env->pending_interrupts & PPC_INTERRUPT_MCK) && (env->spr[SPR_LPCR] & LPCR_P7_PECE2)) { return true; } - if ((env->pending_interrupts & (1u << PPC_INTERRUPT_HMI)) && + if ((env->pending_interrupts & PPC_INTERRUPT_HMI) && (env->spr[SPR_LPCR] & LPCR_P7_PECE2)) { return true; } - if (env->pending_interrupts & (1u << PPC_INTERRUPT_RESET)) { + if (env->pending_interrupts & PPC_INTERRUPT_RESET) { return true; } return false; @@ -6142,31 +6142,31 @@ static bool cpu_has_work_POWER8(CPUState *cs) if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) { return false; } - if ((env->pending_interrupts & (1u << PPC_INTERRUPT_EXT)) && + if ((env->pending_interrupts & PPC_INTERRUPT_EXT) && (env->spr[SPR_LPCR] & LPCR_P8_PECE2)) { return true; } - if ((env->pending_interrupts & (1u << PPC_INTERRUPT_DECR)) && + if ((env->pending_interrupts & PPC_INTERRUPT_DECR) && (env->spr[SPR_LPCR] & LPCR_P8_PECE3)) { return true; } - if ((env->pending_interrupts & (1u << PPC_INTERRUPT_MCK)) && + if ((env->pending_interrupts & PPC_INTERRUPT_MCK) && (env->spr[SPR_LPCR] & LPCR_P8_PECE4)) { return true; } - if ((env->pending_interrupts & (1u << PPC_INTERRUPT_HMI)) && + if ((env->pending_interrupts & PPC_INTERRUPT_HMI) && (env->spr[SPR_LPCR] & LPCR_P8_PECE4)) { return true; } - if ((env->pending_interrupts & (1u << PPC_INTERRUPT_DOORBELL)) && + if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) && (env->spr[SPR_LPCR] & LPCR_P8_PECE0)) { return true; } - if ((env->pending_interrupts & (1u << PPC_INTERRUPT_HDOORBELL)) && + if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) && (env->spr[SPR_LPCR] & LPCR_P8_PECE1)) { return true; } - if (env->pending_interrupts & (1u << PPC_INTERRUPT_RESET)) { + if (env->pending_interrupts & PPC_INTERRUPT_RESET) { return true; } return false; @@ -6368,7 +6368,7 @@ static bool cpu_has_work_POWER9(CPUState *cs) return true; } /* External Exception */ - if ((env->pending_interrupts & (1u << PPC_INTERRUPT_EXT)) && + if ((env->pending_interrupts & PPC_INTERRUPT_EXT) && (env->spr[SPR_LPCR] & LPCR_EEE)) { bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC); if (!heic || !FIELD_EX64_HV(env->msr) || @@ -6377,31 +6377,31 @@ static bool cpu_has_work_POWER9(CPUState *cs) } } /* Decrementer Exception */ - if ((env->pending_interrupts & (1u << PPC_INTERRUPT_DECR)) && + if ((env->pending_interrupts & PPC_INTERRUPT_DECR) && (env->spr[SPR_LPCR] & LPCR_DEE)) { return true; } /* Machine Check or Hypervisor Maintenance Exception */ - if ((env->pending_interrupts & (1u << PPC_INTERRUPT_MCK | - 1u << PPC_INTERRUPT_HMI)) && (env->spr[SPR_LPCR] & LPCR_OEE)) { + if ((env->pending_interrupts & (PPC_INTERRUPT_MCK | PPC_INTERRUPT_HMI)) + && (env->spr[SPR_LPCR] & LPCR_OEE)) { return true; } /* Privileged Doorbell Exception */ - if ((env->pending_interrupts & (1u << PPC_INTERRUPT_DOORBELL)) && + if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) && (env->spr[SPR_LPCR] & LPCR_PDEE)) { return true; } /* Hypervisor Doorbell Exception */ - if ((env->pending_interrupts & (1u << PPC_INTERRUPT_HDOORBELL)) && + if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) && (env->spr[SPR_LPCR] & LPCR_HDEE)) { return true; } /* Hypervisor virtualization exception */ - if ((env->pending_interrupts & (1u << PPC_INTERRUPT_HVIRT)) && + if ((env->pending_interrupts & PPC_INTERRUPT_HVIRT) && (env->spr[SPR_LPCR] & LPCR_HVEE)) { return true; } - if (env->pending_interrupts & (1u << PPC_INTERRUPT_RESET)) { + if (env->pending_interrupts & PPC_INTERRUPT_RESET) { return true; } return false; @@ -6601,7 +6601,7 @@ static bool cpu_has_work_POWER10(CPUState *cs) return true; } /* External Exception */ - if ((env->pending_interrupts & (1u << PPC_INTERRUPT_EXT)) && + if ((env->pending_interrupts & PPC_INTERRUPT_EXT) && (env->spr[SPR_LPCR] & LPCR_EEE)) { bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC); if (!heic || !FIELD_EX64_HV(env->msr) || @@ -6610,31 +6610,31 @@ static bool cpu_has_work_POWER10(CPUState *cs) } } /* Decrementer Exception */ - if ((env->pending_interrupts & (1u << PPC_INTERRUPT_DECR)) && + if ((env->pending_interrupts & PPC_INTERRUPT_DECR) && (env->spr[SPR_LPCR] & LPCR_DEE)) { return true; } /* Machine Check or Hypervisor Maintenance Exception */ - if ((env->pending_interrupts & (1u << PPC_INTERRUPT_MCK | - 1u << PPC_INTERRUPT_HMI)) && (env->spr[SPR_LPCR] & LPCR_OEE)) { + if ((env->pending_interrupts & (PPC_INTERRUPT_MCK | PPC_INTERRUPT_HMI)) + && (env->spr[SPR_LPCR] & LPCR_OEE)) { return true; } /* Privileged Doorbell Exception */ - if ((env->pending_interrupts & (1u << PPC_INTERRUPT_DOORBELL)) && + if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) && (env->spr[SPR_LPCR] & LPCR_PDEE)) { return true; } /* Hypervisor Doorbell Exception */ - if ((env->pending_interrupts & (1u << PPC_INTERRUPT_HDOORBELL)) && + if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) && (env->spr[SPR_LPCR] & LPCR_HDEE)) { return true; } /* Hypervisor virtualization exception */ - if ((env->pending_interrupts & (1u << PPC_INTERRUPT_HVIRT)) && + if ((env->pending_interrupts & PPC_INTERRUPT_HVIRT) && (env->spr[SPR_LPCR] & LPCR_HVEE)) { return true; } - if (env->pending_interrupts & (1u << PPC_INTERRUPT_RESET)) { + if (env->pending_interrupts & PPC_INTERRUPT_RESET) { return true; } return false; diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 43f2480..d168789 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -1689,21 +1689,21 @@ static void ppc_hw_interrupt(CPUPPCState *env) bool async_deliver; /* External reset */ - if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) { - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET); + if (env->pending_interrupts & PPC_INTERRUPT_RESET) { + env->pending_interrupts &= ~PPC_INTERRUPT_RESET; powerpc_excp(cpu, POWERPC_EXCP_RESET); return; } /* Machine check exception */ - if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) { - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK); + if (env->pending_interrupts & PPC_INTERRUPT_MCK) { + env->pending_interrupts &= ~PPC_INTERRUPT_MCK; powerpc_excp(cpu, POWERPC_EXCP_MCHECK); return; } #if 0 /* TODO */ /* External debug exception */ - if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) { - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG); + if (env->pending_interrupts & PPC_INTERRUPT_DEBUG) { + env->pending_interrupts &= ~PPC_INTERRUPT_DEBUG; powerpc_excp(cpu, POWERPC_EXCP_DEBUG); return; } @@ -1718,19 +1718,19 @@ static void ppc_hw_interrupt(CPUPPCState *env) async_deliver = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset; /* Hypervisor decrementer exception */ - if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) { + if (env->pending_interrupts & PPC_INTERRUPT_HDECR) { /* LPCR will be clear when not supported so this will work */ bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE); if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hdice) { /* HDEC clears on delivery */ - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR); + env->pending_interrupts &= ~PPC_INTERRUPT_HDECR; powerpc_excp(cpu, POWERPC_EXCP_HDECR); return; } } /* Hypervisor virtualization interrupt */ - if (env->pending_interrupts & (1 << PPC_INTERRUPT_HVIRT)) { + if (env->pending_interrupts & PPC_INTERRUPT_HVIRT) { /* LPCR will be clear when not supported so this will work */ bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE); if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hvice) { @@ -1740,7 +1740,7 @@ static void ppc_hw_interrupt(CPUPPCState *env) } /* External interrupt can ignore MSR:EE under some circumstances */ - if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) { + if (env->pending_interrupts & PPC_INTERRUPT_EXT) { bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0); bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC); /* HEIC blocks delivery to the hypervisor */ @@ -1757,45 +1757,45 @@ static void ppc_hw_interrupt(CPUPPCState *env) } if (FIELD_EX64(env->msr, MSR, CE)) { /* External critical interrupt */ - if (env->pending_interrupts & (1 << PPC_INTERRUPT_CEXT)) { + if (env->pending_interrupts & PPC_INTERRUPT_CEXT) { powerpc_excp(cpu, POWERPC_EXCP_CRITICAL); return; } } if (async_deliver != 0) { /* Watchdog timer on embedded PowerPC */ - if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) { - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT); + if (env->pending_interrupts & PPC_INTERRUPT_WDT) { + env->pending_interrupts &= ~PPC_INTERRUPT_WDT; powerpc_excp(cpu, POWERPC_EXCP_WDT); return; } - if (env->pending_interrupts & (1 << PPC_INTERRUPT_CDOORBELL)) { - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CDOORBELL); + if (env->pending_interrupts & PPC_INTERRUPT_CDOORBELL) { + env->pending_interrupts &= ~PPC_INTERRUPT_CDOORBELL; powerpc_excp(cpu, POWERPC_EXCP_DOORCI); return; } /* Fixed interval timer on embedded PowerPC */ - if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) { - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT); + if (env->pending_interrupts & PPC_INTERRUPT_FIT) { + env->pending_interrupts &= ~PPC_INTERRUPT_FIT; powerpc_excp(cpu, POWERPC_EXCP_FIT); return; } /* Programmable interval timer on embedded PowerPC */ - if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) { - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT); + if (env->pending_interrupts & PPC_INTERRUPT_PIT) { + env->pending_interrupts &= ~PPC_INTERRUPT_PIT; powerpc_excp(cpu, POWERPC_EXCP_PIT); return; } /* Decrementer exception */ - if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) { + if (env->pending_interrupts & PPC_INTERRUPT_DECR) { if (ppc_decr_clear_on_delivery(env)) { - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR); + env->pending_interrupts &= ~PPC_INTERRUPT_DECR; } powerpc_excp(cpu, POWERPC_EXCP_DECR); return; } - if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) { - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL); + if (env->pending_interrupts & PPC_INTERRUPT_DOORBELL) { + env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL; if (is_book3s_arch2x(env)) { powerpc_excp(cpu, POWERPC_EXCP_SDOOR); } else { @@ -1803,31 +1803,31 @@ static void ppc_hw_interrupt(CPUPPCState *env) } return; } - if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDOORBELL)) { - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDOORBELL); + if (env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) { + env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL; powerpc_excp(cpu, POWERPC_EXCP_SDOOR_HV); return; } - if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) { - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM); + if (env->pending_interrupts & PPC_INTERRUPT_PERFM) { + env->pending_interrupts &= ~PPC_INTERRUPT_PERFM; powerpc_excp(cpu, POWERPC_EXCP_PERFM); return; } /* Thermal interrupt */ - if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) { - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM); + if (env->pending_interrupts & PPC_INTERRUPT_THERM) { + env->pending_interrupts &= ~PPC_INTERRUPT_THERM; powerpc_excp(cpu, POWERPC_EXCP_THERM); return; } /* EBB exception */ - if (env->pending_interrupts & (1 << PPC_INTERRUPT_EBB)) { + if (env->pending_interrupts & PPC_INTERRUPT_EBB) { /* * EBB exception must be taken in problem state and * with BESCR_GE set. */ if (FIELD_EX64(env->msr, MSR, PR) && (env->spr[SPR_BESCR] & BESCR_GE)) { - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_EBB); + env->pending_interrupts &= ~PPC_INTERRUPT_EBB; if (env->spr[SPR_BESCR] & BESCR_PMEO) { powerpc_excp(cpu, POWERPC_EXCP_PERFM_EBB); @@ -2104,7 +2104,7 @@ static void do_ebb(CPUPPCState *env, int ebb_excp) if (FIELD_EX64(env->msr, MSR, PR)) { powerpc_excp(cpu, ebb_excp); } else { - env->pending_interrupts |= 1 << PPC_INTERRUPT_EBB; + env->pending_interrupts |= PPC_INTERRUPT_EBB; cpu_interrupt(cs, CPU_INTERRUPT_HARD); } } @@ -2298,7 +2298,7 @@ void helper_msgclr(CPUPPCState *env, target_ulong rb) return; } - env->pending_interrupts &= ~(1 << irq); + env->pending_interrupts &= ~irq; } void helper_msgsnd(target_ulong rb) @@ -2317,7 +2317,7 @@ void helper_msgsnd(target_ulong rb) CPUPPCState *cenv = &cpu->env; if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) { - cenv->pending_interrupts |= 1 << irq; + cenv->pending_interrupts |= irq; cpu_interrupt(cs, CPU_INTERRUPT_HARD); } } @@ -2342,7 +2342,7 @@ void helper_book3s_msgclr(CPUPPCState *env, target_ulong rb) return; } - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDOORBELL); + env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL; } static void book3s_msgsnd_common(int pir, int irq) @@ -2356,7 +2356,7 @@ static void book3s_msgsnd_common(int pir, int irq) /* TODO: broadcast message to all threads of the same processor */ if (cenv->spr_cb[SPR_PIR].default_value == pir) { - cenv->pending_interrupts |= 1 << irq; + cenv->pending_interrupts |= irq; cpu_interrupt(cs, CPU_INTERRUPT_HARD); } } @@ -2383,7 +2383,7 @@ void helper_book3s_msgclrp(CPUPPCState *env, target_ulong rb) return; } - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL); + env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL; } /* diff --git a/target/ppc/misc_helper.c b/target/ppc/misc_helper.c index b0a5e7c..05e3557 100644 --- a/target/ppc/misc_helper.c +++ b/target/ppc/misc_helper.c @@ -163,7 +163,7 @@ target_ulong helper_load_dpdes(CPUPPCState *env) helper_hfscr_facility_check(env, HFSCR_MSGP, "load DPDES", HFSCR_IC_MSGP); /* TODO: TCG supports only one thread */ - if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) { + if (env->pending_interrupts & PPC_INTERRUPT_DOORBELL) { dpdes = 1; } @@ -185,10 +185,10 @@ void helper_store_dpdes(CPUPPCState *env, target_ulong val) } if (val & 0x1) { - env->pending_interrupts |= 1 << PPC_INTERRUPT_DOORBELL; + env->pending_interrupts |= PPC_INTERRUPT_DOORBELL; cpu_interrupt(cs, CPU_INTERRUPT_HARD); } else { - env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL); + env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL; } } #endif /* defined(TARGET_PPC64) */ -- cgit v1.1 From 7b694df6a6deeac8ede0512f983c70463968021a Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Tue, 11 Oct 2022 17:48:02 -0300 Subject: target/ppc: always use ppc_set_irq to set env->pending_interrupts Use ppc_set_irq to raise/clear interrupts to ensure CPU_INTERRUPT_HARD will be set/reset accordingly. Reviewed-by: Fabiano Rosas Signed-off-by: Matheus Ferst Message-Id: <20221011204829.1641124-3-matheus.ferst@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/excp_helper.c | 17 +++++++---------- target/ppc/misc_helper.c | 9 ++------- 2 files changed, 9 insertions(+), 17 deletions(-) (limited to 'target') diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index d168789..37d3526 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -23,6 +23,7 @@ #include "exec/exec-all.h" #include "internal.h" #include "helper_regs.h" +#include "hw/ppc/ppc.h" #include "trace.h" @@ -2086,7 +2087,6 @@ void helper_rfebb(CPUPPCState *env, target_ulong s) static void do_ebb(CPUPPCState *env, int ebb_excp) { PowerPCCPU *cpu = env_archcpu(env); - CPUState *cs = CPU(cpu); /* * FSCR_EBB and FSCR_IC_EBB are the same bits used with @@ -2104,8 +2104,7 @@ static void do_ebb(CPUPPCState *env, int ebb_excp) if (FIELD_EX64(env->msr, MSR, PR)) { powerpc_excp(cpu, ebb_excp); } else { - env->pending_interrupts |= PPC_INTERRUPT_EBB; - cpu_interrupt(cs, CPU_INTERRUPT_HARD); + ppc_set_irq(cpu, PPC_INTERRUPT_EBB, 1); } } @@ -2298,7 +2297,7 @@ void helper_msgclr(CPUPPCState *env, target_ulong rb) return; } - env->pending_interrupts &= ~irq; + ppc_set_irq(env_archcpu(env), irq, 0); } void helper_msgsnd(target_ulong rb) @@ -2317,8 +2316,7 @@ void helper_msgsnd(target_ulong rb) CPUPPCState *cenv = &cpu->env; if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) { - cenv->pending_interrupts |= irq; - cpu_interrupt(cs, CPU_INTERRUPT_HARD); + ppc_set_irq(cpu, irq, 1); } } qemu_mutex_unlock_iothread(); @@ -2342,7 +2340,7 @@ void helper_book3s_msgclr(CPUPPCState *env, target_ulong rb) return; } - env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL; + ppc_set_irq(env_archcpu(env), PPC_INTERRUPT_HDOORBELL, 0); } static void book3s_msgsnd_common(int pir, int irq) @@ -2356,8 +2354,7 @@ static void book3s_msgsnd_common(int pir, int irq) /* TODO: broadcast message to all threads of the same processor */ if (cenv->spr_cb[SPR_PIR].default_value == pir) { - cenv->pending_interrupts |= irq; - cpu_interrupt(cs, CPU_INTERRUPT_HARD); + ppc_set_irq(cpu, irq, 1); } } qemu_mutex_unlock_iothread(); @@ -2383,7 +2380,7 @@ void helper_book3s_msgclrp(CPUPPCState *env, target_ulong rb) return; } - env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL; + ppc_set_irq(env_archcpu(env), PPC_INTERRUPT_HDOORBELL, 0); } /* diff --git a/target/ppc/misc_helper.c b/target/ppc/misc_helper.c index 05e3557..a9bc152 100644 --- a/target/ppc/misc_helper.c +++ b/target/ppc/misc_helper.c @@ -25,6 +25,7 @@ #include "qemu/error-report.h" #include "qemu/main-loop.h" #include "mmu-book3s-v3.h" +#include "hw/ppc/ppc.h" #include "helper_regs.h" @@ -173,7 +174,6 @@ target_ulong helper_load_dpdes(CPUPPCState *env) void helper_store_dpdes(CPUPPCState *env, target_ulong val) { PowerPCCPU *cpu = env_archcpu(env); - CPUState *cs = CPU(cpu); helper_hfscr_facility_check(env, HFSCR_MSGP, "store DPDES", HFSCR_IC_MSGP); @@ -184,12 +184,7 @@ void helper_store_dpdes(CPUPPCState *env, target_ulong val) return; } - if (val & 0x1) { - env->pending_interrupts |= PPC_INTERRUPT_DOORBELL; - cpu_interrupt(cs, CPU_INTERRUPT_HARD); - } else { - env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL; - } + ppc_set_irq(cpu, PPC_INTERRUPT_DOORBELL, val & 0x1); } #endif /* defined(TARGET_PPC64) */ -- cgit v1.1 From de76b85c961378795a9e3044881554b25a4db333 Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Tue, 11 Oct 2022 17:48:03 -0300 Subject: target/ppc: split interrupt masking and delivery from ppc_hw_interrupt Split ppc_hw_interrupt into an interrupt masking method, ppc_next_unmasked_interrupt, and an interrupt processing method, ppc_deliver_interrupt. Signed-off-by: Matheus Ferst Reviewed-by: Fabiano Rosas Message-Id: <20221011204829.1641124-4-matheus.ferst@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/excp_helper.c | 201 +++++++++++++++++++++++++++++------------------ 1 file changed, 125 insertions(+), 76 deletions(-) (limited to 'target') diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 37d3526..759bad5 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -1684,29 +1684,22 @@ void ppc_cpu_do_interrupt(CPUState *cs) powerpc_excp(cpu, cs->exception_index); } -static void ppc_hw_interrupt(CPUPPCState *env) +static int ppc_next_unmasked_interrupt(CPUPPCState *env) { - PowerPCCPU *cpu = env_archcpu(env); bool async_deliver; /* External reset */ if (env->pending_interrupts & PPC_INTERRUPT_RESET) { - env->pending_interrupts &= ~PPC_INTERRUPT_RESET; - powerpc_excp(cpu, POWERPC_EXCP_RESET); - return; + return PPC_INTERRUPT_RESET; } /* Machine check exception */ if (env->pending_interrupts & PPC_INTERRUPT_MCK) { - env->pending_interrupts &= ~PPC_INTERRUPT_MCK; - powerpc_excp(cpu, POWERPC_EXCP_MCHECK); - return; + return PPC_INTERRUPT_MCK; } #if 0 /* TODO */ /* External debug exception */ if (env->pending_interrupts & PPC_INTERRUPT_DEBUG) { - env->pending_interrupts &= ~PPC_INTERRUPT_DEBUG; - powerpc_excp(cpu, POWERPC_EXCP_DEBUG); - return; + return PPC_INTERRUPT_DEBUG; } #endif @@ -1724,9 +1717,7 @@ static void ppc_hw_interrupt(CPUPPCState *env) bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE); if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hdice) { /* HDEC clears on delivery */ - env->pending_interrupts &= ~PPC_INTERRUPT_HDECR; - powerpc_excp(cpu, POWERPC_EXCP_HDECR); - return; + return PPC_INTERRUPT_HDECR; } } @@ -1735,8 +1726,7 @@ static void ppc_hw_interrupt(CPUPPCState *env) /* LPCR will be clear when not supported so this will work */ bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE); if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hvice) { - powerpc_excp(cpu, POWERPC_EXCP_HVIRT); - return; + return PPC_INTERRUPT_HVIRT; } } @@ -1748,77 +1738,47 @@ static void ppc_hw_interrupt(CPUPPCState *env) if ((async_deliver && !(heic && FIELD_EX64_HV(env->msr) && !FIELD_EX64(env->msr, MSR, PR))) || (env->has_hv_mode && !FIELD_EX64_HV(env->msr) && !lpes0)) { - if (books_vhyp_promotes_external_to_hvirt(cpu)) { - powerpc_excp(cpu, POWERPC_EXCP_HVIRT); - } else { - powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL); - } - return; + return PPC_INTERRUPT_EXT; } } if (FIELD_EX64(env->msr, MSR, CE)) { /* External critical interrupt */ if (env->pending_interrupts & PPC_INTERRUPT_CEXT) { - powerpc_excp(cpu, POWERPC_EXCP_CRITICAL); - return; + return PPC_INTERRUPT_CEXT; } } if (async_deliver != 0) { /* Watchdog timer on embedded PowerPC */ if (env->pending_interrupts & PPC_INTERRUPT_WDT) { - env->pending_interrupts &= ~PPC_INTERRUPT_WDT; - powerpc_excp(cpu, POWERPC_EXCP_WDT); - return; + return PPC_INTERRUPT_WDT; } if (env->pending_interrupts & PPC_INTERRUPT_CDOORBELL) { - env->pending_interrupts &= ~PPC_INTERRUPT_CDOORBELL; - powerpc_excp(cpu, POWERPC_EXCP_DOORCI); - return; + return PPC_INTERRUPT_CDOORBELL; } /* Fixed interval timer on embedded PowerPC */ if (env->pending_interrupts & PPC_INTERRUPT_FIT) { - env->pending_interrupts &= ~PPC_INTERRUPT_FIT; - powerpc_excp(cpu, POWERPC_EXCP_FIT); - return; + return PPC_INTERRUPT_FIT; } /* Programmable interval timer on embedded PowerPC */ if (env->pending_interrupts & PPC_INTERRUPT_PIT) { - env->pending_interrupts &= ~PPC_INTERRUPT_PIT; - powerpc_excp(cpu, POWERPC_EXCP_PIT); - return; + return PPC_INTERRUPT_PIT; } /* Decrementer exception */ if (env->pending_interrupts & PPC_INTERRUPT_DECR) { - if (ppc_decr_clear_on_delivery(env)) { - env->pending_interrupts &= ~PPC_INTERRUPT_DECR; - } - powerpc_excp(cpu, POWERPC_EXCP_DECR); - return; + return PPC_INTERRUPT_DECR; } if (env->pending_interrupts & PPC_INTERRUPT_DOORBELL) { - env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL; - if (is_book3s_arch2x(env)) { - powerpc_excp(cpu, POWERPC_EXCP_SDOOR); - } else { - powerpc_excp(cpu, POWERPC_EXCP_DOORI); - } - return; + return PPC_INTERRUPT_DOORBELL; } if (env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) { - env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL; - powerpc_excp(cpu, POWERPC_EXCP_SDOOR_HV); - return; + return PPC_INTERRUPT_HDOORBELL; } if (env->pending_interrupts & PPC_INTERRUPT_PERFM) { - env->pending_interrupts &= ~PPC_INTERRUPT_PERFM; - powerpc_excp(cpu, POWERPC_EXCP_PERFM); - return; + return PPC_INTERRUPT_PERFM; } /* Thermal interrupt */ if (env->pending_interrupts & PPC_INTERRUPT_THERM) { - env->pending_interrupts &= ~PPC_INTERRUPT_THERM; - powerpc_excp(cpu, POWERPC_EXCP_THERM); - return; + return PPC_INTERRUPT_THERM; } /* EBB exception */ if (env->pending_interrupts & PPC_INTERRUPT_EBB) { @@ -1828,20 +1788,100 @@ static void ppc_hw_interrupt(CPUPPCState *env) */ if (FIELD_EX64(env->msr, MSR, PR) && (env->spr[SPR_BESCR] & BESCR_GE)) { - env->pending_interrupts &= ~PPC_INTERRUPT_EBB; - - if (env->spr[SPR_BESCR] & BESCR_PMEO) { - powerpc_excp(cpu, POWERPC_EXCP_PERFM_EBB); - } else if (env->spr[SPR_BESCR] & BESCR_EEO) { - powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL_EBB); - } - - return; + return PPC_INTERRUPT_EBB; } } } - if (env->resume_as_sreset) { + return 0; +} + +static void ppc_deliver_interrupt(CPUPPCState *env, int interrupt) +{ + PowerPCCPU *cpu = env_archcpu(env); + CPUState *cs = env_cpu(env); + + switch (interrupt) { + case PPC_INTERRUPT_RESET: /* External reset */ + env->pending_interrupts &= ~PPC_INTERRUPT_RESET; + powerpc_excp(cpu, POWERPC_EXCP_RESET); + break; + case PPC_INTERRUPT_MCK: /* Machine check exception */ + env->pending_interrupts &= ~PPC_INTERRUPT_MCK; + powerpc_excp(cpu, POWERPC_EXCP_MCHECK); + break; + + case PPC_INTERRUPT_HDECR: /* Hypervisor decrementer exception */ + /* HDEC clears on delivery */ + env->pending_interrupts &= ~PPC_INTERRUPT_HDECR; + powerpc_excp(cpu, POWERPC_EXCP_HDECR); + break; + case PPC_INTERRUPT_HVIRT: /* Hypervisor virtualization interrupt */ + powerpc_excp(cpu, POWERPC_EXCP_HVIRT); + break; + + case PPC_INTERRUPT_EXT: + if (books_vhyp_promotes_external_to_hvirt(cpu)) { + powerpc_excp(cpu, POWERPC_EXCP_HVIRT); + } else { + powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL); + } + break; + case PPC_INTERRUPT_CEXT: /* External critical interrupt */ + powerpc_excp(cpu, POWERPC_EXCP_CRITICAL); + break; + + case PPC_INTERRUPT_WDT: /* Watchdog timer on embedded PowerPC */ + env->pending_interrupts &= ~PPC_INTERRUPT_WDT; + powerpc_excp(cpu, POWERPC_EXCP_WDT); + break; + case PPC_INTERRUPT_CDOORBELL: + env->pending_interrupts &= ~PPC_INTERRUPT_CDOORBELL; + powerpc_excp(cpu, POWERPC_EXCP_DOORCI); + break; + case PPC_INTERRUPT_FIT: /* Fixed interval timer on embedded PowerPC */ + env->pending_interrupts &= ~PPC_INTERRUPT_FIT; + powerpc_excp(cpu, POWERPC_EXCP_FIT); + break; + case PPC_INTERRUPT_PIT: /* Programmable interval timer on embedded ppc */ + env->pending_interrupts &= ~PPC_INTERRUPT_PIT; + powerpc_excp(cpu, POWERPC_EXCP_PIT); + break; + case PPC_INTERRUPT_DECR: /* Decrementer exception */ + if (ppc_decr_clear_on_delivery(env)) { + env->pending_interrupts &= ~PPC_INTERRUPT_DECR; + } + powerpc_excp(cpu, POWERPC_EXCP_DECR); + break; + case PPC_INTERRUPT_DOORBELL: + env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL; + if (is_book3s_arch2x(env)) { + powerpc_excp(cpu, POWERPC_EXCP_SDOOR); + } else { + powerpc_excp(cpu, POWERPC_EXCP_DOORI); + } + break; + case PPC_INTERRUPT_HDOORBELL: + env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL; + powerpc_excp(cpu, POWERPC_EXCP_SDOOR_HV); + break; + case PPC_INTERRUPT_PERFM: + env->pending_interrupts &= ~PPC_INTERRUPT_PERFM; + powerpc_excp(cpu, POWERPC_EXCP_PERFM); + break; + case PPC_INTERRUPT_THERM: /* Thermal interrupt */ + env->pending_interrupts &= ~PPC_INTERRUPT_THERM; + powerpc_excp(cpu, POWERPC_EXCP_THERM); + break; + case PPC_INTERRUPT_EBB: /* EBB exception */ + env->pending_interrupts &= ~PPC_INTERRUPT_EBB; + if (env->spr[SPR_BESCR] & BESCR_PMEO) { + powerpc_excp(cpu, POWERPC_EXCP_PERFM_EBB); + } else if (env->spr[SPR_BESCR] & BESCR_EEO) { + powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL_EBB); + } + break; + case 0: /* * This is a bug ! It means that has_work took us out of halt without * anything to deliver while in a PM state that requires getting @@ -1853,8 +1893,10 @@ static void ppc_hw_interrupt(CPUPPCState *env) * It generally means a discrepancy between the wakeup conditions in the * processor has_work implementation and the logic in this function. */ - cpu_abort(env_cpu(env), - "Wakeup from PM state but interrupt Undelivered"); + assert(!env->resume_as_sreset); + break; + default: + cpu_abort(cs, "Invalid PowerPC interrupt %d. Aborting\n", interrupt); } } @@ -1890,15 +1932,22 @@ bool ppc_cpu_exec_interrupt(CPUState *cs, int interrupt_request) { PowerPCCPU *cpu = POWERPC_CPU(cs); CPUPPCState *env = &cpu->env; + int interrupt; - if (interrupt_request & CPU_INTERRUPT_HARD) { - ppc_hw_interrupt(env); - if (env->pending_interrupts == 0) { - cs->interrupt_request &= ~CPU_INTERRUPT_HARD; - } - return true; + if ((interrupt_request & CPU_INTERRUPT_HARD) == 0) { + return false; } - return false; + + interrupt = ppc_next_unmasked_interrupt(env); + if (interrupt == 0) { + return false; + } + + ppc_deliver_interrupt(env, interrupt); + if (env->pending_interrupts == 0) { + cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); + } + return true; } #endif /* !CONFIG_USER_ONLY */ -- cgit v1.1 From ba2898f79f9d36320abfa7c0589c796810c7186b Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Tue, 11 Oct 2022 17:48:04 -0300 Subject: target/ppc: prepare to split interrupt masking and delivery by excp_model Signed-off-by: Matheus Ferst Reviewed-by: Fabiano Rosas Message-Id: <20221011204829.1641124-5-matheus.ferst@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/excp_helper.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'target') diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 759bad5..0e89d2e 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -1684,7 +1684,7 @@ void ppc_cpu_do_interrupt(CPUState *cs) powerpc_excp(cpu, cs->exception_index); } -static int ppc_next_unmasked_interrupt(CPUPPCState *env) +static int ppc_next_unmasked_interrupt_generic(CPUPPCState *env) { bool async_deliver; @@ -1796,7 +1796,15 @@ static int ppc_next_unmasked_interrupt(CPUPPCState *env) return 0; } -static void ppc_deliver_interrupt(CPUPPCState *env, int interrupt) +static int ppc_next_unmasked_interrupt(CPUPPCState *env) +{ + switch (env->excp_model) { + default: + return ppc_next_unmasked_interrupt_generic(env); + } +} + +static void ppc_deliver_interrupt_generic(CPUPPCState *env, int interrupt) { PowerPCCPU *cpu = env_archcpu(env); CPUState *cs = env_cpu(env); @@ -1900,6 +1908,14 @@ static void ppc_deliver_interrupt(CPUPPCState *env, int interrupt) } } +static void ppc_deliver_interrupt(CPUPPCState *env, int interrupt) +{ + switch (env->excp_model) { + default: + ppc_deliver_interrupt_generic(env, interrupt); + } +} + void ppc_cpu_do_system_reset(CPUState *cs) { PowerPCCPU *cpu = POWERPC_CPU(cs); -- cgit v1.1 From 2dfecf01952f6d4c9c7698ae55d7a425999acaed Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Tue, 11 Oct 2022 17:48:05 -0300 Subject: target/ppc: create an interrupt masking method for POWER9/POWER10 The new method is identical to ppc_next_unmasked_interrupt_generic, processor-specific code will be added/removed in the following patches. Signed-off-by: Matheus Ferst Reviewed-by: Fabiano Rosas Message-Id: <20221011204829.1641124-6-matheus.ferst@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/excp_helper.c | 113 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) (limited to 'target') diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 0e89d2e..4d2fb2e 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -1684,6 +1684,114 @@ void ppc_cpu_do_interrupt(CPUState *cs) powerpc_excp(cpu, cs->exception_index); } +#if defined(TARGET_PPC64) +static int p9_next_unmasked_interrupt(CPUPPCState *env) +{ + bool async_deliver; + + /* External reset */ + if (env->pending_interrupts & PPC_INTERRUPT_RESET) { + return PPC_INTERRUPT_RESET; + } + /* Machine check exception */ + if (env->pending_interrupts & PPC_INTERRUPT_MCK) { + return PPC_INTERRUPT_MCK; + } + + /* + * For interrupts that gate on MSR:EE, we need to do something a + * bit more subtle, as we need to let them through even when EE is + * clear when coming out of some power management states (in order + * for them to become a 0x100). + */ + async_deliver = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset; + + /* Hypervisor decrementer exception */ + if (env->pending_interrupts & PPC_INTERRUPT_HDECR) { + /* LPCR will be clear when not supported so this will work */ + bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE); + if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hdice) { + /* HDEC clears on delivery */ + return PPC_INTERRUPT_HDECR; + } + } + + /* Hypervisor virtualization interrupt */ + if (env->pending_interrupts & PPC_INTERRUPT_HVIRT) { + /* LPCR will be clear when not supported so this will work */ + bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE); + if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hvice) { + return PPC_INTERRUPT_HVIRT; + } + } + + /* External interrupt can ignore MSR:EE under some circumstances */ + if (env->pending_interrupts & PPC_INTERRUPT_EXT) { + bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0); + bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC); + /* HEIC blocks delivery to the hypervisor */ + if ((async_deliver && !(heic && FIELD_EX64_HV(env->msr) && + !FIELD_EX64(env->msr, MSR, PR))) || + (env->has_hv_mode && !FIELD_EX64_HV(env->msr) && !lpes0)) { + return PPC_INTERRUPT_EXT; + } + } + if (FIELD_EX64(env->msr, MSR, CE)) { + /* External critical interrupt */ + if (env->pending_interrupts & PPC_INTERRUPT_CEXT) { + return PPC_INTERRUPT_CEXT; + } + } + if (async_deliver != 0) { + /* Watchdog timer on embedded PowerPC */ + if (env->pending_interrupts & PPC_INTERRUPT_WDT) { + return PPC_INTERRUPT_WDT; + } + if (env->pending_interrupts & PPC_INTERRUPT_CDOORBELL) { + return PPC_INTERRUPT_CDOORBELL; + } + /* Fixed interval timer on embedded PowerPC */ + if (env->pending_interrupts & PPC_INTERRUPT_FIT) { + return PPC_INTERRUPT_FIT; + } + /* Programmable interval timer on embedded PowerPC */ + if (env->pending_interrupts & PPC_INTERRUPT_PIT) { + return PPC_INTERRUPT_PIT; + } + /* Decrementer exception */ + if (env->pending_interrupts & PPC_INTERRUPT_DECR) { + return PPC_INTERRUPT_DECR; + } + if (env->pending_interrupts & PPC_INTERRUPT_DOORBELL) { + return PPC_INTERRUPT_DOORBELL; + } + if (env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) { + return PPC_INTERRUPT_HDOORBELL; + } + if (env->pending_interrupts & PPC_INTERRUPT_PERFM) { + return PPC_INTERRUPT_PERFM; + } + /* Thermal interrupt */ + if (env->pending_interrupts & PPC_INTERRUPT_THERM) { + return PPC_INTERRUPT_THERM; + } + /* EBB exception */ + if (env->pending_interrupts & PPC_INTERRUPT_EBB) { + /* + * EBB exception must be taken in problem state and + * with BESCR_GE set. + */ + if (FIELD_EX64(env->msr, MSR, PR) && + (env->spr[SPR_BESCR] & BESCR_GE)) { + return PPC_INTERRUPT_EBB; + } + } + } + + return 0; +} +#endif + static int ppc_next_unmasked_interrupt_generic(CPUPPCState *env) { bool async_deliver; @@ -1799,6 +1907,11 @@ static int ppc_next_unmasked_interrupt_generic(CPUPPCState *env) static int ppc_next_unmasked_interrupt(CPUPPCState *env) { switch (env->excp_model) { +#if defined(TARGET_PPC64) + case POWERPC_EXCP_POWER9: + case POWERPC_EXCP_POWER10: + return p9_next_unmasked_interrupt(env); +#endif default: return ppc_next_unmasked_interrupt_generic(env); } -- cgit v1.1 From b00e9a2f2be384820a107c28ff97fb4d6ed84b8a Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Tue, 11 Oct 2022 17:48:06 -0300 Subject: target/ppc: remove unused interrupts from p9_next_unmasked_interrupt Remove the following unused interrupts from the POWER9 interrupt masking method: - PPC_INTERRUPT_RESET: only raised for 6xx, 7xx, 970 and POWER5p; - Debug Interrupt: removed in Power ISA v2.07; - Critical Input, Watchdog Timer, and Fixed Interval Timer: only defined for embedded CPUs; - Critical Doorbell Interrupt: removed in Power ISA v3.0; - Programmable Interval Timer: 40x-only. Signed-off-by: Matheus Ferst Reviewed-by: Fabiano Rosas Message-Id: <20221011204829.1641124-7-matheus.ferst@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/excp_helper.c | 36 +++++++----------------------------- 1 file changed, 7 insertions(+), 29 deletions(-) (limited to 'target') diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 4d2fb2e..740a561 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -1685,14 +1685,17 @@ void ppc_cpu_do_interrupt(CPUState *cs) } #if defined(TARGET_PPC64) +#define P9_UNUSED_INTERRUPTS \ + (PPC_INTERRUPT_RESET | PPC_INTERRUPT_DEBUG | PPC_INTERRUPT_CEXT | \ + PPC_INTERRUPT_WDT | PPC_INTERRUPT_CDOORBELL | PPC_INTERRUPT_FIT | \ + PPC_INTERRUPT_PIT | PPC_INTERRUPT_THERM) + static int p9_next_unmasked_interrupt(CPUPPCState *env) { bool async_deliver; - /* External reset */ - if (env->pending_interrupts & PPC_INTERRUPT_RESET) { - return PPC_INTERRUPT_RESET; - } + assert((env->pending_interrupts & P9_UNUSED_INTERRUPTS) == 0); + /* Machine check exception */ if (env->pending_interrupts & PPC_INTERRUPT_MCK) { return PPC_INTERRUPT_MCK; @@ -1736,28 +1739,7 @@ static int p9_next_unmasked_interrupt(CPUPPCState *env) return PPC_INTERRUPT_EXT; } } - if (FIELD_EX64(env->msr, MSR, CE)) { - /* External critical interrupt */ - if (env->pending_interrupts & PPC_INTERRUPT_CEXT) { - return PPC_INTERRUPT_CEXT; - } - } if (async_deliver != 0) { - /* Watchdog timer on embedded PowerPC */ - if (env->pending_interrupts & PPC_INTERRUPT_WDT) { - return PPC_INTERRUPT_WDT; - } - if (env->pending_interrupts & PPC_INTERRUPT_CDOORBELL) { - return PPC_INTERRUPT_CDOORBELL; - } - /* Fixed interval timer on embedded PowerPC */ - if (env->pending_interrupts & PPC_INTERRUPT_FIT) { - return PPC_INTERRUPT_FIT; - } - /* Programmable interval timer on embedded PowerPC */ - if (env->pending_interrupts & PPC_INTERRUPT_PIT) { - return PPC_INTERRUPT_PIT; - } /* Decrementer exception */ if (env->pending_interrupts & PPC_INTERRUPT_DECR) { return PPC_INTERRUPT_DECR; @@ -1771,10 +1753,6 @@ static int p9_next_unmasked_interrupt(CPUPPCState *env) if (env->pending_interrupts & PPC_INTERRUPT_PERFM) { return PPC_INTERRUPT_PERFM; } - /* Thermal interrupt */ - if (env->pending_interrupts & PPC_INTERRUPT_THERM) { - return PPC_INTERRUPT_THERM; - } /* EBB exception */ if (env->pending_interrupts & PPC_INTERRUPT_EBB) { /* -- cgit v1.1 From 3654e238af02fb828b71aa85a4fc475770a3d91a Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Tue, 11 Oct 2022 17:48:07 -0300 Subject: target/ppc: create an interrupt deliver method for POWER9/POWER10 The new method is identical to ppc_deliver_interrupt, processor-specific code will be added/removed in the following patches. Signed-off-by: Matheus Ferst Reviewed-by: Fabiano Rosas Message-Id: <20221011204829.1641124-8-matheus.ferst@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/excp_helper.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) (limited to 'target') diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 740a561..104b48d 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -1895,6 +1895,112 @@ static int ppc_next_unmasked_interrupt(CPUPPCState *env) } } +#if defined(TARGET_PPC64) +static void p9_deliver_interrupt(CPUPPCState *env, int interrupt) +{ + PowerPCCPU *cpu = env_archcpu(env); + CPUState *cs = env_cpu(env); + + switch (interrupt) { + case PPC_INTERRUPT_RESET: /* External reset */ + env->pending_interrupts &= ~PPC_INTERRUPT_RESET; + powerpc_excp(cpu, POWERPC_EXCP_RESET); + break; + case PPC_INTERRUPT_MCK: /* Machine check exception */ + env->pending_interrupts &= ~PPC_INTERRUPT_MCK; + powerpc_excp(cpu, POWERPC_EXCP_MCHECK); + break; + + case PPC_INTERRUPT_HDECR: /* Hypervisor decrementer exception */ + /* HDEC clears on delivery */ + env->pending_interrupts &= ~PPC_INTERRUPT_HDECR; + powerpc_excp(cpu, POWERPC_EXCP_HDECR); + break; + case PPC_INTERRUPT_HVIRT: /* Hypervisor virtualization interrupt */ + powerpc_excp(cpu, POWERPC_EXCP_HVIRT); + break; + + case PPC_INTERRUPT_EXT: + if (books_vhyp_promotes_external_to_hvirt(cpu)) { + powerpc_excp(cpu, POWERPC_EXCP_HVIRT); + } else { + powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL); + } + break; + case PPC_INTERRUPT_CEXT: /* External critical interrupt */ + powerpc_excp(cpu, POWERPC_EXCP_CRITICAL); + break; + + case PPC_INTERRUPT_WDT: /* Watchdog timer on embedded PowerPC */ + env->pending_interrupts &= ~PPC_INTERRUPT_WDT; + powerpc_excp(cpu, POWERPC_EXCP_WDT); + break; + case PPC_INTERRUPT_CDOORBELL: + env->pending_interrupts &= ~PPC_INTERRUPT_CDOORBELL; + powerpc_excp(cpu, POWERPC_EXCP_DOORCI); + break; + case PPC_INTERRUPT_FIT: /* Fixed interval timer on embedded PowerPC */ + env->pending_interrupts &= ~PPC_INTERRUPT_FIT; + powerpc_excp(cpu, POWERPC_EXCP_FIT); + break; + case PPC_INTERRUPT_PIT: /* Programmable interval timer on embedded ppc */ + env->pending_interrupts &= ~PPC_INTERRUPT_PIT; + powerpc_excp(cpu, POWERPC_EXCP_PIT); + break; + case PPC_INTERRUPT_DECR: /* Decrementer exception */ + if (ppc_decr_clear_on_delivery(env)) { + env->pending_interrupts &= ~PPC_INTERRUPT_DECR; + } + powerpc_excp(cpu, POWERPC_EXCP_DECR); + break; + case PPC_INTERRUPT_DOORBELL: + env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL; + if (is_book3s_arch2x(env)) { + powerpc_excp(cpu, POWERPC_EXCP_SDOOR); + } else { + powerpc_excp(cpu, POWERPC_EXCP_DOORI); + } + break; + case PPC_INTERRUPT_HDOORBELL: + env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL; + powerpc_excp(cpu, POWERPC_EXCP_SDOOR_HV); + break; + case PPC_INTERRUPT_PERFM: + env->pending_interrupts &= ~PPC_INTERRUPT_PERFM; + powerpc_excp(cpu, POWERPC_EXCP_PERFM); + break; + case PPC_INTERRUPT_THERM: /* Thermal interrupt */ + env->pending_interrupts &= ~PPC_INTERRUPT_THERM; + powerpc_excp(cpu, POWERPC_EXCP_THERM); + break; + case PPC_INTERRUPT_EBB: /* EBB exception */ + env->pending_interrupts &= ~PPC_INTERRUPT_EBB; + if (env->spr[SPR_BESCR] & BESCR_PMEO) { + powerpc_excp(cpu, POWERPC_EXCP_PERFM_EBB); + } else if (env->spr[SPR_BESCR] & BESCR_EEO) { + powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL_EBB); + } + break; + case 0: + /* + * This is a bug ! It means that has_work took us out of halt without + * anything to deliver while in a PM state that requires getting + * out via a 0x100 + * + * This means we will incorrectly execute past the power management + * instruction instead of triggering a reset. + * + * It generally means a discrepancy between the wakeup conditions in the + * processor has_work implementation and the logic in this function. + */ + assert(!env->resume_as_sreset); + break; + default: + cpu_abort(cs, "Invalid PowerPC interrupt %d. Aborting\n", interrupt); + } +} +#endif + static void ppc_deliver_interrupt_generic(CPUPPCState *env, int interrupt) { PowerPCCPU *cpu = env_archcpu(env); @@ -2002,6 +2108,12 @@ static void ppc_deliver_interrupt_generic(CPUPPCState *env, int interrupt) static void ppc_deliver_interrupt(CPUPPCState *env, int interrupt) { switch (env->excp_model) { +#if defined(TARGET_PPC64) + case POWERPC_EXCP_POWER9: + case POWERPC_EXCP_POWER10: + p9_deliver_interrupt(env, interrupt); + break; +#endif default: ppc_deliver_interrupt_generic(env, interrupt); } -- cgit v1.1 From 1e75ffe40efcf07c3576a9ffb76235975ca96ce7 Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Tue, 11 Oct 2022 17:48:08 -0300 Subject: target/ppc: remove unused interrupts from p9_deliver_interrupt Remove the following unused interrupts from the POWER9 interrupt processing method: - PPC_INTERRUPT_RESET: only raised for 6xx, 7xx, 970 and POWER5p; - Debug Interrupt: removed in Power ISA v2.07; - Critical Input, Watchdog Timer, and Fixed Interval Timer: only defined for embedded CPUs; - Critical Doorbell Interrupt: removed in Power ISA v3.0; - Programmable Interval Timer: 40x-only. Signed-off-by: Matheus Ferst Reviewed-by: Fabiano Rosas Message-Id: <20221011204829.1641124-9-matheus.ferst@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/excp_helper.c | 27 --------------------------- 1 file changed, 27 deletions(-) (limited to 'target') diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 104b48d..288bb20 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -1902,10 +1902,6 @@ static void p9_deliver_interrupt(CPUPPCState *env, int interrupt) CPUState *cs = env_cpu(env); switch (interrupt) { - case PPC_INTERRUPT_RESET: /* External reset */ - env->pending_interrupts &= ~PPC_INTERRUPT_RESET; - powerpc_excp(cpu, POWERPC_EXCP_RESET); - break; case PPC_INTERRUPT_MCK: /* Machine check exception */ env->pending_interrupts &= ~PPC_INTERRUPT_MCK; powerpc_excp(cpu, POWERPC_EXCP_MCHECK); @@ -1927,26 +1923,7 @@ static void p9_deliver_interrupt(CPUPPCState *env, int interrupt) powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL); } break; - case PPC_INTERRUPT_CEXT: /* External critical interrupt */ - powerpc_excp(cpu, POWERPC_EXCP_CRITICAL); - break; - case PPC_INTERRUPT_WDT: /* Watchdog timer on embedded PowerPC */ - env->pending_interrupts &= ~PPC_INTERRUPT_WDT; - powerpc_excp(cpu, POWERPC_EXCP_WDT); - break; - case PPC_INTERRUPT_CDOORBELL: - env->pending_interrupts &= ~PPC_INTERRUPT_CDOORBELL; - powerpc_excp(cpu, POWERPC_EXCP_DOORCI); - break; - case PPC_INTERRUPT_FIT: /* Fixed interval timer on embedded PowerPC */ - env->pending_interrupts &= ~PPC_INTERRUPT_FIT; - powerpc_excp(cpu, POWERPC_EXCP_FIT); - break; - case PPC_INTERRUPT_PIT: /* Programmable interval timer on embedded ppc */ - env->pending_interrupts &= ~PPC_INTERRUPT_PIT; - powerpc_excp(cpu, POWERPC_EXCP_PIT); - break; case PPC_INTERRUPT_DECR: /* Decrementer exception */ if (ppc_decr_clear_on_delivery(env)) { env->pending_interrupts &= ~PPC_INTERRUPT_DECR; @@ -1969,10 +1946,6 @@ static void p9_deliver_interrupt(CPUPPCState *env, int interrupt) env->pending_interrupts &= ~PPC_INTERRUPT_PERFM; powerpc_excp(cpu, POWERPC_EXCP_PERFM); break; - case PPC_INTERRUPT_THERM: /* Thermal interrupt */ - env->pending_interrupts &= ~PPC_INTERRUPT_THERM; - powerpc_excp(cpu, POWERPC_EXCP_THERM); - break; case PPC_INTERRUPT_EBB: /* EBB exception */ env->pending_interrupts &= ~PPC_INTERRUPT_EBB; if (env->spr[SPR_BESCR] & BESCR_PMEO) { -- cgit v1.1 From ed3a24c95a9d8d870bf671d5675b8b4b32a0db75 Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Tue, 11 Oct 2022 17:48:09 -0300 Subject: target/ppc: remove generic architecture checks from p9_deliver_interrupt Signed-off-by: Matheus Ferst Reviewed-by: Fabiano Rosas Message-Id: <20221011204829.1641124-10-matheus.ferst@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/excp_helper.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'target') diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 288bb20..238ce78 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -1925,18 +1925,11 @@ static void p9_deliver_interrupt(CPUPPCState *env, int interrupt) break; case PPC_INTERRUPT_DECR: /* Decrementer exception */ - if (ppc_decr_clear_on_delivery(env)) { - env->pending_interrupts &= ~PPC_INTERRUPT_DECR; - } powerpc_excp(cpu, POWERPC_EXCP_DECR); break; case PPC_INTERRUPT_DOORBELL: env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL; - if (is_book3s_arch2x(env)) { - powerpc_excp(cpu, POWERPC_EXCP_SDOOR); - } else { - powerpc_excp(cpu, POWERPC_EXCP_DOORI); - } + powerpc_excp(cpu, POWERPC_EXCP_SDOOR); break; case PPC_INTERRUPT_HDOORBELL: env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL; -- cgit v1.1 From 0ccd9d67b1ee9289dd96f2d133a618f97f7a89ab Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Tue, 11 Oct 2022 17:48:10 -0300 Subject: target/ppc: move power-saving interrupt masking out of cpu_has_work_POWER9 Move the interrupt masking logic out of cpu_has_work_POWER9 in a new method, p9_interrupt_powersave, that only returns an interrupt if it can wake the processor from power-saving mode. Signed-off-by: Matheus Ferst Reviewed-by: Fabiano Rosas Message-Id: <20221011204829.1641124-11-matheus.ferst@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/cpu_init.c | 126 ++++++++++++++++++++------------------------------ 1 file changed, 50 insertions(+), 76 deletions(-) (limited to 'target') diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index 07171c6..9ecea10 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -6351,6 +6351,52 @@ static bool ppc_pvr_match_power9(PowerPCCPUClass *pcc, uint32_t pvr, bool best) return false; } +static int p9_interrupt_powersave(CPUPPCState *env) +{ + /* External Exception */ + if ((env->pending_interrupts & PPC_INTERRUPT_EXT) && + (env->spr[SPR_LPCR] & LPCR_EEE)) { + bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC); + if (!heic || !FIELD_EX64_HV(env->msr) || + FIELD_EX64(env->msr, MSR, PR)) { + return PPC_INTERRUPT_EXT; + } + } + /* Decrementer Exception */ + if ((env->pending_interrupts & PPC_INTERRUPT_DECR) && + (env->spr[SPR_LPCR] & LPCR_DEE)) { + return PPC_INTERRUPT_DECR; + } + /* Machine Check or Hypervisor Maintenance Exception */ + if (env->spr[SPR_LPCR] & LPCR_OEE) { + if (env->pending_interrupts & PPC_INTERRUPT_MCK) { + return PPC_INTERRUPT_MCK; + } + if (env->pending_interrupts & PPC_INTERRUPT_HMI) { + return PPC_INTERRUPT_HMI; + } + } + /* Privileged Doorbell Exception */ + if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) && + (env->spr[SPR_LPCR] & LPCR_PDEE)) { + return PPC_INTERRUPT_DOORBELL; + } + /* Hypervisor Doorbell Exception */ + if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) && + (env->spr[SPR_LPCR] & LPCR_HDEE)) { + return PPC_INTERRUPT_HDOORBELL; + } + /* Hypervisor virtualization exception */ + if ((env->pending_interrupts & PPC_INTERRUPT_HVIRT) && + (env->spr[SPR_LPCR] & LPCR_HVEE)) { + return PPC_INTERRUPT_HVIRT; + } + if (env->pending_interrupts & PPC_INTERRUPT_RESET) { + return PPC_INTERRUPT_RESET; + } + return 0; +} + static bool cpu_has_work_POWER9(CPUState *cs) { PowerPCCPU *cpu = POWERPC_CPU(cs); @@ -6367,44 +6413,8 @@ static bool cpu_has_work_POWER9(CPUState *cs) if (!(psscr & PSSCR_EC)) { return true; } - /* External Exception */ - if ((env->pending_interrupts & PPC_INTERRUPT_EXT) && - (env->spr[SPR_LPCR] & LPCR_EEE)) { - bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC); - if (!heic || !FIELD_EX64_HV(env->msr) || - FIELD_EX64(env->msr, MSR, PR)) { - return true; - } - } - /* Decrementer Exception */ - if ((env->pending_interrupts & PPC_INTERRUPT_DECR) && - (env->spr[SPR_LPCR] & LPCR_DEE)) { - return true; - } - /* Machine Check or Hypervisor Maintenance Exception */ - if ((env->pending_interrupts & (PPC_INTERRUPT_MCK | PPC_INTERRUPT_HMI)) - && (env->spr[SPR_LPCR] & LPCR_OEE)) { - return true; - } - /* Privileged Doorbell Exception */ - if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) && - (env->spr[SPR_LPCR] & LPCR_PDEE)) { - return true; - } - /* Hypervisor Doorbell Exception */ - if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) && - (env->spr[SPR_LPCR] & LPCR_HDEE)) { - return true; - } - /* Hypervisor virtualization exception */ - if ((env->pending_interrupts & PPC_INTERRUPT_HVIRT) && - (env->spr[SPR_LPCR] & LPCR_HVEE)) { - return true; - } - if (env->pending_interrupts & PPC_INTERRUPT_RESET) { - return true; - } - return false; + + return p9_interrupt_powersave(env) != 0; } else { return FIELD_EX64(env->msr, MSR, EE) && (cs->interrupt_request & CPU_INTERRUPT_HARD); @@ -6600,44 +6610,8 @@ static bool cpu_has_work_POWER10(CPUState *cs) if (!(psscr & PSSCR_EC)) { return true; } - /* External Exception */ - if ((env->pending_interrupts & PPC_INTERRUPT_EXT) && - (env->spr[SPR_LPCR] & LPCR_EEE)) { - bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC); - if (!heic || !FIELD_EX64_HV(env->msr) || - FIELD_EX64(env->msr, MSR, PR)) { - return true; - } - } - /* Decrementer Exception */ - if ((env->pending_interrupts & PPC_INTERRUPT_DECR) && - (env->spr[SPR_LPCR] & LPCR_DEE)) { - return true; - } - /* Machine Check or Hypervisor Maintenance Exception */ - if ((env->pending_interrupts & (PPC_INTERRUPT_MCK | PPC_INTERRUPT_HMI)) - && (env->spr[SPR_LPCR] & LPCR_OEE)) { - return true; - } - /* Privileged Doorbell Exception */ - if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) && - (env->spr[SPR_LPCR] & LPCR_PDEE)) { - return true; - } - /* Hypervisor Doorbell Exception */ - if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) && - (env->spr[SPR_LPCR] & LPCR_HDEE)) { - return true; - } - /* Hypervisor virtualization exception */ - if ((env->pending_interrupts & PPC_INTERRUPT_HVIRT) && - (env->spr[SPR_LPCR] & LPCR_HVEE)) { - return true; - } - if (env->pending_interrupts & PPC_INTERRUPT_RESET) { - return true; - } - return false; + + return p9_interrupt_powersave(env) != 0; } else { return FIELD_EX64(env->msr, MSR, EE) && (cs->interrupt_request & CPU_INTERRUPT_HARD); -- cgit v1.1 From 27796411271837b45c635c537e70d1ecfdcd4e1c Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Tue, 11 Oct 2022 17:48:11 -0300 Subject: target/ppc: add power-saving interrupt masking logic to p9_next_unmasked_interrupt Export p9_interrupt_powersave and use it in p9_next_unmasked_interrupt. Signed-off-by: Matheus Ferst Reviewed-by: Fabiano Rosas Message-Id: <20221011204829.1641124-12-matheus.ferst@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/cpu_init.c | 2 +- target/ppc/excp_helper.c | 46 +++++++++++++++++++++++++++++++++------------- target/ppc/internal.h | 4 ++++ 3 files changed, 38 insertions(+), 14 deletions(-) (limited to 'target') diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index 9ecea10..423d99d 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -6351,7 +6351,7 @@ static bool ppc_pvr_match_power9(PowerPCCPUClass *pcc, uint32_t pvr, bool best) return false; } -static int p9_interrupt_powersave(CPUPPCState *env) +int p9_interrupt_powersave(CPUPPCState *env) { /* External Exception */ if ((env->pending_interrupts & PPC_INTERRUPT_EXT) && diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 238ce78..836c90b 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -1692,28 +1692,39 @@ void ppc_cpu_do_interrupt(CPUState *cs) static int p9_next_unmasked_interrupt(CPUPPCState *env) { - bool async_deliver; + PowerPCCPU *cpu = env_archcpu(env); + CPUState *cs = CPU(cpu); + /* Ignore MSR[EE] when coming out of some power management states */ + bool msr_ee = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset; assert((env->pending_interrupts & P9_UNUSED_INTERRUPTS) == 0); + if (cs->halted) { + if (env->spr[SPR_PSSCR] & PSSCR_EC) { + /* + * When PSSCR[EC] is set, LPCR[PECE] controls which interrupts can + * wakeup the processor + */ + return p9_interrupt_powersave(env); + } else { + /* + * When it's clear, any system-caused exception exits power-saving + * mode, even the ones that gate on MSR[EE]. + */ + msr_ee = true; + } + } + /* Machine check exception */ if (env->pending_interrupts & PPC_INTERRUPT_MCK) { return PPC_INTERRUPT_MCK; } - /* - * For interrupts that gate on MSR:EE, we need to do something a - * bit more subtle, as we need to let them through even when EE is - * clear when coming out of some power management states (in order - * for them to become a 0x100). - */ - async_deliver = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset; - /* Hypervisor decrementer exception */ if (env->pending_interrupts & PPC_INTERRUPT_HDECR) { /* LPCR will be clear when not supported so this will work */ bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE); - if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hdice) { + if ((msr_ee || !FIELD_EX64_HV(env->msr)) && hdice) { /* HDEC clears on delivery */ return PPC_INTERRUPT_HDECR; } @@ -1723,7 +1734,7 @@ static int p9_next_unmasked_interrupt(CPUPPCState *env) if (env->pending_interrupts & PPC_INTERRUPT_HVIRT) { /* LPCR will be clear when not supported so this will work */ bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE); - if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hvice) { + if ((msr_ee || !FIELD_EX64_HV(env->msr)) && hvice) { return PPC_INTERRUPT_HVIRT; } } @@ -1733,13 +1744,13 @@ static int p9_next_unmasked_interrupt(CPUPPCState *env) bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0); bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC); /* HEIC blocks delivery to the hypervisor */ - if ((async_deliver && !(heic && FIELD_EX64_HV(env->msr) && + if ((msr_ee && !(heic && FIELD_EX64_HV(env->msr) && !FIELD_EX64(env->msr, MSR, PR))) || (env->has_hv_mode && !FIELD_EX64_HV(env->msr) && !lpes0)) { return PPC_INTERRUPT_EXT; } } - if (async_deliver != 0) { + if (msr_ee != 0) { /* Decrementer exception */ if (env->pending_interrupts & PPC_INTERRUPT_DECR) { return PPC_INTERRUPT_DECR; @@ -1901,6 +1912,15 @@ static void p9_deliver_interrupt(CPUPPCState *env, int interrupt) PowerPCCPU *cpu = env_archcpu(env); CPUState *cs = env_cpu(env); + if (cs->halted && !(env->spr[SPR_PSSCR] & PSSCR_EC) && + !FIELD_EX64(env->msr, MSR, EE)) { + /* + * A pending interrupt took us out of power-saving, but MSR[EE] says + * that we should return to NIP+4 instead of delivering it. + */ + return; + } + switch (interrupt) { case PPC_INTERRUPT_MCK: /* Machine check exception */ env->pending_interrupts &= ~PPC_INTERRUPT_MCK; diff --git a/target/ppc/internal.h b/target/ppc/internal.h index 337a362..41e79ad 100644 --- a/target/ppc/internal.h +++ b/target/ppc/internal.h @@ -306,4 +306,8 @@ static inline int ger_pack_masks(int pmsk, int ymsk, int xmsk) return msk; } +#if defined(TARGET_PPC64) +int p9_interrupt_powersave(CPUPPCState *env); +#endif + #endif /* PPC_INTERNAL_H */ -- cgit v1.1 From a9899d42012c49169074fb85b61c78aa6e17af8e Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Tue, 11 Oct 2022 17:48:12 -0300 Subject: target/ppc: create an interrupt masking method for POWER8 The new method is identical to ppc_next_unmasked_interrupt_generic, processor-specific code will be added/removed in the following patches. Signed-off-by: Matheus Ferst Reviewed-by: Fabiano Rosas Message-Id: <20221011204829.1641124-13-matheus.ferst@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/excp_helper.c | 108 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) (limited to 'target') diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 836c90b..c7b303a 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -1685,6 +1685,112 @@ void ppc_cpu_do_interrupt(CPUState *cs) } #if defined(TARGET_PPC64) +static int p8_next_unmasked_interrupt(CPUPPCState *env) +{ + bool async_deliver; + + /* External reset */ + if (env->pending_interrupts & PPC_INTERRUPT_RESET) { + return PPC_INTERRUPT_RESET; + } + /* Machine check exception */ + if (env->pending_interrupts & PPC_INTERRUPT_MCK) { + return PPC_INTERRUPT_MCK; + } + + /* + * For interrupts that gate on MSR:EE, we need to do something a + * bit more subtle, as we need to let them through even when EE is + * clear when coming out of some power management states (in order + * for them to become a 0x100). + */ + async_deliver = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset; + + /* Hypervisor decrementer exception */ + if (env->pending_interrupts & PPC_INTERRUPT_HDECR) { + /* LPCR will be clear when not supported so this will work */ + bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE); + if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hdice) { + /* HDEC clears on delivery */ + return PPC_INTERRUPT_HDECR; + } + } + + /* Hypervisor virtualization interrupt */ + if (env->pending_interrupts & PPC_INTERRUPT_HVIRT) { + /* LPCR will be clear when not supported so this will work */ + bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE); + if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hvice) { + return PPC_INTERRUPT_HVIRT; + } + } + + /* External interrupt can ignore MSR:EE under some circumstances */ + if (env->pending_interrupts & PPC_INTERRUPT_EXT) { + bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0); + bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC); + /* HEIC blocks delivery to the hypervisor */ + if ((async_deliver && !(heic && FIELD_EX64_HV(env->msr) && + !FIELD_EX64(env->msr, MSR, PR))) || + (env->has_hv_mode && !FIELD_EX64_HV(env->msr) && !lpes0)) { + return PPC_INTERRUPT_EXT; + } + } + if (FIELD_EX64(env->msr, MSR, CE)) { + /* External critical interrupt */ + if (env->pending_interrupts & PPC_INTERRUPT_CEXT) { + return PPC_INTERRUPT_CEXT; + } + } + if (async_deliver != 0) { + /* Watchdog timer on embedded PowerPC */ + if (env->pending_interrupts & PPC_INTERRUPT_WDT) { + return PPC_INTERRUPT_WDT; + } + if (env->pending_interrupts & PPC_INTERRUPT_CDOORBELL) { + return PPC_INTERRUPT_CDOORBELL; + } + /* Fixed interval timer on embedded PowerPC */ + if (env->pending_interrupts & PPC_INTERRUPT_FIT) { + return PPC_INTERRUPT_FIT; + } + /* Programmable interval timer on embedded PowerPC */ + if (env->pending_interrupts & PPC_INTERRUPT_PIT) { + return PPC_INTERRUPT_PIT; + } + /* Decrementer exception */ + if (env->pending_interrupts & PPC_INTERRUPT_DECR) { + return PPC_INTERRUPT_DECR; + } + if (env->pending_interrupts & PPC_INTERRUPT_DOORBELL) { + return PPC_INTERRUPT_DOORBELL; + } + if (env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) { + return PPC_INTERRUPT_HDOORBELL; + } + if (env->pending_interrupts & PPC_INTERRUPT_PERFM) { + return PPC_INTERRUPT_PERFM; + } + /* Thermal interrupt */ + if (env->pending_interrupts & PPC_INTERRUPT_THERM) { + return PPC_INTERRUPT_THERM; + } + /* EBB exception */ + if (env->pending_interrupts & PPC_INTERRUPT_EBB) { + /* + * EBB exception must be taken in problem state and + * with BESCR_GE set. + */ + if (FIELD_EX64(env->msr, MSR, PR) && + (env->spr[SPR_BESCR] & BESCR_GE)) { + return PPC_INTERRUPT_EBB; + } + } + } + + return 0; +} + #define P9_UNUSED_INTERRUPTS \ (PPC_INTERRUPT_RESET | PPC_INTERRUPT_DEBUG | PPC_INTERRUPT_CEXT | \ PPC_INTERRUPT_WDT | PPC_INTERRUPT_CDOORBELL | PPC_INTERRUPT_FIT | \ @@ -1897,6 +2003,8 @@ static int ppc_next_unmasked_interrupt(CPUPPCState *env) { switch (env->excp_model) { #if defined(TARGET_PPC64) + case POWERPC_EXCP_POWER8: + return p8_next_unmasked_interrupt(env); case POWERPC_EXCP_POWER9: case POWERPC_EXCP_POWER10: return p9_next_unmasked_interrupt(env); -- cgit v1.1 From f6194fdde2e37743d2833b66fc272472190e51cc Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Tue, 11 Oct 2022 17:48:13 -0300 Subject: target/ppc: remove unused interrupts from p8_next_unmasked_interrupt Remove the following unused interrupts from the POWER8 interrupt masking method: - PPC_INTERRUPT_RESET: only raised for 6xx, 7xx, 970, and POWER5p; - Debug Interrupt: removed in Power ISA v2.07; - Hypervisor Virtualization: introduced in Power ISA v3.0; - Critical Input, Watchdog Timer, and Fixed Interval Timer: only defined for embedded CPUs; - Critical Doorbell: processor does not implement the "Embedded.Processor Control" category; - Programmable Interval Timer: 40x-only; - PPC_INTERRUPT_THERM: only raised for 970 and POWER5p; Signed-off-by: Matheus Ferst Reviewed-by: Fabiano Rosas Message-Id: <20221011204829.1641124-14-matheus.ferst@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/excp_helper.c | 45 +++++++-------------------------------------- 1 file changed, 7 insertions(+), 38 deletions(-) (limited to 'target') diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index c7b303a..2bb636a 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -1685,14 +1685,17 @@ void ppc_cpu_do_interrupt(CPUState *cs) } #if defined(TARGET_PPC64) +#define P8_UNUSED_INTERRUPTS \ + (PPC_INTERRUPT_RESET | PPC_INTERRUPT_DEBUG | PPC_INTERRUPT_HVIRT | \ + PPC_INTERRUPT_CEXT | PPC_INTERRUPT_WDT | PPC_INTERRUPT_CDOORBELL | \ + PPC_INTERRUPT_FIT | PPC_INTERRUPT_PIT | PPC_INTERRUPT_THERM) + static int p8_next_unmasked_interrupt(CPUPPCState *env) { bool async_deliver; - /* External reset */ - if (env->pending_interrupts & PPC_INTERRUPT_RESET) { - return PPC_INTERRUPT_RESET; - } + assert((env->pending_interrupts & P8_UNUSED_INTERRUPTS) == 0); + /* Machine check exception */ if (env->pending_interrupts & PPC_INTERRUPT_MCK) { return PPC_INTERRUPT_MCK; @@ -1716,15 +1719,6 @@ static int p8_next_unmasked_interrupt(CPUPPCState *env) } } - /* Hypervisor virtualization interrupt */ - if (env->pending_interrupts & PPC_INTERRUPT_HVIRT) { - /* LPCR will be clear when not supported so this will work */ - bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE); - if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hvice) { - return PPC_INTERRUPT_HVIRT; - } - } - /* External interrupt can ignore MSR:EE under some circumstances */ if (env->pending_interrupts & PPC_INTERRUPT_EXT) { bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0); @@ -1736,28 +1730,7 @@ static int p8_next_unmasked_interrupt(CPUPPCState *env) return PPC_INTERRUPT_EXT; } } - if (FIELD_EX64(env->msr, MSR, CE)) { - /* External critical interrupt */ - if (env->pending_interrupts & PPC_INTERRUPT_CEXT) { - return PPC_INTERRUPT_CEXT; - } - } if (async_deliver != 0) { - /* Watchdog timer on embedded PowerPC */ - if (env->pending_interrupts & PPC_INTERRUPT_WDT) { - return PPC_INTERRUPT_WDT; - } - if (env->pending_interrupts & PPC_INTERRUPT_CDOORBELL) { - return PPC_INTERRUPT_CDOORBELL; - } - /* Fixed interval timer on embedded PowerPC */ - if (env->pending_interrupts & PPC_INTERRUPT_FIT) { - return PPC_INTERRUPT_FIT; - } - /* Programmable interval timer on embedded PowerPC */ - if (env->pending_interrupts & PPC_INTERRUPT_PIT) { - return PPC_INTERRUPT_PIT; - } /* Decrementer exception */ if (env->pending_interrupts & PPC_INTERRUPT_DECR) { return PPC_INTERRUPT_DECR; @@ -1771,10 +1744,6 @@ static int p8_next_unmasked_interrupt(CPUPPCState *env) if (env->pending_interrupts & PPC_INTERRUPT_PERFM) { return PPC_INTERRUPT_PERFM; } - /* Thermal interrupt */ - if (env->pending_interrupts & PPC_INTERRUPT_THERM) { - return PPC_INTERRUPT_THERM; - } /* EBB exception */ if (env->pending_interrupts & PPC_INTERRUPT_EBB) { /* -- cgit v1.1 From 6527e757db546fcdc4a0a695325fb3f1fb0804d5 Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Tue, 11 Oct 2022 17:48:14 -0300 Subject: target/ppc: create an interrupt deliver method for POWER8 The new method is identical to ppc_deliver_interrupt, processor-specific code will be added/removed in the following patches. Signed-off-by: Matheus Ferst Reviewed-by: Fabiano Rosas Message-Id: <20221011204829.1641124-15-matheus.ferst@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/excp_helper.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) (limited to 'target') diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 2bb636a..c2ebb52 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -1984,6 +1984,110 @@ static int ppc_next_unmasked_interrupt(CPUPPCState *env) } #if defined(TARGET_PPC64) +static void p8_deliver_interrupt(CPUPPCState *env, int interrupt) +{ + PowerPCCPU *cpu = env_archcpu(env); + CPUState *cs = env_cpu(env); + + switch (interrupt) { + case PPC_INTERRUPT_RESET: /* External reset */ + env->pending_interrupts &= ~PPC_INTERRUPT_RESET; + powerpc_excp(cpu, POWERPC_EXCP_RESET); + break; + case PPC_INTERRUPT_MCK: /* Machine check exception */ + env->pending_interrupts &= ~PPC_INTERRUPT_MCK; + powerpc_excp(cpu, POWERPC_EXCP_MCHECK); + break; + + case PPC_INTERRUPT_HDECR: /* Hypervisor decrementer exception */ + /* HDEC clears on delivery */ + env->pending_interrupts &= ~PPC_INTERRUPT_HDECR; + powerpc_excp(cpu, POWERPC_EXCP_HDECR); + break; + case PPC_INTERRUPT_HVIRT: /* Hypervisor virtualization interrupt */ + powerpc_excp(cpu, POWERPC_EXCP_HVIRT); + break; + + case PPC_INTERRUPT_EXT: + if (books_vhyp_promotes_external_to_hvirt(cpu)) { + powerpc_excp(cpu, POWERPC_EXCP_HVIRT); + } else { + powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL); + } + break; + case PPC_INTERRUPT_CEXT: /* External critical interrupt */ + powerpc_excp(cpu, POWERPC_EXCP_CRITICAL); + break; + + case PPC_INTERRUPT_WDT: /* Watchdog timer on embedded PowerPC */ + env->pending_interrupts &= ~PPC_INTERRUPT_WDT; + powerpc_excp(cpu, POWERPC_EXCP_WDT); + break; + case PPC_INTERRUPT_CDOORBELL: + env->pending_interrupts &= ~PPC_INTERRUPT_CDOORBELL; + powerpc_excp(cpu, POWERPC_EXCP_DOORCI); + break; + case PPC_INTERRUPT_FIT: /* Fixed interval timer on embedded PowerPC */ + env->pending_interrupts &= ~PPC_INTERRUPT_FIT; + powerpc_excp(cpu, POWERPC_EXCP_FIT); + break; + case PPC_INTERRUPT_PIT: /* Programmable interval timer on embedded ppc */ + env->pending_interrupts &= ~PPC_INTERRUPT_PIT; + powerpc_excp(cpu, POWERPC_EXCP_PIT); + break; + case PPC_INTERRUPT_DECR: /* Decrementer exception */ + if (ppc_decr_clear_on_delivery(env)) { + env->pending_interrupts &= ~PPC_INTERRUPT_DECR; + } + powerpc_excp(cpu, POWERPC_EXCP_DECR); + break; + case PPC_INTERRUPT_DOORBELL: + env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL; + if (is_book3s_arch2x(env)) { + powerpc_excp(cpu, POWERPC_EXCP_SDOOR); + } else { + powerpc_excp(cpu, POWERPC_EXCP_DOORI); + } + break; + case PPC_INTERRUPT_HDOORBELL: + env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL; + powerpc_excp(cpu, POWERPC_EXCP_SDOOR_HV); + break; + case PPC_INTERRUPT_PERFM: + env->pending_interrupts &= ~PPC_INTERRUPT_PERFM; + powerpc_excp(cpu, POWERPC_EXCP_PERFM); + break; + case PPC_INTERRUPT_THERM: /* Thermal interrupt */ + env->pending_interrupts &= ~PPC_INTERRUPT_THERM; + powerpc_excp(cpu, POWERPC_EXCP_THERM); + break; + case PPC_INTERRUPT_EBB: /* EBB exception */ + env->pending_interrupts &= ~PPC_INTERRUPT_EBB; + if (env->spr[SPR_BESCR] & BESCR_PMEO) { + powerpc_excp(cpu, POWERPC_EXCP_PERFM_EBB); + } else if (env->spr[SPR_BESCR] & BESCR_EEO) { + powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL_EBB); + } + break; + case 0: + /* + * This is a bug ! It means that has_work took us out of halt without + * anything to deliver while in a PM state that requires getting + * out via a 0x100 + * + * This means we will incorrectly execute past the power management + * instruction instead of triggering a reset. + * + * It generally means a discrepancy between the wakeup conditions in the + * processor has_work implementation and the logic in this function. + */ + assert(!env->resume_as_sreset); + break; + default: + cpu_abort(cs, "Invalid PowerPC interrupt %d. Aborting\n", interrupt); + } +} + static void p9_deliver_interrupt(CPUPPCState *env, int interrupt) { PowerPCCPU *cpu = env_archcpu(env); @@ -2172,6 +2276,9 @@ static void ppc_deliver_interrupt(CPUPPCState *env, int interrupt) { switch (env->excp_model) { #if defined(TARGET_PPC64) + case POWERPC_EXCP_POWER8: + p8_deliver_interrupt(env, interrupt); + break; case POWERPC_EXCP_POWER9: case POWERPC_EXCP_POWER10: p9_deliver_interrupt(env, interrupt); -- cgit v1.1 From 567372673e4e3aaaa0391bb5ea127e387f4dbd34 Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Tue, 11 Oct 2022 17:48:15 -0300 Subject: target/ppc: remove unused interrupts from p8_deliver_interrupt Remove the following unused interrupts from the POWER8 interrupt processing method: - PPC_INTERRUPT_RESET: only raised for 6xx, 7xx, 970 and POWER5p; - Debug Interrupt: removed in Power ISA v2.07; - Hypervisor Virtualization: introduced in Power ISA v3.0; - Critical Input, Watchdog Timer, and Fixed Interval Timer: only defined for embedded CPUs; - Critical Doorbell: processor does not implement the "Embedded.Processor Control" category; - Programmable Interval Timer: 40x-only; - PPC_INTERRUPT_THERM: only raised for 970 and POWER5p; Signed-off-by: Matheus Ferst Reviewed-by: Fabiano Rosas Message-Id: <20221011204829.1641124-16-matheus.ferst@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/excp_helper.c | 30 ------------------------------ 1 file changed, 30 deletions(-) (limited to 'target') diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index c2ebb52..21cd8d0 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -1990,10 +1990,6 @@ static void p8_deliver_interrupt(CPUPPCState *env, int interrupt) CPUState *cs = env_cpu(env); switch (interrupt) { - case PPC_INTERRUPT_RESET: /* External reset */ - env->pending_interrupts &= ~PPC_INTERRUPT_RESET; - powerpc_excp(cpu, POWERPC_EXCP_RESET); - break; case PPC_INTERRUPT_MCK: /* Machine check exception */ env->pending_interrupts &= ~PPC_INTERRUPT_MCK; powerpc_excp(cpu, POWERPC_EXCP_MCHECK); @@ -2004,9 +2000,6 @@ static void p8_deliver_interrupt(CPUPPCState *env, int interrupt) env->pending_interrupts &= ~PPC_INTERRUPT_HDECR; powerpc_excp(cpu, POWERPC_EXCP_HDECR); break; - case PPC_INTERRUPT_HVIRT: /* Hypervisor virtualization interrupt */ - powerpc_excp(cpu, POWERPC_EXCP_HVIRT); - break; case PPC_INTERRUPT_EXT: if (books_vhyp_promotes_external_to_hvirt(cpu)) { @@ -2015,26 +2008,7 @@ static void p8_deliver_interrupt(CPUPPCState *env, int interrupt) powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL); } break; - case PPC_INTERRUPT_CEXT: /* External critical interrupt */ - powerpc_excp(cpu, POWERPC_EXCP_CRITICAL); - break; - case PPC_INTERRUPT_WDT: /* Watchdog timer on embedded PowerPC */ - env->pending_interrupts &= ~PPC_INTERRUPT_WDT; - powerpc_excp(cpu, POWERPC_EXCP_WDT); - break; - case PPC_INTERRUPT_CDOORBELL: - env->pending_interrupts &= ~PPC_INTERRUPT_CDOORBELL; - powerpc_excp(cpu, POWERPC_EXCP_DOORCI); - break; - case PPC_INTERRUPT_FIT: /* Fixed interval timer on embedded PowerPC */ - env->pending_interrupts &= ~PPC_INTERRUPT_FIT; - powerpc_excp(cpu, POWERPC_EXCP_FIT); - break; - case PPC_INTERRUPT_PIT: /* Programmable interval timer on embedded ppc */ - env->pending_interrupts &= ~PPC_INTERRUPT_PIT; - powerpc_excp(cpu, POWERPC_EXCP_PIT); - break; case PPC_INTERRUPT_DECR: /* Decrementer exception */ if (ppc_decr_clear_on_delivery(env)) { env->pending_interrupts &= ~PPC_INTERRUPT_DECR; @@ -2057,10 +2031,6 @@ static void p8_deliver_interrupt(CPUPPCState *env, int interrupt) env->pending_interrupts &= ~PPC_INTERRUPT_PERFM; powerpc_excp(cpu, POWERPC_EXCP_PERFM); break; - case PPC_INTERRUPT_THERM: /* Thermal interrupt */ - env->pending_interrupts &= ~PPC_INTERRUPT_THERM; - powerpc_excp(cpu, POWERPC_EXCP_THERM); - break; case PPC_INTERRUPT_EBB: /* EBB exception */ env->pending_interrupts &= ~PPC_INTERRUPT_EBB; if (env->spr[SPR_BESCR] & BESCR_PMEO) { -- cgit v1.1 From d66b441d64ca63bb9b50d5d8a054b1836297a6e3 Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Tue, 11 Oct 2022 17:48:16 -0300 Subject: target/ppc: remove generic architecture checks from p8_deliver_interrupt Signed-off-by: Matheus Ferst Reviewed-by: Fabiano Rosas Message-Id: <20221011204829.1641124-17-matheus.ferst@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/excp_helper.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'target') diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 21cd8d0..b4afdc8 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -2010,9 +2010,6 @@ static void p8_deliver_interrupt(CPUPPCState *env, int interrupt) break; case PPC_INTERRUPT_DECR: /* Decrementer exception */ - if (ppc_decr_clear_on_delivery(env)) { - env->pending_interrupts &= ~PPC_INTERRUPT_DECR; - } powerpc_excp(cpu, POWERPC_EXCP_DECR); break; case PPC_INTERRUPT_DOORBELL: -- cgit v1.1 From 788ff1ce44b813475ddcb95726bdd3afdaa40d6d Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Tue, 11 Oct 2022 17:48:17 -0300 Subject: target/ppc: move power-saving interrupt masking out of cpu_has_work_POWER8 Move the interrupt masking logic out of cpu_has_work_POWER8 in a new method, p8_interrupt_powersave, that only returns an interrupt if it can wake the processor from power-saving mode. Signed-off-by: Matheus Ferst Reviewed-by: Fabiano Rosas Message-Id: <20221011204829.1641124-18-matheus.ferst@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/cpu_init.c | 61 ++++++++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 28 deletions(-) (limited to 'target') diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index 423d99d..922390b 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -6133,6 +6133,38 @@ static bool ppc_pvr_match_power8(PowerPCCPUClass *pcc, uint32_t pvr, bool best) return true; } +static int p8_interrupt_powersave(CPUPPCState *env) +{ + if ((env->pending_interrupts & PPC_INTERRUPT_EXT) && + (env->spr[SPR_LPCR] & LPCR_P8_PECE2)) { + return PPC_INTERRUPT_EXT; + } + if ((env->pending_interrupts & PPC_INTERRUPT_DECR) && + (env->spr[SPR_LPCR] & LPCR_P8_PECE3)) { + return PPC_INTERRUPT_DECR; + } + if ((env->pending_interrupts & PPC_INTERRUPT_MCK) && + (env->spr[SPR_LPCR] & LPCR_P8_PECE4)) { + return PPC_INTERRUPT_MCK; + } + if ((env->pending_interrupts & PPC_INTERRUPT_HMI) && + (env->spr[SPR_LPCR] & LPCR_P8_PECE4)) { + return PPC_INTERRUPT_HMI; + } + if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) && + (env->spr[SPR_LPCR] & LPCR_P8_PECE0)) { + return PPC_INTERRUPT_DOORBELL; + } + if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) && + (env->spr[SPR_LPCR] & LPCR_P8_PECE1)) { + return PPC_INTERRUPT_HDOORBELL; + } + if (env->pending_interrupts & PPC_INTERRUPT_RESET) { + return PPC_INTERRUPT_RESET; + } + return 0; +} + static bool cpu_has_work_POWER8(CPUState *cs) { PowerPCCPU *cpu = POWERPC_CPU(cs); @@ -6142,34 +6174,7 @@ static bool cpu_has_work_POWER8(CPUState *cs) if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) { return false; } - if ((env->pending_interrupts & PPC_INTERRUPT_EXT) && - (env->spr[SPR_LPCR] & LPCR_P8_PECE2)) { - return true; - } - if ((env->pending_interrupts & PPC_INTERRUPT_DECR) && - (env->spr[SPR_LPCR] & LPCR_P8_PECE3)) { - return true; - } - if ((env->pending_interrupts & PPC_INTERRUPT_MCK) && - (env->spr[SPR_LPCR] & LPCR_P8_PECE4)) { - return true; - } - if ((env->pending_interrupts & PPC_INTERRUPT_HMI) && - (env->spr[SPR_LPCR] & LPCR_P8_PECE4)) { - return true; - } - if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) && - (env->spr[SPR_LPCR] & LPCR_P8_PECE0)) { - return true; - } - if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) && - (env->spr[SPR_LPCR] & LPCR_P8_PECE1)) { - return true; - } - if (env->pending_interrupts & PPC_INTERRUPT_RESET) { - return true; - } - return false; + return p8_interrupt_powersave(env) != 0; } else { return FIELD_EX64(env->msr, MSR, EE) && (cs->interrupt_request & CPU_INTERRUPT_HARD); -- cgit v1.1 From 64a9b5eebef97d5b742b162625d5bc262be832ec Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Tue, 11 Oct 2022 17:48:18 -0300 Subject: target/ppc: add power-saving interrupt masking logic to p8_next_unmasked_interrupt Export p8_interrupt_powersave and use it in p8_next_unmasked_interrupt. Signed-off-by: Matheus Ferst Reviewed-by: Fabiano Rosas Message-Id: <20221011204829.1641124-19-matheus.ferst@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/cpu_init.c | 2 +- target/ppc/excp_helper.c | 24 ++++++++++++------------ target/ppc/internal.h | 1 + 3 files changed, 14 insertions(+), 13 deletions(-) (limited to 'target') diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index 922390b..68ae22d 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -6133,7 +6133,7 @@ static bool ppc_pvr_match_power8(PowerPCCPUClass *pcc, uint32_t pvr, bool best) return true; } -static int p8_interrupt_powersave(CPUPPCState *env) +int p8_interrupt_powersave(CPUPPCState *env) { if ((env->pending_interrupts & PPC_INTERRUPT_EXT) && (env->spr[SPR_LPCR] & LPCR_P8_PECE2)) { diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index b4afdc8..9fa75c5 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -1692,28 +1692,28 @@ void ppc_cpu_do_interrupt(CPUState *cs) static int p8_next_unmasked_interrupt(CPUPPCState *env) { - bool async_deliver; + PowerPCCPU *cpu = env_archcpu(env); + CPUState *cs = CPU(cpu); + /* Ignore MSR[EE] when coming out of some power management states */ + bool msr_ee = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset; assert((env->pending_interrupts & P8_UNUSED_INTERRUPTS) == 0); + if (cs->halted) { + /* LPCR[PECE] controls which interrupts can exit power-saving mode */ + return p8_interrupt_powersave(env); + } + /* Machine check exception */ if (env->pending_interrupts & PPC_INTERRUPT_MCK) { return PPC_INTERRUPT_MCK; } - /* - * For interrupts that gate on MSR:EE, we need to do something a - * bit more subtle, as we need to let them through even when EE is - * clear when coming out of some power management states (in order - * for them to become a 0x100). - */ - async_deliver = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset; - /* Hypervisor decrementer exception */ if (env->pending_interrupts & PPC_INTERRUPT_HDECR) { /* LPCR will be clear when not supported so this will work */ bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE); - if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hdice) { + if ((msr_ee || !FIELD_EX64_HV(env->msr)) && hdice) { /* HDEC clears on delivery */ return PPC_INTERRUPT_HDECR; } @@ -1724,13 +1724,13 @@ static int p8_next_unmasked_interrupt(CPUPPCState *env) bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0); bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC); /* HEIC blocks delivery to the hypervisor */ - if ((async_deliver && !(heic && FIELD_EX64_HV(env->msr) && + if ((msr_ee && !(heic && FIELD_EX64_HV(env->msr) && !FIELD_EX64(env->msr, MSR, PR))) || (env->has_hv_mode && !FIELD_EX64_HV(env->msr) && !lpes0)) { return PPC_INTERRUPT_EXT; } } - if (async_deliver != 0) { + if (msr_ee != 0) { /* Decrementer exception */ if (env->pending_interrupts & PPC_INTERRUPT_DECR) { return PPC_INTERRUPT_DECR; diff --git a/target/ppc/internal.h b/target/ppc/internal.h index 41e79ad..9069874 100644 --- a/target/ppc/internal.h +++ b/target/ppc/internal.h @@ -308,6 +308,7 @@ static inline int ger_pack_masks(int pmsk, int ymsk, int xmsk) #if defined(TARGET_PPC64) int p9_interrupt_powersave(CPUPPCState *env); +int p8_interrupt_powersave(CPUPPCState *env); #endif #endif /* PPC_INTERNAL_H */ -- cgit v1.1 From bf303fb3f11c3e131f315e44b792ad79a8ae07bb Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Tue, 11 Oct 2022 17:48:19 -0300 Subject: target/ppc: create an interrupt masking method for POWER7 The new method is identical to ppc_next_unmasked_interrupt_generic, processor-specific code will be added/removed in the following patches. Signed-off-by: Matheus Ferst Reviewed-by: Fabiano Rosas Message-Id: <20221011204829.1641124-20-matheus.ferst@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/excp_helper.c | 108 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) (limited to 'target') diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 9fa75c5..d99b76c 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -1685,6 +1685,112 @@ void ppc_cpu_do_interrupt(CPUState *cs) } #if defined(TARGET_PPC64) +static int p7_next_unmasked_interrupt(CPUPPCState *env) +{ + bool async_deliver; + + /* External reset */ + if (env->pending_interrupts & PPC_INTERRUPT_RESET) { + return PPC_INTERRUPT_RESET; + } + /* Machine check exception */ + if (env->pending_interrupts & PPC_INTERRUPT_MCK) { + return PPC_INTERRUPT_MCK; + } + + /* + * For interrupts that gate on MSR:EE, we need to do something a + * bit more subtle, as we need to let them through even when EE is + * clear when coming out of some power management states (in order + * for them to become a 0x100). + */ + async_deliver = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset; + + /* Hypervisor decrementer exception */ + if (env->pending_interrupts & PPC_INTERRUPT_HDECR) { + /* LPCR will be clear when not supported so this will work */ + bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE); + if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hdice) { + /* HDEC clears on delivery */ + return PPC_INTERRUPT_HDECR; + } + } + + /* Hypervisor virtualization interrupt */ + if (env->pending_interrupts & PPC_INTERRUPT_HVIRT) { + /* LPCR will be clear when not supported so this will work */ + bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE); + if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hvice) { + return PPC_INTERRUPT_HVIRT; + } + } + + /* External interrupt can ignore MSR:EE under some circumstances */ + if (env->pending_interrupts & PPC_INTERRUPT_EXT) { + bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0); + bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC); + /* HEIC blocks delivery to the hypervisor */ + if ((async_deliver && !(heic && FIELD_EX64_HV(env->msr) && + !FIELD_EX64(env->msr, MSR, PR))) || + (env->has_hv_mode && !FIELD_EX64_HV(env->msr) && !lpes0)) { + return PPC_INTERRUPT_EXT; + } + } + if (FIELD_EX64(env->msr, MSR, CE)) { + /* External critical interrupt */ + if (env->pending_interrupts & PPC_INTERRUPT_CEXT) { + return PPC_INTERRUPT_CEXT; + } + } + if (async_deliver != 0) { + /* Watchdog timer on embedded PowerPC */ + if (env->pending_interrupts & PPC_INTERRUPT_WDT) { + return PPC_INTERRUPT_WDT; + } + if (env->pending_interrupts & PPC_INTERRUPT_CDOORBELL) { + return PPC_INTERRUPT_CDOORBELL; + } + /* Fixed interval timer on embedded PowerPC */ + if (env->pending_interrupts & PPC_INTERRUPT_FIT) { + return PPC_INTERRUPT_FIT; + } + /* Programmable interval timer on embedded PowerPC */ + if (env->pending_interrupts & PPC_INTERRUPT_PIT) { + return PPC_INTERRUPT_PIT; + } + /* Decrementer exception */ + if (env->pending_interrupts & PPC_INTERRUPT_DECR) { + return PPC_INTERRUPT_DECR; + } + if (env->pending_interrupts & PPC_INTERRUPT_DOORBELL) { + return PPC_INTERRUPT_DOORBELL; + } + if (env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) { + return PPC_INTERRUPT_HDOORBELL; + } + if (env->pending_interrupts & PPC_INTERRUPT_PERFM) { + return PPC_INTERRUPT_PERFM; + } + /* Thermal interrupt */ + if (env->pending_interrupts & PPC_INTERRUPT_THERM) { + return PPC_INTERRUPT_THERM; + } + /* EBB exception */ + if (env->pending_interrupts & PPC_INTERRUPT_EBB) { + /* + * EBB exception must be taken in problem state and + * with BESCR_GE set. + */ + if (FIELD_EX64(env->msr, MSR, PR) && + (env->spr[SPR_BESCR] & BESCR_GE)) { + return PPC_INTERRUPT_EBB; + } + } + } + + return 0; +} + #define P8_UNUSED_INTERRUPTS \ (PPC_INTERRUPT_RESET | PPC_INTERRUPT_DEBUG | PPC_INTERRUPT_HVIRT | \ PPC_INTERRUPT_CEXT | PPC_INTERRUPT_WDT | PPC_INTERRUPT_CDOORBELL | \ @@ -1972,6 +2078,8 @@ static int ppc_next_unmasked_interrupt(CPUPPCState *env) { switch (env->excp_model) { #if defined(TARGET_PPC64) + case POWERPC_EXCP_POWER7: + return p7_next_unmasked_interrupt(env); case POWERPC_EXCP_POWER8: return p8_next_unmasked_interrupt(env); case POWERPC_EXCP_POWER9: -- cgit v1.1 From c8e1de2e421fcb5ce88443bd819f919e3eab13f2 Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Tue, 11 Oct 2022 17:48:20 -0300 Subject: target/ppc: remove unused interrupts from p7_next_unmasked_interrupt Remove the following unused interrupts from the POWER7 interrupt masking method: - PPC_INTERRUPT_RESET: only raised for 6xx, 7xx, 970 and POWER5p; - Hypervisor Virtualization: introduced in Power ISA v3.0; - Hypervisor Doorbell and Event-Based Branch: introduced in Power ISA v2.07; - Critical Input, Watchdog Timer, and Fixed Interval Timer: only defined for embedded CPUs; - Doorbell and Critical Doorbell Interrupt: processor does not implement the Embedded.Processor Control category; - Programmable Interval Timer: 40x-only; - PPC_INTERRUPT_THERM: only raised for 970 and POWER5p; Signed-off-by: Matheus Ferst Reviewed-by: Fabiano Rosas Message-Id: <20221011204829.1641124-21-matheus.ferst@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/excp_helper.c | 63 ++++++------------------------------------------ 1 file changed, 8 insertions(+), 55 deletions(-) (limited to 'target') diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index d99b76c..08db3a4 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -1685,14 +1685,18 @@ void ppc_cpu_do_interrupt(CPUState *cs) } #if defined(TARGET_PPC64) +#define P7_UNUSED_INTERRUPTS \ + (PPC_INTERRUPT_RESET | PPC_INTERRUPT_HVIRT | PPC_INTERRUPT_CEXT | \ + PPC_INTERRUPT_WDT | PPC_INTERRUPT_CDOORBELL | PPC_INTERRUPT_FIT | \ + PPC_INTERRUPT_PIT | PPC_INTERRUPT_DOORBELL | PPC_INTERRUPT_HDOORBELL | \ + PPC_INTERRUPT_THERM | PPC_INTERRUPT_EBB) + static int p7_next_unmasked_interrupt(CPUPPCState *env) { bool async_deliver; - /* External reset */ - if (env->pending_interrupts & PPC_INTERRUPT_RESET) { - return PPC_INTERRUPT_RESET; - } + assert((env->pending_interrupts & P7_UNUSED_INTERRUPTS) == 0); + /* Machine check exception */ if (env->pending_interrupts & PPC_INTERRUPT_MCK) { return PPC_INTERRUPT_MCK; @@ -1716,15 +1720,6 @@ static int p7_next_unmasked_interrupt(CPUPPCState *env) } } - /* Hypervisor virtualization interrupt */ - if (env->pending_interrupts & PPC_INTERRUPT_HVIRT) { - /* LPCR will be clear when not supported so this will work */ - bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE); - if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hvice) { - return PPC_INTERRUPT_HVIRT; - } - } - /* External interrupt can ignore MSR:EE under some circumstances */ if (env->pending_interrupts & PPC_INTERRUPT_EXT) { bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0); @@ -1736,56 +1731,14 @@ static int p7_next_unmasked_interrupt(CPUPPCState *env) return PPC_INTERRUPT_EXT; } } - if (FIELD_EX64(env->msr, MSR, CE)) { - /* External critical interrupt */ - if (env->pending_interrupts & PPC_INTERRUPT_CEXT) { - return PPC_INTERRUPT_CEXT; - } - } if (async_deliver != 0) { - /* Watchdog timer on embedded PowerPC */ - if (env->pending_interrupts & PPC_INTERRUPT_WDT) { - return PPC_INTERRUPT_WDT; - } - if (env->pending_interrupts & PPC_INTERRUPT_CDOORBELL) { - return PPC_INTERRUPT_CDOORBELL; - } - /* Fixed interval timer on embedded PowerPC */ - if (env->pending_interrupts & PPC_INTERRUPT_FIT) { - return PPC_INTERRUPT_FIT; - } - /* Programmable interval timer on embedded PowerPC */ - if (env->pending_interrupts & PPC_INTERRUPT_PIT) { - return PPC_INTERRUPT_PIT; - } /* Decrementer exception */ if (env->pending_interrupts & PPC_INTERRUPT_DECR) { return PPC_INTERRUPT_DECR; } - if (env->pending_interrupts & PPC_INTERRUPT_DOORBELL) { - return PPC_INTERRUPT_DOORBELL; - } - if (env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) { - return PPC_INTERRUPT_HDOORBELL; - } if (env->pending_interrupts & PPC_INTERRUPT_PERFM) { return PPC_INTERRUPT_PERFM; } - /* Thermal interrupt */ - if (env->pending_interrupts & PPC_INTERRUPT_THERM) { - return PPC_INTERRUPT_THERM; - } - /* EBB exception */ - if (env->pending_interrupts & PPC_INTERRUPT_EBB) { - /* - * EBB exception must be taken in problem state and - * with BESCR_GE set. - */ - if (FIELD_EX64(env->msr, MSR, PR) && - (env->spr[SPR_BESCR] & BESCR_GE)) { - return PPC_INTERRUPT_EBB; - } - } } return 0; -- cgit v1.1 From d93a48561c59b08958c9c37191248492a7acb8e4 Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Tue, 11 Oct 2022 17:48:21 -0300 Subject: target/ppc: create an interrupt deliver method for POWER7 The new method is identical to ppc_deliver_interrupt, processor-specific code will be added/removed in the following patches. Signed-off-by: Matheus Ferst Reviewed-by: Fabiano Rosas Message-Id: <20221011204829.1641124-22-matheus.ferst@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/excp_helper.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) (limited to 'target') diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 08db3a4..5bb0501 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -2045,6 +2045,110 @@ static int ppc_next_unmasked_interrupt(CPUPPCState *env) } #if defined(TARGET_PPC64) +static void p7_deliver_interrupt(CPUPPCState *env, int interrupt) +{ + PowerPCCPU *cpu = env_archcpu(env); + CPUState *cs = env_cpu(env); + + switch (interrupt) { + case PPC_INTERRUPT_RESET: /* External reset */ + env->pending_interrupts &= ~PPC_INTERRUPT_RESET; + powerpc_excp(cpu, POWERPC_EXCP_RESET); + break; + case PPC_INTERRUPT_MCK: /* Machine check exception */ + env->pending_interrupts &= ~PPC_INTERRUPT_MCK; + powerpc_excp(cpu, POWERPC_EXCP_MCHECK); + break; + + case PPC_INTERRUPT_HDECR: /* Hypervisor decrementer exception */ + /* HDEC clears on delivery */ + env->pending_interrupts &= ~PPC_INTERRUPT_HDECR; + powerpc_excp(cpu, POWERPC_EXCP_HDECR); + break; + case PPC_INTERRUPT_HVIRT: /* Hypervisor virtualization interrupt */ + powerpc_excp(cpu, POWERPC_EXCP_HVIRT); + break; + + case PPC_INTERRUPT_EXT: + if (books_vhyp_promotes_external_to_hvirt(cpu)) { + powerpc_excp(cpu, POWERPC_EXCP_HVIRT); + } else { + powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL); + } + break; + case PPC_INTERRUPT_CEXT: /* External critical interrupt */ + powerpc_excp(cpu, POWERPC_EXCP_CRITICAL); + break; + + case PPC_INTERRUPT_WDT: /* Watchdog timer on embedded PowerPC */ + env->pending_interrupts &= ~PPC_INTERRUPT_WDT; + powerpc_excp(cpu, POWERPC_EXCP_WDT); + break; + case PPC_INTERRUPT_CDOORBELL: + env->pending_interrupts &= ~PPC_INTERRUPT_CDOORBELL; + powerpc_excp(cpu, POWERPC_EXCP_DOORCI); + break; + case PPC_INTERRUPT_FIT: /* Fixed interval timer on embedded PowerPC */ + env->pending_interrupts &= ~PPC_INTERRUPT_FIT; + powerpc_excp(cpu, POWERPC_EXCP_FIT); + break; + case PPC_INTERRUPT_PIT: /* Programmable interval timer on embedded ppc */ + env->pending_interrupts &= ~PPC_INTERRUPT_PIT; + powerpc_excp(cpu, POWERPC_EXCP_PIT); + break; + case PPC_INTERRUPT_DECR: /* Decrementer exception */ + if (ppc_decr_clear_on_delivery(env)) { + env->pending_interrupts &= ~PPC_INTERRUPT_DECR; + } + powerpc_excp(cpu, POWERPC_EXCP_DECR); + break; + case PPC_INTERRUPT_DOORBELL: + env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL; + if (is_book3s_arch2x(env)) { + powerpc_excp(cpu, POWERPC_EXCP_SDOOR); + } else { + powerpc_excp(cpu, POWERPC_EXCP_DOORI); + } + break; + case PPC_INTERRUPT_HDOORBELL: + env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL; + powerpc_excp(cpu, POWERPC_EXCP_SDOOR_HV); + break; + case PPC_INTERRUPT_PERFM: + env->pending_interrupts &= ~PPC_INTERRUPT_PERFM; + powerpc_excp(cpu, POWERPC_EXCP_PERFM); + break; + case PPC_INTERRUPT_THERM: /* Thermal interrupt */ + env->pending_interrupts &= ~PPC_INTERRUPT_THERM; + powerpc_excp(cpu, POWERPC_EXCP_THERM); + break; + case PPC_INTERRUPT_EBB: /* EBB exception */ + env->pending_interrupts &= ~PPC_INTERRUPT_EBB; + if (env->spr[SPR_BESCR] & BESCR_PMEO) { + powerpc_excp(cpu, POWERPC_EXCP_PERFM_EBB); + } else if (env->spr[SPR_BESCR] & BESCR_EEO) { + powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL_EBB); + } + break; + case 0: + /* + * This is a bug ! It means that has_work took us out of halt without + * anything to deliver while in a PM state that requires getting + * out via a 0x100 + * + * This means we will incorrectly execute past the power management + * instruction instead of triggering a reset. + * + * It generally means a discrepancy between the wakeup conditions in the + * processor has_work implementation and the logic in this function. + */ + assert(!env->resume_as_sreset); + break; + default: + cpu_abort(cs, "Invalid PowerPC interrupt %d. Aborting\n", interrupt); + } +} + static void p8_deliver_interrupt(CPUPPCState *env, int interrupt) { PowerPCCPU *cpu = env_archcpu(env); @@ -2304,6 +2408,9 @@ static void ppc_deliver_interrupt(CPUPPCState *env, int interrupt) { switch (env->excp_model) { #if defined(TARGET_PPC64) + case POWERPC_EXCP_POWER7: + p7_deliver_interrupt(env, interrupt); + break; case POWERPC_EXCP_POWER8: p8_deliver_interrupt(env, interrupt); break; -- cgit v1.1 From ec0f351af109e2b3d94ae50f5fe560a435b544d1 Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Tue, 11 Oct 2022 17:48:22 -0300 Subject: target/ppc: remove unused interrupts from p7_deliver_interrupt Remove the following unused interrupts from the POWER7 interrupt processing method: - PPC_INTERRUPT_RESET: only raised for 6xx, 7xx, 970 and POWER5p; - Hypervisor Virtualization: introduced in Power ISA v3.0; - Hypervisor Doorbell and Event-Based Branch: introduced in Power ISA v2.07; - Critical Input, Watchdog Timer, and Fixed Interval Timer: only defined for embedded CPUs; - Doorbell and Critical Doorbell Interrupt: processor does not implement the Embedded.Processor Control category; - Programmable Interval Timer: 40x-only; - PPC_INTERRUPT_THERM: only raised for 970 and POWER5p; Signed-off-by: Matheus Ferst Reviewed-by: Fabiano Rosas Message-Id: <20221011204829.1641124-23-matheus.ferst@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/excp_helper.c | 50 ------------------------------------------------ 1 file changed, 50 deletions(-) (limited to 'target') diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 5bb0501..5373e08 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -2051,10 +2051,6 @@ static void p7_deliver_interrupt(CPUPPCState *env, int interrupt) CPUState *cs = env_cpu(env); switch (interrupt) { - case PPC_INTERRUPT_RESET: /* External reset */ - env->pending_interrupts &= ~PPC_INTERRUPT_RESET; - powerpc_excp(cpu, POWERPC_EXCP_RESET); - break; case PPC_INTERRUPT_MCK: /* Machine check exception */ env->pending_interrupts &= ~PPC_INTERRUPT_MCK; powerpc_excp(cpu, POWERPC_EXCP_MCHECK); @@ -2065,9 +2061,6 @@ static void p7_deliver_interrupt(CPUPPCState *env, int interrupt) env->pending_interrupts &= ~PPC_INTERRUPT_HDECR; powerpc_excp(cpu, POWERPC_EXCP_HDECR); break; - case PPC_INTERRUPT_HVIRT: /* Hypervisor virtualization interrupt */ - powerpc_excp(cpu, POWERPC_EXCP_HVIRT); - break; case PPC_INTERRUPT_EXT: if (books_vhyp_promotes_external_to_hvirt(cpu)) { @@ -2076,60 +2069,17 @@ static void p7_deliver_interrupt(CPUPPCState *env, int interrupt) powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL); } break; - case PPC_INTERRUPT_CEXT: /* External critical interrupt */ - powerpc_excp(cpu, POWERPC_EXCP_CRITICAL); - break; - case PPC_INTERRUPT_WDT: /* Watchdog timer on embedded PowerPC */ - env->pending_interrupts &= ~PPC_INTERRUPT_WDT; - powerpc_excp(cpu, POWERPC_EXCP_WDT); - break; - case PPC_INTERRUPT_CDOORBELL: - env->pending_interrupts &= ~PPC_INTERRUPT_CDOORBELL; - powerpc_excp(cpu, POWERPC_EXCP_DOORCI); - break; - case PPC_INTERRUPT_FIT: /* Fixed interval timer on embedded PowerPC */ - env->pending_interrupts &= ~PPC_INTERRUPT_FIT; - powerpc_excp(cpu, POWERPC_EXCP_FIT); - break; - case PPC_INTERRUPT_PIT: /* Programmable interval timer on embedded ppc */ - env->pending_interrupts &= ~PPC_INTERRUPT_PIT; - powerpc_excp(cpu, POWERPC_EXCP_PIT); - break; case PPC_INTERRUPT_DECR: /* Decrementer exception */ if (ppc_decr_clear_on_delivery(env)) { env->pending_interrupts &= ~PPC_INTERRUPT_DECR; } powerpc_excp(cpu, POWERPC_EXCP_DECR); break; - case PPC_INTERRUPT_DOORBELL: - env->pending_interrupts &= ~PPC_INTERRUPT_DOORBELL; - if (is_book3s_arch2x(env)) { - powerpc_excp(cpu, POWERPC_EXCP_SDOOR); - } else { - powerpc_excp(cpu, POWERPC_EXCP_DOORI); - } - break; - case PPC_INTERRUPT_HDOORBELL: - env->pending_interrupts &= ~PPC_INTERRUPT_HDOORBELL; - powerpc_excp(cpu, POWERPC_EXCP_SDOOR_HV); - break; case PPC_INTERRUPT_PERFM: env->pending_interrupts &= ~PPC_INTERRUPT_PERFM; powerpc_excp(cpu, POWERPC_EXCP_PERFM); break; - case PPC_INTERRUPT_THERM: /* Thermal interrupt */ - env->pending_interrupts &= ~PPC_INTERRUPT_THERM; - powerpc_excp(cpu, POWERPC_EXCP_THERM); - break; - case PPC_INTERRUPT_EBB: /* EBB exception */ - env->pending_interrupts &= ~PPC_INTERRUPT_EBB; - if (env->spr[SPR_BESCR] & BESCR_PMEO) { - powerpc_excp(cpu, POWERPC_EXCP_PERFM_EBB); - } else if (env->spr[SPR_BESCR] & BESCR_EEO) { - powerpc_excp(cpu, POWERPC_EXCP_EXTERNAL_EBB); - } - break; case 0: /* * This is a bug ! It means that has_work took us out of halt without -- cgit v1.1 From 3f34e809ac856831949843d2adc45fab00f8b244 Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Tue, 11 Oct 2022 17:48:23 -0300 Subject: target/ppc: remove generic architecture checks from p7_deliver_interrupt Signed-off-by: Matheus Ferst Reviewed-by: Fabiano Rosas Message-Id: <20221011204829.1641124-24-matheus.ferst@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/excp_helper.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'target') diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 5373e08..9164dc2 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -2071,9 +2071,6 @@ static void p7_deliver_interrupt(CPUPPCState *env, int interrupt) break; case PPC_INTERRUPT_DECR: /* Decrementer exception */ - if (ppc_decr_clear_on_delivery(env)) { - env->pending_interrupts &= ~PPC_INTERRUPT_DECR; - } powerpc_excp(cpu, POWERPC_EXCP_DECR); break; case PPC_INTERRUPT_PERFM: -- cgit v1.1 From b34d358a212908326a43216162e90934015b02e7 Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Tue, 11 Oct 2022 17:48:24 -0300 Subject: target/ppc: move power-saving interrupt masking out of cpu_has_work_POWER7 Move the interrupt masking logic out of cpu_has_work_POWER7 in a new method, p7_interrupt_powersave, that only returns an interrupt if it can wake the processor from power-saving mode. Signed-off-by: Matheus Ferst Reviewed-by: Fabiano Rosas Message-Id: <20221011204829.1641124-25-matheus.ferst@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/cpu_init.c | 45 +++++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 20 deletions(-) (limited to 'target') diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index 68ae22d..0c5ada7 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -5960,6 +5960,30 @@ static bool ppc_pvr_match_power7(PowerPCCPUClass *pcc, uint32_t pvr, bool best) return true; } +static int p7_interrupt_powersave(CPUPPCState *env) +{ + if ((env->pending_interrupts & PPC_INTERRUPT_EXT) && + (env->spr[SPR_LPCR] & LPCR_P7_PECE0)) { + return PPC_INTERRUPT_EXT; + } + if ((env->pending_interrupts & PPC_INTERRUPT_DECR) && + (env->spr[SPR_LPCR] & LPCR_P7_PECE1)) { + return PPC_INTERRUPT_DECR; + } + if ((env->pending_interrupts & PPC_INTERRUPT_MCK) && + (env->spr[SPR_LPCR] & LPCR_P7_PECE2)) { + return PPC_INTERRUPT_MCK; + } + if ((env->pending_interrupts & PPC_INTERRUPT_HMI) && + (env->spr[SPR_LPCR] & LPCR_P7_PECE2)) { + return PPC_INTERRUPT_HMI; + } + if (env->pending_interrupts & PPC_INTERRUPT_RESET) { + return PPC_INTERRUPT_RESET; + } + return 0; +} + static bool cpu_has_work_POWER7(CPUState *cs) { PowerPCCPU *cpu = POWERPC_CPU(cs); @@ -5969,26 +5993,7 @@ static bool cpu_has_work_POWER7(CPUState *cs) if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) { return false; } - if ((env->pending_interrupts & PPC_INTERRUPT_EXT) && - (env->spr[SPR_LPCR] & LPCR_P7_PECE0)) { - return true; - } - if ((env->pending_interrupts & PPC_INTERRUPT_DECR) && - (env->spr[SPR_LPCR] & LPCR_P7_PECE1)) { - return true; - } - if ((env->pending_interrupts & PPC_INTERRUPT_MCK) && - (env->spr[SPR_LPCR] & LPCR_P7_PECE2)) { - return true; - } - if ((env->pending_interrupts & PPC_INTERRUPT_HMI) && - (env->spr[SPR_LPCR] & LPCR_P7_PECE2)) { - return true; - } - if (env->pending_interrupts & PPC_INTERRUPT_RESET) { - return true; - } - return false; + return p7_interrupt_powersave(env) != 0; } else { return FIELD_EX64(env->msr, MSR, EE) && (cs->interrupt_request & CPU_INTERRUPT_HARD); -- cgit v1.1 From 022b7128535d0ec963f724008a5f8b6a842d92ae Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Tue, 11 Oct 2022 17:48:25 -0300 Subject: target/ppc: add power-saving interrupt masking logic to p7_next_unmasked_interrupt Export p7_interrupt_powersave and use it in p7_next_unmasked_interrupt. Signed-off-by: Matheus Ferst Reviewed-by: Fabiano Rosas Message-Id: <20221011204829.1641124-26-matheus.ferst@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/cpu_init.c | 2 +- target/ppc/excp_helper.c | 24 ++++++++++++------------ target/ppc/internal.h | 1 + 3 files changed, 14 insertions(+), 13 deletions(-) (limited to 'target') diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index 0c5ada7..5238229 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -5960,7 +5960,7 @@ static bool ppc_pvr_match_power7(PowerPCCPUClass *pcc, uint32_t pvr, bool best) return true; } -static int p7_interrupt_powersave(CPUPPCState *env) +int p7_interrupt_powersave(CPUPPCState *env) { if ((env->pending_interrupts & PPC_INTERRUPT_EXT) && (env->spr[SPR_LPCR] & LPCR_P7_PECE0)) { diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 9164dc2..14bec24 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -1693,28 +1693,28 @@ void ppc_cpu_do_interrupt(CPUState *cs) static int p7_next_unmasked_interrupt(CPUPPCState *env) { - bool async_deliver; + PowerPCCPU *cpu = env_archcpu(env); + CPUState *cs = CPU(cpu); + /* Ignore MSR[EE] when coming out of some power management states */ + bool msr_ee = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset; assert((env->pending_interrupts & P7_UNUSED_INTERRUPTS) == 0); + if (cs->halted) { + /* LPCR[PECE] controls which interrupts can exit power-saving mode */ + return p7_interrupt_powersave(env); + } + /* Machine check exception */ if (env->pending_interrupts & PPC_INTERRUPT_MCK) { return PPC_INTERRUPT_MCK; } - /* - * For interrupts that gate on MSR:EE, we need to do something a - * bit more subtle, as we need to let them through even when EE is - * clear when coming out of some power management states (in order - * for them to become a 0x100). - */ - async_deliver = FIELD_EX64(env->msr, MSR, EE) || env->resume_as_sreset; - /* Hypervisor decrementer exception */ if (env->pending_interrupts & PPC_INTERRUPT_HDECR) { /* LPCR will be clear when not supported so this will work */ bool hdice = !!(env->spr[SPR_LPCR] & LPCR_HDICE); - if ((async_deliver || !FIELD_EX64_HV(env->msr)) && hdice) { + if ((msr_ee || !FIELD_EX64_HV(env->msr)) && hdice) { /* HDEC clears on delivery */ return PPC_INTERRUPT_HDECR; } @@ -1725,13 +1725,13 @@ static int p7_next_unmasked_interrupt(CPUPPCState *env) bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0); bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC); /* HEIC blocks delivery to the hypervisor */ - if ((async_deliver && !(heic && FIELD_EX64_HV(env->msr) && + if ((msr_ee && !(heic && FIELD_EX64_HV(env->msr) && !FIELD_EX64(env->msr, MSR, PR))) || (env->has_hv_mode && !FIELD_EX64_HV(env->msr) && !lpes0)) { return PPC_INTERRUPT_EXT; } } - if (async_deliver != 0) { + if (msr_ee != 0) { /* Decrementer exception */ if (env->pending_interrupts & PPC_INTERRUPT_DECR) { return PPC_INTERRUPT_DECR; diff --git a/target/ppc/internal.h b/target/ppc/internal.h index 9069874..25827eb 100644 --- a/target/ppc/internal.h +++ b/target/ppc/internal.h @@ -309,6 +309,7 @@ static inline int ger_pack_masks(int pmsk, int ymsk, int xmsk) #if defined(TARGET_PPC64) int p9_interrupt_powersave(CPUPPCState *env); int p8_interrupt_powersave(CPUPPCState *env); +int p7_interrupt_powersave(CPUPPCState *env); #endif #endif /* PPC_INTERNAL_H */ -- cgit v1.1 From 6a8e8188c3c99e987e3d5b9df614a68a5d4bd1e0 Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Tue, 11 Oct 2022 17:48:26 -0300 Subject: target/ppc: remove ppc_store_lpcr from CONFIG_USER_ONLY builds Writes to LPCR are hypervisor privileged. Signed-off-by: Matheus Ferst Reviewed-by: Fabiano Rosas Message-Id: <20221011204829.1641124-27-matheus.ferst@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/cpu.c | 2 ++ target/ppc/cpu.h | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'target') diff --git a/target/ppc/cpu.c b/target/ppc/cpu.c index 0ebac04..e95b4c5 100644 --- a/target/ppc/cpu.c +++ b/target/ppc/cpu.c @@ -73,6 +73,7 @@ void ppc_store_msr(CPUPPCState *env, target_ulong value) hreg_store_msr(env, value, 0); } +#if !defined(CONFIG_USER_ONLY) void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val) { PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); @@ -82,6 +83,7 @@ void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val) /* The gtse bit affects hflags */ hreg_compute_hflags(env); } +#endif static inline void fpscr_set_rounding_mode(CPUPPCState *env) { diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 2433756..ad758b0 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -1370,9 +1370,9 @@ void ppc_translate_init(void); #if !defined(CONFIG_USER_ONLY) void ppc_store_sdr1(CPUPPCState *env, target_ulong value); +void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val); #endif /* !defined(CONFIG_USER_ONLY) */ void ppc_store_msr(CPUPPCState *env, target_ulong value); -void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val); void ppc_cpu_list(void); -- cgit v1.1 From 2fdedcbc69564f52a1c33bedfa291707e998a132 Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Fri, 21 Oct 2022 11:21:54 -0300 Subject: target/ppc: introduce ppc_maybe_interrupt This new method will check if any pending interrupt was unmasked and then call cpu_interrupt/cpu_reset_interrupt accordingly. Code that raises/lowers or masks/unmasks interrupts should call this method to keep CPU_INTERRUPT_HARD coherent with env->pending_interrupts. Signed-off-by: Matheus Ferst Reviewed-by: Daniel Henrique Barboza Message-Id: <20221021142156.4134411-2-matheus.ferst@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/cpu.c | 2 ++ target/ppc/cpu.h | 1 + target/ppc/excp_helper.c | 42 ++++++++++++++++++++++++++++++++++++++++++ target/ppc/helper.h | 1 + target/ppc/helper_regs.c | 2 ++ target/ppc/translate.c | 11 ++++++++++- 6 files changed, 58 insertions(+), 1 deletion(-) (limited to 'target') diff --git a/target/ppc/cpu.c b/target/ppc/cpu.c index e95b4c5..1a97b41 100644 --- a/target/ppc/cpu.c +++ b/target/ppc/cpu.c @@ -82,6 +82,8 @@ void ppc_store_lpcr(PowerPCCPU *cpu, target_ulong val) env->spr[SPR_LPCR] = val & pcc->lpcr_mask; /* The gtse bit affects hflags */ hreg_compute_hflags(env); + + ppc_maybe_interrupt(env); } #endif diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index ad758b0..cc2d030 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -1358,6 +1358,7 @@ int ppc64_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, int ppc32_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs, int cpuid, DumpState *s); #ifndef CONFIG_USER_ONLY +void ppc_maybe_interrupt(CPUPPCState *env); void ppc_cpu_do_interrupt(CPUState *cpu); bool ppc_cpu_exec_interrupt(CPUState *cpu, int int_req); void ppc_cpu_do_system_reset(CPUState *cs); diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 14bec24..0748007 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -390,6 +390,7 @@ static void powerpc_set_excp_state(PowerPCCPU *cpu, target_ulong vector, env->nip = vector; env->msr = msr; hreg_compute_hflags(env); + ppc_maybe_interrupt(env); powerpc_reset_excp_state(cpu); @@ -2044,6 +2045,40 @@ static int ppc_next_unmasked_interrupt(CPUPPCState *env) } } +/* + * Sets CPU_INTERRUPT_HARD if there is at least one unmasked interrupt to be + * delivered and clears CPU_INTERRUPT_HARD otherwise. + * + * This method is called by ppc_set_interrupt when an interrupt is raised or + * lowered, and should also be called whenever an interrupt masking condition + * is changed, e.g.: + * - When relevant bits of MSR are altered, like EE, HV, PR, etc.; + * - When relevant bits of LPCR are altered, like PECE, HDICE, HVICE, etc.; + * - When PSSCR[EC] or env->resume_as_sreset are changed; + * - When cs->halted is changed and the CPU has a different interrupt masking + * logic in power-saving mode (e.g., POWER7/8/9/10); + */ +void ppc_maybe_interrupt(CPUPPCState *env) +{ + CPUState *cs = env_cpu(env); + bool locked = false; + + if (!qemu_mutex_iothread_locked()) { + locked = true; + qemu_mutex_lock_iothread(); + } + + if (ppc_next_unmasked_interrupt(env)) { + cpu_interrupt(cs, CPU_INTERRUPT_HARD); + } else { + cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); + } + + if (locked) { + qemu_mutex_unlock_iothread(); + } +} + #if defined(TARGET_PPC64) static void p7_deliver_interrupt(CPUPPCState *env, int interrupt) { @@ -2479,6 +2514,11 @@ void helper_store_msr(CPUPPCState *env, target_ulong val) } } +void helper_ppc_maybe_interrupt(CPUPPCState *env) +{ + ppc_maybe_interrupt(env); +} + #if defined(TARGET_PPC64) void helper_scv(CPUPPCState *env, uint32_t lev) { @@ -2499,6 +2539,8 @@ void helper_pminsn(CPUPPCState *env, powerpc_pm_insn_t insn) /* Condition for waking up at 0x100 */ env->resume_as_sreset = (insn != PPC_PM_STOP) || (env->spr[SPR_PSSCR] & PSSCR_EC); + + ppc_maybe_interrupt(env); } #endif /* defined(TARGET_PPC64) */ diff --git a/target/ppc/helper.h b/target/ppc/helper.h index 8344fe3..25533b8 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -10,6 +10,7 @@ DEF_HELPER_4(HASHSTP, void, env, tl, tl, tl) DEF_HELPER_4(HASHCHKP, void, env, tl, tl, tl) #if !defined(CONFIG_USER_ONLY) DEF_HELPER_2(store_msr, void, env, tl) +DEF_HELPER_1(ppc_maybe_interrupt, void, env) DEF_HELPER_1(rfi, void, env) DEF_HELPER_1(40x_rfci, void, env) DEF_HELPER_1(rfci, void, env) diff --git a/target/ppc/helper_regs.c b/target/ppc/helper_regs.c index 12235ea..2e85e12 100644 --- a/target/ppc/helper_regs.c +++ b/target/ppc/helper_regs.c @@ -260,6 +260,8 @@ int hreg_store_msr(CPUPPCState *env, target_ulong value, int alter_hv) env->msr = value; hreg_compute_hflags(env); #if !defined(CONFIG_USER_ONLY) + ppc_maybe_interrupt(env); + if (unlikely(FIELD_EX64(env->msr, MSR, POW))) { if (!env->pending_interrupts && (*env->check_pow)(env)) { cs->halted = 1; diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 58fbc15..29e4b72 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -305,6 +305,14 @@ static void gen_icount_io_start(DisasContext *ctx) } } +#if !defined(CONFIG_USER_ONLY) +static void gen_ppc_maybe_interrupt(DisasContext *ctx) +{ + gen_icount_io_start(ctx); + gen_helper_ppc_maybe_interrupt(cpu_env); +} +#endif + /* * Tells the caller what is the appropriate exception to generate and prepares * SPR registers for this exception. @@ -6161,7 +6169,6 @@ static void gen_tlbilx_booke206(DisasContext *ctx) #endif /* defined(CONFIG_USER_ONLY) */ } - /* wrtee */ static void gen_wrtee(DisasContext *ctx) { @@ -6175,6 +6182,7 @@ static void gen_wrtee(DisasContext *ctx) tcg_gen_andi_tl(t0, cpu_gpr[rD(ctx->opcode)], (1 << MSR_EE)); tcg_gen_andi_tl(cpu_msr, cpu_msr, ~(1 << MSR_EE)); tcg_gen_or_tl(cpu_msr, cpu_msr, t0); + gen_ppc_maybe_interrupt(ctx); tcg_temp_free(t0); /* * Stop translation to have a chance to raise an exception if we @@ -6193,6 +6201,7 @@ static void gen_wrteei(DisasContext *ctx) CHK_SV(ctx); if (ctx->opcode & 0x00008000) { tcg_gen_ori_tl(cpu_msr, cpu_msr, (1 << MSR_EE)); + gen_ppc_maybe_interrupt(ctx); /* Stop translation to have a chance to raise an exception */ ctx->base.is_jmp = DISAS_EXIT_UPDATE; } else { -- cgit v1.1 From ab9cfa04523e0312c741e16ca54c5fa4e1eee9e2 Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Fri, 21 Oct 2022 11:21:55 -0300 Subject: target/ppc: unify cpu->has_work based on cs->interrupt_request Now that cs->interrupt_request indicates if there is any unmasked interrupt, checking if the CPU has work to do can be simplified to a single check that works for all CPU models. Reviewed-by: Fabiano Rosas Signed-off-by: Matheus Ferst Message-Id: <20221021142156.4134411-3-matheus.ferst@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/cpu_init.c | 94 +-------------------------------------------------- 1 file changed, 1 insertion(+), 93 deletions(-) (limited to 'target') diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index 5238229..b149055 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -5984,27 +5984,10 @@ int p7_interrupt_powersave(CPUPPCState *env) return 0; } -static bool cpu_has_work_POWER7(CPUState *cs) -{ - PowerPCCPU *cpu = POWERPC_CPU(cs); - CPUPPCState *env = &cpu->env; - - if (cs->halted) { - if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) { - return false; - } - return p7_interrupt_powersave(env) != 0; - } else { - return FIELD_EX64(env->msr, MSR, EE) && - (cs->interrupt_request & CPU_INTERRUPT_HARD); - } -} - POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); - CPUClass *cc = CPU_CLASS(oc); dc->fw_name = "PowerPC,POWER7"; dc->desc = "POWER7"; @@ -6013,7 +5996,6 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data) pcc->pcr_supported = PCR_COMPAT_2_06 | PCR_COMPAT_2_05; pcc->init_proc = init_proc_POWER7; pcc->check_pow = check_pow_nocheck; - cc->has_work = cpu_has_work_POWER7; pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB | PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | @@ -6170,27 +6152,10 @@ int p8_interrupt_powersave(CPUPPCState *env) return 0; } -static bool cpu_has_work_POWER8(CPUState *cs) -{ - PowerPCCPU *cpu = POWERPC_CPU(cs); - CPUPPCState *env = &cpu->env; - - if (cs->halted) { - if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) { - return false; - } - return p8_interrupt_powersave(env) != 0; - } else { - return FIELD_EX64(env->msr, MSR, EE) && - (cs->interrupt_request & CPU_INTERRUPT_HARD); - } -} - POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); - CPUClass *cc = CPU_CLASS(oc); dc->fw_name = "PowerPC,POWER8"; dc->desc = "POWER8"; @@ -6199,7 +6164,6 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data) pcc->pcr_supported = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_COMPAT_2_05; pcc->init_proc = init_proc_POWER8; pcc->check_pow = check_pow_nocheck; - cc->has_work = cpu_has_work_POWER8; pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB | PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | @@ -6407,35 +6371,10 @@ int p9_interrupt_powersave(CPUPPCState *env) return 0; } -static bool cpu_has_work_POWER9(CPUState *cs) -{ - PowerPCCPU *cpu = POWERPC_CPU(cs); - CPUPPCState *env = &cpu->env; - - if (cs->halted) { - uint64_t psscr = env->spr[SPR_PSSCR]; - - if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) { - return false; - } - - /* If EC is clear, just return true on any pending interrupt */ - if (!(psscr & PSSCR_EC)) { - return true; - } - - return p9_interrupt_powersave(env) != 0; - } else { - return FIELD_EX64(env->msr, MSR, EE) && - (cs->interrupt_request & CPU_INTERRUPT_HARD); - } -} - POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); - CPUClass *cc = CPU_CLASS(oc); dc->fw_name = "PowerPC,POWER9"; dc->desc = "POWER9"; @@ -6445,7 +6384,6 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data) PCR_COMPAT_2_05; pcc->init_proc = init_proc_POWER9; pcc->check_pow = check_pow_nocheck; - cc->has_work = cpu_has_work_POWER9; pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB | PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | @@ -6604,35 +6542,10 @@ static bool ppc_pvr_match_power10(PowerPCCPUClass *pcc, uint32_t pvr, bool best) return false; } -static bool cpu_has_work_POWER10(CPUState *cs) -{ - PowerPCCPU *cpu = POWERPC_CPU(cs); - CPUPPCState *env = &cpu->env; - - if (cs->halted) { - uint64_t psscr = env->spr[SPR_PSSCR]; - - if (!(cs->interrupt_request & CPU_INTERRUPT_HARD)) { - return false; - } - - /* If EC is clear, just return true on any pending interrupt */ - if (!(psscr & PSSCR_EC)) { - return true; - } - - return p9_interrupt_powersave(env) != 0; - } else { - return FIELD_EX64(env->msr, MSR, EE) && - (cs->interrupt_request & CPU_INTERRUPT_HARD); - } -} - POWERPC_FAMILY(POWER10)(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); - CPUClass *cc = CPU_CLASS(oc); dc->fw_name = "PowerPC,POWER10"; dc->desc = "POWER10"; @@ -6643,7 +6556,6 @@ POWERPC_FAMILY(POWER10)(ObjectClass *oc, void *data) PCR_COMPAT_2_06 | PCR_COMPAT_2_05; pcc->init_proc = init_proc_POWER10; pcc->check_pow = check_pow_nocheck; - cc->has_work = cpu_has_work_POWER10; pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB | PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | @@ -7216,11 +7128,7 @@ static void ppc_restore_state_to_opc(CPUState *cs, static bool ppc_cpu_has_work(CPUState *cs) { - PowerPCCPU *cpu = POWERPC_CPU(cs); - CPUPPCState *env = &cpu->env; - - return FIELD_EX64(env->msr, MSR, EE) && - (cs->interrupt_request & CPU_INTERRUPT_HARD); + return cs->interrupt_request & CPU_INTERRUPT_HARD; } static void ppc_cpu_reset(DeviceState *dev) -- cgit v1.1 From 9c713713dac70fe7eaa9b403234a71024a729eb4 Mon Sep 17 00:00:00 2001 From: Matheus Ferst Date: Fri, 21 Oct 2022 11:21:56 -0300 Subject: target/ppc: move the p*_interrupt_powersave methods to excp_helper.c Move the methods to excp_helper.c and make them static. Reviewed-by: Fabiano Rosas Signed-off-by: Matheus Ferst Message-Id: <20221021142156.4134411-4-matheus.ferst@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/cpu_init.c | 102 ----------------------------------------------- target/ppc/excp_helper.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++ target/ppc/internal.h | 6 --- 3 files changed, 102 insertions(+), 108 deletions(-) (limited to 'target') diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index b149055..32e9415 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -5960,30 +5960,6 @@ static bool ppc_pvr_match_power7(PowerPCCPUClass *pcc, uint32_t pvr, bool best) return true; } -int p7_interrupt_powersave(CPUPPCState *env) -{ - if ((env->pending_interrupts & PPC_INTERRUPT_EXT) && - (env->spr[SPR_LPCR] & LPCR_P7_PECE0)) { - return PPC_INTERRUPT_EXT; - } - if ((env->pending_interrupts & PPC_INTERRUPT_DECR) && - (env->spr[SPR_LPCR] & LPCR_P7_PECE1)) { - return PPC_INTERRUPT_DECR; - } - if ((env->pending_interrupts & PPC_INTERRUPT_MCK) && - (env->spr[SPR_LPCR] & LPCR_P7_PECE2)) { - return PPC_INTERRUPT_MCK; - } - if ((env->pending_interrupts & PPC_INTERRUPT_HMI) && - (env->spr[SPR_LPCR] & LPCR_P7_PECE2)) { - return PPC_INTERRUPT_HMI; - } - if (env->pending_interrupts & PPC_INTERRUPT_RESET) { - return PPC_INTERRUPT_RESET; - } - return 0; -} - POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); @@ -6120,38 +6096,6 @@ static bool ppc_pvr_match_power8(PowerPCCPUClass *pcc, uint32_t pvr, bool best) return true; } -int p8_interrupt_powersave(CPUPPCState *env) -{ - if ((env->pending_interrupts & PPC_INTERRUPT_EXT) && - (env->spr[SPR_LPCR] & LPCR_P8_PECE2)) { - return PPC_INTERRUPT_EXT; - } - if ((env->pending_interrupts & PPC_INTERRUPT_DECR) && - (env->spr[SPR_LPCR] & LPCR_P8_PECE3)) { - return PPC_INTERRUPT_DECR; - } - if ((env->pending_interrupts & PPC_INTERRUPT_MCK) && - (env->spr[SPR_LPCR] & LPCR_P8_PECE4)) { - return PPC_INTERRUPT_MCK; - } - if ((env->pending_interrupts & PPC_INTERRUPT_HMI) && - (env->spr[SPR_LPCR] & LPCR_P8_PECE4)) { - return PPC_INTERRUPT_HMI; - } - if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) && - (env->spr[SPR_LPCR] & LPCR_P8_PECE0)) { - return PPC_INTERRUPT_DOORBELL; - } - if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) && - (env->spr[SPR_LPCR] & LPCR_P8_PECE1)) { - return PPC_INTERRUPT_HDOORBELL; - } - if (env->pending_interrupts & PPC_INTERRUPT_RESET) { - return PPC_INTERRUPT_RESET; - } - return 0; -} - POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); @@ -6325,52 +6269,6 @@ static bool ppc_pvr_match_power9(PowerPCCPUClass *pcc, uint32_t pvr, bool best) return false; } -int p9_interrupt_powersave(CPUPPCState *env) -{ - /* External Exception */ - if ((env->pending_interrupts & PPC_INTERRUPT_EXT) && - (env->spr[SPR_LPCR] & LPCR_EEE)) { - bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC); - if (!heic || !FIELD_EX64_HV(env->msr) || - FIELD_EX64(env->msr, MSR, PR)) { - return PPC_INTERRUPT_EXT; - } - } - /* Decrementer Exception */ - if ((env->pending_interrupts & PPC_INTERRUPT_DECR) && - (env->spr[SPR_LPCR] & LPCR_DEE)) { - return PPC_INTERRUPT_DECR; - } - /* Machine Check or Hypervisor Maintenance Exception */ - if (env->spr[SPR_LPCR] & LPCR_OEE) { - if (env->pending_interrupts & PPC_INTERRUPT_MCK) { - return PPC_INTERRUPT_MCK; - } - if (env->pending_interrupts & PPC_INTERRUPT_HMI) { - return PPC_INTERRUPT_HMI; - } - } - /* Privileged Doorbell Exception */ - if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) && - (env->spr[SPR_LPCR] & LPCR_PDEE)) { - return PPC_INTERRUPT_DOORBELL; - } - /* Hypervisor Doorbell Exception */ - if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) && - (env->spr[SPR_LPCR] & LPCR_HDEE)) { - return PPC_INTERRUPT_HDOORBELL; - } - /* Hypervisor virtualization exception */ - if ((env->pending_interrupts & PPC_INTERRUPT_HVIRT) && - (env->spr[SPR_LPCR] & LPCR_HVEE)) { - return PPC_INTERRUPT_HVIRT; - } - if (env->pending_interrupts & PPC_INTERRUPT_RESET) { - return PPC_INTERRUPT_RESET; - } - return 0; -} - POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index 0748007..09a8156 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -1692,6 +1692,30 @@ void ppc_cpu_do_interrupt(CPUState *cs) PPC_INTERRUPT_PIT | PPC_INTERRUPT_DOORBELL | PPC_INTERRUPT_HDOORBELL | \ PPC_INTERRUPT_THERM | PPC_INTERRUPT_EBB) +static int p7_interrupt_powersave(CPUPPCState *env) +{ + if ((env->pending_interrupts & PPC_INTERRUPT_EXT) && + (env->spr[SPR_LPCR] & LPCR_P7_PECE0)) { + return PPC_INTERRUPT_EXT; + } + if ((env->pending_interrupts & PPC_INTERRUPT_DECR) && + (env->spr[SPR_LPCR] & LPCR_P7_PECE1)) { + return PPC_INTERRUPT_DECR; + } + if ((env->pending_interrupts & PPC_INTERRUPT_MCK) && + (env->spr[SPR_LPCR] & LPCR_P7_PECE2)) { + return PPC_INTERRUPT_MCK; + } + if ((env->pending_interrupts & PPC_INTERRUPT_HMI) && + (env->spr[SPR_LPCR] & LPCR_P7_PECE2)) { + return PPC_INTERRUPT_HMI; + } + if (env->pending_interrupts & PPC_INTERRUPT_RESET) { + return PPC_INTERRUPT_RESET; + } + return 0; +} + static int p7_next_unmasked_interrupt(CPUPPCState *env) { PowerPCCPU *cpu = env_archcpu(env); @@ -1750,6 +1774,38 @@ static int p7_next_unmasked_interrupt(CPUPPCState *env) PPC_INTERRUPT_CEXT | PPC_INTERRUPT_WDT | PPC_INTERRUPT_CDOORBELL | \ PPC_INTERRUPT_FIT | PPC_INTERRUPT_PIT | PPC_INTERRUPT_THERM) +static int p8_interrupt_powersave(CPUPPCState *env) +{ + if ((env->pending_interrupts & PPC_INTERRUPT_EXT) && + (env->spr[SPR_LPCR] & LPCR_P8_PECE2)) { + return PPC_INTERRUPT_EXT; + } + if ((env->pending_interrupts & PPC_INTERRUPT_DECR) && + (env->spr[SPR_LPCR] & LPCR_P8_PECE3)) { + return PPC_INTERRUPT_DECR; + } + if ((env->pending_interrupts & PPC_INTERRUPT_MCK) && + (env->spr[SPR_LPCR] & LPCR_P8_PECE4)) { + return PPC_INTERRUPT_MCK; + } + if ((env->pending_interrupts & PPC_INTERRUPT_HMI) && + (env->spr[SPR_LPCR] & LPCR_P8_PECE4)) { + return PPC_INTERRUPT_HMI; + } + if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) && + (env->spr[SPR_LPCR] & LPCR_P8_PECE0)) { + return PPC_INTERRUPT_DOORBELL; + } + if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) && + (env->spr[SPR_LPCR] & LPCR_P8_PECE1)) { + return PPC_INTERRUPT_HDOORBELL; + } + if (env->pending_interrupts & PPC_INTERRUPT_RESET) { + return PPC_INTERRUPT_RESET; + } + return 0; +} + static int p8_next_unmasked_interrupt(CPUPPCState *env) { PowerPCCPU *cpu = env_archcpu(env); @@ -1825,6 +1881,52 @@ static int p8_next_unmasked_interrupt(CPUPPCState *env) PPC_INTERRUPT_WDT | PPC_INTERRUPT_CDOORBELL | PPC_INTERRUPT_FIT | \ PPC_INTERRUPT_PIT | PPC_INTERRUPT_THERM) +static int p9_interrupt_powersave(CPUPPCState *env) +{ + /* External Exception */ + if ((env->pending_interrupts & PPC_INTERRUPT_EXT) && + (env->spr[SPR_LPCR] & LPCR_EEE)) { + bool heic = !!(env->spr[SPR_LPCR] & LPCR_HEIC); + if (!heic || !FIELD_EX64_HV(env->msr) || + FIELD_EX64(env->msr, MSR, PR)) { + return PPC_INTERRUPT_EXT; + } + } + /* Decrementer Exception */ + if ((env->pending_interrupts & PPC_INTERRUPT_DECR) && + (env->spr[SPR_LPCR] & LPCR_DEE)) { + return PPC_INTERRUPT_DECR; + } + /* Machine Check or Hypervisor Maintenance Exception */ + if (env->spr[SPR_LPCR] & LPCR_OEE) { + if (env->pending_interrupts & PPC_INTERRUPT_MCK) { + return PPC_INTERRUPT_MCK; + } + if (env->pending_interrupts & PPC_INTERRUPT_HMI) { + return PPC_INTERRUPT_HMI; + } + } + /* Privileged Doorbell Exception */ + if ((env->pending_interrupts & PPC_INTERRUPT_DOORBELL) && + (env->spr[SPR_LPCR] & LPCR_PDEE)) { + return PPC_INTERRUPT_DOORBELL; + } + /* Hypervisor Doorbell Exception */ + if ((env->pending_interrupts & PPC_INTERRUPT_HDOORBELL) && + (env->spr[SPR_LPCR] & LPCR_HDEE)) { + return PPC_INTERRUPT_HDOORBELL; + } + /* Hypervisor virtualization exception */ + if ((env->pending_interrupts & PPC_INTERRUPT_HVIRT) && + (env->spr[SPR_LPCR] & LPCR_HVEE)) { + return PPC_INTERRUPT_HVIRT; + } + if (env->pending_interrupts & PPC_INTERRUPT_RESET) { + return PPC_INTERRUPT_RESET; + } + return 0; +} + static int p9_next_unmasked_interrupt(CPUPPCState *env) { PowerPCCPU *cpu = env_archcpu(env); diff --git a/target/ppc/internal.h b/target/ppc/internal.h index 25827eb..337a362 100644 --- a/target/ppc/internal.h +++ b/target/ppc/internal.h @@ -306,10 +306,4 @@ static inline int ger_pack_masks(int pmsk, int ymsk, int xmsk) return msk; } -#if defined(TARGET_PPC64) -int p9_interrupt_powersave(CPUPPCState *env); -int p8_interrupt_powersave(CPUPPCState *env); -int p7_interrupt_powersave(CPUPPCState *env); -#endif - #endif /* PPC_INTERNAL_H */ -- cgit v1.1 From 8b3d1c49a9f0f315d2b292c1791430c0f382afa4 Mon Sep 17 00:00:00 2001 From: Leandro Lupori Date: Tue, 25 Oct 2022 17:24:23 -0300 Subject: target/ppc: Add new PMC HFLAGS Add 2 new PMC related HFLAGS: - HFLAGS_PMCJCE - value of MMCR0 PMCjCE bit - HFLAGS_PMC_OTHER - set if a PMC other than PMC5-6 is enabled These flags allow further optimization of PMC5 update code, by allowing frequently tested conditions to be performed at translation time. Signed-off-by: Leandro Lupori Reviewed-by: Daniel Henrique Barboza Message-Id: <20221025202424.195984-3-leandro.lupori@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/cpu.h | 4 +++- target/ppc/helper_regs.c | 6 ++++++ target/ppc/translate.c | 4 ++++ 3 files changed, 13 insertions(+), 1 deletion(-) (limited to 'target') diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index cc2d030..81d4263 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -696,7 +696,9 @@ enum { HFLAGS_PR = 14, /* MSR_PR */ HFLAGS_PMCC0 = 15, /* MMCR0 PMCC bit 0 */ HFLAGS_PMCC1 = 16, /* MMCR0 PMCC bit 1 */ - HFLAGS_INSN_CNT = 17, /* PMU instruction count enabled */ + HFLAGS_PMCJCE = 17, /* MMCR0 PMCjCE bit */ + HFLAGS_PMC_OTHER = 18, /* PMC other than PMC5-6 is enabled */ + HFLAGS_INSN_CNT = 19, /* PMU instruction count enabled */ HFLAGS_VSX = 23, /* MSR_VSX if cpu has VSX */ HFLAGS_VR = 25, /* MSR_VR if cpu has VRE */ diff --git a/target/ppc/helper_regs.c b/target/ppc/helper_regs.c index 2e85e12..c0aee58 100644 --- a/target/ppc/helper_regs.c +++ b/target/ppc/helper_regs.c @@ -109,6 +109,9 @@ static uint32_t hreg_compute_hflags_value(CPUPPCState *env) if (env->spr[SPR_POWER_MMCR0] & MMCR0_PMCC1) { hflags |= 1 << HFLAGS_PMCC1; } + if (env->spr[SPR_POWER_MMCR0] & MMCR0_PMCjCE) { + hflags |= 1 << HFLAGS_PMCJCE; + } #ifndef CONFIG_USER_ONLY if (!env->has_hv_mode || (msr & (1ull << MSR_HV))) { @@ -119,6 +122,9 @@ static uint32_t hreg_compute_hflags_value(CPUPPCState *env) if (env->pmc_ins_cnt) { hflags |= 1 << HFLAGS_INSN_CNT; } + if (env->pmc_ins_cnt & 0x1e) { + hflags |= 1 << HFLAGS_PMC_OTHER; + } #endif /* diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 29e4b72..8d79522 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -177,6 +177,8 @@ struct DisasContext { bool hr; bool mmcr0_pmcc0; bool mmcr0_pmcc1; + bool mmcr0_pmcjce; + bool pmc_other; bool pmu_insn_cnt; ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */ int singlestep_enabled; @@ -7512,6 +7514,8 @@ static void ppc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) ctx->hr = (hflags >> HFLAGS_HR) & 1; ctx->mmcr0_pmcc0 = (hflags >> HFLAGS_PMCC0) & 1; ctx->mmcr0_pmcc1 = (hflags >> HFLAGS_PMCC1) & 1; + ctx->mmcr0_pmcjce = (hflags >> HFLAGS_PMCJCE) & 1; + ctx->pmc_other = (hflags >> HFLAGS_PMC_OTHER) & 1; ctx->pmu_insn_cnt = (hflags >> HFLAGS_INSN_CNT) & 1; ctx->singlestep_enabled = 0; -- cgit v1.1 From eeaaefe9fa8b95a7ed39ee86257f3bf1af751804 Mon Sep 17 00:00:00 2001 From: Leandro Lupori Date: Tue, 25 Oct 2022 17:24:24 -0300 Subject: target/ppc: Increment PMC5 with inline insns Profiling QEMU during Fedora 35 for PPC64 boot revealed that 6.39% of total time was being spent in helper_insns_inc(), on a POWER9 machine. To avoid calling this helper every time PMCs had to be incremented, an inline implementation of PMC5 increment and check for overflow was developed. This led to a reduction of about 12% in Fedora's boot time. Signed-off-by: Leandro Lupori Reviewed-by: Daniel Henrique Barboza Message-Id: <20221025202424.195984-4-leandro.lupori@eldorado.org.br> Signed-off-by: Daniel Henrique Barboza --- target/ppc/helper.h | 1 + target/ppc/power8-pmu.c | 74 +++++++++++++++++++++++++------------------------ target/ppc/power8-pmu.h | 3 ++ target/ppc/translate.c | 28 +++++++++++++++++-- 4 files changed, 67 insertions(+), 39 deletions(-) (limited to 'target') diff --git a/target/ppc/helper.h b/target/ppc/helper.h index 25533b8..8dd22a3 100644 --- a/target/ppc/helper.h +++ b/target/ppc/helper.h @@ -30,6 +30,7 @@ DEF_HELPER_2(store_mmcr1, void, env, tl) DEF_HELPER_3(store_pmc, void, env, i32, i64) DEF_HELPER_2(read_pmc, tl, env, i32) DEF_HELPER_2(insns_inc, void, env, i32) +DEF_HELPER_1(handle_pmc5_overflow, void, env) #endif DEF_HELPER_1(check_tlb_flush_local, void, env) DEF_HELPER_1(check_tlb_flush_global, void, env) diff --git a/target/ppc/power8-pmu.c b/target/ppc/power8-pmu.c index beeab5c..1381072 100644 --- a/target/ppc/power8-pmu.c +++ b/target/ppc/power8-pmu.c @@ -22,8 +22,6 @@ #if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) -#define PMC_COUNTER_NEGATIVE_VAL 0x80000000UL - static bool pmc_has_overflow_enabled(CPUPPCState *env, int sprn) { if (sprn == SPR_POWER_PMC1) { @@ -88,49 +86,47 @@ static bool pmu_increment_insns(CPUPPCState *env, uint32_t num_insns) bool overflow_triggered = false; target_ulong tmp; - if (unlikely(ins_cnt & 0x1e)) { - if (ins_cnt & (1 << 1)) { - tmp = env->spr[SPR_POWER_PMC1]; - tmp += num_insns; - if (tmp >= PMC_COUNTER_NEGATIVE_VAL && (mmcr0 & MMCR0_PMC1CE)) { - tmp = PMC_COUNTER_NEGATIVE_VAL; - overflow_triggered = true; - } - env->spr[SPR_POWER_PMC1] = tmp; + if (ins_cnt & (1 << 1)) { + tmp = env->spr[SPR_POWER_PMC1]; + tmp += num_insns; + if (tmp >= PMC_COUNTER_NEGATIVE_VAL && (mmcr0 & MMCR0_PMC1CE)) { + tmp = PMC_COUNTER_NEGATIVE_VAL; + overflow_triggered = true; } + env->spr[SPR_POWER_PMC1] = tmp; + } - if (ins_cnt & (1 << 2)) { - tmp = env->spr[SPR_POWER_PMC2]; - tmp += num_insns; - if (tmp >= PMC_COUNTER_NEGATIVE_VAL && (mmcr0 & MMCR0_PMCjCE)) { - tmp = PMC_COUNTER_NEGATIVE_VAL; - overflow_triggered = true; - } - env->spr[SPR_POWER_PMC2] = tmp; + if (ins_cnt & (1 << 2)) { + tmp = env->spr[SPR_POWER_PMC2]; + tmp += num_insns; + if (tmp >= PMC_COUNTER_NEGATIVE_VAL && (mmcr0 & MMCR0_PMCjCE)) { + tmp = PMC_COUNTER_NEGATIVE_VAL; + overflow_triggered = true; + } + env->spr[SPR_POWER_PMC2] = tmp; + } + + if (ins_cnt & (1 << 3)) { + tmp = env->spr[SPR_POWER_PMC3]; + tmp += num_insns; + if (tmp >= PMC_COUNTER_NEGATIVE_VAL && (mmcr0 & MMCR0_PMCjCE)) { + tmp = PMC_COUNTER_NEGATIVE_VAL; + overflow_triggered = true; } + env->spr[SPR_POWER_PMC3] = tmp; + } - if (ins_cnt & (1 << 3)) { - tmp = env->spr[SPR_POWER_PMC3]; + if (ins_cnt & (1 << 4)) { + target_ulong mmcr1 = env->spr[SPR_POWER_MMCR1]; + int sel = extract64(mmcr1, MMCR1_PMC4EVT_EXTR, MMCR1_EVT_SIZE); + if (sel == 0x02 || (env->spr[SPR_CTRL] & CTRL_RUN)) { + tmp = env->spr[SPR_POWER_PMC4]; tmp += num_insns; if (tmp >= PMC_COUNTER_NEGATIVE_VAL && (mmcr0 & MMCR0_PMCjCE)) { tmp = PMC_COUNTER_NEGATIVE_VAL; overflow_triggered = true; } - env->spr[SPR_POWER_PMC3] = tmp; - } - - if (ins_cnt & (1 << 4)) { - target_ulong mmcr1 = env->spr[SPR_POWER_MMCR1]; - int sel = extract64(mmcr1, MMCR1_PMC4EVT_EXTR, MMCR1_EVT_SIZE); - if (sel == 0x02 || (env->spr[SPR_CTRL] & CTRL_RUN)) { - tmp = env->spr[SPR_POWER_PMC4]; - tmp += num_insns; - if (tmp >= PMC_COUNTER_NEGATIVE_VAL && (mmcr0 & MMCR0_PMCjCE)) { - tmp = PMC_COUNTER_NEGATIVE_VAL; - overflow_triggered = true; - } - env->spr[SPR_POWER_PMC4] = tmp; - } + env->spr[SPR_POWER_PMC4] = tmp; } } @@ -310,6 +306,12 @@ static void fire_PMC_interrupt(PowerPCCPU *cpu) raise_ebb_perfm_exception(env); } +void helper_handle_pmc5_overflow(CPUPPCState *env) +{ + env->spr[SPR_POWER_PMC5] = PMC_COUNTER_NEGATIVE_VAL; + fire_PMC_interrupt(env_archcpu(env)); +} + /* This helper assumes that the PMC is running. */ void helper_insns_inc(CPUPPCState *env, uint32_t num_insns) { diff --git a/target/ppc/power8-pmu.h b/target/ppc/power8-pmu.h index 9692dd7..c0093e2 100644 --- a/target/ppc/power8-pmu.h +++ b/target/ppc/power8-pmu.h @@ -14,6 +14,9 @@ #define POWER8_PMU_H #if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) + +#define PMC_COUNTER_NEGATIVE_VAL 0x80000000UL + void cpu_ppc_pmu_init(CPUPPCState *env); void pmu_update_summaries(CPUPPCState *env); #else diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 8d79522..19c1d17 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -36,6 +36,7 @@ #include "exec/log.h" #include "qemu/atomic128.h" #include "spr_common.h" +#include "power8-pmu.h" #include "qemu/qemu-print.h" #include "qapi/error.h" @@ -4271,6 +4272,9 @@ static void pmu_count_insns(DisasContext *ctx) } #if !defined(CONFIG_USER_ONLY) + TCGLabel *l; + TCGv t0; + /* * The PMU insns_inc() helper stops the internal PMU timer if a * counter overflows happens. In that case, if the guest is @@ -4279,8 +4283,26 @@ static void pmu_count_insns(DisasContext *ctx) */ gen_icount_io_start(ctx); - gen_helper_insns_inc(cpu_env, tcg_constant_i32(ctx->base.num_insns)); -#else + /* Avoid helper calls when only PMC5-6 are enabled. */ + if (!ctx->pmc_other) { + l = gen_new_label(); + t0 = tcg_temp_new(); + + gen_load_spr(t0, SPR_POWER_PMC5); + tcg_gen_addi_tl(t0, t0, ctx->base.num_insns); + gen_store_spr(SPR_POWER_PMC5, t0); + /* Check for overflow, if it's enabled */ + if (ctx->mmcr0_pmcjce) { + tcg_gen_brcondi_tl(TCG_COND_LT, t0, PMC_COUNTER_NEGATIVE_VAL, l); + gen_helper_handle_pmc5_overflow(cpu_env); + } + + gen_set_label(l); + tcg_temp_free(t0); + } else { + gen_helper_insns_inc(cpu_env, tcg_constant_i32(ctx->base.num_insns)); + } + #else /* * User mode can read (but not write) PMC5 and start/stop * the PMU via MMCR0_FC. In this case just increment @@ -4293,7 +4315,7 @@ static void pmu_count_insns(DisasContext *ctx) gen_store_spr(SPR_POWER_PMC5, t0); tcg_temp_free(t0); -#endif /* #if !defined(CONFIG_USER_ONLY) */ + #endif /* #if !defined(CONFIG_USER_ONLY) */ } #else static void pmu_count_insns(DisasContext *ctx) -- cgit v1.1 From fb22d743b93b49b73930aff40d3ba9d252f81a56 Mon Sep 17 00:00:00 2001 From: Leandro Lupori Date: Fri, 28 Oct 2022 15:36:17 -0300 Subject: target/ppc: Fix regression in Radix MMU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 47e83d9107 ended up unintentionally changing the control flow of ppc_radix64_process_scoped_xlate(). When guest_visible is false, it must not raise an exception, even if the radix configuration is not valid. This regression prevented Linux boot in a nested environment with L1 using TCG and emulating KVM (cap-nested-hv=on) and L2 using KVM. L2 would hang on Linux's futex_init(), when it tested how a futex_atomic_cmpxchg_inatomic() handled a fault, because L1 would start a loop of trying to perform partition scoped translations and raising exceptions. Fixes: 47e83d9107 ("target/ppc: Improve Radix xlate level validation") Reported-by: Victor Colombo Signed-off-by: Leandro Lupori Tested-by: VĂ­ctor Colombo Reviewed-by: Daniel Henrique Barboza Message-Id: <20221028183617.121786-1-leandro.lupori@eldorado.org.br> [danielhb: use %"PRIu64" to print 'nls'] Signed-off-by: Daniel Henrique Barboza --- target/ppc/mmu-radix64.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) (limited to 'target') diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c index 00f2e9f..031efda 100644 --- a/target/ppc/mmu-radix64.c +++ b/target/ppc/mmu-radix64.c @@ -238,6 +238,8 @@ static void ppc_radix64_set_rc(PowerPCCPU *cpu, MMUAccessType access_type, static bool ppc_radix64_is_valid_level(int level, int psize, uint64_t nls) { + bool ret; + /* * Check if this is a valid level, according to POWER9 and POWER10 * Processor User's Manuals, sections 4.10.4.1 and 5.10.6.1, respectively: @@ -249,16 +251,25 @@ static bool ppc_radix64_is_valid_level(int level, int psize, uint64_t nls) */ switch (level) { case 0: /* Root Page Dir */ - return psize == 52 && nls == 13; + ret = psize == 52 && nls == 13; + break; case 1: case 2: - return nls == 9; + ret = nls == 9; + break; case 3: - return nls == 9 || nls == 5; + ret = nls == 9 || nls == 5; + break; default: - qemu_log_mask(LOG_GUEST_ERROR, "invalid radix level: %d\n", level); - return false; + ret = false; + } + + if (unlikely(!ret)) { + qemu_log_mask(LOG_GUEST_ERROR, "invalid radix configuration: " + "level %d size %d nls %"PRIu64"\n", + level, psize, nls); } + return ret; } static int ppc_radix64_next_level(AddressSpace *as, vaddr eaddr, @@ -519,11 +530,13 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, if (!ppc_radix64_is_valid_level(level++, *g_page_size, nls)) { fault_cause |= DSISR_R_BADCONFIG; - return 1; + ret = 1; + } else { + ret = ppc_radix64_next_level(cs->as, eaddr & R_EADDR_MASK, + &h_raddr, &nls, g_page_size, + &pte, &fault_cause); } - ret = ppc_radix64_next_level(cs->as, eaddr & R_EADDR_MASK, &h_raddr, - &nls, g_page_size, &pte, &fault_cause); if (ret) { /* No valid pte */ if (guest_visible) { -- cgit v1.1