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