qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 1/3] Hexagon (target/hexagon) Use QEMU decodetree (32-bit instructions)
  2024-01-08 22:48 Taylor Simpson
@ 2024-01-08 22:48 ` Taylor Simpson
  2024-01-15  0:20   ` Brian Cain
  0 siblings, 1 reply; 8+ messages in thread
From: Taylor Simpson @ 2024-01-08 22:48 UTC (permalink / raw)
  To: qemu-devel
  Cc: bcain, quic_mathbern, sidneym, quic_mliebel, richard.henderson,
	philmd, ale, anjo, ltaylorsimpson

The Decodetree Specification can be found here
https://www.qemu.org/docs/master/devel/decodetree.html

Covers all 32-bit instructions, including HVX

We generate separate decoders for each instruction class.  The reason
will be more apparent in the next patch in this series.

We add 2 new scripts
    gen_decodetree.py        Generate the input to decodetree.py
    gen_trans_funcs.py       Generate the trans_* functions used by the
                             output of decodetree.py

Since the functions generated by decodetree.py take DisasContext * as an
argument, we add the argument to a couple of functions that didn't need
it previously.  We also set the insn field in DisasContext during decode
because it is used by the trans_* functions.

There is a g_assert_not_reached() in decode_insns() in decode.c to
verify we never try to use the old decoder on 32-bit instructions

Signed-off-by: Taylor Simpson <ltaylorsimpson@gmail.com>
---
 target/hexagon/decode.h           |   5 +-
 target/hexagon/decode.c           |  54 ++++++++-
 target/hexagon/translate.c        |   4 +-
 target/hexagon/README             |  13 +-
 target/hexagon/gen_decodetree.py  | 193 ++++++++++++++++++++++++++++++
 target/hexagon/gen_trans_funcs.py | 132 ++++++++++++++++++++
 target/hexagon/meson.build        |  55 +++++++++
 7 files changed, 442 insertions(+), 14 deletions(-)
 create mode 100755 target/hexagon/gen_decodetree.py
 create mode 100755 target/hexagon/gen_trans_funcs.py

diff --git a/target/hexagon/decode.h b/target/hexagon/decode.h
index c66f5ea64d..3f3012b978 100644
--- a/target/hexagon/decode.h
+++ b/target/hexagon/decode.h
@@ -21,12 +21,13 @@
 #include "cpu.h"
 #include "opcodes.h"
 #include "insn.h"
+#include "translate.h"
 
 void decode_init(void);
 
 void decode_send_insn_to(Packet *packet, int start, int newloc);
 
-int decode_packet(int max_words, const uint32_t *words, Packet *pkt,
-                  bool disas_only);
+int decode_packet(DisasContext *ctx, int max_words, const uint32_t *words,
+                  Packet *pkt, bool disas_only);
 
 #endif
diff --git a/target/hexagon/decode.c b/target/hexagon/decode.c
index 946c55cc71..bddad1f75e 100644
--- a/target/hexagon/decode.c
+++ b/target/hexagon/decode.c
@@ -52,6 +52,34 @@ DEF_REGMAP(R_8,   8,  0, 1, 2, 3, 4, 5, 6, 7)
 #define DECODE_MAPPED_REG(OPNUM, NAME) \
     insn->regno[OPNUM] = DECODE_REGISTER_##NAME[insn->regno[OPNUM]];
 
