xref: /qemu/target/hexagon/gen_trans_funcs.py (revision 513823e7521a09ed7ad1e32e6454bac3b2cbf52d)
1#!/usr/bin/env python3
2
3##
4##  Copyright (c) 2024 Taylor Simpson <ltaylorsimpson@gmail.com>
5##
6##  This program is free software; you can redistribute it and/or modify
7##  it under the terms of the GNU General Public License as published by
8##  the Free Software Foundation; either version 2 of the License, or
9##  (at your option) any later version.
10##
11##  This program is distributed in the hope that it will be useful,
12##  but WITHOUT ANY WARRANTY; without even the implied warranty of
13##  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14##  GNU General Public License for more details.
15##
16##  You should have received a copy of the GNU General Public License
17##  along with this program; if not, see <http://www.gnu.org/licenses/>.
18##
19
20import io
21import re
22
23import sys
24import textwrap
25import iset
26import hex_common
27import argparse
28
29encs = {
30    tag: "".join(reversed(iset.iset[tag]["enc"].replace(" ", "")))
31    for tag in iset.tags
32    if iset.iset[tag]["enc"] != "MISSING ENCODING"
33}
34
35
36regre = re.compile(r"((?<!DUP)[MNORCPQXSGVZA])([stuvwxyzdefg]+)([.]?[LlHh]?)(\d+S?)")
37immre = re.compile(r"[#]([rRsSuUm])(\d+)(?:[:](\d+))?")
38
39
40def ordered_unique(l):
41    return sorted(set(l), key=l.index)
42
43
44def code_fmt(txt):
45    return textwrap.indent(textwrap.dedent(txt), "    ")
46
47open_curly = "{"
48close_curly = "}"
49
50def mark_which_imm_extended(f, tag):
51    immre = re.compile(r"IMMEXT\([rRsSuUm]")
52    imm = immre.findall(hex_common.semdict[tag])
53    if len(imm) == 0:
54        # No extended operand found
55        return
56    letter = re.split("\\(", imm[0])[1]
57    f.write(code_fmt(f"""\
58        insn->which_extended = {0 if letter.islower() else 1};
59    """))
60
61##
62## Generate the QEMU decodetree trans_<tag> function for each instruction
63##     For A2_add: Rd32=add(Rs32,Rt32)
64##     We produce:
65##     static bool trans_A2_add(DisasContext *ctx, arg_A2_add *args)
66##     {
67##         Insn *insn = ctx->insn;
68##         insn->opcode = A2_add;
69##         insn->regno[0] = args->Rd;
70##         insn->regno[1] = args->Rs;
71##         insn->regno[2] = args->Rt;
72##         insn->new_read_idx = -1;
73##         insn->dest_idx = 0;
74##         insn->has_pred_dest = false;
75##         return true;
76##     }
77##
78def gen_trans_funcs(f):
79    f.write(f"/* DO NOT MODIFY - This file is generated by {sys.argv[0]} */\n\n")
80    for tag in sorted(encs.keys(), key=iset.tags.index):
81        regs = ordered_unique(regre.findall(iset.iset[tag]["syntax"]))
82        imms = ordered_unique(immre.findall(iset.iset[tag]["syntax"]))
83
84        f.write(textwrap.dedent(f"""\
85            static bool trans_{tag}(DisasContext *ctx, arg_{tag} *args)
86            {open_curly}
87                Insn *insn = ctx->insn;
88                insn->opcode = {tag};
89        """))
90
91        new_read_idx = -1
92        dest_idx = -1
93        dest_idx_reg_id = None
94        has_pred_dest = "false"
95        for regno, (reg_type, reg_id, *_) in enumerate(regs):
96            reg = hex_common.get_register(tag, reg_type, reg_id)
97            f.write(code_fmt(f"""\
98                insn->regno[{regno}] = args->{reg_type}{reg_id};
99            """))
100            if reg.is_read() and reg.is_new():
101                new_read_idx = regno
102            if reg.is_written():
103                # dest_idx should be the first destination alphabetically
104                if dest_idx_reg_id is None or reg_id < dest_idx_reg_id:
105                    dest_idx = regno
106                    dest_idx_reg_id = reg_id
107            if reg_type == "P" and reg.is_written() and not reg.is_read():
108                has_pred_dest = "true"
109
110        if len(imms) != 0:
111            mark_which_imm_extended(f, tag)
112
113        for imm in imms:
114            imm_type = imm[0]
115            imm_letter = "i" if imm_type.islower() else "I"
116            immno = 0 if imm_type.islower() else 1
117            imm_shift = int(imm[2]) if imm[2] else 0
118            if imm_shift:
119                f.write(code_fmt(f"""\
120                    insn->immed[{immno}] =
121                        shift_left(ctx, args->{imm_type}{imm_letter},
122                                   {imm_shift}, {immno});
123                """))
124            else:
125                f.write(code_fmt(f"""\
126                    insn->immed[{immno}] = args->{imm_type}{imm_letter};
127                """))
128
129        f.write(code_fmt(f"""\
130            insn->new_read_idx = {new_read_idx};
131            insn->dest_idx = {dest_idx};
132            insn->has_pred_dest = {has_pred_dest};
133        """))
134        f.write(textwrap.dedent(f"""\
135                return true;
136            {close_curly}
137        """))
138
139
140def main():
141    parser = argparse.ArgumentParser(
142        description="Emit trans_*() functions to be called by " \
143                    "instruction decoder"
144    )
145    parser.add_argument("semantics", help="semantics file")
146    parser.add_argument("out", help="output file")
147    args = parser.parse_args()
148    hex_common.read_semantics_file(args.semantics)
149    hex_common.init_registers()
150    with open(args.out, "w") as f:
151        gen_trans_funcs(f)
152
153
154if __name__ == "__main__":
155    main()
156