> -----Original Message----- > From: Taylor Simpson <ltaylorsimp...@gmail.com> > Sent: Monday, January 8, 2024 4:49 PM > To: qemu-devel@nongnu.org > Cc: Brian Cain <bc...@quicinc.com>; Matheus Bernardino (QUIC) > <quic_mathb...@quicinc.com>; Sid Manning <sidn...@quicinc.com>; Marco > Liebel (QUIC) <quic_mlie...@quicinc.com>; richard.hender...@linaro.org; > phi...@linaro.org; a...@rev.ng; a...@rev.ng; ltaylorsimp...@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 <ltaylorsimp...@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 <ltaylorsimp...@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 <ltaylorsimp...@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 <bc...@quicinc.com>