From a919483f3498f9cd15ad3e101f923b4c4387eda6 Mon Sep 17 00:00:00 2001 From: Dmitry Selyutin Date: Mon, 29 May 2023 01:04:57 +0300 Subject: [PATCH] ppc/svp64: introduce SVP64 opcode lookup --- include/opcode/ppc.h | 4 ++ opcodes/ppc-dis.c | 21 +++++++- opcodes/ppc-svp64-dis.c | 116 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 139 insertions(+), 2 deletions(-) create mode 100644 opcodes/ppc-svp64-dis.c diff --git a/include/opcode/ppc.h b/include/opcode/ppc.h index e9e1c6316d8..e7ca06e23c1 100644 --- a/include/opcode/ppc.h +++ b/include/opcode/ppc.h @@ -281,6 +281,10 @@ extern const unsigned int spe2_num_opcodes; /* A macro used to hash 8-byte PREFIX instructions. */ #define PPC_PREFIX_SEG(i) (PPC_OP (i) >> 1) +/* A macro to extract the major opcode from an SVP64 instruction. + This is PPC-compatible due to the way SVP64 remaps instructions. */ +#define SVP64_OP(i) PPC_OP (PPC_GET_SUFFIX (i)) + /* The operands table is an array of struct powerpc_operand. */ diff --git a/opcodes/ppc-dis.c b/opcodes/ppc-dis.c index 75472730ac8..81b9f5bcb12 100644 --- a/opcodes/ppc-dis.c +++ b/opcodes/ppc-dis.c @@ -28,6 +28,8 @@ #include "opcode/ppc.h" #include "libiberty.h" +#include "ppc-svp64-dis.c" + /* This file provides several disassembler functions, all of which use the disassembler interface defined in dis-asm.h. Several functions are provided because this file handles disassembly for the PowerPC @@ -528,6 +530,8 @@ disassemble_init_powerpc (struct disassemble_info *info) break; } } + + svp64_disassemble_init (); } powerpc_init_dialect (info); @@ -1165,10 +1169,11 @@ print_insn_powerpc (bfd_vma memaddr, /* Get the major opcode of the insn. */ opcode = NULL; - if ((dialect & PPC_OPCODE_POWER10) != 0 + if ((dialect & (PPC_OPCODE_POWER10 | PPC_OPCODE_SVP64)) != 0 && PPC_OP (insn) == 0x1) { uint64_t temp_insn, suffix; + status = (*info->read_memory_func) (memaddr + 4, buffer, 4, info); if (status == 0) { @@ -1177,7 +1182,19 @@ print_insn_powerpc (bfd_vma memaddr, else suffix = bfd_getl32 (buffer); temp_insn = (insn << 32) | suffix; - opcode = lookup_prefix (temp_insn, dialect & ~PPC_OPCODE_ANY); + + if ((dialect & PPC_OPCODE_SVP64) != 0) + { + opcode = svp64_lookup (temp_insn, dialect); + if (opcode != NULL) + { + insn = temp_insn; + insn_length = 8; + } + } + + if (opcode == NULL) + opcode = lookup_prefix (temp_insn, dialect & ~PPC_OPCODE_ANY); if (opcode == NULL && (dialect & PPC_OPCODE_ANY) != 0) opcode = lookup_prefix (temp_insn, dialect); if (opcode != NULL) diff --git a/opcodes/ppc-svp64-dis.c b/opcodes/ppc-svp64-dis.c new file mode 100644 index 00000000000..0d50997b1d9 --- /dev/null +++ b/opcodes/ppc-svp64-dis.c @@ -0,0 +1,116 @@ +/* ppc-dis.c -- Disassemble PowerPC instructions + Copyright (C) 1994-2022 Free Software Foundation, Inc. + Written by Dmitry Selyutin (ghostmansd). + Sponsored by NLnet and NGI POINTER under EU Grants 871528 and 957073. + + This file is part of the GNU opcodes library. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + It 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 General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with this file; see the file COPYING. If not, write to the + Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#include + +#define SVP64_RECORD_SEGS (1 + SVP64_OP (-1)) +static unsigned short svp64_record_indices[SVP64_RECORD_SEGS + 1]; + +static const struct powerpc_opcode * +lookup_powerpc (uint64_t insn, ppc_cpu_t dialect); + +static void +svp64_disassemble_init (void) +{ + size_t seg; + size_t idx; + + for (seg = 0, idx = 0; seg <= SVP64_RECORD_SEGS; seg++) + { + svp64_record_indices[seg] = idx; + for (; idx < svp64_nr_records; idx++) + { + const struct svp64_opcode *opcode; + const struct svp64_opcode *opcode_end; + + opcode = svp64_records[idx].opcodes; + opcode_end = (opcode + svp64_records[idx].nr_opcodes); + + if (seg < SVP64_OP (opcode->value)) + break; + + /* Check that the segment doesn't break in the middle. */ + for (; opcode < opcode_end; ++opcode) + { + if (seg < SVP64_OP (opcode->value)) + abort (); + } + } + } +} + +static const struct svp64_record * +svp64_lookup_record (uint32_t insn, + const struct svp64_record *start, + const struct svp64_record *end) +{ + const struct svp64_record *record; + + for (record = start; record < end; ++record) + { + const struct svp64_opcode *opcode; + const struct svp64_opcode *opcode_end; + + opcode = record->opcodes; + opcode_end = (opcode + record->nr_opcodes); + for (; opcode < opcode_end; ++opcode) + { + if ((opcode->value & opcode->mask) == + (insn & opcode->mask)) + return record; + } + } + + return NULL; +} + +static const struct powerpc_opcode * +svp64_lookup (uint64_t insn, ppc_cpu_t dialect) +{ + uint32_t suffix; + unsigned long op; + const struct powerpc_opcode *opcode; + const struct svp64_record *record; + const struct svp64_record *record_start; + const struct svp64_record *record_end; + struct svp64_insn svp64_insn = {insn}; + + if ((svp64_insn_get_prefix_po (&svp64_insn) != 0x1) || + (svp64_insn_get_prefix_id (&svp64_insn) != 0x3)) + return NULL; + + suffix = (uint32_t)svp64_insn_get_suffix (&svp64_insn); + opcode = lookup_powerpc (suffix, dialect & ~PPC_OPCODE_ANY); + if (opcode == NULL && (dialect & PPC_OPCODE_ANY) != 0) + opcode = lookup_powerpc (suffix, dialect); + if (opcode == NULL) + return NULL; + + op = SVP64_OP (suffix); + record_start = svp64_records + svp64_record_indices[op]; + record_end = (svp64_records + svp64_record_indices[op + 1]); + record = svp64_lookup_record (suffix, record_start, record_end); + if (record == NULL) + return NULL; + + return opcode; +} -- 2.30.2