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            hex_common.bad_register(regtype, regid)
91    else:
92        hex_common.bad_register(regtype, regid)
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        hex_common.bad_register(regtype, regid)
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        hex_common.bad_register(regtype, regid)
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 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 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                    hex_common.bad_register(regtype, regid)
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 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                    hex_common.bad_register(regtype, regid)
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 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 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        if (hex_common.need_pkt_need_commit(tag)):
291            f.write(", uint32_t pkt_need_commit")
292
293        if hex_common.need_PC(tag):
294            if i > 0:
295                f.write(", ")
296            f.write("target_ulong PC")
297            i += 1
298        if hex_common.helper_needs_next_PC(tag):
299            if i > 0:
300                f.write(", ")
301            f.write("target_ulong next_PC")
302            i += 1
303        if hex_common.need_slot(tag):
304            if i > 0:
305                f.write(", ")
306            f.write("uint32_t slotval")
307            i += 1
308        if hex_common.need_part1(tag):
309            if i > 0:
310                f.write(", ")
311            f.write("uint32_t part1")
312        f.write(")\n{\n")
313        if hex_common.need_ea(tag):
314            gen_decl_ea(f)
315        ## Declare the return variable
316        i = 0
317        if "A_CONDEXEC" not in hex_common.attribdict[tag]:
318            for regtype, regid in regs:
319                if hex_common.is_writeonly(regid):
320                    gen_helper_dest_decl_opn(f, regtype, regid, i)
321                i += 1
322
323        for regtype, regid in regs:
324            if hex_common.is_read(regid):
325                if hex_common.is_pair(regid):
326                    if hex_common.is_hvx_reg(regtype):
327                        gen_helper_src_var_ext_pair(f, regtype, regid, i)
328                elif hex_common.is_single(regid):
329                    if hex_common.is_hvx_reg(regtype):
330                        gen_helper_src_var_ext(f, regtype, regid)
331                else:
332                    hex_common.bad_register(regtype, regid)
333
334        if hex_common.need_slot(tag):
335            if "A_LOAD" in hex_common.attribdict[tag]:
336                f.write("    bool pkt_has_store_s1 = slotval & 0x1;\n")
337            f.write("    uint32_t slot = slotval >> 1;\n")
338
339        if "A_FPOP" in hex_common.attribdict[tag]:
340            f.write("    arch_fpop_start(env);\n")
341
342        f.write(f"    {hex_common.semdict[tag]}\n")
343
344        if "A_FPOP" in hex_common.attribdict[tag]:
345            f.write("    arch_fpop_end(env);\n")
346
347        ## Save/return the return variable
348        for regtype, regid in regs:
349            if hex_common.is_written(regid):
350                gen_helper_return_opn(f, regtype, regid, i)
351        f.write("}\n\n")
352        ## End of the helper definition
353
354
355def main():
356    hex_common.read_semantics_file(sys.argv[1])
357    hex_common.read_attribs_file(sys.argv[2])
358    hex_common.read_overrides_file(sys.argv[3])
359    hex_common.read_overrides_file(sys.argv[4])
360    ## Whether or not idef-parser is enabled is
361    ## determined by the number of arguments to
362    ## this script:
363    ##
364    ##   5 args. -> not enabled,
365    ##   6 args. -> idef-parser enabled.
366    ##
367    ## The 6:th arg. then holds a list of the successfully
368    ## parsed instructions.
369    is_idef_parser_enabled = len(sys.argv) > 6
370    if is_idef_parser_enabled:
371        hex_common.read_idef_parser_enabled_file(sys.argv[5])
372    hex_common.calculate_attribs()
373    tagregs = hex_common.get_tagregs()
374    tagimms = hex_common.get_tagimms()
375
376    output_file = sys.argv[-1]
377    with open(output_file, "w") as f:
378        for tag in hex_common.tags:
379            ## Skip the priv instructions
380            if "A_PRIV" in hex_common.attribdict[tag]:
381                continue
382            ## Skip the guest instructions
383            if "A_GUEST" in hex_common.attribdict[tag]:
384                continue
385            ## Skip the diag instructions
386            if tag == "Y6_diag":
387                continue
388            if tag == "Y6_diag0":
389                continue
390            if tag == "Y6_diag1":
391                continue
392            if hex_common.skip_qemu_helper(tag):
393                continue
394            if hex_common.is_idef_parser_enabled(tag):
395                continue
396
397            gen_helper_function(f, tag, tagregs, tagimms)
398
399
400if __name__ == "__main__":
401    main()
402