master
py 165 lines 5.39 KB
Raw
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
20 import io
21 import re
22
23 import sys
24 import textwrap
25 import iset
26 import hex_common
27 import argparse
28
29 encs = {
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
36 regre = re.compile(r"((?<!DUP)[MNORCPQXSGVZA])([stuvwxyzdefg]+)([.]?[LlHh]?)(\d+S?)")
37 immre = re.compile(r"[#]([rRsSuUm])(\d+)(?:[:](\d+))?")
38
39
40 def ordered_unique(l):
41 return sorted(set(l), key=l.index)
42
43
44 def code_fmt(txt):
45 return textwrap.indent(textwrap.dedent(txt), " ")
46
47 open_curly = "{"
48 close_curly = "}"
49
50 def 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 ##
78 def 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 dest_is_pair = "false"
95 dest_is_gpr = "false"
96 has_pred_dest = "false"
97 for regno, (reg_type, reg_id, *_) in enumerate(regs):
98 reg = hex_common.get_register(tag, reg_type, reg_id)
99 f.write(code_fmt(f"""\
100 insn->regno[{regno}] = args->{reg_type}{reg_id};
101 """))
102 if reg.is_read() and reg.is_new():
103 new_read_idx = regno
104 if reg.is_written():
105 # dest_idx should be the first destination alphabetically
106 if dest_idx_reg_id is None or reg_id < dest_idx_reg_id:
107 dest_idx = regno
108 dest_idx_reg_id = reg_id
109 dest_is_pair = ("true"
110 if isinstance(reg, hex_common.Pair)
111 else "false")
112 dest_is_gpr = ("true"
113 if reg_type == "R"
114 else "false")
115 if reg_type == "P" and reg.is_written() and not reg.is_read():
116 has_pred_dest = "true"
117
118 if len(imms) != 0:
119 mark_which_imm_extended(f, tag)
120
121 for imm in imms:
122 imm_type = imm[0]
123 imm_letter = "i" if imm_type.islower() else "I"
124 immno = 0 if imm_type.islower() else 1
125 imm_shift = int(imm[2]) if imm[2] else 0
126 if imm_shift:
127 f.write(code_fmt(f"""\
128 insn->immed[{immno}] =
129 shift_left(ctx, args->{imm_type}{imm_letter},
130 {imm_shift}, {immno});
131 """))
132 else:
133 f.write(code_fmt(f"""\
134 insn->immed[{immno}] = args->{imm_type}{imm_letter};
135 """))
136
137 f.write(code_fmt(f"""\
138 insn->new_read_idx = {new_read_idx};
139 insn->dest_idx = {dest_idx};
140 insn->dest_is_pair = {dest_is_pair};
141 insn->dest_is_gpr = {dest_is_gpr};
142 insn->has_pred_dest = {has_pred_dest};
143 """))
144 f.write(textwrap.dedent(f"""\
145 return true;
146 {close_curly}
147 """))
148
149
150 def main():
151 parser = argparse.ArgumentParser(
152 description="Emit trans_*() functions to be called by " \
153 "instruction decoder"
154 )
155 parser.add_argument("semantics", help="semantics file")
156 parser.add_argument("out", help="output file")
157 args = parser.parse_args()
158 hex_common.read_semantics_file(args.semantics)
159 hex_common.init_registers()
160 with open(args.out, "w") as f:
161 gen_trans_funcs(f)
162
163
164 if __name__ == "__main__":
165 main()