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