xref: /qemu/target/hexagon/hex_common.py (revision 7653b1ea)
1#!/usr/bin/env python3
2
3##
4##  Copyright(c) 2019-2023 Qualcomm Innovation Center, Inc. All Rights Reserved.
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 sys
21import re
22import string
23import textwrap
24
25behdict = {}  # tag ->behavior
26semdict = {}  # tag -> semantics
27attribdict = {}  # tag -> attributes
28macros = {}  # macro -> macro information...
29attribinfo = {}  # Register information and misc
30registers = {}  # register -> register functions
31new_registers = {}
32tags = []  # list of all tags
33overrides = {}  # tags with helper overrides
34idef_parser_enabled = {}  # tags enabled for idef-parser
35
36# We should do this as a hash for performance,
37# but to keep order let's keep it as a list.
38def uniquify(seq):
39    seen = set()
40    seen_add = seen.add
41    return [x for x in seq if x not in seen and not seen_add(x)]
42
43
44regre = re.compile(r"((?<!DUP)[MNORCPQXSGVZA])([stuvwxyzdefg]+)([.]?[LlHh]?)(\d+S?)")
45immre = re.compile(r"[#]([rRsSuUm])(\d+)(?:[:](\d+))?")
46reg_or_immre = re.compile(
47    r"(((?<!DUP)[MNRCOPQXSGVZA])([stuvwxyzdefg]+)"
48    r"([.]?[LlHh]?)(\d+S?))|([#]([rRsSuUm])(\d+)[:]?(\d+)?)"
49)
50relimmre = re.compile(r"[#]([rR])(\d+)(?:[:](\d+))?")
51absimmre = re.compile(r"[#]([sSuUm])(\d+)(?:[:](\d+))?")
52
53finished_macros = set()
54
55
56def expand_macro_attribs(macro, allmac_re):
57    if macro.key not in finished_macros:
58        # Get a list of all things that might be macros
59        l = allmac_re.findall(macro.beh)
60        for submacro in l:
61            if not submacro:
62                continue
63            if not macros[submacro]:
64                raise Exception(f"Couldn't find macro: <{l}>")
65            macro.attribs |= expand_macro_attribs(macros[submacro], allmac_re)
66            finished_macros.add(macro.key)
67    return macro.attribs
68
69
70# When qemu needs an attribute that isn't in the imported files,
71# we'll add it here.
72def add_qemu_macro_attrib(name, attrib):
73    macros[name].attribs.add(attrib)
74
75
76immextre = re.compile(r"f(MUST_)?IMMEXT[(]([UuSsRr])")
77
78
79def is_cond_jump(tag):
80    if tag == "J2_rte":
81        return False
82    if "A_HWLOOP0_END" in attribdict[tag] or "A_HWLOOP1_END" in attribdict[tag]:
83        return False
84    return re.compile(r"(if.*fBRANCH)|(if.*fJUMPR)").search(semdict[tag]) != None
85
86
87def is_cond_call(tag):
88    return re.compile(r"(if.*fCALL)").search(semdict[tag]) != None
89
90
91def calculate_attribs():
92    add_qemu_macro_attrib("fREAD_PC", "A_IMPLICIT_READS_PC")
93    add_qemu_macro_attrib("fTRAP", "A_IMPLICIT_READS_PC")
94    add_qemu_macro_attrib("fSET_OVERFLOW", "A_IMPLICIT_WRITES_USR")
95    add_qemu_macro_attrib("fSET_LPCFG", "A_IMPLICIT_WRITES_USR")
96    add_qemu_macro_attrib("fLOAD", "A_SCALAR_LOAD")
97    add_qemu_macro_attrib("fSTORE", "A_SCALAR_STORE")
98    add_qemu_macro_attrib('fLSBNEW0', 'A_IMPLICIT_READS_P0')
99    add_qemu_macro_attrib('fLSBNEW0NOT', 'A_IMPLICIT_READS_P0')
100    add_qemu_macro_attrib('fREAD_P0', 'A_IMPLICIT_READS_P0')
101    add_qemu_macro_attrib('fLSBNEW1', 'A_IMPLICIT_READS_P1')
102    add_qemu_macro_attrib('fLSBNEW1NOT', 'A_IMPLICIT_READS_P1')
103    add_qemu_macro_attrib('fREAD_P3', 'A_IMPLICIT_READS_P3')
104
105    # Recurse down macros, find attributes from sub-macros
106    macroValues = list(macros.values())
107    allmacros_restr = "|".join(set([m.re.pattern for m in macroValues]))
108    allmacros_re = re.compile(allmacros_restr)
109    for macro in macroValues:
110        expand_macro_attribs(macro, allmacros_re)
111    # Append attributes to all instructions
112    for tag in tags:
113        for macname in allmacros_re.findall(semdict[tag]):
114            if not macname:
115                continue
116            macro = macros[macname]
117            attribdict[tag] |= set(macro.attribs)
118    # Mark conditional jumps and calls
119    #     Not all instructions are properly marked with A_CONDEXEC
120    for tag in tags:
121        if is_cond_jump(tag) or is_cond_call(tag):
122            attribdict[tag].add("A_CONDEXEC")
123
124
125def SEMANTICS(tag, beh, sem):
126    # print tag,beh,sem
127    behdict[tag] = beh
128    semdict[tag] = sem
129    attribdict[tag] = set()
130    tags.append(tag)  # dicts have no order, this is for order
131
132
133def ATTRIBUTES(tag, attribstring):
134    attribstring = attribstring.replace("ATTRIBS", "").replace("(", "").replace(")", "")
135    if not attribstring:
136        return
137    attribs = attribstring.split(",")
138    for attrib in attribs:
139        attribdict[tag].add(attrib.strip())
140
141
142class Macro(object):
143    __slots__ = ["key", "name", "beh", "attribs", "re"]
144
145    def __init__(self, name, beh, attribs):
146        self.key = name
147        self.name = name
148        self.beh = beh
149        self.attribs = set(attribs)
150        self.re = re.compile("\\b" + name + "\\b")
151
152
153def MACROATTRIB(macname, beh, attribstring):
154    attribstring = attribstring.replace("(", "").replace(")", "")
155    if attribstring:
156        attribs = attribstring.split(",")
157    else:
158        attribs = []
159    macros[macname] = Macro(macname, beh, attribs)
160
161def compute_tag_regs(tag, full):
162    tagregs = regre.findall(behdict[tag])
163    if not full:
164        tagregs = map(lambda reg: reg[:2], tagregs)
165    return uniquify(tagregs)
166
167def compute_tag_immediates(tag):
168    return uniquify(immre.findall(behdict[tag]))
169
170
171##
172##  tagregs is the main data structure we'll use
173##  tagregs[tag] will contain the registers used by an instruction
174##  Within each entry, we'll use the regtype and regid fields
175##      regtype can be one of the following
176##          C                control register
177##          N                new register value
178##          P                predicate register
179##          R                GPR register
180##          M                modifier register
181##          Q                HVX predicate vector
182##          V                HVX vector register
183##          O                HVX new vector register
184##      regid can be one of the following
185##          d, e             destination register
186##          dd               destination register pair
187##          s, t, u, v, w    source register
188##          ss, tt, uu, vv   source register pair
189##          x, y             read-write register
190##          xx, yy           read-write register pair
191##
192def get_tagregs(full=False):
193    compute_func = lambda tag: compute_tag_regs(tag, full)
194    return dict(zip(tags, list(map(compute_func, tags))))
195
196def get_tagimms():
197    return dict(zip(tags, list(map(compute_tag_immediates, tags))))
198
199
200def need_slot(tag):
201    if (
202        "A_CVI_SCATTER" not in attribdict[tag]
203        and "A_CVI_GATHER" not in attribdict[tag]
204        and ("A_STORE" in attribdict[tag]
205             or "A_LOAD" in attribdict[tag])
206    ):
207        return 1
208    else:
209        return 0
210
211
212def need_part1(tag):
213    return re.compile(r"fPART1").search(semdict[tag])
214
215
216def need_ea(tag):
217    return re.compile(r"\bEA\b").search(semdict[tag])
218
219
220def need_PC(tag):
221    return "A_IMPLICIT_READS_PC" in attribdict[tag]
222
223
224def need_next_PC(tag):
225    return "A_CALL" in attribdict[tag]
226
227
228def need_pkt_has_multi_cof(tag):
229    return "A_COF" in attribdict[tag]
230
231
232def need_pkt_need_commit(tag):
233    return 'A_IMPLICIT_WRITES_USR' in attribdict[tag]
234
235
236def skip_qemu_helper(tag):
237    return tag in overrides.keys()
238
239
240def is_idef_parser_enabled(tag):
241    return tag in idef_parser_enabled
242
243
244def imm_name(immlett):
245    return f"{immlett}iV"
246
247
248def read_semantics_file(name):
249    eval_line = ""
250    for line in open(name, "rt").readlines():
251        if not line.startswith("#"):
252            eval_line += line
253            if line.endswith("\\\n"):
254                eval_line.rstrip("\\\n")
255            else:
256                eval(eval_line.strip())
257                eval_line = ""
258
259
260def read_attribs_file(name):
261    attribre = re.compile(
262        r"DEF_ATTRIB\(([A-Za-z0-9_]+), ([^,]*), "
263        + r'"([A-Za-z0-9_\.]*)", "([A-Za-z0-9_\.]*)"\)'
264    )
265    for line in open(name, "rt").readlines():
266        if not attribre.match(line):
267            continue
268        (attrib_base, descr, rreg, wreg) = attribre.findall(line)[0]
269        attrib_base = "A_" + attrib_base
270        attribinfo[attrib_base] = {"rreg": rreg, "wreg": wreg, "descr": descr}
271
272
273def read_overrides_file(name):
274    overridere = re.compile(r"#define fGEN_TCG_([A-Za-z0-9_]+)\(.*")
275    for line in open(name, "rt").readlines():
276        if not overridere.match(line):
277            continue
278        tag = overridere.findall(line)[0]
279        overrides[tag] = True
280
281
282def read_idef_parser_enabled_file(name):
283    global idef_parser_enabled
284    with open(name, "r") as idef_parser_enabled_file:
285        lines = idef_parser_enabled_file.read().strip().split("\n")
286        idef_parser_enabled = set(lines)
287
288
289def is_predicated(tag):
290    return "A_CONDEXEC" in attribdict[tag]
291
292
293def code_fmt(txt):
294    return textwrap.indent(textwrap.dedent(txt), "    ")
295
296
297def hvx_newv(tag):
298    if "A_CVI_NEW" in attribdict[tag]:
299        return "EXT_NEW"
300    elif "A_CVI_TMP" in attribdict[tag] or "A_CVI_TMP_DST" in attribdict[tag]:
301        return "EXT_TMP"
302    else:
303        return "EXT_DFL"
304
305def vreg_offset_func(tag):
306    if "A_CVI_TMP" in attribdict[tag] or "A_CVI_TMP_DST" in attribdict[tag]:
307        return "ctx_tmp_vreg_off"
308    else:
309        return "ctx_future_vreg_off"
310
311class HelperArg:
312    def __init__(self, proto_arg, call_arg, func_arg):
313        self.proto_arg = proto_arg
314        self.call_arg = call_arg
315        self.func_arg = func_arg
316
317class Register:
318    def __init__(self, regtype, regid):
319        self.regtype = regtype
320        self.regid = regid
321        self.reg_num = f"{regtype}{regid}N"
322    def decl_reg_num(self, f, regno):
323        f.write(code_fmt(f"""\
324            const int {self.reg_num} = insn->regno[{regno}];
325        """))
326    def idef_arg(self, declared):
327        declared.append(self.reg_tcg())
328    def helper_arg(self):
329        return HelperArg(
330            self.helper_proto_type(),
331            self.reg_tcg(),
332            f"{self.helper_arg_type()} {self.helper_arg_name()}"
333        )
334
335#
336# Every register is either Single or Pair or Hvx
337#
338class Scalar:
339    def is_scalar_reg(self):
340        return True
341    def is_hvx_reg(self):
342        return False
343    def helper_arg_name(self):
344        return self.reg_tcg()
345
346class Single(Scalar):
347    def helper_proto_type(self):
348        return "s32"
349    def helper_arg_type(self):
350        return "int32_t"
351
352class Pair(Scalar):
353    def helper_proto_type(self):
354        return "s64"
355    def helper_arg_type(self):
356        return "int64_t"
357
358class Hvx:
359    def is_scalar_reg(self):
360        return False
361    def is_hvx_reg(self):
362        return True
363    def hvx_off(self):
364        return f"{self.reg_tcg()}_off"
365    def helper_proto_type(self):
366        return "ptr"
367    def helper_arg_type(self):
368        return "void *"
369    def helper_arg_name(self):
370        return f"{self.reg_tcg()}_void"
371
372#
373# Every register is either Dest or OldSource or NewSource or ReadWrite
374#
375class Dest:
376    def reg_tcg(self):
377        return f"{self.regtype}{self.regid}V"
378    def is_written(self):
379        return True
380    def is_writeonly(self):
381        return True
382    def is_read(self):
383        return False
384    def is_readwrite(self):
385        return False
386
387class Source:
388    def is_written(self):
389        return False
390    def is_writeonly(self):
391        return False
392    def is_read(self):
393        return True
394    def is_readwrite(self):
395        return False
396
397class OldSource(Source):
398    def reg_tcg(self):
399        return f"{self.regtype}{self.regid}V"
400
401class NewSource(Source):
402    def reg_tcg(self):
403        return f"{self.regtype}{self.regid}N"
404
405class ReadWrite:
406    def reg_tcg(self):
407        return f"{self.regtype}{self.regid}V"
408    def is_written(self):
409        return True
410    def is_writeonly(self):
411        return False
412    def is_read(self):
413        return True
414    def is_readwrite(self):
415        return True
416
417class GprDest(Register, Single, Dest):
418    def decl_tcg(self, f, tag, regno):
419        self.decl_reg_num(f, regno)
420        f.write(code_fmt(f"""\
421            TCGv {self.reg_tcg()} = get_result_gpr(ctx, {self.reg_num});
422        """))
423    def log_write(self, f, tag):
424        f.write(code_fmt(f"""\
425            gen_log_reg_write(ctx, {self.reg_num}, {self.reg_tcg()});
426        """))
427    def analyze_write(self, f, tag, regno):
428        self.decl_reg_num(f, regno)
429        predicated = "true" if is_predicated(tag) else "false"
430        f.write(code_fmt(f"""\
431            ctx_log_reg_write(ctx, {self.reg_num}, {predicated});
432        """))
433
434class GprSource(Register, Single, OldSource):
435    def decl_tcg(self, f, tag, regno):
436        self.decl_reg_num(f, regno)
437        f.write(code_fmt(f"""\
438            TCGv {self.reg_tcg()} = hex_gpr[{self.reg_num}];
439        """))
440    def analyze_read(self, f, regno):
441        self.decl_reg_num(f, regno)
442        f.write(code_fmt(f"""\
443            ctx_log_reg_read(ctx, {self.reg_num});
444        """))
445
446class GprNewSource(Register, Single, NewSource):
447    def decl_tcg(self, f, tag, regno):
448        f.write(code_fmt(f"""\
449            TCGv {self.reg_tcg()} = get_result_gpr(ctx, insn->regno[{regno}]);
450        """))
451    def analyze_read(self, f, regno):
452        self.decl_reg_num(f, regno)
453        f.write(code_fmt(f"""\
454            ctx_log_reg_read(ctx, {self.reg_num});
455        """))
456
457class GprReadWrite(Register, Single, ReadWrite):
458    def decl_tcg(self, f, tag, regno):
459        self.decl_reg_num(f, regno)
460        f.write(code_fmt(f"""\
461            TCGv {self.reg_tcg()} = get_result_gpr(ctx, {self.reg_num});
462        """))
463        ## For read/write registers, we need to get the original value into
464        ## the result TCGv.  For predicated instructions, this is done in
465        ## gen_start_packet.  For un-predicated instructions, we do it here.
466        if not is_predicated(tag):
467            f.write(code_fmt(f"""\
468                tcg_gen_mov_tl({self.reg_tcg()}, hex_gpr[{self.reg_num}]);
469            """))
470    def log_write(self, f, tag):
471        f.write(code_fmt(f"""\
472            gen_log_reg_write(ctx, {self.reg_num}, {self.reg_tcg()});
473        """))
474    def analyze_write(self, f, tag, regno):
475        self.decl_reg_num(f, regno)
476        predicated = "true" if is_predicated(tag) else "false"
477        f.write(code_fmt(f"""\
478            ctx_log_reg_write(ctx, {self.reg_num}, {predicated});
479        """))
480
481class ControlDest(Register, Single, Dest):
482    def decl_reg_num(self, f, regno):
483        f.write(code_fmt(f"""\
484            const int {self.reg_num} = insn->regno[{regno}]  + HEX_REG_SA0;
485        """))
486    def decl_tcg(self, f, tag, regno):
487        self.decl_reg_num(f, regno)
488        f.write(code_fmt(f"""\
489            TCGv {self.reg_tcg()} = get_result_gpr(ctx, {self.reg_num});
490        """))
491    def log_write(self, f, tag):
492        f.write(code_fmt(f"""\
493            gen_write_ctrl_reg(ctx, {self.reg_num}, {self.reg_tcg()});
494        """))
495    def analyze_write(self, f, tag, regno):
496        self.decl_reg_num(f, regno)
497        predicated = "true" if is_predicated(tag) else "false"
498        f.write(code_fmt(f"""\
499            ctx_log_reg_write(ctx, {self.reg_num}, {predicated});
500        """))
501
502class ControlSource(Register, Single, OldSource):
503    def decl_reg_num(self, f, regno):
504        f.write(code_fmt(f"""\
505            const int {self.reg_num} = insn->regno[{regno}]  + HEX_REG_SA0;
506        """))
507    def decl_tcg(self, f, tag, regno):
508        self.decl_reg_num(f, regno);
509        f.write(code_fmt(f"""\
510            TCGv {self.reg_tcg()} = tcg_temp_new();
511            gen_read_ctrl_reg(ctx, {self.reg_num}, {self.reg_tcg()});
512        """))
513    def analyze_read(self, f, regno):
514        self.decl_reg_num(f, regno)
515        f.write(code_fmt(f"""\
516            ctx_log_reg_read(ctx, {self.reg_num});
517        """))
518
519class ModifierSource(Register, Single, OldSource):
520    def decl_reg_num(self, f, regno):
521        f.write(code_fmt(f"""\
522            const int {self.reg_num} = insn->regno[{regno}] + HEX_REG_M0;
523        """))
524    def decl_tcg(self, f, tag, regno):
525        self.decl_reg_num(f, regno)
526        f.write(code_fmt(f"""\
527            TCGv {self.reg_tcg()} = hex_gpr[{self.reg_num}];
528            TCGv CS G_GNUC_UNUSED =
529                hex_gpr[{self.reg_num} - HEX_REG_M0 + HEX_REG_CS0];
530        """))
531    def idef_arg(self, declared):
532        declared.append(self.reg_tcg())
533        declared.append("CS")
534    def analyze_read(self, f, regno):
535        self.decl_reg_num(f, regno)
536        f.write(code_fmt(f"""\
537            ctx_log_reg_read(ctx, {self.reg_num});
538        """))
539
540class PredDest(Register, Single, Dest):
541    def decl_tcg(self, f, tag, regno):
542        self.decl_reg_num(f, regno)
543        f.write(code_fmt(f"""\
544            TCGv {self.reg_tcg()} = tcg_temp_new();
545        """))
546    def log_write(self, f, tag):
547        f.write(code_fmt(f"""\
548            gen_log_pred_write(ctx, {self.reg_num}, {self.reg_tcg()});
549        """))
550    def analyze_write(self, f, tag, regno):
551        self.decl_reg_num(f, regno)
552        f.write(code_fmt(f"""\
553            ctx_log_pred_write(ctx, {self.reg_num});
554        """))
555
556class PredSource(Register, Single, OldSource):
557    def decl_tcg(self, f, tag, regno):
558        self.decl_reg_num(f, regno)
559        f.write(code_fmt(f"""\
560            TCGv {self.reg_tcg()} = hex_pred[{self.reg_num}];
561        """))
562    def analyze_read(self, f, regno):
563        self.decl_reg_num(f, regno)
564        f.write(code_fmt(f"""\
565            ctx_log_pred_read(ctx, {self.reg_num});
566        """))
567
568class PredNewSource(Register, Single, NewSource):
569    def decl_tcg(self, f, tag, regno):
570        f.write(code_fmt(f"""\
571            TCGv {self.reg_tcg()} = get_result_pred(ctx, insn->regno[{regno}]);
572        """))
573    def analyze_read(self, f, regno):
574        self.decl_reg_num(f, regno)
575        f.write(code_fmt(f"""\
576            ctx_log_pred_read(ctx, {self.reg_num});
577        """))
578
579class PredReadWrite(Register, Single, ReadWrite):
580    def decl_tcg(self, f, tag, regno):
581        self.decl_reg_num(f, regno)
582        f.write(code_fmt(f"""\
583            TCGv {self.reg_tcg()} = tcg_temp_new();
584            tcg_gen_mov_tl({self.reg_tcg()}, hex_pred[{self.reg_num}]);
585        """))
586    def log_write(self, f, tag):
587        f.write(code_fmt(f"""\
588            gen_log_pred_write(ctx, {self.reg_num}, {self.reg_tcg()});
589        """))
590    def analyze_write(self, f, tag, regno):
591        self.decl_reg_num(f, regno)
592        f.write(code_fmt(f"""\
593            ctx_log_pred_write(ctx, {self.reg_num});
594        """))
595
596class PairDest(Register, Pair, Dest):
597    def decl_tcg(self, f, tag, regno):
598        self.decl_reg_num(f, regno)
599        f.write(code_fmt(f"""\
600            TCGv_i64 {self.reg_tcg()} =
601                get_result_gpr_pair(ctx, {self.reg_num});
602        """))
603    def log_write(self, f, tag):
604        f.write(code_fmt(f"""\
605            gen_log_reg_write_pair(ctx, {self.reg_num}, {self.reg_tcg()});
606        """))
607    def analyze_write(self, f, tag, regno):
608        self.decl_reg_num(f, regno)
609        predicated = "true" if is_predicated(tag) else "false"
610        f.write(code_fmt(f"""\
611            ctx_log_reg_write_pair(ctx, {self.reg_num}, {predicated});
612        """))
613
614class PairSource(Register, Pair, OldSource):
615    def decl_tcg(self, f, tag, regno):
616        self.decl_reg_num(f, regno)
617        f.write(code_fmt(f"""\
618            TCGv_i64 {self.reg_tcg()} = tcg_temp_new_i64();
619            tcg_gen_concat_i32_i64({self.reg_tcg()},
620                                    hex_gpr[{self.reg_num}],
621                                    hex_gpr[{self.reg_num} + 1]);
622        """))
623    def analyze_read(self, f, regno):
624        self.decl_reg_num(f, regno)
625        f.write(code_fmt(f"""\
626            ctx_log_reg_read_pair(ctx, {self.reg_num});
627        """))
628
629class PairReadWrite(Register, Pair, ReadWrite):
630    def decl_tcg(self, f, tag, regno):
631        self.decl_reg_num(f, regno)
632        f.write(code_fmt(f"""\
633            TCGv_i64 {self.reg_tcg()} =
634                get_result_gpr_pair(ctx, {self.reg_num});
635            tcg_gen_concat_i32_i64({self.reg_tcg()},
636                                   hex_gpr[{self.reg_num}],
637                                   hex_gpr[{self.reg_num} + 1]);
638        """))
639    def log_write(self, f, tag):
640        f.write(code_fmt(f"""\
641            gen_log_reg_write_pair(ctx, {self.reg_num}, {self.reg_tcg()});
642        """))
643    def analyze_write(self, f, tag, regno):
644        self.decl_reg_num(f, regno)
645        predicated = "true" if is_predicated(tag) else "false"
646        f.write(code_fmt(f"""\
647            ctx_log_reg_write_pair(ctx, {self.reg_num}, {predicated});
648        """))
649
650class ControlPairDest(Register, Pair, Dest):
651    def decl_reg_num(self, f, regno):
652        f.write(code_fmt(f"""\
653            const int {self.reg_num} = insn->regno[{regno}] + HEX_REG_SA0;
654        """))
655    def decl_tcg(self, f, tag, regno):
656        self.decl_reg_num(f, regno)
657        f.write(code_fmt(f"""\
658            TCGv_i64 {self.reg_tcg()} =
659                get_result_gpr_pair(ctx, {self.reg_num});
660        """))
661    def log_write(self, f, tag):
662        f.write(code_fmt(f"""\
663            gen_write_ctrl_reg_pair(ctx, {self.reg_num}, {self.reg_tcg()});
664        """))
665    def analyze_write(self, f, tag, regno):
666        self.decl_reg_num(f, regno)
667        predicated = "true" if is_predicated(tag) else "false"
668        f.write(code_fmt(f"""\
669            ctx_log_reg_write_pair(ctx, {self.reg_num}, {predicated});
670        """))
671
672class ControlPairSource(Register, Pair, OldSource):
673    def decl_reg_num(self, f, regno):
674        f.write(code_fmt(f"""\
675            const int {self.reg_num} = insn->regno[{regno}] + HEX_REG_SA0;
676        """))
677    def decl_tcg(self, f, tag, regno):
678        self.decl_reg_num(f, regno)
679        f.write(code_fmt(f"""\
680            TCGv_i64 {self.reg_tcg()} = tcg_temp_new_i64();
681            gen_read_ctrl_reg_pair(ctx, {self.reg_num}, {self.reg_tcg()});
682        """))
683    def analyze_read(self, f, regno):
684        self.decl_reg_num(f, regno)
685        f.write(code_fmt(f"""\
686            ctx_log_reg_read_pair(ctx, {self.reg_num});
687        """))
688
689class VRegDest(Register, Hvx, Dest):
690    def decl_tcg(self, f, tag, regno):
691        self.decl_reg_num(f, regno)
692        f.write(code_fmt(f"""\
693            const intptr_t {self.hvx_off()} =
694                {vreg_offset_func(tag)}(ctx, {self.reg_num}, 1, true);
695        """))
696        if not skip_qemu_helper(tag):
697            f.write(code_fmt(f"""\
698                TCGv_ptr {self.reg_tcg()} = tcg_temp_new_ptr();
699                tcg_gen_addi_ptr({self.reg_tcg()}, tcg_env, {self.hvx_off()});
700            """))
701    def log_write(self, f, tag):
702        pass
703    def helper_hvx_desc(self, f):
704        f.write(code_fmt(f"""\
705            /* {self.reg_tcg()} is *(MMVector *)({self.helper_arg_name()}) */
706        """))
707    def analyze_write(self, f, tag, regno):
708        self.decl_reg_num(f, regno)
709        newv = hvx_newv(tag)
710        predicated = "true" if is_predicated(tag) else "false"
711        f.write(code_fmt(f"""\
712            ctx_log_vreg_write(ctx, {self.reg_num}, {newv}, {predicated});
713        """))
714
715class VRegSource(Register, Hvx, OldSource):
716    def decl_tcg(self, f, tag, regno):
717        self.decl_reg_num(f, regno)
718        f.write(code_fmt(f"""\
719            const intptr_t {self.hvx_off()} = vreg_src_off(ctx, {self.reg_num});
720        """))
721        if not skip_qemu_helper(tag):
722            f.write(code_fmt(f"""\
723                TCGv_ptr {self.reg_tcg()} = tcg_temp_new_ptr();
724                tcg_gen_addi_ptr({self.reg_tcg()}, tcg_env, {self.hvx_off()});
725            """))
726    def helper_hvx_desc(self, f):
727        f.write(code_fmt(f"""\
728            /* {self.reg_tcg()} is *(MMVector *)({self.helper_arg_name()}) */
729        """))
730    def analyze_read(self, f, regno):
731        self.decl_reg_num(f, regno)
732        f.write(code_fmt(f"""\
733            ctx_log_vreg_read(ctx, {self.reg_num});
734        """))
735
736class VRegNewSource(Register, Hvx, NewSource):
737    def decl_tcg(self, f, tag, regno):
738        self.decl_reg_num(f, regno)
739        if skip_qemu_helper(tag):
740            f.write(code_fmt(f"""\
741                const intptr_t {self.hvx_off()} =
742                    ctx_future_vreg_off(ctx, {self.reg_num}, 1, true);
743            """))
744    def helper_hvx_desc(self, f):
745        f.write(code_fmt(f"""\
746            /* {self.reg_tcg()} is *(MMVector *)({self.helper_arg_name()}) */
747        """))
748    def analyze_read(self, f, regno):
749        self.decl_reg_num(f, regno)
750        f.write(code_fmt(f"""\
751            ctx_log_vreg_read(ctx, {self.reg_num});
752        """))
753
754class VRegReadWrite(Register, Hvx, ReadWrite):
755    def decl_tcg(self, f, tag, regno):
756        self.decl_reg_num(f, regno)
757        f.write(code_fmt(f"""\
758            const intptr_t {self.hvx_off()} =
759                {vreg_offset_func(tag)}(ctx, {self.reg_num}, 1, true);
760            tcg_gen_gvec_mov(MO_64, {self.hvx_off()},
761                             vreg_src_off(ctx, {self.reg_num}),
762                             sizeof(MMVector), sizeof(MMVector));
763        """))
764        if not skip_qemu_helper(tag):
765            f.write(code_fmt(f"""\
766                TCGv_ptr {self.reg_tcg()} = tcg_temp_new_ptr();
767                tcg_gen_addi_ptr({self.reg_tcg()}, tcg_env, {self.hvx_off()});
768            """))
769    def log_write(self, f, tag):
770        pass
771    def helper_hvx_desc(self, f):
772        f.write(code_fmt(f"""\
773            /* {self.reg_tcg()} is *(MMVector *)({self.helper_arg_name()}) */
774        """))
775    def analyze_write(self, f, tag, regno):
776        self.decl_reg_num(f, regno)
777        newv = hvx_newv(tag)
778        predicated = "true" if is_predicated(tag) else "false"
779        f.write(code_fmt(f"""\
780            ctx_log_vreg_write(ctx, {self.reg_num}, {newv}, {predicated});
781        """))
782
783class VRegTmp(Register, Hvx, ReadWrite):
784    def decl_tcg(self, f, tag, regno):
785        self.decl_reg_num(f, regno)
786        f.write(code_fmt(f"""\
787            const intptr_t {self.hvx_off()} = offsetof(CPUHexagonState, vtmp);
788        """))
789        if not skip_qemu_helper(tag):
790            f.write(code_fmt(f"""\
791                TCGv_ptr {self.reg_tcg()} = tcg_temp_new_ptr();
792                tcg_gen_addi_ptr({self.reg_tcg()}, tcg_env, {self.hvx_off()});
793                tcg_gen_gvec_mov(MO_64, {self.hvx_off()},
794                                 vreg_src_off(ctx, {self.reg_num}),
795                                 sizeof(MMVector), sizeof(MMVector));
796            """))
797    def log_write(self, f, tag):
798        f.write(code_fmt(f"""\
799            gen_log_vreg_write(ctx, {self.hvx_off()}, {self.reg_num},
800                               {hvx_newv(tag)});
801        """))
802    def helper_hvx_desc(self, f):
803        f.write(code_fmt(f"""\
804            /* {self.reg_tcg()} is *(MMVector *)({self.helper_arg_name()}) */
805        """))
806    def analyze_write(self, f, tag, regno):
807        self.decl_reg_num(f, regno)
808        newv = hvx_newv(tag)
809        predicated = "true" if is_predicated(tag) else "false"
810        f.write(code_fmt(f"""\
811            ctx_log_vreg_write(ctx, {self.reg_num}, {newv}, {predicated});
812        """))
813
814class VRegPairDest(Register, Hvx, Dest):
815    def decl_tcg(self, f, tag, regno):
816        self.decl_reg_num(f, regno)
817        f.write(code_fmt(f"""\
818            const intptr_t {self.hvx_off()} =
819                {vreg_offset_func(tag)}(ctx, {self.reg_num}, 2, true);
820        """))
821        if not skip_qemu_helper(tag):
822            f.write(code_fmt(f"""\
823                TCGv_ptr {self.reg_tcg()} = tcg_temp_new_ptr();
824                tcg_gen_addi_ptr({self.reg_tcg()}, tcg_env, {self.hvx_off()});
825            """))
826    def log_write(self, f, tag):
827        pass
828    def helper_hvx_desc(self, f):
829        f.write(code_fmt(f"""\
830            /* {self.reg_tcg()} is *(MMVectorPair *)({self.helper_arg_name()}) */
831        """))
832    def analyze_write(self, f, tag, regno):
833        self.decl_reg_num(f, regno)
834        newv = hvx_newv(tag)
835        predicated = "true" if is_predicated(tag) else "false"
836        f.write(code_fmt(f"""\
837            ctx_log_vreg_write_pair(ctx, {self.reg_num}, {newv}, {predicated});
838        """))
839
840class VRegPairSource(Register, Hvx, OldSource):
841    def decl_tcg(self, f, tag, regno):
842        self.decl_reg_num(f, regno)
843        f.write(code_fmt(f"""\
844            const intptr_t {self.hvx_off()} =
845                offsetof(CPUHexagonState, {self.reg_tcg()});
846            tcg_gen_gvec_mov(MO_64, {self.hvx_off()},
847                             vreg_src_off(ctx, {self.reg_num}),
848                             sizeof(MMVector), sizeof(MMVector));
849            tcg_gen_gvec_mov(MO_64, {self.hvx_off()} + sizeof(MMVector),
850                             vreg_src_off(ctx, {self.reg_num} ^ 1),
851                             sizeof(MMVector), sizeof(MMVector));
852        """))
853        if not skip_qemu_helper(tag):
854            f.write(code_fmt(f"""\
855                TCGv_ptr {self.reg_tcg()} = tcg_temp_new_ptr();
856                tcg_gen_addi_ptr({self.reg_tcg()}, tcg_env, {self.hvx_off()});
857            """))
858    def helper_hvx_desc(self, f):
859        f.write(code_fmt(f"""\
860            /* {self.reg_tcg()} is *(MMVectorPair *)({self.helper_arg_name()}) */
861        """))
862    def analyze_read(self, f, regno):
863        self.decl_reg_num(f, regno)
864        f.write(code_fmt(f"""\
865            ctx_log_vreg_read_pair(ctx, {self.reg_num});
866        """))
867
868class VRegPairReadWrite(Register, Hvx, ReadWrite):
869    def decl_tcg(self, f, tag, regno):
870        self.decl_reg_num(f, regno)
871        f.write(code_fmt(f"""\
872            const intptr_t {self.hvx_off()} =
873                offsetof(CPUHexagonState, {self.reg_tcg()});
874            tcg_gen_gvec_mov(MO_64, {self.hvx_off()},
875                             vreg_src_off(ctx, {self.reg_num}),
876                             sizeof(MMVector), sizeof(MMVector));
877            tcg_gen_gvec_mov(MO_64, {self.hvx_off()} + sizeof(MMVector),
878                             vreg_src_off(ctx, {self.reg_num} ^ 1),
879                             sizeof(MMVector), sizeof(MMVector));
880        """))
881        if not skip_qemu_helper(tag):
882            f.write(code_fmt(f"""\
883                TCGv_ptr {self.reg_tcg()} = tcg_temp_new_ptr();
884                tcg_gen_addi_ptr({self.reg_tcg()}, tcg_env, {self.hvx_off()});
885            """))
886    def log_write(self, f, tag):
887        f.write(code_fmt(f"""\
888            gen_log_vreg_write_pair(ctx, {self.hvx_off()}, {self.reg_num},
889                                    {hvx_newv(tag)});
890        """))
891    def helper_hvx_desc(self, f):
892        f.write(code_fmt(f"""\
893            /* {self.reg_tcg()} is *(MMVectorPair *)({self.helper_arg_name()}) */
894        """))
895    def analyze_write(self, f, tag, regno):
896        self.decl_reg_num(f, regno)
897        newv = hvx_newv(tag)
898        predicated = "true" if is_predicated(tag) else "false"
899        f.write(code_fmt(f"""\
900            ctx_log_vreg_write_pair(ctx, {self.reg_num}, {newv}, {predicated});
901        """))
902
903class QRegDest(Register, Hvx, Dest):
904    def decl_tcg(self, f, tag, regno):
905        self.decl_reg_num(f, regno)
906        f.write(code_fmt(f"""\
907            const intptr_t {self.hvx_off()} =
908                get_result_qreg(ctx, {self.reg_num});
909        """))
910        if not skip_qemu_helper(tag):
911            f.write(code_fmt(f"""\
912                TCGv_ptr {self.reg_tcg()} = tcg_temp_new_ptr();
913                tcg_gen_addi_ptr({self.reg_tcg()}, tcg_env, {self.hvx_off()});
914            """))
915    def log_write(self, f, tag):
916        pass
917    def helper_hvx_desc(self, f):
918        f.write(code_fmt(f"""\
919            /* {self.reg_tcg()} is *(MMQReg *)({self.helper_arg_name()}) */
920        """))
921    def analyze_write(self, f, tag, regno):
922        self.decl_reg_num(f, regno)
923        f.write(code_fmt(f"""\
924            ctx_log_qreg_write(ctx, {self.reg_num});
925        """))
926
927class QRegSource(Register, Hvx, OldSource):
928    def decl_tcg(self, f, tag, regno):
929        self.decl_reg_num(f, regno)
930        f.write(code_fmt(f"""\
931            const intptr_t {self.hvx_off()} =
932                offsetof(CPUHexagonState, QRegs[{self.reg_num}]);
933        """))
934        if not skip_qemu_helper(tag):
935            f.write(code_fmt(f"""\
936                TCGv_ptr {self.reg_tcg()} = tcg_temp_new_ptr();
937                tcg_gen_addi_ptr({self.reg_tcg()}, tcg_env, {self.hvx_off()});
938            """))
939    def helper_hvx_desc(self, f):
940        f.write(code_fmt(f"""\
941            /* {self.reg_tcg()} is *(MMQReg *)({self.helper_arg_name()}) */
942        """))
943    def analyze_read(self, f, regno):
944        self.decl_reg_num(f, regno)
945        f.write(code_fmt(f"""\
946            ctx_log_qreg_read(ctx, {self.reg_num});
947        """))
948
949class QRegReadWrite(Register, Hvx, ReadWrite):
950    def decl_tcg(self, f, tag, regno):
951        self.decl_reg_num(f, regno)
952        f.write(code_fmt(f"""\
953            const intptr_t {self.hvx_off()} =
954                get_result_qreg(ctx, {self.reg_num});
955            tcg_gen_gvec_mov(MO_64, {self.hvx_off()},
956                             offsetof(CPUHexagonState, QRegs[{self.reg_num}]),
957                             sizeof(MMQReg), sizeof(MMQReg));
958        """))
959        if not skip_qemu_helper(tag):
960            f.write(code_fmt(f"""\
961                TCGv_ptr {self.reg_tcg()} = tcg_temp_new_ptr();
962                tcg_gen_addi_ptr({self.reg_tcg()}, tcg_env, {self.hvx_off()});
963            """))
964    def log_write(self, f, tag):
965        pass
966    def helper_hvx_desc(self, f):
967        f.write(code_fmt(f"""\
968            /* {self.reg_tcg()} is *(MMQReg *)({self.helper_arg_name()}) */
969        """))
970    def analyze_write(self, f, tag, regno):
971        self.decl_reg_num(f, regno)
972        f.write(code_fmt(f"""\
973            ctx_log_qreg_write(ctx, {self.reg_num});
974        """))
975
976def init_registers():
977    regs = {
978        GprDest("R", "d"),
979        GprDest("R", "e"),
980        GprSource("R", "s"),
981        GprSource("R", "t"),
982        GprSource("R", "u"),
983        GprSource("R", "v"),
984        GprReadWrite("R", "x"),
985        GprReadWrite("R", "y"),
986        ControlDest("C", "d"),
987        ControlSource("C", "s"),
988        ModifierSource("M", "u"),
989        PredDest("P", "d"),
990        PredDest("P", "e"),
991        PredSource("P", "s"),
992        PredSource("P", "t"),
993        PredSource("P", "u"),
994        PredSource("P", "v"),
995        PredReadWrite("P", "x"),
996        PairDest("R", "dd"),
997        PairDest("R", "ee"),
998        PairSource("R", "ss"),
999        PairSource("R", "tt"),
1000        PairReadWrite("R", "xx"),
1001        PairReadWrite("R", "yy"),
1002        ControlPairDest("C", "dd"),
1003        ControlPairSource("C", "ss"),
1004        VRegDest("V", "d"),
1005        VRegSource("V", "s"),
1006        VRegSource("V", "u"),
1007        VRegSource("V", "v"),
1008        VRegSource("V", "w"),
1009        VRegReadWrite("V", "x"),
1010        VRegTmp("V", "y"),
1011        VRegPairDest("V", "dd"),
1012        VRegPairSource("V", "uu"),
1013        VRegPairSource("V", "vv"),
1014        VRegPairReadWrite("V", "xx"),
1015        QRegDest("Q", "d"),
1016        QRegDest("Q", "e"),
1017        QRegSource("Q", "s"),
1018        QRegSource("Q", "t"),
1019        QRegSource("Q", "u"),
1020        QRegSource("Q", "v"),
1021        QRegReadWrite("Q", "x"),
1022    }
1023    for reg in regs:
1024        registers[f"{reg.regtype}{reg.regid}"] = reg
1025
1026    new_regs = {
1027        GprNewSource("N", "s"),
1028        GprNewSource("N", "t"),
1029        PredNewSource("P", "t"),
1030        PredNewSource("P", "u"),
1031        PredNewSource("P", "v"),
1032        VRegNewSource("O", "s"),
1033    }
1034    for reg in new_regs:
1035        new_registers[f"{reg.regtype}{reg.regid}"] = reg
1036
1037def get_register(tag, regtype, regid):
1038    if f"{regtype}{regid}V" in semdict[tag]:
1039        return registers[f"{regtype}{regid}"]
1040    else:
1041        return new_registers[f"{regtype}{regid}"]
1042
1043def helper_ret_type(tag, regs):
1044    ## If there is a scalar result, it is the return type
1045    return_type = HelperArg( "void", "void", "void")
1046    numscalarresults = 0
1047    for regtype, regid in regs:
1048        reg = get_register(tag, regtype, regid)
1049        if reg.is_written() and reg.is_scalar_reg():
1050            return_type = HelperArg(
1051                reg.helper_proto_type(),
1052                reg.reg_tcg(),
1053                reg.helper_arg_type()
1054            )
1055    if numscalarresults > 1:
1056        raise Exception("numscalarresults > 1")
1057    return return_type
1058
1059def helper_args(tag, regs, imms):
1060    args = []
1061
1062    ## First argument is the CPU state
1063    args.append(HelperArg(
1064        "env",
1065        "tcg_env",
1066        "CPUHexagonState *env"
1067    ))
1068
1069    ## For predicated instructions, we pass in the destination register
1070    if is_predicated(tag):
1071        for regtype, regid in regs:
1072            reg = get_register(tag, regtype, regid)
1073            if reg.is_writeonly() and not reg.is_hvx_reg():
1074                args.append(reg.helper_arg())
1075
1076    ## Pass the HVX destination registers
1077    for regtype, regid in regs:
1078        reg = get_register(tag, regtype, regid)
1079        if reg.is_written() and reg.is_hvx_reg():
1080            args.append(reg.helper_arg())
1081
1082    ## Pass the source registers
1083    for regtype, regid in regs:
1084        reg = get_register(tag, regtype, regid)
1085        if reg.is_read() and not (reg.is_hvx_reg() and reg.is_readwrite()):
1086            args.append(reg.helper_arg())
1087
1088    ## Pass the immediates
1089    for immlett, bits, immshift in imms:
1090        args.append(HelperArg(
1091            "s32",
1092            f"tcg_constant_tl({imm_name(immlett)})",
1093            f"int32_t {imm_name(immlett)}"
1094        ))
1095
1096    ## Other stuff the helper might need
1097    if need_pkt_has_multi_cof(tag):
1098        args.append(HelperArg(
1099            "i32",
1100            "tcg_constant_tl(ctx->pkt->pkt_has_multi_cof)",
1101            "uint32_t pkt_has_multi_cof"
1102        ))
1103    if need_pkt_need_commit(tag):
1104        args.append(HelperArg(
1105            "i32",
1106            "tcg_constant_tl(ctx->need_commit)",
1107            "uint32_t pkt_need_commit"
1108        ))
1109    if need_PC(tag):
1110        args.append(HelperArg(
1111            "i32",
1112            "tcg_constant_tl(ctx->pkt->pc)",
1113            "target_ulong PC"
1114        ))
1115    if need_next_PC(tag):
1116        args.append(HelperArg(
1117            "i32",
1118            "tcg_constant_tl(ctx->next_PC)",
1119            "target_ulong next_PC"
1120        ))
1121    if need_slot(tag):
1122        args.append(HelperArg(
1123            "i32",
1124            "gen_slotval(ctx)",
1125            "uint32_t slotval"
1126        ))
1127    if need_part1(tag):
1128        args.append(HelperArg(
1129            "i32",
1130            "tcg_constant_tl(insn->part1)"
1131            "uint32_t part1"
1132        ))
1133    return args
1134