From nobody Tue Feb 10 07:57:35 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1618348651; cv=none; d=zohomail.com; s=zohoarc; b=WWT7wC3V4oPPMvLSnE9fsix+mSxIYrBa17uKPUYWDRmNY9jGkiCzXvX8Vm1ZyVviJZON2q+SiQ8upyKVgH9Pl7HZikqdo9znABgjjE2iv+l9w/nmTQlUaWNcrD1cRnoI0T6Kwcbq0K569GgJr5LWFLsattFfjufgF7McT3bJhSs= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1618348651; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=xCS8iw2L/+7uI7hOJVACMWXRKINbSgt1ufvS4G8cLhA=; b=HVs1wgcQ3FK5yZxw1aP72tnxywez9eAc8WwStVva1vWgtx3uU5R12NNGeXyC8mPBojQavRjVwbZiSFA7obsHGKs1r0OYri219pgAwwdo9pUJncRbSGeNt0P5WkzgBsfo+vksSU4rYojAxHibcQn9IopbMqZBVYpdl6g4kpNnUyo= ARC-Authentication-Results: i=1; mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1618348651672142.04138271619604; Tue, 13 Apr 2021 14:17:31 -0700 (PDT) Received: from localhost ([::1]:60184 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lWQPa-0001AR-HB for importer@patchew.org; Tue, 13 Apr 2021 17:17:30 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:52934) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lWQMA-0007dJ-0l; Tue, 13 Apr 2021 17:13:58 -0400 Received: from [201.28.113.2] (port=27024 helo=outlook.eldorado.org.br) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lWQM7-0007YY-Ey; Tue, 13 Apr 2021 17:13:57 -0400 Received: from power9a ([10.10.71.235]) by outlook.eldorado.org.br with Microsoft SMTPSVC(8.5.9600.16384); Tue, 13 Apr 2021 18:13:42 -0300 Received: from eldorado.org.br (unknown [10.10.70.45]) by power9a (Postfix) with ESMTP id 0958E8011B4; Tue, 13 Apr 2021 18:13:42 -0300 (-03) From: Luis Pires To: qemu-devel@nongnu.org, qemu-ppc@nongnu.org Subject: [PATCH 4/5] target/ppc: Base changes to allow 32/64-bit insns Date: Tue, 13 Apr 2021 18:11:28 -0300 Message-Id: <20210413211129.457272-5-luis.pires@eldorado.org.br> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210413211129.457272-1-luis.pires@eldorado.org.br> References: <20210413211129.457272-1-luis.pires@eldorado.org.br> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-OriginalArrivalTime: 13 Apr 2021 21:13:42.0344 (UTC) FILETIME=[E19C4480:01D730A9] X-Host-Lookup-Failed: Reverse DNS lookup failed for 201.28.113.2 (failed) Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=201.28.113.2; envelope-from=luis.pires@eldorado.org.br; helo=outlook.eldorado.org.br X-Spam_score_int: -10 X-Spam_score: -1.1 X-Spam_bar: - X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, RDNS_NONE=0.793, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: richard.henderson@linaro.org, f4bug@amsat.org, Luis Pires , lagarcia@br.ibm.com, bruno.larsen@eldorado.org.br, matheus.ferst@eldorado.org.br, david@gibson.dropbear.id.au Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" These changes add the basic support for 32- and 64-bit instruction decoding using decodetree. Apart from the instruction decoding itself, it also takes care of some pre-requisite changes, such as removing hard-coded instruction sizes throughout the code and raising an alignment exception should a prefixed instruction cross a 64-byte boundary. Signed-off-by: Luis Pires --- target/ppc/cpu.h | 1 + target/ppc/meson.build | 5 ++ target/ppc/ppc.decode | 18 ++++ target/ppc/translate.c | 191 ++++++++++++++++++++++++++++++++--------- 4 files changed, 174 insertions(+), 41 deletions(-) create mode 100644 target/ppc/ppc.decode diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index e73416da68..9bb2805a22 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -148,6 +148,7 @@ enum { POWERPC_EXCP_ALIGN_PROT =3D 0x04, /* Access cross protection bound= ary */ POWERPC_EXCP_ALIGN_BAT =3D 0x05, /* Access cross a BAT/seg bounda= ry */ POWERPC_EXCP_ALIGN_CACHE =3D 0x06, /* Impossible dcbz access = */ + POWERPC_EXCP_ALIGN_INSN =3D 0x07, /* Pref. insn x-ing 64-byte boun= dary */ /* Exception subtypes for POWERPC_EXCP_PROGRAM = */ /* FP exceptions = */ POWERPC_EXCP_FP =3D 0x10, diff --git a/target/ppc/meson.build b/target/ppc/meson.build index bbfef90e08..feed383a2b 100644 --- a/target/ppc/meson.build +++ b/target/ppc/meson.build @@ -1,4 +1,9 @@ +gen =3D [ + decodetree.process('ppc.decode', extra_args: ['--varinsnwidth=3D64', '--= noloadfunc']) +] + ppc_ss =3D ss.source_set() +ppc_ss.add(gen) ppc_ss.add(files( 'cpu-models.c', 'cpu.c', diff --git a/target/ppc/ppc.decode b/target/ppc/ppc.decode new file mode 100644 index 0000000000..84bb73ac19 --- /dev/null +++ b/target/ppc/ppc.decode @@ -0,0 +1,18 @@ +# +# Power ISA instruction decode definitions. +# +# Copyright (c) 2021 Luis Pires +# +# 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 . +# diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 0984ce637b..0f123f7b80 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -154,6 +154,11 @@ void ppc_translate_init(void) /* internal defines */ struct DisasContext { DisasContextBase base; + + /* + * 'opcode' should be considered deprecated and be used only + * by legacy non-decodetree code + */ uint32_t opcode; uint32_t exception; /* Routine used to access memory */ @@ -180,6 +185,8 @@ struct DisasContext { uint32_t flags; uint64_t insns_flags; uint64_t insns_flags2; + target_ulong insn_size; + CPUPPCState *env; }; =20 /* Return true iff byteswap is needed in a scalar memop */ @@ -199,6 +206,10 @@ static inline bool need_byteswap(const DisasContext *c= tx) # define NARROW_MODE(C) 0 #endif =20 +#if defined(DO_PPC_STATISTICS) +static uint64_t ppc_decodetree_hit_count; +#endif + struct opc_handler_t { /* invalid bits for instruction 1 (Rc(opcode) =3D=3D 0) */ uint32_t inval1; @@ -254,7 +265,7 @@ static void gen_exception_err(DisasContext *ctx, uint32= _t excp, uint32_t error) * faulting instruction */ if (ctx->exception =3D=3D POWERPC_EXCP_NONE) { - gen_update_nip(ctx, ctx->base.pc_next - 4); + gen_update_nip(ctx, ctx->base.pc_next - ctx->insn_size); } t0 =3D tcg_const_i32(excp); t1 =3D tcg_const_i32(error); @@ -273,7 +284,7 @@ static void gen_exception(DisasContext *ctx, uint32_t e= xcp) * faulting instruction */ if (ctx->exception =3D=3D POWERPC_EXCP_NONE) { - gen_update_nip(ctx, ctx->base.pc_next - 4); + gen_update_nip(ctx, ctx->base.pc_next - ctx->insn_size); } t0 =3D tcg_const_i32(excp); gen_helper_raise_exception(cpu_env, t0); @@ -3113,7 +3124,8 @@ static void gen_eieio(DisasContext *ctx) */ if (!(ctx->insns_flags2 & PPC2_ISA300)) { qemu_log_mask(LOG_GUEST_ERROR, "invalid eieio using bit 6 at @" - TARGET_FMT_lx "\n", ctx->base.pc_next - 4); + TARGET_FMT_lx "\n", + ctx->base.pc_next - ctx->insn_size); } else { bar =3D TCG_MO_ST_LD; } @@ -3782,14 +3794,14 @@ static void gen_b(DisasContext *ctx) li =3D LI(ctx->opcode); li =3D (li ^ 0x02000000) - 0x02000000; if (likely(AA(ctx->opcode) =3D=3D 0)) { - target =3D ctx->base.pc_next + li - 4; + target =3D ctx->base.pc_next + li - ctx->insn_size; } else { target =3D li; } if (LK(ctx->opcode)) { gen_setlr(ctx, ctx->base.pc_next); } - gen_update_cfar(ctx, ctx->base.pc_next - 4); + gen_update_cfar(ctx, ctx->base.pc_next - ctx->insn_size); gen_goto_tb(ctx, 0, target); } =20 @@ -3888,11 +3900,11 @@ static void gen_bcond(DisasContext *ctx, int type) } tcg_temp_free_i32(temp); } - gen_update_cfar(ctx, ctx->base.pc_next - 4); + gen_update_cfar(ctx, ctx->base.pc_next - ctx->insn_size); if (type =3D=3D BCOND_IM) { target_ulong li =3D (target_long)((int16_t)(BD(ctx->opcode))); if (likely(AA(ctx->opcode) =3D=3D 0)) { - gen_goto_tb(ctx, 0, ctx->base.pc_next + li - 4); + gen_goto_tb(ctx, 0, ctx->base.pc_next + li - ctx->insn_size); } else { gen_goto_tb(ctx, 0, li); } @@ -4008,7 +4020,7 @@ static void gen_rfi(DisasContext *ctx) if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { gen_io_start(); } - gen_update_cfar(ctx, ctx->base.pc_next - 4); + gen_update_cfar(ctx, ctx->base.pc_next - ctx->insn_size); gen_helper_rfi(cpu_env); gen_sync_exception(ctx); #endif @@ -4025,7 +4037,7 @@ static void gen_rfid(DisasContext *ctx) if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { gen_io_start(); } - gen_update_cfar(ctx, ctx->base.pc_next - 4); + gen_update_cfar(ctx, ctx->base.pc_next - ctx->insn_size); gen_helper_rfid(cpu_env); gen_sync_exception(ctx); #endif @@ -4042,7 +4054,7 @@ static void gen_rfscv(DisasContext *ctx) if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) { gen_io_start(); } - gen_update_cfar(ctx, ctx->base.pc_next - 4); + gen_update_cfar(ctx, ctx->base.pc_next - ctx->insn_size); gen_helper_rfscv(cpu_env); gen_sync_exception(ctx); #endif @@ -4338,7 +4350,7 @@ static inline void gen_op_mfspr(DisasContext *ctx) if (sprn !=3D SPR_PVR) { qemu_log_mask(LOG_GUEST_ERROR, "Trying to read privileged = spr " "%d (0x%03x) at " TARGET_FMT_lx "\n", sprn, = sprn, - ctx->base.pc_next - 4); + ctx->base.pc_next - ctx->insn_size); } gen_priv_exception(ctx, POWERPC_EXCP_PRIV_REG); } @@ -4352,7 +4364,8 @@ static inline void gen_op_mfspr(DisasContext *ctx) /* Not defined */ qemu_log_mask(LOG_GUEST_ERROR, "Trying to read invalid spr %d (0x%03x) at " - TARGET_FMT_lx "\n", sprn, sprn, ctx->base.pc_next - = 4); + TARGET_FMT_lx "\n", sprn, sprn, + ctx->base.pc_next - ctx->insn_size); =20 /* * The behaviour depends on MSR:PR and SPR# bit 0x10, it can @@ -4516,7 +4529,7 @@ static void gen_mtspr(DisasContext *ctx) /* Privilege exception */ qemu_log_mask(LOG_GUEST_ERROR, "Trying to write privileged spr= " "%d (0x%03x) at " TARGET_FMT_lx "\n", sprn, sprn, - ctx->base.pc_next - 4); + ctx->base.pc_next - ctx->insn_size); gen_priv_exception(ctx, POWERPC_EXCP_PRIV_REG); } } else { @@ -4530,7 +4543,8 @@ static void gen_mtspr(DisasContext *ctx) /* Not defined */ qemu_log_mask(LOG_GUEST_ERROR, "Trying to write invalid spr %d (0x%03x) at " - TARGET_FMT_lx "\n", sprn, sprn, ctx->base.pc_next - = 4); + TARGET_FMT_lx "\n", sprn, sprn, + ctx->base.pc_next - ctx->insn_size); =20 =20 /* @@ -6900,6 +6914,60 @@ static inline void set_avr64(int regno, TCGv_i64 src= , bool high) tcg_gen_st_i64(src, cpu_env, avr64_offset(regno, high)); } =20 +/* + * Check if a given 32-bit value is a prefix for a 64-bit instruction. + */ +static inline int is_insn_prefix(uint32_t insn) +{ + return (opc1(insn) =3D=3D 0x01); +} + +/* + * Load a 32- or 64-bit instruction. + * + * 32-bit instructions are returned in the higher 32-bits + */ +static uint64_t ppc_load_insn(DisasContext *ctx) +{ + uint64_t insn; + uint32_t insn_part; + + /* read 4 bytes */ + insn_part =3D translator_ldl_swap(ctx->env, ctx->base.pc_next, + need_byteswap(ctx)); + insn =3D ((uint64_t)insn_part) << 32; + ctx->base.pc_next +=3D 4; + ctx->insn_size =3D 4; + + if (is_insn_prefix(insn_part)) { + /* read 4 more bytes */ + insn_part =3D translator_ldl_swap(ctx->env, ctx->base.pc_next, + need_byteswap(ctx)); + insn |=3D insn_part; + + ctx->base.pc_next +=3D 4; + ctx->insn_size +=3D 4; + } + + return insn; +} + +/* + * Peek at the next instruction's size. + */ +static target_ulong ppc_peek_next_insn_size(DisasContext *ctx) +{ + uint32_t insn_part; + + /* read 4 bytes */ + insn_part =3D translator_ldl_swap(ctx->env, ctx->base.pc_next, + need_byteswap(ctx)); + + return is_insn_prefix(insn_part) ? 8 : 4; +} + +#include "decode-ppc.c.inc" + #include "translate/fp-impl.c.inc" =20 #include "translate/vmx-impl.c.inc" @@ -7832,7 +7900,7 @@ void ppc_cpu_dump_statistics(CPUState *cs, int flags) opc_handler_t **t1, **t2, **t3, *handler; int op1, op2, op3; =20 - t1 =3D cpu->env.opcodes; + t1 =3D cpu->opcodes; for (op1 =3D 0; op1 < 64; op1++) { handler =3D t1[op1]; if (is_indirect_opcode(handler)) { @@ -7872,6 +7940,10 @@ void ppc_cpu_dump_statistics(CPUState *cs, int flags) handler->count, handler->count); } } + + qemu_printf("decodetree: " + "%016" PRIx64 " %" PRId64 "\n", + ppc_decodetree_hit_count, ppc_decodetree_hit_count); #endif } =20 @@ -7879,7 +7951,6 @@ static void ppc_tr_init_disas_context(DisasContextBas= e *dcbase, CPUState *cs) { DisasContext *ctx =3D container_of(dcbase, DisasContext, base); CPUPPCState *env =3D cs->env_ptr; - int bound; =20 ctx->exception =3D POWERPC_EXCP_NONE; ctx->spr_cb =3D env->spr_cb; @@ -7961,8 +8032,7 @@ static void ppc_tr_init_disas_context(DisasContextBas= e *dcbase, CPUState *cs) msr_se =3D 1; #endif =20 - bound =3D -(ctx->base.pc_first | TARGET_PAGE_MASK) / 4; - ctx->base.max_insns =3D MIN(ctx->base.max_insns, bound); + ctx->env =3D env; } =20 static void ppc_tr_tb_start(DisasContextBase *db, CPUState *cs) @@ -7979,37 +8049,31 @@ static bool ppc_tr_breakpoint_check(DisasContextBas= e *dcbase, CPUState *cs, { DisasContext *ctx =3D container_of(dcbase, DisasContext, base); =20 + target_ulong insn_size =3D ppc_peek_next_insn_size(ctx); + gen_debug_exception(ctx); dcbase->is_jmp =3D DISAS_NORETURN; /* * The address covered by the breakpoint must be included in * [tb->pc, tb->pc + tb->size) in order to for it to be properly - * cleared -- thus we increment the PC here so that the logic - * setting tb->size below does the right thing. + * cleared -- thus we increment the PC here. */ - ctx->base.pc_next +=3D 4; + ctx->base.pc_next +=3D insn_size; return true; } =20 -static void ppc_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) +/* + * Legacy (non-decodetree) 32-bit instruction translation code. + * + * Any new instructions should be implemented using the decode tree, + * and not use this code. + */ +static void ppc_tr_translate_insn_legacy(DisasContext *ctx, CPUState *cs) { - DisasContext *ctx =3D container_of(dcbase, DisasContext, base); PowerPCCPU *cpu =3D POWERPC_CPU(cs); CPUPPCState *env =3D cs->env_ptr; opc_handler_t **table, *handler; =20 - LOG_DISAS("----------------\n"); - LOG_DISAS("nip=3D" TARGET_FMT_lx " super=3D%d ir=3D%d\n", - ctx->base.pc_next, ctx->mem_idx, (int)msr_ir); - - ctx->opcode =3D translator_ldl_swap(env, ctx->base.pc_next, - need_byteswap(ctx)); - - LOG_DISAS("translate opcode %08x (%02x %02x %02x %02x) (%s)\n", - ctx->opcode, opc1(ctx->opcode), opc2(ctx->opcode), - opc3(ctx->opcode), opc4(ctx->opcode), - ctx->le_mode ? "little" : "big"); - ctx->base.pc_next +=3D 4; table =3D cpu->opcodes; handler =3D table[opc1(ctx->opcode)]; if (is_indirect_opcode(handler)) { @@ -8031,7 +8095,8 @@ static void ppc_tr_translate_insn(DisasContextBase *d= cbase, CPUState *cs) TARGET_FMT_lx " %d\n", opc1(ctx->opcode), opc2(ctx->opcode), opc3(ctx->opcode), opc4(ctx->opcode), - ctx->opcode, ctx->base.pc_next - 4, (int)msr_ir); + ctx->opcode, ctx->base.pc_next - ctx->insn_size, + (int)msr_ir); } else { uint32_t inval; =20 @@ -8048,7 +8113,7 @@ static void ppc_tr_translate_insn(DisasContextBase *d= cbase, CPUState *cs) TARGET_FMT_lx "\n", ctx->opcode & inval, opc1(ctx->opcode), opc2(ctx->opcode), opc3(ctx->opcode), opc4(ctx->opcode), - ctx->opcode, ctx->base.pc_next - 4); + ctx->opcode, ctx->base.pc_next - ctx->insn_size); gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); ctx->base.is_jmp =3D DISAS_NORETURN; return; @@ -8067,11 +8132,55 @@ static void ppc_tr_translate_insn(DisasContextBase = *dcbase, CPUState *cs) uint32_t excp =3D gen_prep_dbgex(ctx); gen_exception_nip(ctx, excp, ctx->base.pc_next); } +} =20 - if (tcg_check_temp_count()) { - qemu_log("Opcode %02x %02x %02x %02x (%08x) leaked " - "temporaries\n", opc1(ctx->opcode), opc2(ctx->opcode), - opc3(ctx->opcode), opc4(ctx->opcode), ctx->opcode); +static void ppc_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) +{ +#if defined(PPC_DEBUG_DISAS) + /* env is needed by LOG_DISAS */ + CPUPPCState *env =3D cs->env_ptr; +#endif + DisasContext *ctx =3D container_of(dcbase, DisasContext, base); + uint64_t insn; + + LOG_DISAS("----------------\n"); + LOG_DISAS("nip=3D" TARGET_FMT_lx " super=3D%d ir=3D%d\n", + ctx->base.pc_next, ctx->mem_idx, (int)msr_ir); + + /* load the next insn, keeping track of the insn size */ + insn =3D ppc_load_insn(ctx); + + if (unlikely(ctx->insn_size =3D=3D 8 && + (ctx->base.pc_next & 0x3f) =3D=3D 0x04)) { + /* + * Raise alignment exception when a 64-bit insn crosses a + * 64-byte boundary + */ + gen_exception_err(ctx, POWERPC_EXCP_ALIGN, POWERPC_EXCP_ALIGN_INSN= ); + } else { + LOG_DISAS("translate opcode %016" PRIx64 " (%s)\n", + insn, ctx->le_mode ? "little" : "big"); + + if (!decode(ctx, insn)) { + /* + * Instruction not found in decode tree. + * Fall back to legacy 32-bit instruction code. + * + * ppc_load_insn() keeps 32-bit instructions in the high + * 32-bits of insn. + */ + ctx->opcode =3D (uint32_t)(insn >> 32); + ppc_tr_translate_insn_legacy(ctx, cs); + } else { +#if defined(DO_PPC_STATISTICS) + ppc_decodetree_hit_count++; +#endif + } + + if (tcg_check_temp_count()) { + qemu_log("Opcode (%016" PRIx64 ") leaked " + "temporaries\n", insn); + } } =20 ctx->base.is_jmp =3D ctx->exception =3D=3D POWERPC_EXCP_NONE ? --=20 2.25.1