+/* Helper functions for decode_*_generated.c.inc */
+#define DECODE_MAPPED(NAME) \
+static int decode_mapped_reg_##NAME(DisasContext *ctx, int x) \
+{ \
+    return DECODE_REGISTER_##NAME[x]; \
+}
+DECODE_MAPPED(R_16)
+DECODE_MAPPED(R_8)
+
+/* Helper function for decodetree_trans_funcs_generated.c.inc */
+static int shift_left(DisasContext *ctx, int x, int n, int immno)
+{
+    int ret = x;
+    Insn *insn = ctx->insn;
+    if (!insn->extension_valid ||
+        insn->which_extended != immno) {
+        ret <<= n;
+    }
+    return ret;
+}
+
+/* Include the generated decoder for 32 bit insn */
+#include "decode_normal_generated.c.inc"
+#include "decode_hvx_generated.c.inc"
+
+/* Include the generated helpers for the decoder */
+#include "decodetree_trans_funcs_generated.c.inc"
+
 typedef struct {
     const struct DectreeTable *table_link;
     const struct DectreeTable *table_link_b;
@@ -550,7 +578,8 @@ apply_extender(Packet *pkt, int i, uint32_t extender)
     int immed_num;
     uint32_t base_immed;
 
-    immed_num = opcode_which_immediate_is_extended(pkt->insn[i].opcode);
+    immed_num = pkt->insn[i].which_extended;
+    g_assert(immed_num == opcode_which_immediate_is_extended(pkt->insn[i].opcode));
     base_immed = pkt->insn[i].immed[immed_num];
 
     pkt->insn[i].immed[immed_num] = extender | fZXTN(6, 32, base_immed);
@@ -762,12 +791,19 @@ decode_insns_tablewalk(Insn *insn, const DectreeTable *table,
 }
 
 static unsigned int
-decode_insns(Insn *insn, uint32_t encoding)
+decode_insns(DisasContext *ctx, Insn *insn, uint32_t encoding)
 {
     const DectreeTable *table;
     if (parse_bits(encoding) != 0) {
+        if (decode_normal(ctx, encoding) ||
+            decode_hvx(ctx, encoding)) {
+            insn->generate = opcode_genptr[insn->opcode];
+            insn->iclass = iclass_bits(encoding);
+            return 1;
+        }
         /* Start with PP table - 32 bit instructions */
         table = &dectree_table_DECODE_ROOT_32;
+        g_assert_not_reached();
     } else {
         /* start with EE table - duplex instructions */
         table = &dectree_table_DECODE_ROOT_EE;
@@ -916,8 +952,8 @@ decode_set_slot_number(Packet *pkt)
  * or number of words used on success
  */
 
-int decode_packet(int max_words, const uint32_t *words, Packet *pkt,
-                  bool disas_only)
+int decode_packet(DisasContext *ctx, int max_words, const uint32_t *words,
+                  Packet *pkt, bool disas_only)
 {
     int num_insns = 0;
     int words_read = 0;
@@ -930,9 +966,11 @@ int decode_packet(int max_words, const uint32_t *words, Packet *pkt,
     memset(pkt, 0, sizeof(*pkt));
     /* Try to build packet */
     while (!end_of_packet && (words_read < max_words)) {
+        Insn *insn = &pkt->insn[num_insns];
+        ctx->insn = insn;
         encoding32 = words[words_read];
         end_of_packet = is_packet_end(encoding32);
-        new_insns = decode_insns(&pkt->insn[num_insns], encoding32);
+        new_insns = decode_insns(ctx, insn, encoding32);
         g_assert(new_insns > 0);
         /*
          * If we saw an extender, mark next word extended so immediate
@@ -1006,9 +1044,13 @@ int decode_packet(int max_words, const uint32_t *words, Packet *pkt,
 int disassemble_hexagon(uint32_t *words, int nwords, bfd_vma pc,
                         GString *buf)
 {
+    DisasContext ctx;
     Packet pkt;
 
-    if (decode_packet(nwords, words, &pkt, true) > 0) {
+    memset(&ctx, 0, sizeof(DisasContext));
+    ctx.pkt = &pkt;
+
+    if (decode_packet(&ctx, nwords, words, &pkt, true) > 0) {
         snprint_a_pkt_disas(buf, &pkt, words, pc);
         return pkt.encod_pkt_size_in_bytes;
     } else {
diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c
index 666c061180..95579ae243 100644
--- a/target/hexagon/translate.c
+++ b/target/hexagon/translate.c
@@ -1033,10 +1033,10 @@ static void decode_and_translate_packet(CPUHexagonState *env, DisasContext *ctx)
         return;
     }
 
-    if (decode_packet(nwords, words, &pkt, false) > 0) {
+    ctx->pkt = &pkt;
+    if (decode_packet(ctx, nwords, words, &pkt, false) > 0) {
         pkt.pc = ctx->base.pc_next;
         HEX_DEBUG_PRINT_PKT(&pkt);
-        ctx->pkt = &pkt;
         gen_start_packet(ctx);
         for (i = 0; i < pkt.num_insns; i++) {
             ctx->insn = &pkt.insn[i];
diff --git a/target/hexagon/README b/target/hexagon/README
index 69b2ffe9bb..1b2a4d0eac 100644
--- a/target/hexagon/README
+++ b/target/hexagon/README
@@ -189,11 +189,16 @@ the packet, and we mark the implicit writes.  After the analysis is performed,
 we initialize the result register for each of the predicated assignments.
 
 In addition to instruction semantics, we use a generator to create the decode
-tree.  This generation is also a two step process.  The first step is to run
-target/hexagon/gen_dectree_import.c to produce
+tree.  This generation is a four step process.
+Step 1 is to run target/hexagon/gen_dectree_import.c to produce
     <BUILD_DIR>/target/hexagon/iset.py
-This file is imported by target/hexagon/dectree.py to produce
-    <BUILD_DIR>/target/hexagon/dectree_generated.h.inc
+Step 2 is to import iset.py into target/hexagon/gen_decodetree.py to produce
+    <BUILD_DIR>/target/hexagon/normal_decode_generated
+    <BUILD_DIR>/target/hexagon/hvx_decode_generated
+Step 3 is to process the above files with QEMU's decodetree.py to produce
+    <BUILD_DIR>/target/hexagon/decode_*_generated.c.inc
+Step 4 is to import iset.py into target/hexagon/gen_trans_funcs.py to produce
+    <BUILD_DIR>/target/hexagon/decodetree_trans_funcs_generated.c.inc
 
 *** Key Files ***
 
diff --git a/target/hexagon/gen_decodetree.py b/target/hexagon/gen_decodetree.py
new file mode 100755
index 0000000000..1693148ec0
--- /dev/null
+++ b/target/hexagon/gen_decodetree.py
@@ -0,0 +1,193 @@
+#!/usr/bin/env python3
+
+##
+##  Copyright (c) 2024 Taylor Simpson <ltaylorsimpson@gmail.com>
+##
+##  This program 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 2 of the License, or
+##  (at your option) any later version.
+##
+##  This program 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 program; if not, see <http://www.gnu.org/licenses/>.
+##
+
+import io
+import re
+
+import sys
+import textwrap
+import iset
+import hex_common
+
+encs = {
+    tag: "".join(reversed(iset.iset[tag]["enc"].replace(" ", "")))
+    for tag in iset.tags
+    if iset.iset[tag]["enc"] != "MISSING ENCODING"
+}
+
+
+regre = re.compile(r"((?<!DUP)[MNORCPQXSGVZA])([stuvwxyzdefg]+)([.]?[LlHh]?)(\d+S?)")
+immre = re.compile(r"[#]([rRsSuUm])(\d+)(?:[:](\d+))?")
+
+
+def ordered_unique(l):
+    return sorted(set(l), key=l.index)
+
+num_registers = {"R": 32, "V": 32}
+
+operand_letters = {
+    "P",
+    "i",
+    "I",
+    "r",
+    "s",
+    "t",
+    "u",
+    "v",
+    "w",
+    "x",
+    "y",
+    "z",
+    "d",
+    "e",
+    "f",
+    "g"
+}
+
+#
+# These instructions have unused operand letters in their encoding
+# They don't correspond to actual operands in the instruction semantics
+# We will mark them as ignored in QEMU decodetree
+#
+tags_with_unused_d_encoding = {
+    "R6_release_at_vi",
+    "R6_release_st_vi",
+    "S4_stored_rl_at_vi",
+    "S4_stored_rl_st_vi",
+    "S2_storew_rl_at_vi",
+    "S2_stored_rl_at_vi",
+    "S2_storew_rl_st_vi",
+}
+
+tags_with_unused_t_encoding = {
+    "R6_release_at_vi",
+    "R6_release_st_vi",
+}
+
+def skip_tag(tag, class_to_decode):
+    enc_class = iset.iset[tag]["enc_class"]
+    return enc_class != class_to_decode
+
+
+##
+## Generate the QEMU decodetree file for each instruction in class_to_decode
+##     For A2_add: Rd32=add(Rs32,Rt32)
+##     We produce:
+##     %A2_add_Rd   0:5
+##     %A2_add_Rs   16:5
+##     %A2_add_Rt   8:5
+##     @A2_add  11110011000.......-.....---..... Rd=%A2_add_Rd Rs=%A2_add_Rs Rt=%A2_add_Rt %PP
+##     A2_add   ..................-.....---..... @A2_add
+##
+def gen_decodetree_file(f, class_to_decode):
+    f.write(f"## DO NOT MODIFY - This file is generated by {sys.argv[0]}\n\n")
+    f.write("%PP\t14:2\n\n")
+    for tag in sorted(encs.keys(), key=iset.tags.index):
+        if skip_tag(tag, class_to_decode):
+            continue
+
+        f.write("########################################")
+        f.write("########################################\n")
+
+        enc = encs[tag]
+        enc_str = "".join(reversed(encs[tag]))
+        f.write(f"## {tag}:\t{enc_str}\n")
+        f.write("##\n")
+
+        regs = ordered_unique(regre.findall(iset.iset[tag]["syntax"]))
+        imms = ordered_unique(immre.findall(iset.iset[tag]["syntax"]))
+
+        # Write the field definitions for the registers
+        regno = 0
+        for reg in regs:
+            reg_type = reg[0]
+            reg_id = reg[1]
+            reg_letter = reg_id[0]
+            reg_num_choices = int(reg[3].rstrip("S"))
+            reg_mapping = reg[0] + "".join(["_" for letter in reg[1]]) + reg[3]
+            reg_enc_fields = re.findall(reg_letter + "+", enc)
+
+            # Check for some errors
+            if len(reg_enc_fields) == 0:
+                raise Exception(f"{tag} missing register field!")
+            if len(reg_enc_fields) > 1:
+                raise Exception(f"{tag} has split register field!")
+            reg_enc_field = reg_enc_fields[0]
+            if 2 ** len(reg_enc_field) != reg_num_choices:
+                raise Exception(f"{tag} has incorrect register field width!")
+
+            f.write(f"%{tag}_{reg_type}{reg_id}\t")
+            f.write(f"{enc.index(reg_enc_field)}:{len(reg_enc_field)}")
+            if (reg_type in num_registers and
+                reg_num_choices != num_registers[reg_type]):
+                f.write(f"\t!function=decode_mapped_reg_{reg_mapping}")
+            f.write("\n")
+            regno += 1
+
+        # Write the field definitions for the immediates
+        for imm in imms:
+            immno = 1 if imm[0].isupper() else 0
+            imm_type = imm[0]
+            imm_width = int(imm[1])
+            imm_letter = "i" if imm_type.islower() else "I"
+            fields = []
+            sign_mark = "s" if imm_type.lower() in "sr" else ""
+            for m in reversed(list(re.finditer(imm_letter + "+", enc))):
+                fields.append(f"{m.start()}:{sign_mark}{m.end() - m.start()}")
+                sign_mark = ""
+            field_str = " ".join(fields)
+            f.write(f"%{tag}_{imm_type}{imm_letter}\t{field_str}\n")
+
+        ## Handle instructions with unused encoding letters
+        ## Change the unused letters to ignored
+        if tag in tags_with_unused_d_encoding:
+            enc_str = enc_str.replace("d", "-")
+        if tag in tags_with_unused_t_encoding:
+            enc_str = enc_str.replace("t", "-")
+
+        # Replace the operand letters with .
+        for x in operand_letters:
+            enc_str = enc_str.replace(x, ".")
+
+        # Write the instruction format
+        f.write(f"@{tag}\t{enc_str}")
+        for reg in regs:
+            reg_type = reg[0]
+            reg_id = reg[1]
+            f.write(f" {reg_type}{reg_id}=%{tag}_{reg_type}{reg_id}")
+        for imm in imms:
+            imm_type = imm[0]
+            imm_letter = "i" if imm_type.islower() else "I"
+            f.write(f" {imm_type}{imm_letter}=%{tag}_{imm_type}{imm_letter}")
+
+        f.write(" %PP\n")
+
+         # Replace the 0s and 1s with .
+        for x in { "0", "1" }:
+            enc_str = enc_str.replace(x, ".")
+
+        # Write the instruction pattern
+        f.write(f"{tag}\t{enc_str} @{tag}\n")
+
+
+if __name__ == "__main__":
+    hex_common.read_semantics_file(sys.argv[1])
+    class_to_decode = sys.argv[2]
+    with open(sys.argv[3], "w") as f:
+        gen_decodetree_file(f, class_to_decode)
diff --git a/target/hexagon/gen_trans_funcs.py b/target/hexagon/gen_trans_funcs.py
new file mode 100755
index 0000000000..c907131009
--- /dev/null
+++ b/target/hexagon/gen_trans_funcs.py
@@ -0,0 +1,132 @@
+#!/usr/bin/env python3
+
+##
+##  Copyright (c) 2024 Taylor Simpson <ltaylorsimpson@gmail.com>
+##
+##  This program 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 2 of the License, or
+##  (at your option) any later version.
+##
+##  This program 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 program; if not, see <http://www.gnu.org/licenses/>.
+##
+
+import io
+import re
+
+import sys
+import textwrap
+import iset
+import hex_common
+
+encs = {
+    tag: "".join(reversed(iset.iset[tag]["enc"].replace(" ", "")))
+    for tag in iset.tags
+    if iset.iset[tag]["enc"] != "MISSING ENCODING"
+}
+
+
+regre = re.compile(r"((?<!DUP)[MNORCPQXSGVZA])([stuvwxyzdefg]+)([.]?[LlHh]?)(\d+S?)")
+immre = re.compile(r"[#]([rRsSuUm])(\d+)(?:[:](\d+))?")
+
+
+def ordered_unique(l):
+    return sorted(set(l), key=l.index)
+
+
+def skip_tag(tag, classes):
+    enc_class = iset.iset[tag]["enc_class"]
+    return enc_class not in classes
+
+
+def code_fmt(txt):
+    return textwrap.indent(textwrap.dedent(txt), "    ")
+
+open_curly = "{"
+close_curly = "}"
+
+def mark_which_imm_extended(f, tag):
+    immre = re.compile(r"IMMEXT\([rRsSuUm]")
+    imm = immre.findall(hex_common.semdict[tag])
+    if len(imm) == 0:
+        # No extended operand found
+        return
+    letter = re.split("\\(", imm[0])[1]
+    f.write(code_fmt(f"""\
+        insn->which_extended = {0 if letter.islower() else 1};
+    """))
+
+##
+## Generate the QEMU decodetree trans_<tag> function for each instruction
+##     For A2_add: Rd32=add(Rs32,Rt32)
+##     We produce:
+##     static bool trans_A2_add(DisasContext *ctx, arg_A2_add *args)
+##     {
+##         Insn *insn = ctx->insn;
+##         insn->opcode = A2_add;
+##         insn->regno[0] = args->Rd;
+##         insn->regno[1] = args->Rs;
+##         insn->regno[2] = args->Rt;
+##         return true;
+##     }
+##
+def gen_trans_funcs(f, classes):
+    f.write(f"/* DO NOT MODIFY - This file is generated by {sys.argv[0]} */\n\n")
+    for tag in sorted(encs.keys(), key=iset.tags.index):
+        if skip_tag(tag, classes):
+            continue
+
+        regs = ordered_unique(regre.findall(iset.iset[tag]["syntax"]))
+        imms = ordered_unique(immre.findall(iset.iset[tag]["syntax"]))
+
+        f.write(textwrap.dedent(f"""\
+            static bool trans_{tag}(DisasContext *ctx, arg_{tag} *args)
+            {open_curly}
+                Insn *insn = ctx->insn;
+                insn->opcode = {tag};
+        """))
+
+        regno = 0
+        for reg in regs:
+            reg_type = reg[0]
+            reg_id = reg[1]
+            f.write(code_fmt(f"""\
+                insn->regno[{regno}] = args->{reg_type}{reg_id};
+            """))
+            regno += 1
+
+        if len(imms) != 0:
+            mark_which_imm_extended(f, tag)
+
+        for imm in imms:
+            imm_type = imm[0]
+            imm_letter = "i" if imm_type.islower() else "I"
+            immno = 0 if imm_type.islower() else 1
+            imm_shift = int(imm[2]) if imm[2] else 0
+            if imm_shift:
+                f.write(code_fmt(f"""\
+                    insn->immed[{immno}] =
+                        shift_left(ctx, args->{imm_type}{imm_letter},
+                                   {imm_shift}, {immno});
+                """))
+            else:
+                f.write(code_fmt(f"""\
+                    insn->immed[{immno}] = args->{imm_type}{imm_letter};
+                """))
+
+        f.write(textwrap.dedent(f"""\
+                return true;
+            {close_curly}
+        """))
+
+
+if __name__ == "__main__":
+    hex_common.read_semantics_file(sys.argv[1])
+    with open(sys.argv[2], "w") as f:
+        gen_trans_funcs(f, { "NORMAL", "EXT_mmvec" })
diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build
index da8e608d00..831bd5716a 100644
--- a/target/hexagon/meson.build
+++ b/target/hexagon/meson.build
@@ -133,6 +133,61 @@ dectree_generated = custom_target(
 )
 hexagon_ss.add(dectree_generated)
 
+#
+# Generate the input to the QEMU decodetree.py script
+#
+normal_decode_generated = custom_target(
+    'normal_decode_generated',
+    output: 'normal_decode_generated',
+    depends: [iset_py, semantics_generated],
+    env: {'PYTHONPATH': meson.current_build_dir()},
+    command: [python, files('gen_decodetree.py'), semantics_generated, 'NORMAL', '@OUTPUT@'],
+)
+hexagon_ss.add(normal_decode_generated)
+
+hvx_decode_generated = custom_target(
+    'hvx_decode_generated',
+    output: 'hvx_decode_generated',
+    depends: [iset_py, semantics_generated],
+    env: {'PYTHONPATH': meson.current_build_dir()},
+    command: [python, files('gen_decodetree.py'), semantics_generated, 'EXT_mmvec', '@OUTPUT@'],
+)
+hexagon_ss.add(hvx_decode_generated)
+
+#
+# Run the QEMU decodetree.py script to produce the instruction decoder
+#
+decodetree_py = meson.current_source_dir() / '../../scripts/decodetree.py'
+decode_normal_generated = custom_target(
+    'decode_normal_generated.c.inc',
+    output: 'decode_normal_generated.c.inc',
+    input: normal_decode_generated,
+    env: {'PYTHONPATH': meson.current_build_dir()},
+    command: [python, files(decodetree_py), normal_decode_generated, '--static-decode=decode_normal', '-o', '@OUTPUT@'],
+)
+hexagon_ss.add(decode_normal_generated)
+
+decode_hvx_generated = custom_target(
+    'decode_hvx_generated.c.inc',
+    output: 'decode_hvx_generated.c.inc',
+    input: hvx_decode_generated,
+    env: {'PYTHONPATH': meson.current_build_dir()},
+    command: [python, files(decodetree_py), hvx_decode_generated, '--static-decode=decode_hvx', '-o', '@OUTPUT@'],
+)
+hexagon_ss.add(decode_hvx_generated)
+
+#
+# Generate the trans_* functions that the decoder will use
+#
+decodetree_trans_funcs_generated = custom_target(
+    'decodetree_trans_funcs_generated.c.inc',
+    output: 'decodetree_trans_funcs_generated.c.inc',
+    depends: [iset_py, semantics_generated],
+    env: {'PYTHONPATH': meson.current_build_dir()},
+    command: [python, files('gen_trans_funcs.py'), semantics_generated, '@OUTPUT@'],
+)
+hexagon_ss.add(decodetree_trans_funcs_generated)
+
 hexagon_ss.add(files(
     'cpu.c',
     'translate.c',
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* RE: [PATCH v2 1/3] Hexagon (target/hexagon) Use QEMU decodetree (32-bit instructions)
  2024-01-08 22:48 ` [PATCH v2 1/3] Hexagon (target/hexagon) Use QEMU decodetree (32-bit instructions) Taylor Simpson
@ 2024-01-15  0:20   ` Brian Cain
  2024-01-15 21:38     ` ltaylorsimpson
  0 siblings, 1 reply; 8+ messages in thread
From: Brian Cain @ 2024-01-15  0:20 UTC (permalink / raw)
  To: Taylor Simpson, qemu-devel@nongnu.org
  Cc: Matheus Bernardino (QUIC), Sid Manning, Marco Liebel (QUIC),
	richard.henderson@linaro.org, philmd@linaro.org, ale@rev.ng,
	anjo@rev.ng



> -----Original Message-----
> From: Taylor Simpson <ltaylorsimpson@gmail.com>
> Sent: Monday, January 8, 2024 4:49 PM
> To: qemu-devel@nongnu.org
> Cc: Brian Cain <bcain@quicinc.com>; Matheus Bernardino (QUIC)
> <quic_mathbern@quicinc.com>; Sid Manning <sidneym@quicinc.com>; Marco
> Liebel (QUIC) <quic_mliebel@quicinc.com>; richard.henderson@linaro.org;
> philmd@linaro.org; ale@rev.ng; anjo@rev.ng; ltaylorsimpson@gmail.com
> Subject: [PATCH v2 1/3] Hexagon (target/hexagon) Use QEMU decodetree (32-
> bit instructions)
> 
> WARNING: This email originated from outside of Qualcomm. Please be wary of
> any links or attachments, and do not enable macros.
> 
> The Decodetree Specification can be found here
> https://www.qemu.org/docs/master/devel/decodetree.html
> 
> Covers all 32-bit instructions, including HVX
> 
> We generate separate decoders for each instruction class.  The reason
> will be more apparent in the next patch in this series.
> 
> We add 2 new scripts
>     gen_decodetree.py        Generate the input to decodetree.py
>     gen_trans_funcs.py       Generate the trans_* functions used by the
>                              output of decodetree.py
> 
> Since the functions generated by decodetree.py take DisasContext * as an
> argument, we add the argument to a couple of functions that didn't need
> it previously.  We also set the insn field in DisasContext during decode
> because it is used by the trans_* functions.
> 
> There is a g_assert_not_reached() in decode_insns() in decode.c to
> verify we never try to use the old decoder on 32-bit instructions
> 
> Signed-off-by: Taylor Simpson <ltaylorsimpson@gmail.com>
> ---
>  target/hexagon/decode.h           |   5 +-
>  target/hexagon/decode.c           |  54 ++++++++-
>  target/hexagon/translate.c        |   4 +-
>  target/hexagon/README             |  13 +-
>  target/hexagon/gen_decodetree.py  | 193 ++++++++++++++++++++++++++++++
>  target/hexagon/gen_trans_funcs.py | 132 ++++++++++++++++++++
>  target/hexagon/meson.build        |  55 +++++++++
>  7 files changed, 442 insertions(+), 14 deletions(-)
>  create mode 100755 target/hexagon/gen_decodetree.py
>  create mode 100755 target/hexagon/gen_trans_funcs.py
> 
> diff --git a/target/hexagon/decode.h b/target/hexagon/decode.h
> index c66f5ea64d..3f3012b978 100644
> --- a/target/hexagon/decode.h
> +++ b/target/hexagon/decode.h
> @@ -21,12 +21,13 @@
>  #include "cpu.h"
>  #include "opcodes.h"
>  #include "insn.h"
> +#include "translate.h"
> 
>  void decode_init(void);
> 
>  void decode_send_insn_to(Packet *packet, int start, int newloc);
> 
> -int decode_packet(int max_words, const uint32_t *words, Packet *pkt,
> -                  bool disas_only);
> +int decode_packet(DisasContext *ctx, int max_words, const uint32_t *words,
> +                  Packet *pkt, bool disas_only);
> 
>  #endif
> diff --git a/target/hexagon/decode.c b/target/hexagon/decode.c
> index 946c55cc71..bddad1f75e 100644
> --- a/target/hexagon/decode.c
> +++ b/target/hexagon/decode.c
> @@ -52,6 +52,34 @@ DEF_REGMAP(R_8,   8,  0, 1, 2, 3, 4, 5, 6, 7)
>  #define DECODE_MAPPED_REG(OPNUM, NAME) \
>      insn->regno[OPNUM] = DECODE_REGISTER_##NAME[insn->regno[OPNUM]];
> 
> +/* Helper functions for decode_*_generated.c.inc */
> +#define DECODE_MAPPED(NAME) \
> +static int decode_mapped_reg_##NAME(DisasContext *ctx, int x) \
> +{ \
> +    return DECODE_REGISTER_##NAME[x]; \
> +}
> +DECODE_MAPPED(R_16)
> +DECODE_MAPPED(R_8)
> +
> +/* Helper function for decodetree_trans_funcs_generated.c.inc */
> +static int shift_left(DisasContext *ctx, int x, int n, int immno)
> +{
> +    int ret = x;
> +    Insn *insn = ctx->insn;
> +    if (!insn->extension_valid ||
> +        insn->which_extended != immno) {
> +        ret <<= n;
> +    }
> +    return ret;
> +}
> +
> +/* Include the generated decoder for 32 bit insn */
> +#include "decode_normal_generated.c.inc"
> +#include "decode_hvx_generated.c.inc"
> +
> +/* Include the generated helpers for the decoder */
> +#include "decodetree_trans_funcs_generated.c.inc"
> +
>  typedef struct {
>      const struct DectreeTable *table_link;
>      const struct DectreeTable *table_link_b;
> @@ -550,7 +578,8 @@ apply_extender(Packet *pkt, int i, uint32_t extender)
>      int immed_num;
>      uint32_t base_immed;
> 
> -    immed_num = opcode_which_immediate_is_extended(pkt->insn[i].opcode);
> +    immed_num = pkt->insn[i].which_extended;
> +    g_assert(immed_num == opcode_which_immediate_is_extended(pkt-
> >insn[i].opcode));
>      base_immed = pkt->insn[i].immed[immed_num];
> 
>      pkt->insn[i].immed[immed_num] = extender | fZXTN(6, 32, base_immed);
> @@ -762,12 +791,19 @@ decode_insns_tablewalk(Insn *insn, const
> DectreeTable *table,
>  }
> 
>  static unsigned int
> -decode_insns(Insn *insn, uint32_t encoding)
> +decode_insns(DisasContext *ctx, Insn *insn, uint32_t encoding)
>  {
>      const DectreeTable *table;
>      if (parse_bits(encoding) != 0) {
> +        if (decode_normal(ctx, encoding) ||
> +            decode_hvx(ctx, encoding)) {
> +            insn->generate = opcode_genptr[insn->opcode];
> +            insn->iclass = iclass_bits(encoding);
> +            return 1;
> +        }
>          /* Start with PP table - 32 bit instructions */
>          table = &dectree_table_DECODE_ROOT_32;
> +        g_assert_not_reached();
>      } else {
>          /* start with EE table - duplex instructions */
>          table = &dectree_table_DECODE_ROOT_EE;
> @@ -916,8 +952,8 @@ decode_set_slot_number(Packet *pkt)
>   * or number of words used on success
>   */
> 
> -int decode_packet(int max_words, const uint32_t *words, Packet *pkt,
> -                  bool disas_only)
> +int decode_packet(DisasContext *ctx, int max_words, const uint32_t *words,
> +                  Packet *pkt, bool disas_only)
>  {
>      int num_insns = 0;
>      int words_read = 0;
> @@ -930,9 +966,11 @@ int decode_packet(int max_words, const uint32_t
> *words, Packet *pkt,
>      memset(pkt, 0, sizeof(*pkt));
>      /* Try to build packet */
>      while (!end_of_packet && (words_read < max_words)) {
> +        Insn *insn = &pkt->insn[num_insns];
> +        ctx->insn = insn;
>          encoding32 = words[words_read];
>          end_of_packet = is_packet_end(encoding32);
> -        new_insns = decode_insns(&pkt->insn[num_insns], encoding32);
> +        new_insns = decode_insns(ctx, insn, encoding32);
>          g_assert(new_insns > 0);
>          /*
>           * If we saw an extender, mark next word extended so immediate
> @@ -1006,9 +1044,13 @@ int decode_packet(int max_words, const uint32_t
> *words, Packet *pkt,
>  int disassemble_hexagon(uint32_t *words, int nwords, bfd_vma pc,
>                          GString *buf)
>  {
> +    DisasContext ctx;
>      Packet pkt;
> 
> -    if (decode_packet(nwords, words, &pkt, true) > 0) {
> +    memset(&ctx, 0, sizeof(DisasContext));
> +    ctx.pkt = &pkt;
> +
> +    if (decode_packet(&ctx, nwords, words, &pkt, true) > 0) {
>          snprint_a_pkt_disas(buf, &pkt, words, pc);
>          return pkt.encod_pkt_size_in_bytes;
>      } else {
> diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c
> index 666c061180..95579ae243 100644
> --- a/target/hexagon/translate.c
> +++ b/target/hexagon/translate.c
> @@ -1033,10 +1033,10 @@ static void
> decode_and_translate_packet(CPUHexagonState *env, DisasContext *ctx)
>          return;
>      }
> 
> -    if (decode_packet(nwords, words, &pkt, false) > 0) {
> +    ctx->pkt = &pkt;
> +    if (decode_packet(ctx, nwords, words, &pkt, false) > 0) {
>          pkt.pc = ctx->base.pc_next;
>          HEX_DEBUG_PRINT_PKT(&pkt);
> -        ctx->pkt = &pkt;
>          gen_start_packet(ctx);
>          for (i = 0; i < pkt.num_insns; i++) {
>              ctx->insn = &pkt.insn[i];
> diff --git a/target/hexagon/README b/target/hexagon/README
> index 69b2ffe9bb..1b2a4d0eac 100644
> --- a/target/hexagon/README
> +++ b/target/hexagon/README
> @@ -189,11 +189,16 @@ the packet, and we mark the implicit writes.  After
> the analysis is performed,
>  we initialize the result register for each of the predicated assignments.
> 
>  In addition to instruction semantics, we use a generator to create the decode
> -tree.  This generation is also a two step process.  The first step is to run
> -target/hexagon/gen_dectree_import.c to produce
> +tree.  This generation is a four step process.
> +Step 1 is to run target/hexagon/gen_dectree_import.c to produce
>      <BUILD_DIR>/target/hexagon/iset.py
> -This file is imported by target/hexagon/dectree.py to produce
> -    <BUILD_DIR>/target/hexagon/dectree_generated.h.inc
> +Step 2 is to import iset.py into target/hexagon/gen_decodetree.py to produce
> +    <BUILD_DIR>/target/hexagon/normal_decode_generated
> +    <BUILD_DIR>/target/hexagon/hvx_decode_generated
> +Step 3 is to process the above files with QEMU's decodetree.py to produce
> +    <BUILD_DIR>/target/hexagon/decode_*_generated.c.inc
> +Step 4 is to import iset.py into target/hexagon/gen_trans_funcs.py to produce
> +    <BUILD_DIR>/target/hexagon/decodetree_trans_funcs_generated.c.inc
> 
>  *** Key Files ***
> 
> diff --git a/target/hexagon/gen_decodetree.py
> b/target/hexagon/gen_decodetree.py
> new file mode 100755
> index 0000000000..1693148ec0
> --- /dev/null
> +++ b/target/hexagon/gen_decodetree.py
> @@ -0,0 +1,193 @@
> +#!/usr/bin/env python3
> +
> +##
> +##  Copyright (c) 2024 Taylor Simpson <ltaylorsimpson@gmail.com>
> +##
> +##  This program 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 2 of the License, or
> +##  (at your option) any later version.
> +##
> +##  This program 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 program; if not, see <http://www.gnu.org/licenses/>.
> +##
> +
> +import io
> +import re
> +
> +import sys
> +import textwrap
> +import iset
> +import hex_common
> +
> +encs = {
> +    tag: "".join(reversed(iset.iset[tag]["enc"].replace(" ", "")))
> +    for tag in iset.tags
> +    if iset.iset[tag]["enc"] != "MISSING ENCODING"
> +}
> +
> +
> +regre =
> re.compile(r"((?<!DUP)[MNORCPQXSGVZA])([stuvwxyzdefg]+)([.]?[LlHh]?)(\d+S
> ?)")
> +immre = re.compile(r"[#]([rRsSuUm])(\d+)(?:[:](\d+))?")
> +
> +
> +def ordered_unique(l):
> +    return sorted(set(l), key=l.index)
> +
> +num_registers = {"R": 32, "V": 32}
> +
> +operand_letters = {
> +    "P",
> +    "i",
> +    "I",
> +    "r",
> +    "s",
> +    "t",
> +    "u",
> +    "v",
> +    "w",
> +    "x",
> +    "y",
> +    "z",
> +    "d",
> +    "e",
> +    "f",
> +    "g"
> +}
> +
> +#
> +# These instructions have unused operand letters in their encoding
> +# They don't correspond to actual operands in the instruction semantics
> +# We will mark them as ignored in QEMU decodetree
> +#
> +tags_with_unused_d_encoding = {
> +    "R6_release_at_vi",
> +    "R6_release_st_vi",
> +    "S4_stored_rl_at_vi",
> +    "S4_stored_rl_st_vi",
> +    "S2_storew_rl_at_vi",
> +    "S2_stored_rl_at_vi",
> +    "S2_storew_rl_st_vi",
> +}
> +
> +tags_with_unused_t_encoding = {
> +    "R6_release_at_vi",
> +    "R6_release_st_vi",
> +}
> +
> +def skip_tag(tag, class_to_decode):
> +    enc_class = iset.iset[tag]["enc_class"]
> +    return enc_class != class_to_decode
> +
> +
> +##
> +## Generate the QEMU decodetree file for each instruction in class_to_decode
> +##     For A2_add: Rd32=add(Rs32,Rt32)
> +##     We produce:
> +##     %A2_add_Rd   0:5
> +##     %A2_add_Rs   16:5
> +##     %A2_add_Rt   8:5
> +##     @A2_add  11110011000.......-.....---..... Rd=%A2_add_Rd Rs=%A2_add_Rs
> Rt=%A2_add_Rt %PP
> +##     A2_add   ..................-.....---..... @A2_add
> +##
> +def gen_decodetree_file(f, class_to_decode):
> +    f.write(f"## DO NOT MODIFY - This file is generated by {sys.argv[0]}\n\n")
> +    f.write("%PP\t14:2\n\n")
> +    for tag in sorted(encs.keys(), key=iset.tags.index):
> +        if skip_tag(tag, class_to_decode):
> +            continue
> +
> +        f.write("########################################")
> +        f.write("########################################\n")
> +
> +        enc = encs[tag]
> +        enc_str = "".join(reversed(encs[tag]))
> +        f.write(f"## {tag}:\t{enc_str}\n")
> +        f.write("##\n")
> +
> +        regs = ordered_unique(regre.findall(iset.iset[tag]["syntax"]))
> +        imms = ordered_unique(immre.findall(iset.iset[tag]["syntax"]))
> +
> +        # Write the field definitions for the registers
> +        regno = 0
> +        for reg in regs:
> +            reg_type = reg[0]
> +            reg_id = reg[1]
> +            reg_letter = reg_id[0]
> +            reg_num_choices = int(reg[3].rstrip("S"))
> +            reg_mapping = reg[0] + "".join(["_" for letter in reg[1]]) + reg[3]
> +            reg_enc_fields = re.findall(reg_letter + "+", enc)
> +
> +            # Check for some errors
> +            if len(reg_enc_fields) == 0:
> +                raise Exception(f"{tag} missing register field!")
> +            if len(reg_enc_fields) > 1:
> +                raise Exception(f"{tag} has split register field!")
> +            reg_enc_field = reg_enc_fields[0]
> +            if 2 ** len(reg_enc_field) != reg_num_choices:
> +                raise Exception(f"{tag} has incorrect register field width!")
> +
> +            f.write(f"%{tag}_{reg_type}{reg_id}\t")
> +            f.write(f"{enc.index(reg_enc_field)}:{len(reg_enc_field)}")
> +            if (reg_type in num_registers and
> +                reg_num_choices != num_registers[reg_type]):
> +                f.write(f"\t!function=decode_mapped_reg_{reg_mapping}")
> +            f.write("\n")
> +            regno += 1
> +
> +        # Write the field definitions for the immediates
> +        for imm in imms:
> +            immno = 1 if imm[0].isupper() else 0
> +            imm_type = imm[0]
> +            imm_width = int(imm[1])
> +            imm_letter = "i" if imm_type.islower() else "I"
> +            fields = []
> +            sign_mark = "s" if imm_type.lower() in "sr" else ""
> +            for m in reversed(list(re.finditer(imm_letter + "+", enc))):
> +                fields.append(f"{m.start()}:{sign_mark}{m.end() - m.start()}")
> +                sign_mark = ""
> +            field_str = " ".join(fields)
> +            f.write(f"%{tag}_{imm_type}{imm_letter}\t{field_str}\n")
> +
> +        ## Handle instructions with unused encoding letters
> +        ## Change the unused letters to ignored
> +        if tag in tags_with_unused_d_encoding:
> +            enc_str = enc_str.replace("d", "-")
> +        if tag in tags_with_unused_t_encoding:
> +            enc_str = enc_str.replace("t", "-")
> +
> +        # Replace the operand letters with .
> +        for x in operand_letters:
> +            enc_str = enc_str.replace(x, ".")
> +
> +        # Write the instruction format
> +        f.write(f"@{tag}\t{enc_str}")
> +        for reg in regs:
> +            reg_type = reg[0]
> +            reg_id = reg[1]
> +            f.write(f" {reg_type}{reg_id}=%{tag}_{reg_type}{reg_id}")
> +        for imm in imms:
> +            imm_type = imm[0]
> +            imm_letter = "i" if imm_type.islower() else "I"
> +            f.write(f" {imm_type}{imm_letter}=%{tag}_{imm_type}{imm_letter}")
> +
> +        f.write(" %PP\n")
> +
> +         # Replace the 0s and 1s with .
> +        for x in { "0", "1" }:
> +            enc_str = enc_str.replace(x, ".")
> +
> +        # Write the instruction pattern
> +        f.write(f"{tag}\t{enc_str} @{tag}\n")
> +
> +
> +if __name__ == "__main__":
> +    hex_common.read_semantics_file(sys.argv[1])
> +    class_to_decode = sys.argv[2]
> +    with open(sys.argv[3], "w") as f:
> +        gen_decodetree_file(f, class_to_decode)
> diff --git a/target/hexagon/gen_trans_funcs.py
> b/target/hexagon/gen_trans_funcs.py
> new file mode 100755
> index 0000000000..c907131009
> --- /dev/null
> +++ b/target/hexagon/gen_trans_funcs.py
> @@ -0,0 +1,132 @@
> +#!/usr/bin/env python3
> +
> +##
> +##  Copyright (c) 2024 Taylor Simpson <ltaylorsimpson@gmail.com>
> +##
> +##  This program 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 2 of the License, or
> +##  (at your option) any later version.
> +##
> +##  This program 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 program; if not, see <http://www.gnu.org/licenses/>.
> +##
> +
> +import io
> +import re
> +
> +import sys
> +import textwrap
> +import iset
> +import hex_common
> +
> +encs = {
> +    tag: "".join(reversed(iset.iset[tag]["enc"].replace(" ", "")))
> +    for tag in iset.tags
> +    if iset.iset[tag]["enc"] != "MISSING ENCODING"
> +}
> +
> +
> +regre =
> re.compile(r"((?<!DUP)[MNORCPQXSGVZA])([stuvwxyzdefg]+)([.]?[LlHh]?)(\d+S
> ?)")
> +immre = re.compile(r"[#]([rRsSuUm])(\d+)(?:[:](\d+))?")
> +
> +
> +def ordered_unique(l):
> +    return sorted(set(l), key=l.index)
> +
> +
> +def skip_tag(tag, classes):
> +    enc_class = iset.iset[tag]["enc_class"]
> +    return enc_class not in classes
> +
> +
> +def code_fmt(txt):
> +    return textwrap.indent(textwrap.dedent(txt), "    ")
> +
> +open_curly = "{"
> +close_curly = "}"
> +
> +def mark_which_imm_extended(f, tag):
> +    immre = re.compile(r"IMMEXT\([rRsSuUm]")
> +    imm = immre.findall(hex_common.semdict[tag])
> +    if len(imm) == 0:
> +        # No extended operand found
> +        return
> +    letter = re.split("\\(", imm[0])[1]
> +    f.write(code_fmt(f"""\
> +        insn->which_extended = {0 if letter.islower() else 1};
> +    """))
> +
> +##
> +## Generate the QEMU decodetree trans_<tag> function for each instruction
> +##     For A2_add: Rd32=add(Rs32,Rt32)
> +##     We produce:
> +##     static bool trans_A2_add(DisasContext *ctx, arg_A2_add *args)
> +##     {
> +##         Insn *insn = ctx->insn;
> +##         insn->opcode = A2_add;
> +##         insn->regno[0] = args->Rd;
> +##         insn->regno[1] = args->Rs;
> +##         insn->regno[2] = args->Rt;
> +##         return true;
> +##     }
> +##
> +def gen_trans_funcs(f, classes):
> +    f.write(f"/* DO NOT MODIFY - This file is generated by {sys.argv[0]} */\n\n")
> +    for tag in sorted(encs.keys(), key=iset.tags.index):
> +        if skip_tag(tag, classes):
> +            continue
> +
> +        regs = ordered_unique(regre.findall(iset.iset[tag]["syntax"]))
> +        imms = ordered_unique(immre.findall(iset.iset[tag]["syntax"]))
> +
> +        f.write(textwrap.dedent(f"""\
> +            static bool trans_{tag}(DisasContext *ctx, arg_{tag} *args)
> +            {open_curly}
> +                Insn *insn = ctx->insn;
> +                insn->opcode = {tag};
> +        """))
> +
> +        regno = 0
> +        for reg in regs:
> +            reg_type = reg[0]
> +            reg_id = reg[1]
> +            f.write(code_fmt(f"""\
> +                insn->regno[{regno}] = args->{reg_type}{reg_id};
> +            """))
> +            regno += 1
> +
> +        if len(imms) != 0:
> +            mark_which_imm_extended(f, tag)
> +
> +        for imm in imms:
> +            imm_type = imm[0]
> +            imm_letter = "i" if imm_type.islower() else "I"
> +            immno = 0 if imm_type.islower() else 1
> +            imm_shift = int(imm[2]) if imm[2] else 0
> +            if imm_shift:
> +                f.write(code_fmt(f"""\
> +                    insn->immed[{immno}] =
> +                        shift_left(ctx, args->{imm_type}{imm_letter},
> +                                   {imm_shift}, {immno});
> +                """))
> +            else:
> +                f.write(code_fmt(f"""\
> +                    insn->immed[{immno}] = args->{imm_type}{imm_letter};
> +                """))
> +
> +        f.write(textwrap.dedent(f"""\
> +                return true;
> +            {close_curly}
> +        """))
> +
> +
> +if __name__ == "__main__":
> +    hex_common.read_semantics_file(sys.argv[1])
> +    with open(sys.argv[2], "w") as f:
> +        gen_trans_funcs(f, { "NORMAL", "EXT_mmvec" })
> diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build
> index da8e608d00..831bd5716a 100644
> --- a/target/hexagon/meson.build
> +++ b/target/hexagon/meson.build
> @@ -133,6 +133,61 @@ dectree_generated = custom_target(
>  )
>  hexagon_ss.add(dectree_generated)
> 
> +#
> +# Generate the input to the QEMU decodetree.py script
> +#
> +normal_decode_generated = custom_target(
> +    'normal_decode_generated',
> +    output: 'normal_decode_generated',
> +    depends: [iset_py, semantics_generated],
> +    env: {'PYTHONPATH': meson.current_build_dir()},
> +    command: [python, files('gen_decodetree.py'), semantics_generated,
> 'NORMAL', '@OUTPUT@'],
> +)
> +hexagon_ss.add(normal_decode_generated)
> +
> +hvx_decode_generated = custom_target(
> +    'hvx_decode_generated',
> +    output: 'hvx_decode_generated',
> +    depends: [iset_py, semantics_generated],
> +    env: {'PYTHONPATH': meson.current_build_dir()},
> +    command: [python, files('gen_decodetree.py'), semantics_generated,
> 'EXT_mmvec', '@OUTPUT@'],
> +)
> +hexagon_ss.add(hvx_decode_generated)
> +
> +#
> +# Run the QEMU decodetree.py script to produce the instruction decoder
> +#
> +decodetree_py = meson.current_source_dir() / '../../scripts/decodetree.py'
> +decode_normal_generated = custom_target(
> +    'decode_normal_generated.c.inc',
> +    output: 'decode_normal_generated.c.inc',
> +    input: normal_decode_generated,
> +    env: {'PYTHONPATH': meson.current_build_dir()},
> +    command: [python, files(decodetree_py), normal_decode_generated, '--
> static-decode=decode_normal', '-o', '@OUTPUT@'],
> +)
> +hexagon_ss.add(decode_normal_generated)
> +
> +decode_hvx_generated = custom_target(
> +    'decode_hvx_generated.c.inc',
> +    output: 'decode_hvx_generated.c.inc',
> +    input: hvx_decode_generated,
> +    env: {'PYTHONPATH': meson.current_build_dir()},
> +    command: [python, files(decodetree_py), hvx_decode_generated, '--static-
> decode=decode_hvx', '-o', '@OUTPUT@'],
> +)
> +hexagon_ss.add(decode_hvx_generated)
> +
> +#
> +# Generate the trans_* functions that the decoder will use
> +#
> +decodetree_trans_funcs_generated = custom_target(
> +    'decodetree_trans_funcs_generated.c.inc',
> +    output: 'decodetree_trans_funcs_generated.c.inc',
> +    depends: [iset_py, semantics_generated],
> +    env: {'PYTHONPATH': meson.current_build_dir()},
> +    command: [python, files('gen_trans_funcs.py'), semantics_generated,
> '@OUTPUT@'],
> +)
> +hexagon_ss.add(decodetree_trans_funcs_generated)
> +
>  hexagon_ss.add(files(
>      'cpu.c',
>      'translate.c',
> --
> 2.34.1

LGTM, but some nitpicky suggestions:

diff --git a/target/hexagon/gen_decodetree.py b/target/hexagon/gen_decodetree.py
index 2dff975f55..62bd8a62b6 100755
--- a/target/hexagon/gen_decodetree.py
+++ b/target/hexagon/gen_decodetree.py
@@ -57,7 +57,7 @@ def ordered_unique(l):
     "d",
     "e",
     "f",
-    "g"
+    "g",
 }
 
 #
@@ -104,9 +104,6 @@ def gen_decodetree_file(f, class_to_decode):
         if skip_tag(tag, class_to_decode):
             continue
 
-        f.write("########################################")
-        f.write("########################################\n")
-
         enc = encs[tag]
         enc_str = "".join(reversed(encs[tag]))
 
@@ -115,21 +112,21 @@ def gen_decodetree_file(f, class_to_decode):
         if is_subinsn:
             enc_str = "---" + enc_str
 
-        f.write(f"## {tag}:\t{enc_str}\n")
-        f.write("##\n")
+        f.write(("#" * 80) + "\n"
+                f"## {tag}:\t{enc_str}\n"
+                "##\n")
 
         regs = ordered_unique(regre.findall(iset.iset[tag]["syntax"]))
         imms = ordered_unique(immre.findall(iset.iset[tag]["syntax"]))
 
         # Write the field definitions for the registers
-        regno = 0
-        for reg in regs:
-            reg_type = reg[0]
-            reg_id = reg[1]
+        for regno, reg in enumerate(regs):
+            reg_type, reg_id, _, reg_enc_size = reg
             reg_letter = reg_id[0]
-            reg_num_choices = int(reg[3].rstrip("S"))
-            reg_mapping = reg[0] + "".join(["_" for letter in reg[1]]) + reg[3]
+            reg_num_choices = int(reg_enc_size.rstrip("S"))
+            reg_mapping = reg_type + "".join("_" for letter in reg_id) + reg_enc_size
             reg_enc_fields = re.findall(reg_letter + "+", enc)
+            print(f'{reg} -> {reg_enc_fields}')
 
             # Check for some errors
             if len(reg_enc_fields) == 0:
@@ -140,13 +137,12 @@ def gen_decodetree_file(f, class_to_decode):
             if 2 ** len(reg_enc_field) != reg_num_choices:
                 raise Exception(f"{tag} has incorrect register field width!")
 
-            f.write(f"%{tag}_{reg_type}{reg_id}\t")
-            f.write(f"{enc.index(reg_enc_field)}:{len(reg_enc_field)}")
+            f.write(f"%{tag}_{reg_type}{reg_id}\t"
+                    f"{enc.index(reg_enc_field)}:{len(reg_enc_field)}")
             if (reg_type in num_registers and
                 reg_num_choices != num_registers[reg_type]):
                 f.write(f"\t!function=decode_mapped_reg_{reg_mapping}")
             f.write("\n")
-            regno += 1
 
         # Write the field definitions for the immediates
         for imm in imms:
@@ -189,8 +185,7 @@ def gen_decodetree_file(f, class_to_decode):
         f.write("\n")
 
          # Replace the 0s and 1s with .
-        for x in { "0", "1" }:
-            enc_str = enc_str.replace(x, ".")
+        enc_str = enc_str.replace("0", ".").replace("1", ".")
 
         # Write the instruction pattern
         f.write(f"{tag}\t{enc_str} @{tag}\n")


Consider some or all of the above, but regardless --

Reviewed-by: Brian Cain <bcain@quicinc.com>

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* RE: [PATCH v2 1/3] Hexagon (target/hexagon) Use QEMU decodetree (32-bit instructions)
  2024-01-15  0:20   ` Brian Cain
@ 2024-01-15 21:38     ` ltaylorsimpson
  0 siblings, 0 replies; 8+ messages in thread
From: ltaylorsimpson @ 2024-01-15 21:38 UTC (permalink / raw)
  To: 'Brian Cain', qemu-devel
  Cc: 'Matheus Bernardino (QUIC)', 'Sid Manning',
	'Marco Liebel (QUIC)', richard.henderson, philmd, ale,
	anjo



> -----Original Message-----
> From: Brian Cain <bcain@quicinc.com>
> Sent: Sunday, January 14, 2024 5:21 PM
> To: Taylor Simpson <ltaylorsimpson@gmail.com>; qemu-devel@nongnu.org
> Cc: Matheus Bernardino (QUIC) <quic_mathbern@quicinc.com>; Sid
> Manning <sidneym@quicinc.com>; Marco Liebel (QUIC)
> <quic_mliebel@quicinc.com>; richard.henderson@linaro.org;
> philmd@linaro.org; ale@rev.ng; anjo@rev.ng
> Subject: RE: [PATCH v2 1/3] Hexagon (target/hexagon) Use QEMU
> decodetree (32-bit instructions)
> 
> 
> 
> > -----Original Message-----
> > From: Taylor Simpson <ltaylorsimpson@gmail.com>
> > Sent: Monday, January 8, 2024 4:49 PM
> > To: qemu-devel@nongnu.org
> > Cc: Brian Cain <bcain@quicinc.com>; Matheus Bernardino (QUIC)
> > <quic_mathbern@quicinc.com>; Sid Manning <sidneym@quicinc.com>;
> Marco
> > Liebel (QUIC) <quic_mliebel@quicinc.com>;
> > richard.henderson@linaro.org; philmd@linaro.org; ale@rev.ng;
> > anjo@rev.ng; ltaylorsimpson@gmail.com
> > Subject: [PATCH v2 1/3] Hexagon (target/hexagon) Use QEMU decodetree
> > (32- bit instructions)
> >
> >
> > The Decodetree Specification can be found here
> > https://www.qemu.org/docs/master/devel/decodetree.html
> >
> > Covers all 32-bit instructions, including HVX
> >
> > We generate separate decoders for each instruction class.  The reason
> > will be more apparent in the next patch in this series.
> >
> > We add 2 new scripts
> >     gen_decodetree.py        Generate the input to decodetree.py
> >     gen_trans_funcs.py       Generate the trans_* functions used by the
> >                              output of decodetree.py
> >
> > Since the functions generated by decodetree.py take DisasContext * as
> > an argument, we add the argument to a couple of functions that didn't
> > need it previously.  We also set the insn field in DisasContext during
> > decode because it is used by the trans_* functions.
> >
> > There is a g_assert_not_reached() in decode_insns() in decode.c to
> > verify we never try to use the old decoder on 32-bit instructions
> >
> > Signed-off-by: Taylor Simpson <ltaylorsimpson@gmail.com>
> > ---
> >  target/hexagon/decode.h           |   5 +-
> >  target/hexagon/decode.c           |  54 ++++++++-
> >  target/hexagon/translate.c        |   4 +-
> >  target/hexagon/README             |  13 +-
> >  target/hexagon/gen_decodetree.py  | 193
> > ++++++++++++++++++++++++++++++
> target/hexagon/gen_trans_funcs.py | 132 ++++++++++++++++++++
> >  target/hexagon/meson.build        |  55 +++++++++
> >  7 files changed, 442 insertions(+), 14 deletions(-)  create mode
> > 100755 target/hexagon/gen_decodetree.py  create mode 100755
> > target/hexagon/gen_trans_funcs.py
> >
> 
> LGTM, but some nitpicky suggestions:
> 
> diff --git a/target/hexagon/gen_decodetree.py
> b/target/hexagon/gen_decodetree.py
> index 2dff975f55..62bd8a62b6 100755
> --- a/target/hexagon/gen_decodetree.py
> +++ b/target/hexagon/gen_decodetree.py
> @@ -57,7 +57,7 @@ def ordered_unique(l):
>      "d",
>      "e",
>      "f",
> -    "g"
> +    "g",
>  }
> 
>  #
> @@ -104,9 +104,6 @@ def gen_decodetree_file(f, class_to_decode):
>          if skip_tag(tag, class_to_decode):
>              continue
> 
> -        f.write("########################################")
> -        f.write("########################################\n")
> -
>          enc = encs[tag]
>          enc_str = "".join(reversed(encs[tag]))
> 
> @@ -115,21 +112,21 @@ def gen_decodetree_file(f, class_to_decode):
>          if is_subinsn:
>              enc_str = "---" + enc_str
> 
> -        f.write(f"## {tag}:\t{enc_str}\n")
> -        f.write("##\n")
> +        f.write(("#" * 80) + "\n"
> +                f"## {tag}:\t{enc_str}\n"
> +                "##\n")
> 
>          regs = ordered_unique(regre.findall(iset.iset[tag]["syntax"]))
>          imms = ordered_unique(immre.findall(iset.iset[tag]["syntax"]))
> 
>          # Write the field definitions for the registers
> -        regno = 0
> -        for reg in regs:
> -            reg_type = reg[0]
> -            reg_id = reg[1]
> +        for regno, reg in enumerate(regs):
> +            reg_type, reg_id, _, reg_enc_size = reg
>              reg_letter = reg_id[0]
> -            reg_num_choices = int(reg[3].rstrip("S"))
> -            reg_mapping = reg[0] + "".join(["_" for letter in reg[1]]) + reg[3]
> +            reg_num_choices = int(reg_enc_size.rstrip("S"))
> +            reg_mapping = reg_type + "".join("_" for letter in reg_id)
> + + reg_enc_size
>              reg_enc_fields = re.findall(reg_letter + "+", enc)
> +            print(f'{reg} -> {reg_enc_fields}')
> 
>              # Check for some errors
>              if len(reg_enc_fields) == 0:
> @@ -140,13 +137,12 @@ def gen_decodetree_file(f, class_to_decode):
>              if 2 ** len(reg_enc_field) != reg_num_choices:
>                  raise Exception(f"{tag} has incorrect register field width!")
> 
> -            f.write(f"%{tag}_{reg_type}{reg_id}\t")
> -            f.write(f"{enc.index(reg_enc_field)}:{len(reg_enc_field)}")
> +            f.write(f"%{tag}_{reg_type}{reg_id}\t"
> +                    f"{enc.index(reg_enc_field)}:{len(reg_enc_field)}")
>              if (reg_type in num_registers and
>                  reg_num_choices != num_registers[reg_type]):
>                  f.write(f"\t!function=decode_mapped_reg_{reg_mapping}")
>              f.write("\n")
> -            regno += 1
> 
>          # Write the field definitions for the immediates
>          for imm in imms:
> @@ -189,8 +185,7 @@ def gen_decodetree_file(f, class_to_decode):
>          f.write("\n")
> 
>           # Replace the 0s and 1s with .
> -        for x in { "0", "1" }:
> -            enc_str = enc_str.replace(x, ".")
> +        enc_str = enc_str.replace("0", ".").replace("1", ".")
> 
>          # Write the instruction pattern
>          f.write(f"{tag}\t{enc_str} @{tag}\n")
> 
> 
> Consider some or all of the above, but regardless --
> 
> Reviewed-by: Brian Cain <bcain@quicinc.com>

Thanks,
I will make the changes you suggest.

Taylor




^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v2 0/3] Hexagon (target/hexagon) Use QEMU decodetree
@ 2024-01-15 22:14 Taylor Simpson
  2024-01-15 22:14 ` [PATCH v2 1/3] Hexagon (target/hexagon) Use QEMU decodetree (32-bit instructions) Taylor Simpson
                   ` (3 more replies)
  0 siblings, 4 replies; 8+ messages in thread
From: Taylor Simpson @ 2024-01-15 22:14 UTC (permalink / raw)
  To: qemu-devel
  Cc: bcain, quic_mathbern, sidneym, quic_mliebel, richard.henderson,
	philmd, ale, anjo, ltaylorsimpson

Replace the old Hexagon dectree.py with QEMU decodetree

**** Changes in v2 ****
Suggested Python improvements from Brian Cain <bcain@quicinc.com>


Taylor Simpson (3):
  Hexagon (target/hexagon) Use QEMU decodetree (32-bit instructions)
  Hexagon (target/hexagon) Use QEMU decodetree (16-bit instructions)
  Hexagon (target/hexagon) Remove old dectree.py

 target/hexagon/decode.h             |   5 +-
 target/hexagon/opcodes.h            |   2 -
 target/hexagon/decode.c             | 435 +++++++---------------------
 target/hexagon/gen_dectree_import.c |  49 ----
 target/hexagon/opcodes.c            |  29 --
 target/hexagon/translate.c          |   4 +-
 target/hexagon/README               |  14 +-
 target/hexagon/dectree.py           | 403 --------------------------
 target/hexagon/gen_decodetree.py    | 198 +++++++++++++
 target/hexagon/gen_trans_funcs.py   | 124 ++++++++
 target/hexagon/meson.build          | 147 +++++++++-
 11 files changed, 586 insertions(+), 824 deletions(-)
 delete mode 100755 target/hexagon/dectree.py
 create mode 100755 target/hexagon/gen_decodetree.py
 create mode 100755 target/hexagon/gen_trans_funcs.py

-- 
2.34.1



^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v2 1/3] Hexagon (target/hexagon) Use QEMU decodetree (32-bit instructions)
  2024-01-15 22:14 [PATCH v2 0/3] Hexagon (target/hexagon) Use QEMU decodetree Taylor Simpson
@ 2024-01-15 22:14 ` Taylor Simpson
  2024-01-15 22:14 ` [PATCH v2 2/3] Hexagon (target/hexagon) Use QEMU decodetree (16-bit instructions) Taylor Simpson
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 8+ messages in thread
From: Taylor Simpson @ 2024-01-15 22:14 UTC (permalink / raw)
  To: qemu-devel
  Cc: bcain, quic_mathbern, sidneym, quic_mliebel, richard.henderson,
	philmd, ale, anjo, ltaylorsimpson

The Decodetree Specification can be found here
https://www.qemu.org/docs/master/devel/decodetree.html

Covers all 32-bit instructions, including HVX

We generate separate decoders for each instruction class.  The reason
will be more apparent in the next patch in this series.

We add 2 new scripts
    gen_decodetree.py        Generate the input to decodetree.py
    gen_trans_funcs.py       Generate the trans_* functions used by the
                             output of decodetree.py

Since the functions generated by decodetree.py take DisasContext * as an
argument, we add the argument to a couple of functions that didn't need
it previously.  We also set the insn field in DisasContext during decode
because it is used by the trans_* functions.

There is a g_assert_not_reached() in decode_insns() in decode.c to
verify we never try to use the old decoder on 32-bit instructions

Signed-off-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Reviewed-by: Brian Cain <bcain@quicinc.com>
---
 target/hexagon/decode.h           |   5 +-
 target/hexagon/decode.c           |  54 ++++++++-
 target/hexagon/translate.c        |   4 +-
 target/hexagon/README             |  13 +-
 target/hexagon/gen_decodetree.py  | 190 ++++++++++++++++++++++++++++++
 target/hexagon/gen_trans_funcs.py | 132 +++++++++++++++++++++
 target/hexagon/meson.build        |  55 +++++++++
 7 files changed, 439 insertions(+), 14 deletions(-)
 create mode 100755 target/hexagon/gen_decodetree.py
 create mode 100755 target/hexagon/gen_trans_funcs.py

diff --git a/target/hexagon/decode.h b/target/hexagon/decode.h
index c66f5ea64d..3f3012b978 100644
--- a/target/hexagon/decode.h
+++ b/target/hexagon/decode.h
@@ -21,12 +21,13 @@
 #include "cpu.h"
 #include "opcodes.h"
 #include "insn.h"
+#include "translate.h"
 
 void decode_init(void);
 
 void decode_send_insn_to(Packet *packet, int start, int newloc);
 
-int decode_packet(int max_words, const uint32_t *words, Packet *pkt,
-                  bool disas_only);
+int decode_packet(DisasContext *ctx, int max_words, const uint32_t *words,
+                  Packet *pkt, bool disas_only);
 
 #endif
diff --git a/target/hexagon/decode.c b/target/hexagon/decode.c
index 946c55cc71..bddad1f75e 100644
--- a/target/hexagon/decode.c
+++ b/target/hexagon/decode.c
@@ -52,6 +52,34 @@ DEF_REGMAP(R_8,   8,  0, 1, 2, 3, 4, 5, 6, 7)
 #define DECODE_MAPPED_REG(OPNUM, NAME) \
     insn->regno[OPNUM] = DECODE_REGISTER_##NAME[insn->regno[OPNUM]];
 
+/* Helper functions for decode_*_generated.c.inc */
+#define DECODE_MAPPED(NAME) \
+static int decode_mapped_reg_##NAME(DisasContext *ctx, int x) \
+{ \
+    return DECODE_REGISTER_##NAME[x]; \
+}
+DECODE_MAPPED(R_16)
+DECODE_MAPPED(R_8)
+
+/* Helper function for decodetree_trans_funcs_generated.c.inc */
+static int shift_left(DisasContext *ctx, int x, int n, int immno)
+{
+    int ret = x;
+    Insn *insn = ctx->insn;
+    if (!insn->extension_valid ||
+        insn->which_extended != immno) {
+        ret <<= n;
+    }
+    return ret;
+}
+
+/* Include the generated decoder for 32 bit insn */
+#include "decode_normal_generated.c.inc"
+#include "decode_hvx_generated.c.inc"
+
+/* Include the generated helpers for the decoder */
+#include "decodetree_trans_funcs_generated.c.inc"
+
 typedef struct {
     const struct DectreeTable *table_link;
     const struct DectreeTable *table_link_b;
@@ -550,7 +578,8 @@ apply_extender(Packet *pkt, int i, uint32_t extender)
     int immed_num;
     uint32_t base_immed;
 
-    immed_num = opcode_which_immediate_is_extended(pkt->insn[i].opcode);
+    immed_num = pkt->insn[i].which_extended;
+    g_assert(immed_num == opcode_which_immediate_is_extended(pkt->insn[i].opcode));
     base_immed = pkt->insn[i].immed[immed_num];
 
     pkt->insn[i].immed[immed_num] = extender | fZXTN(6, 32, base_immed);
@@ -762,12 +791,19 @@ decode_insns_tablewalk(Insn *insn, const DectreeTable *table,
 }
 
 static unsigned int
-decode_insns(Insn *insn, uint32_t encoding)
+decode_insns(DisasContext *ctx, Insn *insn, uint32_t encoding)
 {
     const DectreeTable *table;
     if (parse_bits(encoding) != 0) {
+        if (decode_normal(ctx, encoding) ||
+            decode_hvx(ctx, encoding)) {
+            insn->generate = opcode_genptr[insn->opcode];
+            insn->iclass = iclass_bits(encoding);
+            return 1;
+        }
         /* Start with PP table - 32 bit instructions */
         table = &dectree_table_DECODE_ROOT_32;
+        g_assert_not_reached();
     } else {
         /* start with EE table - duplex instructions */
         table = &dectree_table_DECODE_ROOT_EE;
@@ -916,8 +952,8 @@ decode_set_slot_number(Packet *pkt)
  * or number of words used on success
  */
 
-int decode_packet(int max_words, const uint32_t *words, Packet *pkt,
-                  bool disas_only)
+int decode_packet(DisasContext *ctx, int max_words, const uint32_t *words,
+                  Packet *pkt, bool disas_only)
 {
     int num_insns = 0;
     int words_read = 0;
@@ -930,9 +966,11 @@ int decode_packet(int max_words, const uint32_t *words, Packet *pkt,
     memset(pkt, 0, sizeof(*pkt));
     /* Try to build packet */
     while (!end_of_packet && (words_read < max_words)) {
+        Insn *insn = &pkt->insn[num_insns];
+        ctx->insn = insn;
         encoding32 = words[words_read];
         end_of_packet = is_packet_end(encoding32);
-        new_insns = decode_insns(&pkt->insn[num_insns], encoding32);
+        new_insns = decode_insns(ctx, insn, encoding32);
         g_assert(new_insns > 0);
         /*
          * If we saw an extender, mark next word extended so immediate
@@ -1006,9 +1044,13 @@ int decode_packet(int max_words, const uint32_t *words, Packet *pkt,
 int disassemble_hexagon(uint32_t *words, int nwords, bfd_vma pc,
                         GString *buf)
 {
+    DisasContext ctx;
     Packet pkt;
 
-    if (decode_packet(nwords, words, &pkt, true) > 0) {
+    memset(&ctx, 0, sizeof(DisasContext));
+    ctx.pkt = &pkt;
+
+    if (decode_packet(&ctx, nwords, words, &pkt, true) > 0) {
         snprint_a_pkt_disas(buf, &pkt, words, pc);
         return pkt.encod_pkt_size_in_bytes;
     } else {
diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c
index 666c061180..95579ae243 100644
--- a/target/hexagon/translate.c
+++ b/target/hexagon/translate.c
@@ -1033,10 +1033,10 @@ static void decode_and_translate_packet(CPUHexagonState *env, DisasContext *ctx)
         return;
     }
 
-    if (decode_packet(nwords, words, &pkt, false) > 0) {
+    ctx->pkt = &pkt;
+    if (decode_packet(ctx, nwords, words, &pkt, false) > 0) {
         pkt.pc = ctx->base.pc_next;
         HEX_DEBUG_PRINT_PKT(&pkt);
-        ctx->pkt = &pkt;
         gen_start_packet(ctx);
         for (i = 0; i < pkt.num_insns; i++) {
             ctx->insn = &pkt.insn[i];
diff --git a/target/hexagon/README b/target/hexagon/README
index 69b2ffe9bb..1b2a4d0eac 100644
--- a/target/hexagon/README
+++ b/target/hexagon/README
@@ -189,11 +189,16 @@ the packet, and we mark the implicit writes.  After the analysis is performed,
 we initialize the result register for each of the predicated assignments.
 
 In addition to instruction semantics, we use a generator to create the decode
-tree.  This generation is also a two step process.  The first step is to run
-target/hexagon/gen_dectree_import.c to produce
+tree.  This generation is a four step process.
+Step 1 is to run target/hexagon/gen_dectree_import.c to produce
     <BUILD_DIR>/target/hexagon/iset.py
-This file is imported by target/hexagon/dectree.py to produce
-    <BUILD_DIR>/target/hexagon/dectree_generated.h.inc
+Step 2 is to import iset.py into target/hexagon/gen_decodetree.py to produce
+    <BUILD_DIR>/target/hexagon/normal_decode_generated
+    <BUILD_DIR>/target/hexagon/hvx_decode_generated
+Step 3 is to process the above files with QEMU's decodetree.py to produce
+    <BUILD_DIR>/target/hexagon/decode_*_generated.c.inc
+Step 4 is to import iset.py into target/hexagon/gen_trans_funcs.py to produce
+    <BUILD_DIR>/target/hexagon/decodetree_trans_funcs_generated.c.inc
 
 *** Key Files ***
 
diff --git a/target/hexagon/gen_decodetree.py b/target/hexagon/gen_decodetree.py
new file mode 100755
index 0000000000..9634554142
--- /dev/null
+++ b/target/hexagon/gen_decodetree.py
@@ -0,0 +1,190 @@
+#!/usr/bin/env python3
+
+##
+##  Copyright (c) 2024 Taylor Simpson <ltaylorsimpson@gmail.com>
+##
+##  This program 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 2 of the License, or
+##  (at your option) any later version.
+##
+##  This program 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 program; if not, see <http://www.gnu.org/licenses/>.
+##
+
+import io
+import re
+
+import sys
+import textwrap
+import iset
+import hex_common
+
+encs = {
+    tag: "".join(reversed(iset.iset[tag]["enc"].replace(" ", "")))
+    for tag in iset.tags
+    if iset.iset[tag]["enc"] != "MISSING ENCODING"
+}
+
+
+regre = re.compile(r"((?<!DUP)[MNORCPQXSGVZA])([stuvwxyzdefg]+)([.]?[LlHh]?)(\d+S?)")
+immre = re.compile(r"[#]([rRsSuUm])(\d+)(?:[:](\d+))?")
+
+
+def ordered_unique(l):
+    return sorted(set(l), key=l.index)
+
+num_registers = {"R": 32, "V": 32}
+
+operand_letters = {
+    "P",
+    "i",
+    "I",
+    "r",
+    "s",
+    "t",
+    "u",
+    "v",
+    "w",
+    "x",
+    "y",
+    "z",
+    "d",
+    "e",
+    "f",
+    "g",
+}
+
+#
+# These instructions have unused operand letters in their encoding
+# They don't correspond to actual operands in the instruction semantics
+# We will mark them as ignored in QEMU decodetree
+#
+tags_with_unused_d_encoding = {
+    "R6_release_at_vi",
+    "R6_release_st_vi",
+    "S4_stored_rl_at_vi",
+    "S4_stored_rl_st_vi",
+    "S2_storew_rl_at_vi",
+    "S2_stored_rl_at_vi",
+    "S2_storew_rl_st_vi",
+}
+
+tags_with_unused_t_encoding = {
+    "R6_release_at_vi",
+    "R6_release_st_vi",
+}
+
+def skip_tag(tag, class_to_decode):
+    enc_class = iset.iset[tag]["enc_class"]
+    return enc_class != class_to_decode
+
+
+##
+## Generate the QEMU decodetree file for each instruction in class_to_decode
+##     For A2_add: Rd32=add(Rs32,Rt32)
+##     We produce:
+##     %A2_add_Rd   0:5
+##     %A2_add_Rs   16:5
+##     %A2_add_Rt   8:5
+##     @A2_add  11110011000.......-.....---..... Rd=%A2_add_Rd Rs=%A2_add_Rs Rt=%A2_add_Rt %PP
+##     A2_add   ..................-.....---..... @A2_add
+##
+def gen_decodetree_file(f, class_to_decode):
+    f.write(f"## DO NOT MODIFY - This file is generated by {sys.argv[0]}\n\n")
+    f.write("%PP\t14:2\n\n")
+    for tag in sorted(encs.keys(), key=iset.tags.index):
+        if skip_tag(tag, class_to_decode):
+            continue
+
+        enc = encs[tag]
+        enc_str = "".join(reversed(encs[tag]))
+        f.write(("#" * 80) + "\n"
+                f"## {tag}:\t{enc_str}\n"
+                "##\n")
+
+
+        regs = ordered_unique(regre.findall(iset.iset[tag]["syntax"]))
+        imms = ordered_unique(immre.findall(iset.iset[tag]["syntax"]))
+
+        # Write the field definitions for the registers
+        for regno, reg in enumerate(regs):
+            reg_type, reg_id, _, reg_enc_size = reg
+            reg_letter = reg_id[0]
+            reg_num_choices = int(reg_enc_size.rstrip("S"))
+            reg_mapping = reg_type + "".join("_" for letter in reg_id) + \
+                          reg_enc_size
+            reg_enc_fields = re.findall(reg_letter + "+", enc)
+
+            # Check for some errors
+            if len(reg_enc_fields) == 0:
+                raise Exception(f"{tag} missing register field!")
+            if len(reg_enc_fields) > 1:
+                raise Exception(f"{tag} has split register field!")
+            reg_enc_field = reg_enc_fields[0]
+            if 2 ** len(reg_enc_field) != reg_num_choices:
+                raise Exception(f"{tag} has incorrect register field width!")
+
+            f.write(f"%{tag}_{reg_type}{reg_id}\t"
+                    f"{enc.index(reg_enc_field)}:{len(reg_enc_field)}")
+
+            if (reg_type in num_registers and
+                reg_num_choices != num_registers[reg_type]):
+                f.write(f"\t!function=decode_mapped_reg_{reg_mapping}")
+            f.write("\n")
+
+        # Write the field definitions for the immediates
+        for imm in imms:
+            immno = 1 if imm[0].isupper() else 0
+            imm_type = imm[0]
+            imm_width = int(imm[1])
+            imm_letter = "i" if imm_type.islower() else "I"
+            fields = []
+            sign_mark = "s" if imm_type.lower() in "sr" else ""
+            for m in reversed(list(re.finditer(imm_letter + "+", enc))):
+                fields.append(f"{m.start()}:{sign_mark}{m.end() - m.start()}")
+                sign_mark = ""
+            field_str = " ".join(fields)
+            f.write(f"%{tag}_{imm_type}{imm_letter}\t{field_str}\n")
+
+        ## Handle instructions with unused encoding letters
+        ## Change the unused letters to ignored
+        if tag in tags_with_unused_d_encoding:
+            enc_str = enc_str.replace("d", "-")
+        if tag in tags_with_unused_t_encoding:
+            enc_str = enc_str.replace("t", "-")
+
+        # Replace the operand letters with .
+        for x in operand_letters:
+            enc_str = enc_str.replace(x, ".")
+
+        # Write the instruction format
+        f.write(f"@{tag}\t{enc_str}")
+        for reg in regs:
+            reg_type = reg[0]
+            reg_id = reg[1]
+            f.write(f" {reg_type}{reg_id}=%{tag}_{reg_type}{reg_id}")
+        for imm in imms:
+            imm_type = imm[0]
+            imm_letter = "i" if imm_type.islower() else "I"
+            f.write(f" {imm_type}{imm_letter}=%{tag}_{imm_type}{imm_letter}")
+
+        f.write(" %PP\n")
+
+         # Replace the 0s and 1s with .
+        enc_str = enc_str.replace("0", ".").replace("1", ".")
+
+        # Write the instruction pattern
+        f.write(f"{tag}\t{enc_str} @{tag}\n")
+
+
+if __name__ == "__main__":
+    hex_common.read_semantics_file(sys.argv[1])
+    class_to_decode = sys.argv[2]
+    with open(sys.argv[3], "w") as f:
+        gen_decodetree_file(f, class_to_decode)
diff --git a/target/hexagon/gen_trans_funcs.py b/target/hexagon/gen_trans_funcs.py
new file mode 100755
index 0000000000..c907131009
--- /dev/null
+++ b/target/hexagon/gen_trans_funcs.py
@@ -0,0 +1,132 @@
+#!/usr/bin/env python3
+
+##
+##  Copyright (c) 2024 Taylor Simpson <ltaylorsimpson@gmail.com>
+##
+##  This program 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 2 of the License, or
+##  (at your option) any later version.
+##
+##  This program 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 program; if not, see <http://www.gnu.org/licenses/>.
+##
+
+import io
+import re
+
+import sys
+import textwrap
+import iset
+import hex_common
+
+encs = {
+    tag: "".join(reversed(iset.iset[tag]["enc"].replace(" ", "")))
+    for tag in iset.tags
+    if iset.iset[tag]["enc"] != "MISSING ENCODING"
+}
+
+
+regre = re.compile(r"((?<!DUP)[MNORCPQXSGVZA])([stuvwxyzdefg]+)([.]?[LlHh]?)(\d+S?)")
+immre = re.compile(r"[#]([rRsSuUm])(\d+)(?:[:](\d+))?")
+
+
+def ordered_unique(l):
+    return sorted(set(l), key=l.index)
+
+
+def skip_tag(tag, classes):
+    enc_class = iset.iset[tag]["enc_class"]
+    return enc_class not in classes
+
+
+def code_fmt(txt):
+    return textwrap.indent(textwrap.dedent(txt), "    ")
+
+open_curly = "{"
+close_curly = "}"
+
+def mark_which_imm_extended(f, tag):
+    immre = re.compile(r"IMMEXT\([rRsSuUm]")
+    imm = immre.findall(hex_common.semdict[tag])
+    if len(imm) == 0:
+        # No extended operand found
+        return
+    letter = re.split("\\(", imm[0])[1]
+    f.write(code_fmt(f"""\
+        insn->which_extended = {0 if letter.islower() else 1};
+    """))
+
+##
+## Generate the QEMU decodetree trans_<tag> function for each instruction
+##     For A2_add: Rd32=add(Rs32,Rt32)
+##     We produce:
+##     static bool trans_A2_add(DisasContext *ctx, arg_A2_add *args)
+##     {
+##         Insn *insn = ctx->insn;
+##         insn->opcode = A2_add;
+##         insn->regno[0] = args->Rd;
+##         insn->regno[1] = args->Rs;
+##         insn->regno[2] = args->Rt;
+##         return true;
+##     }
+##
+def gen_trans_funcs(f, classes):
+    f.write(f"/* DO NOT MODIFY - This file is generated by {sys.argv[0]} */\n\n")
+    for tag in sorted(encs.keys(), key=iset.tags.index):
+        if skip_tag(tag, classes):
+            continue
+
+        regs = ordered_unique(regre.findall(iset.iset[tag]["syntax"]))
+        imms = ordered_unique(immre.findall(iset.iset[tag]["syntax"]))
+
+        f.write(textwrap.dedent(f"""\
+            static bool trans_{tag}(DisasContext *ctx, arg_{tag} *args)
+            {open_curly}
+                Insn *insn = ctx->insn;
+                insn->opcode = {tag};
+        """))
+
+        regno = 0
+        for reg in regs:
+            reg_type = reg[0]
+            reg_id = reg[1]
+            f.write(code_fmt(f"""\
+                insn->regno[{regno}] = args->{reg_type}{reg_id};
+            """))
+            regno += 1
+
+        if len(imms) != 0:
+            mark_which_imm_extended(f, tag)
+
+        for imm in imms:
+            imm_type = imm[0]
+            imm_letter = "i" if imm_type.islower() else "I"
+            immno = 0 if imm_type.islower() else 1
+            imm_shift = int(imm[2]) if imm[2] else 0
+            if imm_shift:
+                f.write(code_fmt(f"""\
+                    insn->immed[{immno}] =
+                        shift_left(ctx, args->{imm_type}{imm_letter},
+                                   {imm_shift}, {immno});
+                """))
+            else:
+                f.write(code_fmt(f"""\
+                    insn->immed[{immno}] = args->{imm_type}{imm_letter};
+                """))
+
+        f.write(textwrap.dedent(f"""\
+                return true;
+            {close_curly}
+        """))
+
+
+if __name__ == "__main__":
+    hex_common.read_semantics_file(sys.argv[1])
+    with open(sys.argv[2], "w") as f:
+        gen_trans_funcs(f, { "NORMAL", "EXT_mmvec" })
diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build
index da8e608d00..831bd5716a 100644
--- a/target/hexagon/meson.build
+++ b/target/hexagon/meson.build
@@ -133,6 +133,61 @@ dectree_generated = custom_target(
 )
 hexagon_ss.add(dectree_generated)
 
+#
+# Generate the input to the QEMU decodetree.py script
+#
+normal_decode_generated = custom_target(
+    'normal_decode_generated',
+    output: 'normal_decode_generated',
+    depends: [iset_py, semantics_generated],
+    env: {'PYTHONPATH': meson.current_build_dir()},
+    command: [python, files('gen_decodetree.py'), semantics_generated, 'NORMAL', '@OUTPUT@'],
+)
+hexagon_ss.add(normal_decode_generated)
+
+hvx_decode_generated = custom_target(
+    'hvx_decode_generated',
+    output: 'hvx_decode_generated',
+    depends: [iset_py, semantics_generated],
+    env: {'PYTHONPATH': meson.current_build_dir()},
+    command: [python, files('gen_decodetree.py'), semantics_generated, 'EXT_mmvec', '@OUTPUT@'],
+)
+hexagon_ss.add(hvx_decode_generated)
+
+#
+# Run the QEMU decodetree.py script to produce the instruction decoder
+#
+decodetree_py = meson.current_source_dir() / '../../scripts/decodetree.py'
+decode_normal_generated = custom_target(
+    'decode_normal_generated.c.inc',
+    output: 'decode_normal_generated.c.inc',
+    input: normal_decode_generated,
+    env: {'PYTHONPATH': meson.current_build_dir()},
+    command: [python, files(decodetree_py), normal_decode_generated, '--static-decode=decode_normal', '-o', '@OUTPUT@'],
+)
+hexagon_ss.add(decode_normal_generated)
+
+decode_hvx_generated = custom_target(
+    'decode_hvx_generated.c.inc',
+    output: 'decode_hvx_generated.c.inc',
+    input: hvx_decode_generated,
+    env: {'PYTHONPATH': meson.current_build_dir()},
+    command: [python, files(decodetree_py), hvx_decode_generated, '--static-decode=decode_hvx', '-o', '@OUTPUT@'],
+)
+hexagon_ss.add(decode_hvx_generated)
+
+#
+# Generate the trans_* functions that the decoder will use
+#
+decodetree_trans_funcs_generated = custom_target(
+    'decodetree_trans_funcs_generated.c.inc',
+    output: 'decodetree_trans_funcs_generated.c.inc',
+    depends: [iset_py, semantics_generated],
+    env: {'PYTHONPATH': meson.current_build_dir()},
+    command: [python, files('gen_trans_funcs.py'), semantics_generated, '@OUTPUT@'],
+)
+hexagon_ss.add(decodetree_trans_funcs_generated)
+
 hexagon_ss.add(files(
     'cpu.c',
     'translate.c',
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 2/3] Hexagon (target/hexagon) Use QEMU decodetree (16-bit instructions)
  2024-01-15 22:14 [PATCH v2 0/3] Hexagon (target/hexagon) Use QEMU decodetree Taylor Simpson
  2024-01-15 22:14 ` [PATCH v2 1/3] Hexagon (target/hexagon) Use QEMU decodetree (32-bit instructions) Taylor Simpson
@ 2024-01-15 22:14 ` Taylor Simpson
  2024-01-15 22:14 ` [PATCH v2 3/3] Hexagon (target/hexagon) Remove old dectree.py Taylor Simpson
  2024-01-16  5:45 ` [PATCH v2 0/3] Hexagon (target/hexagon) Use QEMU decodetree Brian Cain
  3 siblings, 0 replies; 8+ messages in thread
From: Taylor Simpson @ 2024-01-15 22:14 UTC (permalink / raw)
  To: qemu-devel
  Cc: bcain, quic_mathbern, sidneym, quic_mliebel, richard.henderson,
	philmd, ale, anjo, ltaylorsimpson

Section 10.3 of the Hexagon V73 Programmer's Reference Manual

A duplex is encoded as a 32-bit instruction with bits [15:14] set to 00.
The sub-instructions that comprise a duplex are encoded as 13-bit fields
in the duplex.

Create a decoder for each subinstruction class (a, l1, l2, s1, s2).

Extend gen_trans_funcs.py to handle all instructions rather than
filter by instruction class.

There is a g_assert_not_reached() in decode_insns() in decode.c to
verify we never try to use the old decoder on 16-bit instructions.

Signed-off-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Reviewed-by: Brian Cain <bcain@quicinc.com>
---
 target/hexagon/decode.c           | 85 +++++++++++++++++++++++++++++
 target/hexagon/README             |  1 +
 target/hexagon/gen_decodetree.py  | 12 ++++-
 target/hexagon/gen_trans_funcs.py | 12 +----
 target/hexagon/meson.build        | 90 +++++++++++++++++++++++++++++++
 5 files changed, 188 insertions(+), 12 deletions(-)

diff --git a/target/hexagon/decode.c b/target/hexagon/decode.c
index bddad1f75e..160b23a895 100644
--- a/target/hexagon/decode.c
+++ b/target/hexagon/decode.c
@@ -60,6 +60,7 @@ static int decode_mapped_reg_##NAME(DisasContext *ctx, int x) \
 }
 DECODE_MAPPED(R_16)
 DECODE_MAPPED(R_8)
+DECODE_MAPPED(R__8)
 
 /* Helper function for decodetree_trans_funcs_generated.c.inc */
 static int shift_left(DisasContext *ctx, int x, int n, int immno)
@@ -77,6 +78,13 @@ static int shift_left(DisasContext *ctx, int x, int n, int immno)
 #include "decode_normal_generated.c.inc"
 #include "decode_hvx_generated.c.inc"
 
+/* Include the generated decoder for 16 bit insn */
+#include "decode_subinsn_a_generated.c.inc"
+#include "decode_subinsn_l1_generated.c.inc"
+#include "decode_subinsn_l2_generated.c.inc"
+#include "decode_subinsn_s1_generated.c.inc"
+#include "decode_subinsn_s2_generated.c.inc"
+
 /* Include the generated helpers for the decoder */
 #include "decodetree_trans_funcs_generated.c.inc"
 
@@ -790,6 +798,63 @@ decode_insns_tablewalk(Insn *insn, const DectreeTable *table,
     }
 }
 
+/*
+ * Section 10.3 of the Hexagon V73 Programmer's Reference Manual
+ *
+ * A duplex is encoded as a 32-bit instruction with bits [15:14] set to 00.
+ * The sub-instructions that comprise a duplex are encoded as 13-bit fields
+ * in the duplex.
+ *
+ * Per table 10-4, the 4-bit duplex iclass is encoded in bits 31:29, 13
+ */
+static uint32_t get_duplex_iclass(uint32_t encoding)
+{
+    uint32_t iclass = extract32(encoding, 13, 1);
+    iclass = deposit32(iclass, 1, 3, extract32(encoding, 29, 3));
+    return iclass;
+}
+
+/*
+ * Per table 10-5, the duplex ICLASS field values that specify the group of
+ * each sub-instruction in a duplex
+ *
+ * This table points to the decode instruction for each entry in the table
+ */
+typedef bool (*subinsn_decode_func)(DisasContext *ctx, uint16_t insn);
+typedef struct {
+    subinsn_decode_func decode_slot0_subinsn;
+    subinsn_decode_func decode_slot1_subinsn;
+} subinsn_decode_groups;
+
+static const subinsn_decode_groups decode_groups[16] = {
+    [0x0] = { decode_subinsn_l1, decode_subinsn_l1 },
+    [0x1] = { decode_subinsn_l2, decode_subinsn_l1 },
+    [0x2] = { decode_subinsn_l2, decode_subinsn_l2 },
+    [0x3] = { decode_subinsn_a,  decode_subinsn_a },
+    [0x4] = { decode_subinsn_l1, decode_subinsn_a },
+    [0x5] = { decode_subinsn_l2, decode_subinsn_a },
+    [0x6] = { decode_subinsn_s1, decode_subinsn_a },
+    [0x7] = { decode_subinsn_s2, decode_subinsn_a },
+    [0x8] = { decode_subinsn_s1, decode_subinsn_l1 },
+    [0x9] = { decode_subinsn_s1, decode_subinsn_l2 },
+    [0xa] = { decode_subinsn_s1, decode_subinsn_s1 },
+    [0xb] = { decode_subinsn_s2, decode_subinsn_s1 },
+    [0xc] = { decode_subinsn_s2, decode_subinsn_l1 },
+    [0xd] = { decode_subinsn_s2, decode_subinsn_l2 },
+    [0xe] = { decode_subinsn_s2, decode_subinsn_s2 },
+    [0xf] = { NULL,              NULL },              /* Reserved */
+};
+
+static uint16_t get_slot0_subinsn(uint32_t encoding)
+{
+    return extract32(encoding, 0, 13);
+}
+
+static uint16_t get_slot1_subinsn(uint32_t encoding)
+{
+    return extract32(encoding, 16, 13);
+}
+
 static unsigned int
 decode_insns(DisasContext *ctx, Insn *insn, uint32_t encoding)
 {
@@ -805,8 +870,28 @@ decode_insns(DisasContext *ctx, Insn *insn, uint32_t encoding)
         table = &dectree_table_DECODE_ROOT_32;
         g_assert_not_reached();
     } else {
+        uint32_t iclass = get_duplex_iclass(encoding);
+        unsigned int slot0_subinsn = get_slot0_subinsn(encoding);
+        unsigned int slot1_subinsn = get_slot1_subinsn(encoding);
+        subinsn_decode_func decode_slot0_subinsn =
+            decode_groups[iclass].decode_slot0_subinsn;
+        subinsn_decode_func decode_slot1_subinsn =
+            decode_groups[iclass].decode_slot1_subinsn;
+
+        /* The slot1 subinsn needs to be in the packet first */
+        if (decode_slot1_subinsn(ctx, slot1_subinsn)) {
+            insn->generate = opcode_genptr[insn->opcode];
+            insn->iclass = iclass_bits(encoding);
+            ctx->insn = ++insn;
+            if (decode_slot0_subinsn(ctx, slot0_subinsn)) {
+                insn->generate = opcode_genptr[insn->opcode];
+                insn->iclass = iclass_bits(encoding);
+                return 2;
+            }
+        }
         /* start with EE table - duplex instructions */
         table = &dectree_table_DECODE_ROOT_EE;
+        g_assert_not_reached();
     }
     return decode_insns_tablewalk(insn, table, encoding);
 }
diff --git a/target/hexagon/README b/target/hexagon/README
index 1b2a4d0eac..746ebec378 100644
--- a/target/hexagon/README
+++ b/target/hexagon/README
@@ -195,6 +195,7 @@ Step 1 is to run target/hexagon/gen_dectree_import.c to produce
 Step 2 is to import iset.py into target/hexagon/gen_decodetree.py to produce
     <BUILD_DIR>/target/hexagon/normal_decode_generated
     <BUILD_DIR>/target/hexagon/hvx_decode_generated
+    <BUILD_DIR>/target/hexagon/subinsn_*_decode_generated
 Step 3 is to process the above files with QEMU's decodetree.py to produce
     <BUILD_DIR>/target/hexagon/decode_*_generated.c.inc
 Step 4 is to import iset.py into target/hexagon/gen_trans_funcs.py to produce
diff --git a/target/hexagon/gen_decodetree.py b/target/hexagon/gen_decodetree.py
index 9634554142..a4fcd622c5 100755
--- a/target/hexagon/gen_decodetree.py
+++ b/target/hexagon/gen_decodetree.py
@@ -96,8 +96,10 @@ def skip_tag(tag, class_to_decode):
 ##     A2_add   ..................-.....---..... @A2_add
 ##
 def gen_decodetree_file(f, class_to_decode):
+    is_subinsn = class_to_decode.startswith("SUBINSN_")
     f.write(f"## DO NOT MODIFY - This file is generated by {sys.argv[0]}\n\n")
-    f.write("%PP\t14:2\n\n")
+    if not is_subinsn:
+        f.write("%PP\t14:2\n\n")
     for tag in sorted(encs.keys(), key=iset.tags.index):
         if skip_tag(tag, class_to_decode):
             continue
@@ -108,6 +110,10 @@ def gen_decodetree_file(f, class_to_decode):
                 f"## {tag}:\t{enc_str}\n"
                 "##\n")
 
+        # The subinstructions come with a 13-bit encoding, but
+        # decodetree.py needs 16 bits
+        if is_subinsn:
+            enc_str = "---" + enc_str
 
         regs = ordered_unique(regre.findall(iset.iset[tag]["syntax"]))
         imms = ordered_unique(immre.findall(iset.iset[tag]["syntax"]))
@@ -174,7 +180,9 @@ def gen_decodetree_file(f, class_to_decode):
             imm_letter = "i" if imm_type.islower() else "I"
             f.write(f" {imm_type}{imm_letter}=%{tag}_{imm_type}{imm_letter}")
 
-        f.write(" %PP\n")
+        if not is_subinsn:
+            f.write(" %PP")
+        f.write("\n")
 
          # Replace the 0s and 1s with .
         enc_str = enc_str.replace("0", ".").replace("1", ".")
diff --git a/target/hexagon/gen_trans_funcs.py b/target/hexagon/gen_trans_funcs.py
index c907131009..53e844a44b 100755
--- a/target/hexagon/gen_trans_funcs.py
+++ b/target/hexagon/gen_trans_funcs.py
@@ -40,11 +40,6 @@ def ordered_unique(l):
     return sorted(set(l), key=l.index)
 
 
-def skip_tag(tag, classes):
-    enc_class = iset.iset[tag]["enc_class"]
-    return enc_class not in classes
-
-
 def code_fmt(txt):
     return textwrap.indent(textwrap.dedent(txt), "    ")
 
@@ -76,12 +71,9 @@ def mark_which_imm_extended(f, tag):
 ##         return true;
 ##     }
 ##
-def gen_trans_funcs(f, classes):
+def gen_trans_funcs(f):
     f.write(f"/* DO NOT MODIFY - This file is generated by {sys.argv[0]} */\n\n")
     for tag in sorted(encs.keys(), key=iset.tags.index):
-        if skip_tag(tag, classes):
-            continue
-
         regs = ordered_unique(regre.findall(iset.iset[tag]["syntax"]))
         imms = ordered_unique(immre.findall(iset.iset[tag]["syntax"]))
 
@@ -129,4 +121,4 @@ def gen_trans_funcs(f, classes):
 if __name__ == "__main__":
     hex_common.read_semantics_file(sys.argv[1])
     with open(sys.argv[2], "w") as f:
-        gen_trans_funcs(f, { "NORMAL", "EXT_mmvec" })
+        gen_trans_funcs(f)
diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build
index 831bd5716a..1bd1ebcba1 100644
--- a/target/hexagon/meson.build
+++ b/target/hexagon/meson.build
@@ -154,6 +154,51 @@ hvx_decode_generated = custom_target(
 )
 hexagon_ss.add(hvx_decode_generated)
 
+subinsn_a_decode_generated = custom_target(
+    'subinsn_a_decode_generated',
+    output: 'subinsn_a_decode_generated',
+    depends: [iset_py, semantics_generated],
+    env: {'PYTHONPATH': meson.current_build_dir()},
+    command: [python, files('gen_decodetree.py'), semantics_generated, 'SUBINSN_A', '@OUTPUT@'],
+)
+hexagon_ss.add(subinsn_a_decode_generated)
+
+subinsn_l1_decode_generated = custom_target(
+    'subinsn_l1_decode_generated',
+    output: 'subinsn_l1_decode_generated',
+    depends: [iset_py, semantics_generated],
+    env: {'PYTHONPATH': meson.current_build_dir()},
+    command: [python, files('gen_decodetree.py'), semantics_generated, 'SUBINSN_L1', '@OUTPUT@'],
+)
+hexagon_ss.add(subinsn_l1_decode_generated)
+
+subinsn_l2_decode_generated = custom_target(
+    'subinsn_l2_decode_generated',
+    output: 'subinsn_l2_decode_generated',
+    depends: [iset_py, semantics_generated],
+    env: {'PYTHONPATH': meson.current_build_dir()},
+    command: [python, files('gen_decodetree.py'), semantics_generated, 'SUBINSN_L2', '@OUTPUT@'],
+)
+hexagon_ss.add(subinsn_l2_decode_generated)
+
+subinsn_s1_decode_generated = custom_target(
+    'subinsn_s1_decode_generated',
+    output: 'subinsn_s1_decode_generated',
+    depends: [iset_py, semantics_generated],
+    env: {'PYTHONPATH': meson.current_build_dir()},
+    command: [python, files('gen_decodetree.py'), semantics_generated, 'SUBINSN_S1', '@OUTPUT@'],
+)
+hexagon_ss.add(subinsn_s1_decode_generated)
+
+subinsn_s2_decode_generated = custom_target(
+    'subinsn_s2_decode_generated',
+    output: 'subinsn_s2_decode_generated',
+    depends: [iset_py, semantics_generated],
+    env: {'PYTHONPATH': meson.current_build_dir()},
+    command: [python, files('gen_decodetree.py'), semantics_generated, 'SUBINSN_S2', '@OUTPUT@'],
+)
+hexagon_ss.add(subinsn_s2_decode_generated)
+
 #
 # Run the QEMU decodetree.py script to produce the instruction decoder
 #
@@ -176,6 +221,51 @@ decode_hvx_generated = custom_target(
 )
 hexagon_ss.add(decode_hvx_generated)
 
+decode_subinsn_a_generated = custom_target(
+    'decode_subinsn_a_generated.c.inc',
+    output: 'decode_subinsn_a_generated.c.inc',
+    input: subinsn_a_decode_generated,
+    env: {'PYTHONPATH': meson.current_build_dir()},
+    command: [python, files(decodetree_py), subinsn_a_decode_generated, ['--static-decode=decode_subinsn_a', '--insnwidth=16'], '-o', '@OUTPUT@'],
+)
+hexagon_ss.add(decode_subinsn_a_generated)
+
+decode_subinsn_l1_generated = custom_target(
+    'decode_subinsn_l1_generated.c.inc',
+    output: 'decode_subinsn_l1_generated.c.inc',
+    input: subinsn_l1_decode_generated,
+    env: {'PYTHONPATH': meson.current_build_dir()},
+    command: [python, files(decodetree_py), subinsn_l1_decode_generated, ['--static-decode=decode_subinsn_l1', '--insnwidth=16'], '-o', '@OUTPUT@'],
+)
+hexagon_ss.add(decode_subinsn_l1_generated)
+
+decode_subinsn_l2_generated = custom_target(
+    'decode_subinsn_l2_generated.c.inc',
+    output: 'decode_subinsn_l2_generated.c.inc',
+    input: subinsn_l2_decode_generated,
+    env: {'PYTHONPATH': meson.current_build_dir()},
+    command: [python, files(decodetree_py), subinsn_l2_decode_generated, ['--static-decode=decode_subinsn_l2', '--insnwidth=16'], '-o', '@OUTPUT@'],
+)
+hexagon_ss.add(decode_subinsn_l2_generated)
+
+decode_subinsn_s1_generated = custom_target(
+    'decode_subinsn_s1_generated.c.inc',
+    output: 'decode_subinsn_s1_generated.c.inc',
+    input: subinsn_s1_decode_generated,
+    env: {'PYTHONPATH': meson.current_build_dir()},
+    command: [python, files(decodetree_py), subinsn_s1_decode_generated, ['--static-decode=decode_subinsn_s1', '--insnwidth=16'], '-o', '@OUTPUT@'],
+)
+hexagon_ss.add(decode_subinsn_s1_generated)
+
+decode_subinsn_s2_generated = custom_target(
+    'decode_subinsn_s2_generated.c.inc',
+    output: 'decode_subinsn_s2_generated.c.inc',
+    input: subinsn_s2_decode_generated,
+    env: {'PYTHONPATH': meson.current_build_dir()},
+    command: [python, files(decodetree_py), subinsn_s2_decode_generated, ['--static-decode=decode_subinsn_s2', '--insnwidth=16'], '-o', '@OUTPUT@'],
+)
+hexagon_ss.add(decode_subinsn_s2_generated)
+
 #
 # Generate the trans_* functions that the decoder will use
 #
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 3/3] Hexagon (target/hexagon) Remove old dectree.py
  2024-01-15 22:14 [PATCH v2 0/3] Hexagon (target/hexagon) Use QEMU decodetree Taylor Simpson
  2024-01-15 22:14 ` [PATCH v2 1/3] Hexagon (target/hexagon) Use QEMU decodetree (32-bit instructions) Taylor Simpson
  2024-01-15 22:14 ` [PATCH v2 2/3] Hexagon (target/hexagon) Use QEMU decodetree (16-bit instructions) Taylor Simpson
@ 2024-01-15 22:14 ` Taylor Simpson
  2024-01-16  5:45 ` [PATCH v2 0/3] Hexagon (target/hexagon) Use QEMU decodetree Brian Cain
  3 siblings, 0 replies; 8+ messages in thread
From: Taylor Simpson @ 2024-01-15 22:14 UTC (permalink / raw)
  To: qemu-devel
  Cc: bcain, quic_mathbern, sidneym, quic_mliebel, richard.henderson,
	philmd, ale, anjo, ltaylorsimpson

Now that we are using QEMU decodetree.py, remove the old decoder

Signed-off-by: Taylor Simpson <ltaylorsimpson@gmail.com>
Reviewed-by: Brian Cain <bcain@quicinc.com>
---
 target/hexagon/opcodes.h            |   2 -
 target/hexagon/decode.c             | 344 ------------------------
 target/hexagon/gen_dectree_import.c |  49 ----
 target/hexagon/opcodes.c            |  29 --
 target/hexagon/dectree.py           | 403 ----------------------------
 target/hexagon/meson.build          |  12 -
 6 files changed, 839 deletions(-)
 delete mode 100755 target/hexagon/dectree.py

diff --git a/target/hexagon/opcodes.h b/target/hexagon/opcodes.h
index 6e90e00fe2..fa7e321950 100644
--- a/target/hexagon/opcodes.h
+++ b/target/hexagon/opcodes.h
@@ -53,6 +53,4 @@ extern const OpcodeEncoding opcode_encodings[XX_LAST_OPCODE];
 
 void opcode_init(void);
 
-int opcode_which_immediate_is_extended(Opcode opcode);
-
 #endif
diff --git a/target/hexagon/decode.c b/target/hexagon/decode.c
index 160b23a895..a40210ca1e 100644
--- a/target/hexagon/decode.c
+++ b/target/hexagon/decode.c
@@ -88,175 +88,6 @@ static int shift_left(DisasContext *ctx, int x, int n, int immno)
 /* Include the generated helpers for the decoder */
 #include "decodetree_trans_funcs_generated.c.inc"
 
-typedef struct {
-    const struct DectreeTable *table_link;
-    const struct DectreeTable *table_link_b;
-    Opcode opcode;
-    enum {
-        DECTREE_ENTRY_INVALID,
-        DECTREE_TABLE_LINK,
-        DECTREE_SUBINSNS,
-        DECTREE_EXTSPACE,
-        DECTREE_TERMINAL
-    } type;
-} DectreeEntry;
-
-typedef struct DectreeTable {
-    unsigned int (*lookup_function)(int startbit, int width, uint32_t opcode);
-    unsigned int size;
-    unsigned int startbit;
-    unsigned int width;
-    const DectreeEntry table[];
-} DectreeTable;
-
-#define DECODE_NEW_TABLE(TAG, SIZE, WHATNOT) \
-    static const DectreeTable dectree_table_##TAG;
-#define TABLE_LINK(TABLE)                     /* NOTHING */
-#define TERMINAL(TAG, ENC)                    /* NOTHING */
-#define SUBINSNS(TAG, CLASSA, CLASSB, ENC)    /* NOTHING */
-#define EXTSPACE(TAG, ENC)                    /* NOTHING */
-#define INVALID()                             /* NOTHING */
-#define DECODE_END_TABLE(...)                 /* NOTHING */
-#define DECODE_MATCH_INFO(...)                /* NOTHING */
-#define DECODE_LEGACY_MATCH_INFO(...)         /* NOTHING */
-#define DECODE_OPINFO(...)                    /* NOTHING */
-
-#include "dectree_generated.h.inc"
-
-#undef DECODE_OPINFO
-#undef DECODE_MATCH_INFO
-#undef DECODE_LEGACY_MATCH_INFO
-#undef DECODE_END_TABLE
-#undef INVALID
-#undef TERMINAL
-#undef SUBINSNS
-#undef EXTSPACE
-#undef TABLE_LINK
-#undef DECODE_NEW_TABLE
-#undef DECODE_SEPARATOR_BITS
-
-#define DECODE_SEPARATOR_BITS(START, WIDTH) NULL, START, WIDTH
-#define DECODE_NEW_TABLE_HELPER(TAG, SIZE, FN, START, WIDTH) \
-    static const DectreeTable dectree_table_##TAG = { \
-        .size = SIZE, \
-        .lookup_function = FN, \
-        .startbit = START, \
-        .width = WIDTH, \
-        .table = {
-#define DECODE_NEW_TABLE(TAG, SIZE, WHATNOT) \
-    DECODE_NEW_TABLE_HELPER(TAG, SIZE, WHATNOT)
-
-#define TABLE_LINK(TABLE) \
-    { .type = DECTREE_TABLE_LINK, .table_link = &dectree_table_##TABLE },
-#define TERMINAL(TAG, ENC) \
-    { .type = DECTREE_TERMINAL, .opcode = TAG  },
-#define SUBINSNS(TAG, CLASSA, CLASSB, ENC) \
-    { \
-        .type = DECTREE_SUBINSNS, \
-        .table_link = &dectree_table_DECODE_SUBINSN_##CLASSA, \
-        .table_link_b = &dectree_table_DECODE_SUBINSN_##CLASSB \
-    },
-#define EXTSPACE(TAG, ENC) { .type = DECTREE_EXTSPACE },
-#define INVALID() { .type = DECTREE_ENTRY_INVALID, .opcode = XX_LAST_OPCODE },
-
-#define DECODE_END_TABLE(...) } };
-
-#define DECODE_MATCH_INFO(...)                /* NOTHING */
-#define DECODE_LEGACY_MATCH_INFO(...)         /* NOTHING */
-#define DECODE_OPINFO(...)                    /* NOTHING */
-
-#include "dectree_generated.h.inc"
-
-#undef DECODE_OPINFO
-#undef DECODE_MATCH_INFO
-#undef DECODE_LEGACY_MATCH_INFO
-#undef DECODE_END_TABLE
-#undef INVALID
-#undef TERMINAL
-#undef SUBINSNS
-#undef EXTSPACE
-#undef TABLE_LINK
-#undef DECODE_NEW_TABLE
-#undef DECODE_NEW_TABLE_HELPER
-#undef DECODE_SEPARATOR_BITS
-
-static const DectreeTable dectree_table_DECODE_EXT_EXT_noext = {
-    .size = 1, .lookup_function = NULL, .startbit = 0, .width = 0,
-    .table = {
-        { .type = DECTREE_ENTRY_INVALID, .opcode = XX_LAST_OPCODE },
-    }
-};
-
-static const DectreeTable *ext_trees[XX_LAST_EXT_IDX];
-
-static void decode_ext_init(void)
-{
-    int i;
-    for (i = EXT_IDX_noext; i < EXT_IDX_noext_AFTER; i++) {
-        ext_trees[i] = &dectree_table_DECODE_EXT_EXT_noext;
-    }
-    for (i = EXT_IDX_mmvec; i < EXT_IDX_mmvec_AFTER; i++) {
-        ext_trees[i] = &dectree_table_DECODE_EXT_EXT_mmvec;
-    }
-}
-
-typedef struct {
-    uint32_t mask;
-    uint32_t match;
-} DecodeITableEntry;
-
-#define DECODE_NEW_TABLE(TAG, SIZE, WHATNOT)  /* NOTHING */
-#define TABLE_LINK(TABLE)                     /* NOTHING */
-#define TERMINAL(TAG, ENC)                    /* NOTHING */
-#define SUBINSNS(TAG, CLASSA, CLASSB, ENC)    /* NOTHING */
-#define EXTSPACE(TAG, ENC)                    /* NOTHING */
-#define INVALID()                             /* NOTHING */
-#define DECODE_END_TABLE(...)                 /* NOTHING */
-#define DECODE_OPINFO(...)                    /* NOTHING */
-
-#define DECODE_MATCH_INFO_NORMAL(TAG, MASK, MATCH) \
-    [TAG] = { \
-        .mask = MASK, \
-        .match = MATCH, \
-    },
-
-#define DECODE_MATCH_INFO_NULL(TAG, MASK, MATCH) \
-    [TAG] = { .match = ~0 },
-
-#define DECODE_MATCH_INFO(...) DECODE_MATCH_INFO_NORMAL(__VA_ARGS__)
-#define DECODE_LEGACY_MATCH_INFO(...) /* NOTHING */
-
-static const DecodeITableEntry decode_itable[XX_LAST_OPCODE] = {
-#include "dectree_generated.h.inc"
-};
-
-#undef DECODE_MATCH_INFO
-#define DECODE_MATCH_INFO(...) DECODE_MATCH_INFO_NULL(__VA_ARGS__)
-
-#undef DECODE_LEGACY_MATCH_INFO
-#define DECODE_LEGACY_MATCH_INFO(...) DECODE_MATCH_INFO_NORMAL(__VA_ARGS__)
-
-static const DecodeITableEntry decode_legacy_itable[XX_LAST_OPCODE] = {
-#include "dectree_generated.h.inc"
-};
-
-#undef DECODE_OPINFO
-#undef DECODE_MATCH_INFO
-#undef DECODE_LEGACY_MATCH_INFO
-#undef DECODE_END_TABLE
-#undef INVALID
-#undef TERMINAL
-#undef SUBINSNS
-#undef EXTSPACE
-#undef TABLE_LINK
-#undef DECODE_NEW_TABLE
-#undef DECODE_SEPARATOR_BITS
-
-void decode_init(void)
-{
-    decode_ext_init();
-}
-
 void decode_send_insn_to(Packet *packet, int start, int newloc)
 {
     Insn tmpinsn;
@@ -587,7 +418,6 @@ apply_extender(Packet *pkt, int i, uint32_t extender)
     uint32_t base_immed;
 
     immed_num = pkt->insn[i].which_extended;
-    g_assert(immed_num == opcode_which_immediate_is_extended(pkt->insn[i].opcode));
     base_immed = pkt->insn[i].immed[immed_num];
 
     pkt->insn[i].immed[immed_num] = extender | fZXTN(6, 32, base_immed);
@@ -630,174 +460,6 @@ static SlotMask get_valid_slots(const Packet *pkt, unsigned int slot)
     }
 }
 
-#define DECODE_NEW_TABLE(TAG, SIZE, WHATNOT)     /* NOTHING */
-#define TABLE_LINK(TABLE)                        /* NOTHING */
-#define TERMINAL(TAG, ENC)                       /* NOTHING */
-#define SUBINSNS(TAG, CLASSA, CLASSB, ENC)       /* NOTHING */
-#define EXTSPACE(TAG, ENC)                       /* NOTHING */
-#define INVALID()                                /* NOTHING */
-#define DECODE_END_TABLE(...)                    /* NOTHING */
-#define DECODE_MATCH_INFO(...)                   /* NOTHING */
-#define DECODE_LEGACY_MATCH_INFO(...)            /* NOTHING */
-
-#define DECODE_REG(REGNO, WIDTH, STARTBIT) \
-    insn->regno[REGNO] = ((encoding >> STARTBIT) & ((1 << WIDTH) - 1));
-
-#define DECODE_IMPL_REG(REGNO, VAL) \
-    insn->regno[REGNO] = VAL;
-
-#define DECODE_IMM(IMMNO, WIDTH, STARTBIT, VALSTART) \
-    insn->immed[IMMNO] |= (((encoding >> STARTBIT) & ((1 << WIDTH) - 1))) << \
-                          (VALSTART);
-
-#define DECODE_IMM_SXT(IMMNO, WIDTH) \
-    insn->immed[IMMNO] = ((((int32_t)insn->immed[IMMNO]) << (32 - WIDTH)) >> \
-                          (32 - WIDTH));
-
-#define DECODE_IMM_NEG(IMMNO, WIDTH) \
-    insn->immed[IMMNO] = -insn->immed[IMMNO];
-
-#define DECODE_IMM_SHIFT(IMMNO, SHAMT)                                 \
-    if ((!insn->extension_valid) || \
-        (insn->which_extended != IMMNO)) { \
-        insn->immed[IMMNO] <<= SHAMT; \
-    }
-
-#define DECODE_OPINFO(TAG, BEH) \
-    case TAG: \
-        { BEH  } \
-        break; \
-
-/*
- * Fill in the operands of the instruction
- * dectree_generated.h.inc has a DECODE_OPINFO entry for each opcode
- * For example,
- *     DECODE_OPINFO(A2_addi,
- *          DECODE_REG(0,5,0)
- *          DECODE_REG(1,5,16)
- *          DECODE_IMM(0,7,21,9)
- *          DECODE_IMM(0,9,5,0)
- *          DECODE_IMM_SXT(0,16)
- * with the macros defined above, we'll fill in a switch statement
- * where each case is an opcode tag.
- */
-static void
-decode_op(Insn *insn, Opcode tag, uint32_t encoding)
-{
-    insn->immed[0] = 0;
-    insn->immed[1] = 0;
-    insn->opcode = tag;
-    if (insn->extension_valid) {
-        insn->which_extended = opcode_which_immediate_is_extended(tag);
-    }
-
-    switch (tag) {
-#include "dectree_generated.h.inc"
-    default:
-        break;
-    }
-
-    insn->generate = opcode_genptr[tag];
-
-    insn->iclass = iclass_bits(encoding);
-}
-
-#undef DECODE_REG
-#undef DECODE_IMPL_REG
-#undef DECODE_IMM
-#undef DECODE_IMM_SHIFT
-#undef DECODE_OPINFO
-#undef DECODE_MATCH_INFO
-#undef DECODE_LEGACY_MATCH_INFO
-#undef DECODE_END_TABLE
-#undef INVALID
-#undef TERMINAL
-#undef SUBINSNS
-#undef EXTSPACE
-#undef TABLE_LINK
-#undef DECODE_NEW_TABLE
-#undef DECODE_SEPARATOR_BITS
-
-static unsigned int
-decode_subinsn_tablewalk(Insn *insn, const DectreeTable *table,
-                         uint32_t encoding)
-{
-    unsigned int i;
-    Opcode opc;
-    if (table->lookup_function) {
-        i = table->lookup_function(table->startbit, table->width, encoding);
-    } else {
-        i = extract32(encoding, table->startbit, table->width);
-    }
-    if (table->table[i].type == DECTREE_TABLE_LINK) {
-        return decode_subinsn_tablewalk(insn, table->table[i].table_link,
-                                        encoding);
-    } else if (table->table[i].type == DECTREE_TERMINAL) {
-        opc = table->table[i].opcode;
-        if ((encoding & decode_itable[opc].mask) != decode_itable[opc].match) {
-            return 0;
-        }
-        decode_op(insn, opc, encoding);
-        return 1;
-    } else {
-        return 0;
-    }
-}
-
-static unsigned int get_insn_a(uint32_t encoding)
-{
-    return extract32(encoding, 0, 13);
-}
-
-static unsigned int get_insn_b(uint32_t encoding)
-{
-    return extract32(encoding, 16, 13);
-}
-
-static unsigned int
-decode_insns_tablewalk(Insn *insn, const DectreeTable *table,
-                       uint32_t encoding)
-{
-    unsigned int i;
-    unsigned int a, b;
-    Opcode opc;
-    if (table->lookup_function) {
-        i = table->lookup_function(table->startbit, table->width, encoding);
-    } else {
-        i = extract32(encoding, table->startbit, table->width);
-    }
-    if (table->table[i].type == DECTREE_TABLE_LINK) {
-        return decode_insns_tablewalk(insn, table->table[i].table_link,
-                                      encoding);
-    } else if (table->table[i].type == DECTREE_SUBINSNS) {
-        a = get_insn_a(encoding);
-        b = get_insn_b(encoding);
-        b = decode_subinsn_tablewalk(insn, table->table[i].table_link_b, b);
-        a = decode_subinsn_tablewalk(insn + 1, table->table[i].table_link, a);
-        if ((a == 0) || (b == 0)) {
-            return 0;
-        }
-        return 2;
-    } else if (table->table[i].type == DECTREE_TERMINAL) {
-        opc = table->table[i].opcode;
-        if ((encoding & decode_itable[opc].mask) != decode_itable[opc].match) {
-            if ((encoding & decode_legacy_itable[opc].mask) !=
-                decode_legacy_itable[opc].match) {
-                return 0;
-            }
-        }
-        decode_op(insn, opc, encoding);
-        return 1;
-    } else if (table->table[i].type == DECTREE_EXTSPACE) {
-        /*
-         * For now, HVX will be the only coproc
-         */
-        return decode_insns_tablewalk(insn, ext_trees[EXT_IDX_mmvec], encoding);
-    } else {
-        return 0;
-    }
-}
-
 /*
  * Section 10.3 of the Hexagon V73 Programmer's Reference Manual
  *
@@ -858,7 +520,6 @@ static uint16_t get_slot1_subinsn(uint32_t encoding)
 static unsigned int
 decode_insns(DisasContext *ctx, Insn *insn, uint32_t encoding)
 {
-    const DectreeTable *table;
     if (parse_bits(encoding) != 0) {
         if (decode_normal(ctx, encoding) ||
             decode_hvx(ctx, encoding)) {
@@ -866,8 +527,6 @@ decode_insns(DisasContext *ctx, Insn *insn, uint32_t encoding)
             insn->iclass = iclass_bits(encoding);
             return 1;
         }
-        /* Start with PP table - 32 bit instructions */
-        table = &dectree_table_DECODE_ROOT_32;
         g_assert_not_reached();
     } else {
         uint32_t iclass = get_duplex_iclass(encoding);
@@ -889,11 +548,8 @@ decode_insns(DisasContext *ctx, Insn *insn, uint32_t encoding)
                 return 2;
             }
         }
-        /* start with EE table - duplex instructions */
-        table = &dectree_table_DECODE_ROOT_EE;
         g_assert_not_reached();
     }
-    return decode_insns_tablewalk(insn, table, encoding);
 }
 
 static void decode_add_endloop_insn(Insn *insn, int loopnum)
diff --git a/target/hexagon/gen_dectree_import.c b/target/hexagon/gen_dectree_import.c
index ee354677fd..87f20c14f1 100644
--- a/target/hexagon/gen_dectree_import.c
+++ b/target/hexagon/gen_dectree_import.c
@@ -56,24 +56,6 @@ const char * const opcode_syntax[XX_LAST_OPCODE] = {
 #undef EXTINSN
 };
 
-const char * const opcode_rregs[] = {
-#define REGINFO(TAG, REGINFO, RREGS, WREGS) RREGS,
-#define IMMINFO(TAG, SIGN, SIZE, SHAMT, SIGN2, SIZE2, SHAMT2)  /* nothing */
-#include "op_regs_generated.h.inc"
-    NULL
-#undef REGINFO
-#undef IMMINFO
-};
-
-const char * const opcode_wregs[] = {
-#define REGINFO(TAG, REGINFO, RREGS, WREGS) WREGS,
-#define IMMINFO(TAG, SIGN, SIZE, SHAMT, SIGN2, SIZE2, SHAMT2)  /* nothing */
-#include "op_regs_generated.h.inc"
-    NULL
-#undef REGINFO
-#undef IMMINFO
-};
-
 const OpcodeEncoding opcode_encodings[] = {
 #define DEF_ENC32(TAG, ENCSTR) \
     [TAG] = { .encoding = ENCSTR },
@@ -130,8 +112,6 @@ static void gen_iset_table(FILE *out)
         fprintf(out, "\t\'%s\' : {\n", opcode_names[i]);
         fprintf(out, "\t\t\'tag\' : \'%s\',\n", opcode_names[i]);
         fprintf(out, "\t\t\'syntax\' : \'%s\',\n", opcode_syntax[i]);
-        fprintf(out, "\t\t\'rregs\' : \'%s\',\n", opcode_rregs[i]);
-        fprintf(out, "\t\t\'wregs\' : \'%s\',\n", opcode_wregs[i]);
         fprintf(out, "\t\t\'enc\' : \'%s\',\n", get_opcode_enc(i));
         fprintf(out, "\t\t\'enc_class\' : \'%s\',\n", get_opcode_enc_class(i));
         fprintf(out, "\t},\n");
@@ -150,33 +130,6 @@ static void gen_tags_list(FILE *out)
     fprintf(out, "];\n\n");
 }
 
-static void gen_enc_ext_spaces_table(FILE *out)
-{
-    fprintf(out, "enc_ext_spaces = {\n");
-#define DEF_EXT_SPACE(SPACEID, ENCSTR) \
-    fprintf(out, "\t\'%s\' : \'%s\',\n", #SPACEID, ENCSTR);
-#include "imported/encode.def"
-#undef DEF_EXT_SPACE
-    fprintf(out, "};\n\n");
-}
-
-static void gen_subinsn_groupings_table(FILE *out)
-{
-    fprintf(out, "subinsn_groupings = {\n");
-#define DEF_PACKED32(TAG, TYPEA, TYPEB, ENCSTR) \
-    do { \
-        fprintf(out, "\t\'%s\' : {\n", #TAG); \
-        fprintf(out, "\t\t\'name\' : \'%s\',\n", #TAG); \
-        fprintf(out, "\t\t\'class_a\' : \'%s\',\n", #TYPEA); \
-        fprintf(out, "\t\t\'class_b\' : \'%s\',\n", #TYPEB); \
-        fprintf(out, "\t\t\'enc\' : \'%s\',\n", ENCSTR); \
-        fprintf(out, "\t},\n"); \
-    } while (0);
-#include "imported/encode.def"
-#undef DEF_PACKED32
-    fprintf(out, "};\n\n");
-}
-
 int main(int argc, char *argv[])
 {
     FILE *outfile;
@@ -193,8 +146,6 @@ int main(int argc, char *argv[])
 
     gen_iset_table(outfile);
     gen_tags_list(outfile);
-    gen_enc_ext_spaces_table(outfile);
-    gen_subinsn_groupings_table(outfile);
 
     fclose(outfile);
     return 0;
diff --git a/target/hexagon/opcodes.c b/target/hexagon/opcodes.c
index 35d790cdd5..1f7f3def38 100644
--- a/target/hexagon/opcodes.c
+++ b/target/hexagon/opcodes.c
@@ -111,33 +111,4 @@ void opcode_init(void)
 #include "op_attribs_generated.h.inc"
 #undef OP_ATTRIB
 #undef ATTRIBS
-
-    decode_init();
-}
-
-
-#define NEEDLE "IMMEXT("
-
-int opcode_which_immediate_is_extended(Opcode opcode)
-{
-    const char *p;
-
-    g_assert(opcode < XX_LAST_OPCODE);
-    g_assert(GET_ATTRIB(opcode, A_EXTENDABLE));
-
-    p = opcode_short_semantics[opcode];
-    p = strstr(p, NEEDLE);
-    g_assert(p);
-    p += strlen(NEEDLE);
-    while (isspace(*p)) {
-        p++;
-    }
-    /* lower is always imm 0, upper always imm 1. */
-    if (islower(*p)) {
-        return 0;
-    } else if (isupper(*p)) {
-        return 1;
-    } else {
-        g_assert_not_reached();
-    }
 }
diff --git a/target/hexagon/dectree.py b/target/hexagon/dectree.py
deleted file mode 100755
index 3b32948a04..0000000000
--- a/target/hexagon/dectree.py
+++ /dev/null
@@ -1,403 +0,0 @@
-#!/usr/bin/env python3
-
-##
-##  Copyright(c) 2019-2023 Qualcomm Innovation Center, Inc. All Rights Reserved.
-##
-##  This program 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 2 of the License, or
-##  (at your option) any later version.
-##
-##  This program 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 program; if not, see <http://www.gnu.org/licenses/>.
-##
-
-import io
-import re
-
-import sys
-import iset
-
-encs = {
-    tag: "".join(reversed(iset.iset[tag]["enc"].replace(" ", "")))
-    for tag in iset.tags
-    if iset.iset[tag]["enc"] != "MISSING ENCODING"
-}
-
-enc_classes = set([iset.iset[tag]["enc_class"] for tag in encs.keys()])
-subinsn_enc_classes = set(
-    [enc_class for enc_class in enc_classes if enc_class.startswith("SUBINSN_")]
-)
-ext_enc_classes = set(
-    [
-        enc_class
-        for enc_class in enc_classes
-        if enc_class not in ("NORMAL", "16BIT") and not enc_class.startswith("SUBINSN_")
-    ]
-)
-
-try:
-    subinsn_groupings = iset.subinsn_groupings
-except AttributeError:
-    subinsn_groupings = {}
-
-for tag, subinsn_grouping in subinsn_groupings.items():
-    encs[tag] = "".join(reversed(subinsn_grouping["enc"].replace(" ", "")))
-
-dectree_normal = {"leaves": set()}
-dectree_16bit = {"leaves": set()}
-dectree_subinsn_groupings = {"leaves": set()}
-dectree_subinsns = {name: {"leaves": set()} for name in subinsn_enc_classes}
-dectree_extensions = {name: {"leaves": set()} for name in ext_enc_classes}
-
-for tag in encs.keys():
-    if tag in subinsn_groupings:
-        dectree_subinsn_groupings["leaves"].add(tag)
-        continue
-    enc_class = iset.iset[tag]["enc_class"]
-    if enc_class.startswith("SUBINSN_"):
-        if len(encs[tag]) != 32:
-            encs[tag] = encs[tag] + "0" * (32 - len(encs[tag]))
-        dectree_subinsns[enc_class]["leaves"].add(tag)
-    elif enc_class == "16BIT":
-        if len(encs[tag]) != 16:
-            raise Exception(
-                'Tag "{}" has enc_class "{}" and not an encoding '
-                + "width of 16 bits!".format(tag, enc_class)
-            )
-        dectree_16bit["leaves"].add(tag)
-    else:
-        if len(encs[tag]) != 32:
-            raise Exception(
-                'Tag "{}" has enc_class "{}" and not an encoding '
-                + "width of 32 bits!".format(tag, enc_class)
-            )
-        if enc_class == "NORMAL":
-            dectree_normal["leaves"].add(tag)
-        else:
-            dectree_extensions[enc_class]["leaves"].add(tag)
-
-faketags = set()
-for tag, enc in iset.enc_ext_spaces.items():
-    faketags.add(tag)
-    encs[tag] = "".join(reversed(enc.replace(" ", "")))
-    dectree_normal["leaves"].add(tag)
-
-faketags |= set(subinsn_groupings.keys())
-
-
-def every_bit_counts(bitset):
-    for i in range(1, len(next(iter(bitset)))):
-        if len(set([bits[:i] + bits[i + 1 :] for bits in bitset])) == len(bitset):
-            return False
-    return True
-
-
-def auto_separate(node):
-    tags = node["leaves"]
-    if len(tags) <= 1:
-        return
-    enc_width = len(encs[next(iter(tags))])
-    opcode_bit_for_all = [
-        all([encs[tag][i] in "01" for tag in tags]) for i in range(enc_width)
-    ]
-    opcode_bit_is_0_for_all = [
-        opcode_bit_for_all[i] and all([encs[tag][i] == "0" for tag in tags])
-        for i in range(enc_width)
-    ]
-    opcode_bit_is_1_for_all = [
-        opcode_bit_for_all[i] and all([encs[tag][i] == "1" for tag in tags])
-        for i in range(enc_width)
-    ]
-    differentiator_opcode_bit = [
-        opcode_bit_for_all[i]
-        and not (opcode_bit_is_0_for_all[i] or opcode_bit_is_1_for_all[i])
-        for i in range(enc_width)
-    ]
-    best_width = 0
-    for width in range(4, 0, -1):
-        for lsb in range(enc_width - width, -1, -1):
-            bitset = set([encs[tag][lsb : lsb + width] for tag in tags])
-            if all(differentiator_opcode_bit[lsb : lsb + width]) and (
-                len(bitset) == len(tags) or every_bit_counts(bitset)
-            ):
-                best_width = width
-                best_lsb = lsb
-                caught_all_tags = len(bitset) == len(tags)
-                break
-        if best_width != 0:
-            break
-    if best_width == 0:
-        raise Exception(
-            "Could not find a way to differentiate the encodings "
-            + "of the following tags:\n{}".format("\n".join(tags))
-        )
-    if caught_all_tags:
-        for width in range(1, best_width):
-            for lsb in range(enc_width - width, -1, -1):
-                bitset = set([encs[tag][lsb : lsb + width] for tag in tags])
-                if all(differentiator_opcode_bit[lsb : lsb + width]) and len(
-                    bitset
-                ) == len(tags):
-                    best_width = width
-                    best_lsb = lsb
-                    break
-            else:
-                continue
-            break
-    node["separator_lsb"] = best_lsb
-    node["separator_width"] = best_width
-    node["children"] = []
-    for value in range(2**best_width):
-        child = {}
-        bits = "".join(reversed("{:0{}b}".format(value, best_width)))
-        child["leaves"] = set(
-            [tag for tag in tags if encs[tag][best_lsb : best_lsb + best_width] == bits]
-        )
-        node["children"].append(child)
-    for child in node["children"]:
-        auto_separate(child)
-
-
-auto_separate(dectree_normal)
-auto_separate(dectree_16bit)
-if subinsn_groupings:
-    auto_separate(dectree_subinsn_groupings)
-for dectree_subinsn in dectree_subinsns.values():
-    auto_separate(dectree_subinsn)
-for dectree_ext in dectree_extensions.values():
-    auto_separate(dectree_ext)
-
-for tag in faketags:
-    del encs[tag]
-
-
-def table_name(parents, node):
-    path = parents + [node]
-    root = path[0]
-    tag = next(iter(node["leaves"]))
-    if tag in subinsn_groupings:
-        enc_width = len(subinsn_groupings[tag]["enc"].replace(" ", ""))
-    else:
-        tag = next(iter(node["leaves"] - faketags))
-        enc_width = len(encs[tag])
-    determining_bits = ["_"] * enc_width
-    for parent, child in zip(path[:-1], path[1:]):
-        lsb = parent["separator_lsb"]
-        width = parent["separator_width"]
-        value = parent["children"].index(child)
-        determining_bits[lsb : lsb + width] = list(
-            reversed("{:0{}b}".format(value, width))
-        )
-    if tag in subinsn_groupings:
-        name = "DECODE_ROOT_EE"
-    else:
-        enc_class = iset.iset[tag]["enc_class"]
-        if enc_class in ext_enc_classes:
-            name = "DECODE_EXT_{}".format(enc_class)
-        elif enc_class in subinsn_enc_classes:
-            name = "DECODE_SUBINSN_{}".format(enc_class)
-        else:
-            name = "DECODE_ROOT_{}".format(enc_width)
-    if node != root:
-        name += "_" + "".join(reversed(determining_bits))
-    return name
-
-
-def print_node(f, node, parents):
-    if len(node["leaves"]) <= 1:
-        return
-    name = table_name(parents, node)
-    lsb = node["separator_lsb"]
-    width = node["separator_width"]
-    print(
-        "DECODE_NEW_TABLE({},{},DECODE_SEPARATOR_BITS({},{}))".format(
-            name, 2**width, lsb, width
-        ),
-        file=f,
-    )
-    for child in node["children"]:
-        if len(child["leaves"]) == 0:
-            print("INVALID()", file=f)
-        elif len(child["leaves"]) == 1:
-            (tag,) = child["leaves"]
-            if tag in subinsn_groupings:
-                class_a = subinsn_groupings[tag]["class_a"]
-                class_b = subinsn_groupings[tag]["class_b"]
-                enc = subinsn_groupings[tag]["enc"].replace(" ", "")
-                if "RESERVED" in tag:
-                    print("INVALID()", file=f)
-                else:
-                    print(
-                        'SUBINSNS({},{},{},"{}")'.format(tag, class_a, class_b, enc),
-                        file=f,
-                    )
-            elif tag in iset.enc_ext_spaces:
-                enc = iset.enc_ext_spaces[tag].replace(" ", "")
-                print('EXTSPACE({},"{}")'.format(tag, enc), file=f)
-            else:
-                enc = "".join(reversed(encs[tag]))
-                print('TERMINAL({},"{}")'.format(tag, enc), file=f)
-        else:
-            print("TABLE_LINK({})".format(table_name(parents + [node], child)), file=f)
-    print(
-        "DECODE_END_TABLE({},{},DECODE_SEPARATOR_BITS({},{}))".format(
-            name, 2**width, lsb, width
-        ),
-        file=f,
-    )
-    print(file=f)
-    parents.append(node)
-    for child in node["children"]:
-        print_node(f, child, parents)
-    parents.pop()
-
-
-def print_tree(f, tree):
-    print_node(f, tree, [])
-
-
-def print_match_info(f):
-    for tag in sorted(encs.keys(), key=iset.tags.index):
-        enc = "".join(reversed(encs[tag]))
-        mask = int(re.sub(r"[^1]", r"0", enc.replace("0", "1")), 2)
-        match = int(re.sub(r"[^01]", r"0", enc), 2)
-        suffix = ""
-        print(
-            "DECODE{}_MATCH_INFO({},0x{:x}U,0x{:x}U)".format(suffix, tag, mask, match),
-            file=f,
-        )
-
-
-regre = re.compile(r"((?<!DUP)[MNORCPQXSGVZA])([stuvwxyzdefg]+)([.]?[LlHh]?)(\d+S?)")
-immre = re.compile(r"[#]([rRsSuUm])(\d+)(?:[:](\d+))?")
-
-
-def ordered_unique(l):
-    return sorted(set(l), key=l.index)
-
-
-implicit_registers = {"SP": 29, "FP": 30, "LR": 31}
-
-num_registers = {"R": 32, "V": 32}
-
-
-def print_op_info(f):
-    for tag in sorted(encs.keys(), key=iset.tags.index):
-        enc = encs[tag]
-        print(file=f)
-        print("DECODE_OPINFO({},".format(tag), file=f)
-        regs = ordered_unique(regre.findall(iset.iset[tag]["syntax"]))
-        imms = ordered_unique(immre.findall(iset.iset[tag]["syntax"]))
-        regno = 0
-        for reg in regs:
-            reg_type = reg[0]
-            reg_letter = reg[1][0]
-            reg_num_choices = int(reg[3].rstrip("S"))
-            reg_mapping = reg[0] + "".join(["_" for letter in reg[1]]) + reg[3]
-            reg_enc_fields = re.findall(reg_letter + "+", enc)
-            if len(reg_enc_fields) == 0:
-                raise Exception('Tag "{}" missing register field!'.format(tag))
-            if len(reg_enc_fields) > 1:
-                raise Exception('Tag "{}" has split register field!'.format(tag))
-            reg_enc_field = reg_enc_fields[0]
-            if 2 ** len(reg_enc_field) != reg_num_choices:
-                raise Exception(
-                    'Tag "{}" has incorrect register field width!'.format(tag)
-                )
-            print(
-                "        DECODE_REG({},{},{})".format(
-                    regno, len(reg_enc_field), enc.index(reg_enc_field)
-                ),
-                file=f,
-            )
-            if reg_type in num_registers and reg_num_choices != num_registers[reg_type]:
-                print(
-                    "        DECODE_MAPPED_REG({},{})".format(regno, reg_mapping),
-                    file=f,
-                )
-            regno += 1
-
-        def implicit_register_key(reg):
-            return implicit_registers[reg]
-
-        for reg in sorted(
-            set(
-                [
-                    r
-                    for r in (
-                        iset.iset[tag]["rregs"].split(",")
-                        + iset.iset[tag]["wregs"].split(",")
-                    )
-                    if r in implicit_registers
-                ]
-            ),
-            key=implicit_register_key,
-        ):
-            print(
-                "        DECODE_IMPL_REG({},{})".format(regno, implicit_registers[reg]),
-                file=f,
-            )
-            regno += 1
-        if imms and imms[0][0].isupper():
-            imms = reversed(imms)
-        for imm in imms:
-            if imm[0].isupper():
-                immno = 1
-            else:
-                immno = 0
-            imm_type = imm[0]
-            imm_width = int(imm[1])
-            imm_shift = imm[2]
-            if imm_shift:
-                imm_shift = int(imm_shift)
-            else:
-                imm_shift = 0
-            if imm_type.islower():
-                imm_letter = "i"
-            else:
-                imm_letter = "I"
-            remainder = imm_width
-            for m in reversed(list(re.finditer(imm_letter + "+", enc))):
-                remainder -= m.end() - m.start()
-                print(
-                    "        DECODE_IMM({},{},{},{})".format(
-                        immno, m.end() - m.start(), m.start(), remainder
-                    ),
-                    file=f,
-                )
-            if remainder != 0:
-                if imm[2]:
-                    imm[2] = ":" + imm[2]
-                raise Exception(
-                    'Tag "{}" has an incorrect number of '
-                    + 'encoding bits for immediate "{}"'.format(tag, "".join(imm))
-                )
-            if imm_type.lower() in "sr":
-                print("        DECODE_IMM_SXT({},{})".format(immno, imm_width), file=f)
-            if imm_type.lower() == "n":
-                print("        DECODE_IMM_NEG({},{})".format(immno, imm_width), file=f)
-            if imm_shift:
-                print(
-                    "        DECODE_IMM_SHIFT({},{})".format(immno, imm_shift), file=f
-                )
-        print(")", file=f)
-
-
-if __name__ == "__main__":
-    with open(sys.argv[1], "w") as f:
-        print_tree(f, dectree_normal)
-        print_tree(f, dectree_16bit)
-        if subinsn_groupings:
-            print_tree(f, dectree_subinsn_groupings)
-        for name, dectree_subinsn in sorted(dectree_subinsns.items()):
-            print_tree(f, dectree_subinsn)
-        for name, dectree_ext in sorted(dectree_extensions.items()):
-            print_tree(f, dectree_ext)
-        print_match_info(f)
-        print_op_info(f)
diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build
index 1bd1ebcba1..fb480afc03 100644
--- a/target/hexagon/meson.build
+++ b/target/hexagon/meson.build
@@ -122,18 +122,6 @@ hexagon_ss.add(iset_py)
 
 #
 # Step 4
-# We use the dectree.py script to generate the decode tree header file
-#
-dectree_generated = custom_target(
-    'dectree_generated.h.inc',
-    output: 'dectree_generated.h.inc',
-    depends: [iset_py],
-    env: {'PYTHONPATH': meson.current_build_dir()},
-    command: [python, files('dectree.py'), '@OUTPUT@'],
-)
-hexagon_ss.add(dectree_generated)
-
-#
 # Generate the input to the QEMU decodetree.py script
 #
 normal_decode_generated = custom_target(
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* RE: [PATCH v2 0/3] Hexagon (target/hexagon) Use QEMU decodetree
  2024-01-15 22:14 [PATCH v2 0/3] Hexagon (target/hexagon) Use QEMU decodetree Taylor Simpson
                   ` (2 preceding siblings ...)
  2024-01-15 22:14 ` [PATCH v2 3/3] Hexagon (target/hexagon) Remove old dectree.py Taylor Simpson
@ 2024-01-16  5:45 ` Brian Cain
  3 siblings, 0 replies; 8+ messages in thread
From: Brian Cain @ 2024-01-16  5:45 UTC (permalink / raw)
  To: Taylor Simpson, qemu-devel@nongnu.org
  Cc: Matheus Bernardino (QUIC), Sid Manning, Marco Liebel (QUIC),
	richard.henderson@linaro.org, philmd@linaro.org, ale@rev.ng,
	anjo@rev.ng



> -----Original Message-----
> From: Taylor Simpson <ltaylorsimpson@gmail.com>
> Sent: Monday, January 15, 2024 4:15 PM
> To: qemu-devel@nongnu.org
> Cc: Brian Cain <bcain@quicinc.com>; Matheus Bernardino (QUIC)
> <quic_mathbern@quicinc.com>; Sid Manning <sidneym@quicinc.com>; Marco
> Liebel (QUIC) <quic_mliebel@quicinc.com>; richard.henderson@linaro.org;
> philmd@linaro.org; ale@rev.ng; anjo@rev.ng; ltaylorsimpson@gmail.com
> Subject: [PATCH v2 0/3] Hexagon (target/hexagon) Use QEMU decodetree
> 
> WARNING: This email originated from outside of Qualcomm. Please be wary of
> any links or attachments, and do not enable macros.
> 
> Replace the old Hexagon dectree.py with QEMU decodetree
> 
> **** Changes in v2 ****
> Suggested Python improvements from Brian Cain <bcain@quicinc.com>
> 
> 
> Taylor Simpson (3):
>   Hexagon (target/hexagon) Use QEMU decodetree (32-bit instructions)
>   Hexagon (target/hexagon) Use QEMU decodetree (16-bit instructions)
>   Hexagon (target/hexagon) Remove old dectree.py
> 
>  target/hexagon/decode.h             |   5 +-
>  target/hexagon/opcodes.h            |   2 -
>  target/hexagon/decode.c             | 435 +++++++---------------------
>  target/hexagon/gen_dectree_import.c |  49 ----
>  target/hexagon/opcodes.c            |  29 --
>  target/hexagon/translate.c          |   4 +-
>  target/hexagon/README               |  14 +-
>  target/hexagon/dectree.py           | 403 --------------------------
>  target/hexagon/gen_decodetree.py    | 198 +++++++++++++
>  target/hexagon/gen_trans_funcs.py   | 124 ++++++++
>  target/hexagon/meson.build          | 147 +++++++++-
>  11 files changed, 586 insertions(+), 824 deletions(-)
>  delete mode 100755 target/hexagon/dectree.py
>  create mode 100755 target/hexagon/gen_decodetree.py
>  create mode 100755 target/hexagon/gen_trans_funcs.py
> 
> --
> 2.34.1


Queued - https://github.com/quic/qemu/tree/hex.next



^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2024-01-16  5:46 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-01-15 22:14 [PATCH v2 0/3] Hexagon (target/hexagon) Use QEMU decodetree Taylor Simpson
2024-01-15 22:14 ` [PATCH v2 1/3] Hexagon (target/hexagon) Use QEMU decodetree (32-bit instructions) Taylor Simpson
2024-01-15 22:14 ` [PATCH v2 2/3] Hexagon (target/hexagon) Use QEMU decodetree (16-bit instructions) Taylor Simpson
2024-01-15 22:14 ` [PATCH v2 3/3] Hexagon (target/hexagon) Remove old dectree.py Taylor Simpson
2024-01-16  5:45 ` [PATCH v2 0/3] Hexagon (target/hexagon) Use QEMU decodetree Brian Cain
  -- strict thread matches above, loose matches on Subject: below --
2024-01-08 22:48 Taylor Simpson
2024-01-08 22:48 ` [PATCH v2 1/3] Hexagon (target/hexagon) Use QEMU decodetree (32-bit instructions) Taylor Simpson
2024-01-15  0:20   ` Brian Cain
2024-01-15 21:38     ` ltaylorsimpson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).