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 hex_common
24
25
26##
27## Helpers for gen_helper_function
28##
29def gen_decl_ea(f):
30    f.write("    uint32_t EA;\n")
31
32
33def gen_helper_return_type(f, regtype, regid, regno):
34    if regno > 1:
35        f.write(", ")
36    f.write("int32_t")
37
38
39def gen_helper_return_type_pair(f, regtype, regid, regno):
40    if regno > 1:
41        f.write(", ")
42    f.write("int64_t")
43
44
45def gen_helper_arg(f, regtype, regid, regno):
46    if regno > 0:
47        f.write(", ")
48    f.write(f"int32_t {regtype}{regid}V")
49
50
51def gen_helper_arg_new(f, regtype, regid, regno):
52    if regno >= 0:
53        f.write(", ")
54    f.write(f"int32_t {regtype}{regid}N")
55
56
57def gen_helper_arg_pair(f, regtype, regid, regno):
58    if regno >= 0:
59        f.write(", ")
60    f.write(f"int64_t {regtype}{regid}V")
61
62
63def gen_helper_arg_ext(f, regtype, regid, regno):
64    if regno > 0:
65        f.write(", ")
66    f.write(f"void *{regtype}{regid}V_void")
67
68
69def gen_helper_arg_ext_pair(f, regtype, regid, regno):
70    if regno > 0:
71        f.write(", ")
72    f.write(f"void *{regtype}{regid}V_void")
73
74
75def gen_helper_arg_opn(f, regtype, regid, i, tag):
76    if hex_common.is_pair(regid):
77        if hex_common.is_hvx_reg(regtype):
78            gen_helper_arg_ext_pair(f, regtype, regid, i)
79        else:
80            gen_helper_arg_pair(f, regtype, regid, i)
81    elif hex_common.is_single(regid):
82        if hex_common.is_old_val(regtype, regid, tag):
83            if hex_common.is_hvx_reg(regtype):
84                gen_helper_arg_ext(f, regtype, regid, i)
85            else:
86                gen_helper_arg(f, regtype, regid, i)
87        elif hex_common.is_new_val(regtype, regid, tag):
88            gen_helper_arg_new(f, regtype, regid, i)
89        else:
90            print("Bad register parse: ", regtype, regid, toss, numregs)
91    else:
92        print("Bad register parse: ", regtype, regid, toss, numregs)
93
94
95def gen_helper_arg_imm(f, immlett):
96    f.write(f", int32_t {hex_common.imm_name(immlett)}")
97
98
99def gen_helper_dest_decl(f, regtype, regid, regno, subfield=""):
100    f.write(f"    int32_t {regtype}{regid}V{subfield} = 0;\n")
101
102
103def gen_helper_dest_decl_pair(f, regtype, regid, regno, subfield=""):
104    f.write(f"    int64_t {regtype}{regid}V{subfield} = 0;\n")
105
106
107def gen_helper_dest_decl_ext(f, regtype, regid):
108    if regtype == "Q":
109        f.write(
110            f"    /* {regtype}{regid}V is *(MMQReg *)" f"({regtype}{regid}V_void) */\n"
111        )
112    else:
113        f.write(
114            f"    /* {regtype}{regid}V is *(MMVector *)"
115            f"({regtype}{regid}V_void) */\n"
116        )
117
118
119def gen_helper_dest_decl_ext_pair(f, regtype, regid, regno):
120    f.write(
121        f"    /* {regtype}{regid}V is *(MMVectorPair *))"
122        f"{regtype}{regid}V_void) */\n"
123    )
124
125
126def gen_helper_dest_decl_opn(f, regtype, regid, i):
127    if hex_common.is_pair(regid):
128        if hex_common.is_hvx_reg(regtype):
129            gen_helper_dest_decl_ext_pair(f, regtype, regid, i)
130        else:
131            gen_helper_dest_decl_pair(f, regtype, regid, i)
132    elif hex_common.is_single(regid):
133        if hex_common.is_hvx_reg(regtype):
134            gen_helper_dest_decl_ext(f, regtype, regid)
135        else:
136            gen_helper_dest_decl(f, regtype, regid, i)
137    else:
138        print("Bad register parse: ", regtype, regid, toss, numregs)
139
140
141def gen_helper_src_var_ext(f, regtype, regid):
142    if regtype == "Q":
143        f.write(
144            f"    /* {regtype}{regid}V is *(MMQReg *)" f"({regtype}{regid}V_void) */\n"
145        )
146    else:
147        f.write(
148            f"    /* {regtype}{regid}V is *(MMVector *)"
149            f"({regtype}{regid}V_void) */\n"
150        )
151
152
153def gen_helper_src_var_ext_pair(f, regtype, regid, regno):
154    f.write(
155        f"    /* {regtype}{regid}V{regno} is *(MMVectorPair *)"
156        f"({regtype}{regid}V{regno}_void) */\n"
157    )
158
159
160def gen_helper_return(f, regtype, regid, regno):
161    f.write(f"    return {regtype}{regid}V;\n")
162
163
164def gen_helper_return_pair(f, regtype, regid, regno):
165    f.write(f"    return {regtype}{regid}V;\n")
166
167
168def gen_helper_dst_write_ext(f, regtype, regid):
169    return
170
171
172def gen_helper_dst_write_ext_pair(f, regtype, regid):
173    return
174
175
176def gen_helper_return_opn(f, regtype, regid, i):
177    if hex_common.is_pair(regid):
178        if hex_common.is_hvx_reg(regtype):
179            gen_helper_dst_write_ext_pair(f, regtype, regid)
180        else:
181            gen_helper_return_pair(f, regtype, regid, i)
182    elif hex_common.is_single(regid):
183        if hex_common.is_hvx_reg(regtype):
184            gen_helper_dst_write_ext(f, regtype, regid)
185        else:
186            gen_helper_return(f, regtype, regid, i)
187    else:
188        print("Bad register parse: ", regtype, regid, toss, numregs)
189
190
191##
192## Generate the TCG code to call the helper
193##     For A2_add: Rd32=add(Rs32,Rt32), { RdV=RsV+RtV;}
194##     We produce:
195##       int32_t HELPER(A2_add)(CPUHexagonState *env, int32_t RsV, int32_t RtV)
196##       {
197##           uint32_t slot __attribute__(unused)) = 4;
198##           int32_t RdV = 0;
199##           { RdV=RsV+RtV;}
200##           COUNT_HELPER(A2_add);
201##           return RdV;
202##       }
203##
204def gen_helper_function(f, tag, tagregs, tagimms):
205    regs = tagregs[tag]
206    imms = tagimms[tag]
207
208    numresults = 0
209    numscalarresults = 0
210    numscalarreadwrite = 0
211    for regtype, regid, toss, numregs in regs:
212        if hex_common.is_written(regid):
213            numresults += 1
214            if hex_common.is_scalar_reg(regtype):
215                numscalarresults += 1
216        if hex_common.is_readwrite(regid):
217            if hex_common.is_scalar_reg(regtype):
218                numscalarreadwrite += 1
219
220    if numscalarresults > 1:
221        ## The helper is bogus when there is more than one result
222        f.write(
223            f"void HELPER({tag})(CPUHexagonState *env) " f"{{ BOGUS_HELPER({tag}); }}\n"
224        )
225    else:
226        ## The return type of the function is the type of the destination
227        ## register (if scalar)
228        i = 0
229        for regtype, regid, toss, numregs in regs:
230            if hex_common.is_written(regid):
231                if hex_common.is_pair(regid):
232                    if hex_common.is_hvx_reg(regtype):
233                        continue
234                    else:
235                        gen_helper_return_type_pair(f, regtype, regid, i)
236                elif hex_common.is_single(regid):
237                    if hex_common.is_hvx_reg(regtype):
238                        continue
239                    else:
240                        gen_helper_return_type(f, regtype, regid, i)
241                else:
242                    print("Bad register parse: ", regtype, regid, toss, numregs)
243            i += 1
244
245        if numscalarresults == 0:
246            f.write("void")
247        f.write(f" HELPER({tag})(CPUHexagonState *env")
248
249        ## Arguments include the vector destination operands
250        i = 1
251        for regtype, regid, toss, numregs in regs:
252            if hex_common.is_written(regid):
253                if hex_common.is_pair(regid):
254                    if hex_common.is_hvx_reg(regtype):
255                        gen_helper_arg_ext_pair(f, regtype, regid, i)
256                    else:
257                        continue
258                elif hex_common.is_single(regid):
259                    if hex_common.is_hvx_reg(regtype):
260                        gen_helper_arg_ext(f, regtype, regid, i)
261                    else:
262                        # This is the return value of the function
263                        continue
264                else:
265                    print("Bad register parse: ", regtype, regid, toss, numregs)
266                i += 1
267
268        ## For conditional instructions, we pass in the destination register
269        if "A_CONDEXEC" in hex_common.attribdict[tag]:
270            for regtype, regid, toss, numregs in regs:
271                if hex_common.is_writeonly(regid) and not hex_common.is_hvx_reg(
272                    regtype
273                ):
274                    gen_helper_arg_opn(f, regtype, regid, i, tag)
275                    i += 1
276
277        ## Arguments to the helper function are the source regs and immediates
278        for regtype, regid, toss, numregs in regs:
279            if hex_common.is_read(regid):
280                if hex_common.is_hvx_reg(regtype) and hex_common.is_readwrite(regid):
281                    continue
282                gen_helper_arg_opn(f, regtype, regid, i, tag)
283                i += 1
284        for immlett, bits, immshift in imms:
285            gen_helper_arg_imm(f, immlett)
286            i += 1
287
288        if hex_common.need_pkt_has_multi_cof(tag):
289            f.write(", uint32_t pkt_has_multi_cof")
290
291        if hex_common.need_PC(tag):
292            if i > 0:
293                f.write(", ")
294            f.write("target_ulong PC")
295            i += 1
296        if hex_common.helper_needs_next_PC(tag):
297            if i > 0:
298                f.write(", ")
299            f.write("target_ulong next_PC")
300            i += 1
301        if hex_common.need_slot(tag):
302            if i > 0:
303                f.write(", ")
304            f.write("uint32_t slot")
305            i += 1
306        if hex_common.need_part1(tag):
307            if i > 0:
308                f.write(", ")
309            f.write("uint32_t part1")
310        f.write(")\n{\n")
311        if hex_common.need_ea(tag):
312            gen_decl_ea(f)
313        ## Declare the return variable
314        i = 0
315        if "A_CONDEXEC" not in hex_common.attribdict[tag]:
316            for regtype, regid, toss, numregs in regs:
317                if hex_common.is_writeonly(regid):
318                    gen_helper_dest_decl_opn(f, regtype, regid, i)
319                i += 1
320
321        for regtype, regid, toss, numregs in regs:
322            if hex_common.is_read(regid):
323                if hex_common.is_pair(regid):
324                    if hex_common.is_hvx_reg(regtype):
325                        gen_helper_src_var_ext_pair(f, regtype, regid, i)
326                elif hex_common.is_single(regid):
327                    if hex_common.is_hvx_reg(regtype):
328                        gen_helper_src_var_ext(f, regtype, regid)
329                else:
330                    print("Bad register parse: ", regtype, regid, toss, numregs)
331
332        if "A_FPOP" in hex_common.attribdict[tag]:
333            f.write("    arch_fpop_start(env);\n")
334
335        f.write(f"    {hex_common.semdict[tag]}\n")
336
337        if "A_FPOP" in hex_common.attribdict[tag]:
338            f.write("    arch_fpop_end(env);\n")
339
340        ## Save/return the return variable
341        for regtype, regid, toss, numregs in regs:
342            if hex_common.is_written(regid):
343                gen_helper_return_opn(f, regtype, regid, i)
344        f.write("}\n\n")
345        ## End of the helper definition
346
347
348def main():
349    hex_common.read_semantics_file(sys.argv[1])
350    hex_common.read_attribs_file(sys.argv[2])
351    hex_common.read_overrides_file(sys.argv[3])
352    hex_common.read_overrides_file(sys.argv[4])
353    ## Whether or not idef-parser is enabled is
354    ## determined by the number of arguments to
355    ## this script:
356    ##
357    ##   5 args. -> not enabled,
358    ##   6 args. -> idef-parser enabled.
359    ##
360    ## The 6:th arg. then holds a list of the successfully
361    ## parsed instructions.
362    is_idef_parser_enabled = len(sys.argv) > 6
363    if is_idef_parser_enabled:
364        hex_common.read_idef_parser_enabled_file(sys.argv[5])
365    hex_common.calculate_attribs()
366    tagregs = hex_common.get_tagregs()
367    tagimms = hex_common.get_tagimms()
368
369    output_file = sys.argv[-1]
370    with open(output_file, "w") as f:
371        for tag in hex_common.tags:
372            ## Skip the priv instructions
373            if "A_PRIV" in hex_common.attribdict[tag]:
374                continue
375            ## Skip the guest instructions
376            if "A_GUEST" in hex_common.attribdict[tag]:
377                continue
378            ## Skip the diag instructions
379            if tag == "Y6_diag":
380                continue
381            if tag == "Y6_diag0":
382                continue
383            if tag == "Y6_diag1":
384                continue
385            if hex_common.skip_qemu_helper(tag):
386                continue
387            if hex_common.is_idef_parser_enabled(tag):
388                continue
389
390            gen_helper_function(f, tag, tagregs, tagimms)
391
392
393if __name__ == "__main__":
394    main()
395