Python scripts generate the following files helper_protos_generated.h For each instruction we create DEF_HELPER function prototype helper_funcs_generated.h For each instruction we create the helper function definition tcg_funcs_generated.h For each instruction we create TCG code to generate call to helper shortcode_generated.h Generate a table of instruction "shortcode" semantics opcodes_def_generated.h Gives a list of all the opcodes op_attribs_generated.h Lists all the attributes associated with each instruction op_regs_generated.h Lists the register and immediate operands for each instruction printinsn_generated.h Data for printing (disassembling) each instruction (format string + operands)
Signed-off-by: Taylor Simpson <tsimp...@quicinc.com> --- target/hexagon/gen_helper_funcs.py | 230 +++++++++++++++++++++++++++ target/hexagon/gen_helper_protos.py | 158 +++++++++++++++++++ target/hexagon/gen_op_attribs.py | 46 ++++++ target/hexagon/gen_op_regs.py | 119 ++++++++++++++ target/hexagon/gen_opcodes_def.py | 43 ++++++ target/hexagon/gen_printinsn.py | 182 ++++++++++++++++++++++ target/hexagon/gen_shortcode.py | 71 +++++++++ target/hexagon/gen_tcg_funcs.py | 301 ++++++++++++++++++++++++++++++++++++ target/hexagon/hex_common.py | 204 ++++++++++++++++++++++++ 9 files changed, 1354 insertions(+) create mode 100755 target/hexagon/gen_helper_funcs.py create mode 100755 target/hexagon/gen_helper_protos.py create mode 100755 target/hexagon/gen_op_attribs.py create mode 100755 target/hexagon/gen_op_regs.py create mode 100755 target/hexagon/gen_opcodes_def.py create mode 100755 target/hexagon/gen_printinsn.py create mode 100755 target/hexagon/gen_shortcode.py create mode 100755 target/hexagon/gen_tcg_funcs.py create mode 100755 target/hexagon/hex_common.py diff --git a/target/hexagon/gen_helper_funcs.py b/target/hexagon/gen_helper_funcs.py new file mode 100755 index 0000000..4595887 --- /dev/null +++ b/target/hexagon/gen_helper_funcs.py @@ -0,0 +1,230 @@ +#!/usr/bin/env python3 + +## +## Copyright(c) 2019-2020 Qualcomm Innovation Center, Inc. All Rights Reserved. +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, see <http://www.gnu.org/licenses/>. +## + +import sys +import re +import string +from io import StringIO + +from hex_common import * + +## +## Helpers for gen_helper_function +## +def gen_decl_ea(f): + f.write("size4u_t EA;\n") + +def gen_helper_return_type(f,regtype,regid,regno): + if regno > 1 : f.write(", ") + f.write("int32_t") + +def gen_helper_return_type_pair(f,regtype,regid,regno): + if regno > 1 : f.write(", ") + f.write("int64_t") + +def gen_helper_arg(f,regtype,regid,regno): + if regno > 0 : f.write(", " ) + f.write("int32_t %s%sV" % (regtype,regid)) + +def gen_helper_arg_new(f,regtype,regid,regno): + if regno >= 0 : f.write(", " ) + f.write("int32_t %s%sN" % (regtype,regid)) + +def gen_helper_arg_pair(f,regtype,regid,regno): + if regno >= 0 : f.write(", ") + f.write("int64_t %s%sV" % (regtype,regid)) + +def gen_helper_arg_opn(f,regtype,regid,i,tag): + if (is_pair(regid)): + gen_helper_arg_pair(f,regtype,regid,i) + elif (is_single(regid)): + if is_old_val(regtype, regid, tag): + gen_helper_arg(f,regtype,regid,i) + elif is_new_val(regtype, regid, tag): + gen_helper_arg_new(f,regtype,regid,i) + else: + print("Bad register parse: ",regtype,regid,toss,numregs) + else: + print("Bad register parse: ",regtype,regid,toss,numregs) + +def gen_helper_arg_imm(f,immlett): + f.write(", int32_t %s" % (imm_name(immlett))) + +def gen_helper_dest_decl(f,regtype,regid,regno,subfield=""): + f.write("int32_t %s%sV%s = 0;\n" % \ + (regtype,regid,subfield)) + +def gen_helper_dest_decl_pair(f,regtype,regid,regno,subfield=""): + f.write("int64_t %s%sV%s = 0;\n" % \ + (regtype,regid,subfield)) + +def gen_helper_dest_decl_opn(f,regtype,regid,i): + if (is_pair(regid)): + gen_helper_dest_decl_pair(f,regtype,regid,i) + elif (is_single(regid)): + gen_helper_dest_decl(f,regtype,regid,i) + else: + print("Bad register parse: ",regtype,regid,toss,numregs) + +def gen_helper_return(f,regtype,regid,regno): + f.write("return %s%sV;\n" % (regtype,regid)) + +def gen_helper_return_pair(f,regtype,regid,regno): + f.write("return %s%sV;\n" % (regtype,regid)) + +def gen_helper_return_opn(f, regtype, regid, i): + if (is_pair(regid)): + gen_helper_return_pair(f,regtype,regid,i) + elif (is_single(regid)): + gen_helper_return(f,regtype,regid,i) + else: + print("Bad register parse: ",regtype,regid,toss,numregs) + +## +## Generate the TCG code to call the helper +## For A2_add: Rd32=add(Rs32,Rt32), { RdV=RsV+RtV;} +## We produce: +## #ifndef fGEN_TCG_A2_add +## int32_t HELPER(A2_add)(CPUHexagonState *env, int32_t RsV, int32_t RtV) +## { +## uint32_t slot __attribute__(unused)) = 4; +## int32_t RdV = 0; +## { RdV=RsV+RtV;} +## return RdV; +## } +## #endif +## +def gen_helper_function(f, tag, tagregs, tagimms): + regs = tagregs[tag] + imms = tagimms[tag] + + f.write('#ifndef fGEN_TCG_%s\n' % tag) + numresults = 0 + numscalarresults = 0 + numscalarreadwrite = 0 + for regtype,regid,toss,numregs in regs: + if (is_written(regid)): + numresults += 1 + if (is_scalar_reg(regtype)): + numscalarresults += 1 + if (is_readwrite(regid)): + if (is_scalar_reg(regtype)): + numscalarreadwrite += 1 + + if (numscalarresults > 1): + ## The helper is bogus when there is more than one result + f.write("void HELPER(%s)(CPUHexagonState *env) { BOGUS_HELPER(%s); }\n" + % (tag, tag)) + else: + ## The return type of the function is the type of the destination + ## register + i=0 + for regtype,regid,toss,numregs in regs: + if (is_written(regid)): + if (is_pair(regid)): + gen_helper_return_type_pair(f,regtype,regid,i) + elif (is_single(regid)): + gen_helper_return_type(f,regtype,regid,i) + else: + print("Bad register parse: ",regtype,regid,toss,numregs) + i += 1 + + if (numscalarresults == 0): + f.write("void") + f.write(" HELPER(%s)(CPUHexagonState *env" % tag) + + i = 1 + + ## Arguments to the helper function are the source regs and immediates + for regtype,regid,toss,numregs in regs: + if (is_read(regid)): + gen_helper_arg_opn(f,regtype,regid,i,tag) + i += 1 + for immlett,bits,immshift in imms: + gen_helper_arg_imm(f,immlett) + i += 1 + if need_slot(tag): + if i > 0: f.write(", ") + f.write("uint32_t slot") + i += 1 + if need_part1(tag): + if i > 0: f.write(", ") + f.write("uint32_t part1") + f.write(")\n{\n") + if (not need_slot(tag)): + f.write("uint32_t slot __attribute__((unused)) = 4;\n" ) + if need_ea(tag): gen_decl_ea(f) + ## Declare the return variable + i=0 + for regtype,regid,toss,numregs in regs: + if (is_writeonly(regid)): + gen_helper_dest_decl_opn(f,regtype,regid,i) + i += 1 + + if 'A_FPOP' in attribdict[tag]: + f.write('fFPOP_START();\n'); + + f.write(semdict[tag]) + f.write("\n") + + if 'A_FPOP' in attribdict[tag]: + f.write('fFPOP_END();\n'); + + ## Save/return the return variable + for regtype,regid,toss,numregs in regs: + if (is_written(regid)): + gen_helper_return_opn(f, regtype, regid, i) + f.write("}\n") + ## End of the helper definition + f.write('#endif\n') + +def main(): + read_semantics_file(sys.argv[1]) + read_attribs_file(sys.argv[2]) + calculate_attribs() + tagregs = get_tagregs() + tagimms = get_tagimms() + + f = StringIO() + + for tag in tags: + ## Skip the priv instructions + if ( "A_PRIV" in attribdict[tag] ) : + continue + ## Skip the guest instructions + if ( "A_GUEST" in attribdict[tag] ) : + continue + ## Skip the diag instructions + if ( tag == "Y6_diag" ) : + continue + if ( tag == "Y6_diag0" ) : + continue + if ( tag == "Y6_diag1" ) : + continue + + gen_helper_function(f, tag, tagregs, tagimms) + + + realf = open('helper_funcs_generated.h','w') + realf.write(f.getvalue()) + realf.close() + f.close() + +if __name__ == "__main__": + main() diff --git a/target/hexagon/gen_helper_protos.py b/target/hexagon/gen_helper_protos.py new file mode 100755 index 0000000..6d5ab07 --- /dev/null +++ b/target/hexagon/gen_helper_protos.py @@ -0,0 +1,158 @@ +#!/usr/bin/env python3 + +## +## Copyright(c) 2019-2020 Qualcomm Innovation Center, Inc. All Rights Reserved. +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, see <http://www.gnu.org/licenses/>. +## + +import sys +import re +import string +from io import StringIO + +from hex_common import * + +## +## Helpers for gen_helper_prototype +## +def_helper_types = { + 'N' : 's32', + 'O' : 's32', + 'P' : 's32', + 'M' : 's32', + 'C' : 's32', + 'R' : 's32', + 'V' : 'ptr', + 'Q' : 'ptr' +} + +def_helper_types_pair = { + 'R' : 's64', + 'C' : 's64', + 'S' : 's64', + 'G' : 's64', + 'V' : 'ptr', + 'Q' : 'ptr' +} + +def gen_def_helper_opn(f, tag, regtype, regid, toss, numregs, i): + if (is_pair(regid)): + f.write(", %s" % (def_helper_types_pair[regtype])) + elif (is_single(regid)): + f.write(", %s" % (def_helper_types[regtype])) + else: + print("Bad register parse: ",regtype,regid,toss,numregs) + +## +## Generate the DEF_HELPER prototype for an instruction +## For A2_add: Rd32=add(Rs32,Rt32) +## We produce: +## #ifndef fGEN_TCG_A2_add +## DEF_HELPER_3(A2_add, s32, env, s32, s32) +## #endif +## +def gen_helper_prototype(f, tag, tagregs, tagimms): + regs = tagregs[tag] + imms = tagimms[tag] + + f.write('#ifndef fGEN_TCG_%s\n' % tag) + numresults = 0 + numscalarresults = 0 + numscalarreadwrite = 0 + for regtype,regid,toss,numregs in regs: + if (is_written(regid)): + numresults += 1 + if (is_scalar_reg(regtype)): + numscalarresults += 1 + if (is_readwrite(regid)): + if (is_scalar_reg(regtype)): + numscalarreadwrite += 1 + + if (numscalarresults > 1): + ## The helper is bogus when there is more than one result + f.write('DEF_HELPER_1(%s, void, env)\n' % tag) + else: + ## Figure out how many arguments the helper will take + if (numscalarresults == 0): + def_helper_size = len(regs)+len(imms)+numscalarreadwrite+1 + if need_part1(tag): def_helper_size += 1 + if need_slot(tag): def_helper_size += 1 + f.write('DEF_HELPER_%s(%s' % (def_helper_size, tag)) + ## The return type is void + f.write(', void' ) + else: + def_helper_size = len(regs)+len(imms)+numscalarreadwrite + if need_part1(tag): def_helper_size += 1 + if need_slot(tag): def_helper_size += 1 + f.write('DEF_HELPER_%s(%s' % (def_helper_size, tag)) + + ## Generate the qemu DEF_HELPER type for each result + i=0 + for regtype,regid,toss,numregs in regs: + if (is_written(regid)): + gen_def_helper_opn(f, tag, regtype, regid, toss, numregs, i) + i += 1 + + ## Put the env between the outputs and inputs + f.write(', env' ) + i += 1 + + ## Generate the qemu type for each input operand (regs and immediates) + for regtype,regid,toss,numregs in regs: + if (is_read(regid)): + gen_def_helper_opn(f, tag, regtype, regid, toss, numregs, i) + i += 1 + for immlett,bits,immshift in imms: + f.write(", s32") + + ## Add the arguments for the instruction slot and part1 (if needed) + if need_slot(tag): f.write(', i32' ) + if need_part1(tag): f.write(' , i32' ) + f.write(')\n') + f.write('#endif\n') + +def main(): + read_semantics_file(sys.argv[1]) + read_attribs_file(sys.argv[2]) + calculate_attribs() + tagregs = get_tagregs() + tagimms = get_tagimms() + + f = StringIO() + + for tag in tags: + ## Skip the priv instructions + if ( "A_PRIV" in attribdict[tag] ) : + continue + ## Skip the guest instructions + if ( "A_GUEST" in attribdict[tag] ) : + continue + ## Skip the diag instructions + if ( tag == "Y6_diag" ) : + continue + if ( tag == "Y6_diag0" ) : + continue + if ( tag == "Y6_diag1" ) : + continue + + gen_helper_prototype(f, tag, tagregs, tagimms) + + realf = open('helper_protos_generated.h','w') + realf.write(f.getvalue()) + realf.close() + f.close() + +if __name__ == "__main__": + main() diff --git a/target/hexagon/gen_op_attribs.py b/target/hexagon/gen_op_attribs.py new file mode 100755 index 0000000..663296e --- /dev/null +++ b/target/hexagon/gen_op_attribs.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python3 + +## +## Copyright(c) 2019-2020 Qualcomm Innovation Center, Inc. All Rights Reserved. +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, see <http://www.gnu.org/licenses/>. +## + +import sys +import re +import string +from io import StringIO + +from hex_common import * + +def main(): + read_semantics_file(sys.argv[1]) + read_attribs_file(sys.argv[2]) + calculate_attribs() + + ## + ## Generate the op_attribs_generated.h file + ## Lists all the attributes associated with each instruction + ## + f = StringIO() + for tag in tags: + f.write('OP_ATTRIB(%s,ATTRIBS(%s))\n' % \ + (tag, ','.join(sorted(attribdict[tag])))) + realf = open('op_attribs_generated.h', 'wt') + realf.write(f.getvalue()) + realf.close() + f.close() + +if __name__ == "__main__": + main() diff --git a/target/hexagon/gen_op_regs.py b/target/hexagon/gen_op_regs.py new file mode 100755 index 0000000..abb7441 --- /dev/null +++ b/target/hexagon/gen_op_regs.py @@ -0,0 +1,119 @@ +#!/usr/bin/env python3 + +## +## Copyright(c) 2019-2020 Qualcomm Innovation Center, Inc. All Rights Reserved. +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, see <http://www.gnu.org/licenses/>. +## + +import sys +import re +import string +from io import StringIO + +from hex_common import * + +## +## Generate the op_regs_generated.h file +## Lists the register and immediate operands for each instruction +## +def calculate_regid_reg(tag): + def letter_inc(x): return chr(ord(x)+1) + ordered_implregs = [ 'SP','FP','LR' ] + srcdst_lett = 'X' + src_lett = 'S' + dst_lett = 'D' + retstr = "" + mapdict = {} + for reg in ordered_implregs: + reg_rd = 0 + reg_wr = 0 + if ('A_IMPLICIT_WRITES_'+reg) in attribdict[tag]: reg_wr = 1 + if reg_rd and reg_wr: + retstr += srcdst_lett + mapdict[srcdst_lett] = reg + srcdst_lett = letter_inc(srcdst_lett) + elif reg_rd: + retstr += src_lett + mapdict[src_lett] = reg + src_lett = letter_inc(src_lett) + elif reg_wr: + retstr += dst_lett + mapdict[dst_lett] = reg + dst_lett = letter_inc(dst_lett) + return retstr,mapdict + +def calculate_regid_letters(tag): + retstr,mapdict = calculate_regid_reg(tag) + return retstr + +def strip_reg_prefix(x): + y=x.replace('UREG.','') + y=y.replace('MREG.','') + return y.replace('GREG.','') + +def main(): + read_semantics_file(sys.argv[1]) + read_attribs_file(sys.argv[2]) + tagregs = get_tagregs() + tagimms = get_tagimms() + + f = StringIO() + + for tag in tags: + regs = tagregs[tag] + rregs = [] + wregs = [] + regids = "" + for regtype,regid,toss,numregs in regs: + if is_read(regid): + if regid[0] not in regids: regids += regid[0] + rregs.append(regtype+regid+numregs) + if is_written(regid): + wregs.append(regtype+regid+numregs) + if regid[0] not in regids: regids += regid[0] + for attrib in attribdict[tag]: + if attribinfo[attrib]['rreg']: + rregs.append(strip_reg_prefix(attribinfo[attrib]['rreg'])) + if attribinfo[attrib]['wreg']: + wregs.append(strip_reg_prefix(attribinfo[attrib]['wreg'])) + regids += calculate_regid_letters(tag) + f.write('REGINFO(%s,"%s",\t/*RD:*/\t"%s",\t/*WR:*/\t"%s")\n' % \ + (tag,regids,",".join(rregs),",".join(wregs))) + + for tag in tags: + imms = tagimms[tag] + f.write( 'IMMINFO(%s' % tag) + if not imms: + f.write(''','u',0,0,'U',0,0''') + for sign,size,shamt in imms: + if sign == 'r': sign = 's' + if not shamt: + shamt = "0" + f.write(''','%s',%s,%s''' % (sign,size,shamt)) + if len(imms) == 1: + if sign.isupper(): + myu = 'u' + else: + myu = 'U' + f.write(''','%s',0,0''' % myu) + f.write(')\n') + + realf = open('op_regs_generated.h','w') + realf.write(f.getvalue()) + realf.close() + f.close() + +if __name__ == "__main__": + main() diff --git a/target/hexagon/gen_opcodes_def.py b/target/hexagon/gen_opcodes_def.py new file mode 100755 index 0000000..c34c2b1 --- /dev/null +++ b/target/hexagon/gen_opcodes_def.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 + +## +## Copyright(c) 2019-2020 Qualcomm Innovation Center, Inc. All Rights Reserved. +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, see <http://www.gnu.org/licenses/>. +## + +import sys +import re +import string +from io import StringIO + +from hex_common import * + +def main(): + read_semantics_file(sys.argv[1]) + + ## + ## Generate the opcodes_def_generated.h file + ## Gives a list of all the opcodes + ## + f = StringIO() + for tag in tags: + f.write ( "OPCODE(%s),\n" % (tag) ) + realf = open('opcodes_def_generated.h', 'wt') + realf.write(f.getvalue()) + realf.close() + f.close() + +if __name__ == "__main__": + main() diff --git a/target/hexagon/gen_printinsn.py b/target/hexagon/gen_printinsn.py new file mode 100755 index 0000000..6fb9424 --- /dev/null +++ b/target/hexagon/gen_printinsn.py @@ -0,0 +1,182 @@ +#!/usr/bin/env python3 + +## +## Copyright(c) 2019-2020 Qualcomm Innovation Center, Inc. All Rights Reserved. +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, see <http://www.gnu.org/licenses/>. +## + +import sys +import re +import string +from io import StringIO + +from hex_common import * + +## +## Generate the printinsn_generated.h file +## Data for printing each instruction (format string + operands) +## +def regprinter(m): + str = m.group(1) + str += ":".join(["%d"]*len(m.group(2))) + str += m.group(3) + if ('S' in m.group(1)) and (len(m.group(2)) == 1): + str += "/%s" + elif ('C' in m.group(1)) and (len(m.group(2)) == 1): + str += "/%s" + return str + +def spacify(s): + # Regular expression that matches any operator that contains '=' character: + opswithequal_re = '[-+^&|!<>=]?=' + # Regular expression that matches any assignment operator. + assignment_re = '[-+^&|]?=' + + # Out of the operators that contain the = sign, if the operator is also an + # assignment, spaces will be added around it, unless it's enclosed within + # parentheses, or spaces are already present. + + equals = re.compile(opswithequal_re) + assign = re.compile(assignment_re) + + slen = len(s) + paren_count = {} + i = 0 + pc = 0 + while i < slen: + c = s[i] + if c == '(': + pc += 1 + elif c == ')': + pc -= 1 + paren_count[i] = pc + i += 1 + + # Iterate over all operators that contain the equal sign. If any + # match is also an assignment operator, add spaces around it if + # the parenthesis count is 0. + pos = 0 + out = [] + for m in equals.finditer(s): + ms = m.start() + me = m.end() + # t is the string that matched opswithequal_re. + t = m.string[ms:me] + out += s[pos:ms] + pos = me + if paren_count[ms] == 0: + # Check if the entire string t is an assignment. + am = assign.match(t) + if am and len(am.group(0)) == me-ms: + # Don't add spaces if they are already there. + if ms > 0 and s[ms-1] != ' ': + out.append(' ') + out += t + if me < slen and s[me] != ' ': + out.append(' ') + continue + # If this is not an assignment, just append it to the output + # string. + out += t + + # Append the remaining part of the string. + out += s[pos:len(s)] + return ''.join(out) + +def main(): + read_semantics_file(sys.argv[1]) + read_attribs_file(sys.argv[2]) + + immext_casere = re.compile(r'IMMEXT\(([A-Za-z])') + + f = StringIO() + + for tag in tags: + if not behdict[tag]: continue + extendable_upper_imm = False + extendable_lower_imm = False + m = immext_casere.search(semdict[tag]) + if m: + if m.group(1).isupper(): + extendable_upper_imm = True + else: + extendable_lower_imm = True + beh = behdict[tag] + beh = regre.sub(regprinter,beh) + beh = absimmre.sub(r"#%s0x%x",beh) + beh = relimmre.sub(r"PC+%s%d",beh) + beh = spacify(beh) + # Print out a literal "%s" at the end, used to match empty string + # so C won't complain at us + if ("A_VECX" in attribdict[tag]): macname = "DEF_VECX_PRINTINFO" + else: macname = "DEF_PRINTINFO" + f.write('%s(%s,"%s%%s"' % (macname,tag,beh)) + regs_or_imms = reg_or_immre.findall(behdict[tag]) + ri = 0 + seenregs = {} + for allregs,a,b,c,d,allimm,immlett,bits,immshift in regs_or_imms: + if a: + #register + if b in seenregs: + regno = seenregs[b] + else: + regno = ri + if len(b) == 1: + f.write(',REGNO(%d)' % regno) + if 'S' in a: + f.write(',sreg2str(REGNO(%d))' % regno) + elif 'C' in a: + f.write(',creg2str(REGNO(%d))' % regno) + elif len(b) == 2: + f.write(',REGNO(%d)+1,REGNO(%d)' % (regno,regno)) + elif len(b) == 4: + f.write(',REGNO(%d)^3,REGNO(%d)^2,REGNO(%d)^1,REGNO(%d)' % \ + (regno,regno,regno,regno)) + else: + print("Put some stuff to handle quads here") + if b not in seenregs: + seenregs[b] = ri + ri += 1 + else: + #immediate + if (immlett.isupper()): + if extendable_upper_imm: + if immlett in 'rR': + f.write(',insn->extension_valid?"##":""') + else: + f.write(',insn->extension_valid?"#":""') + else: + f.write(',""') + ii = 1 + else: + if extendable_lower_imm: + if immlett in 'rR': + f.write(',insn->extension_valid?"##":""') + else: + f.write(',insn->extension_valid?"#":""') + else: + f.write(',""') + ii = 0 + f.write(',IMMNO(%d)' % ii) + # append empty string so there is at least one more arg + f.write(',"")\n') + + realf = open('printinsn_generated.h','w') + realf.write(f.getvalue()) + realf.close() + f.close() + +if __name__ == "__main__": + main() diff --git a/target/hexagon/gen_shortcode.py b/target/hexagon/gen_shortcode.py new file mode 100755 index 0000000..3255972 --- /dev/null +++ b/target/hexagon/gen_shortcode.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 + +## +## Copyright(c) 2019-2020 Qualcomm Innovation Center, Inc. All Rights Reserved. +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, see <http://www.gnu.org/licenses/>. +## + +import sys +import re +import string +from io import StringIO + +from hex_common import * + +def gen_shortcode(f, tag): + f.write('DEF_SHORTCODE(%s, %s)\n' % (tag,semdict[tag])) + +def main(): + read_semantics_file(sys.argv[1]) + read_attribs_file(sys.argv[2]) + calculate_attribs() + tagregs = get_tagregs() + tagimms = get_tagimms() + + ## + ## Generate the shortcode_generated.h file + ## + f = StringIO() + + f.write("#ifndef DEF_SHORTCODE\n") + f.write("#define DEF_SHORTCODE(TAG,SHORTCODE) /* Nothing */\n") + f.write("#endif\n") + + for tag in tags: + ## Skip the priv instructions + if ( "A_PRIV" in attribdict[tag] ) : + continue + ## Skip the guest instructions + if ( "A_GUEST" in attribdict[tag] ) : + continue + ## Skip the diag instructions + if ( tag == "Y6_diag" ) : + continue + if ( tag == "Y6_diag0" ) : + continue + if ( tag == "Y6_diag1" ) : + continue + + gen_shortcode(f, tag) + + f.write("#undef DEF_SHORTCODE\n") + + realf = open('shortcode_generated.h','w') + realf.write(f.getvalue()) + realf.close() + f.close() + +if __name__ == "__main__": + main() diff --git a/target/hexagon/gen_tcg_funcs.py b/target/hexagon/gen_tcg_funcs.py new file mode 100755 index 0000000..1b2ef5b --- /dev/null +++ b/target/hexagon/gen_tcg_funcs.py @@ -0,0 +1,301 @@ +#!/usr/bin/env python3 + +## +## Copyright(c) 2019-2020 Qualcomm Innovation Center, Inc. All Rights Reserved. +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, see <http://www.gnu.org/licenses/>. +## + +import sys +import re +import string +from io import StringIO + +from hex_common import * + +## +## Helpers for gen_tcg_func +## +def gen_decl_ea_tcg(f): + f.write("DECL_EA;\n") + +def gen_free_ea_tcg(f): + f.write("FREE_EA;\n") + +def genptr_decl(f,regtype,regid,regno): + regN="%s%sN" % (regtype,regid) + macro = "DECL_%sREG_%s" % (regtype, regid) + f.write("%s(%s%sV, %s, %d, 0);\n" % \ + (macro, regtype, regid, regN, regno)) + +def genptr_decl_new(f,regtype,regid,regno): + regN="%s%sX" % (regtype,regid) + macro = "DECL_NEW_%sREG_%s" % (regtype, regid) + f.write("%s(%s%sN, %s, %d, 0);\n" % \ + (macro, regtype, regid, regN, regno)) + +def genptr_decl_opn(f, tag, regtype, regid, toss, numregs, i): + if (is_pair(regid)): + genptr_decl(f,regtype,regid,i) + elif (is_single(regid)): + if is_old_val(regtype, regid, tag): + genptr_decl(f,regtype,regid,i) + elif is_new_val(regtype, regid, tag): + genptr_decl_new(f,regtype,regid,i) + else: + print("Bad register parse: ",regtype,regid,toss,numregs) + else: + print("Bad register parse: ",regtype,regid,toss,numregs) + +def genptr_decl_imm(f,immlett): + if (immlett.isupper()): + i = 1 + else: + i = 0 + f.write("DECL_IMM(%s,%d);\n" % (imm_name(immlett),i)) + +def genptr_free(f,regtype,regid,regno): + macro = "FREE_%sREG_%s" % (regtype, regid) + f.write("%s(%s%sV);\n" % (macro, regtype, regid)) + +def genptr_free_new(f,regtype,regid,regno): + macro = "FREE_NEW_%sREG_%s" % (regtype, regid) + f.write("%s(%s%sN);\n" % (macro, regtype, regid)) + +def genptr_free_opn(f,regtype,regid,i,tag): + if (is_pair(regid)): + genptr_free(f,regtype,regid,i) + elif (is_single(regid)): + if is_old_val(regtype, regid, tag): + genptr_free(f,regtype,regid,i) + elif is_new_val(regtype, regid, tag): + genptr_free_new(f,regtype,regid,i) + else: + print("Bad register parse: ",regtype,regid,toss,numregs) + else: + print("Bad register parse: ",regtype,regid,toss,numregs) + +def genptr_free_imm(f,immlett): + f.write("FREE_IMM(%s);\n" % (imm_name(immlett))) + +def genptr_src_read(f,regtype,regid): + macro = "READ_%sREG_%s" % (regtype, regid) + f.write("%s(%s%sV, %s%sN);\n" % \ + (macro,regtype,regid,regtype,regid)) + +def genptr_src_read_new(f,regtype,regid): + macro = "READ_NEW_%sREG_%s" % (regtype, regid) + f.write("%s(%s%sN, %s%sX);\n" % \ + (macro,regtype,regid,regtype,regid)) + +def genptr_src_read_opn(f,regtype,regid,tag): + if (is_pair(regid)): + genptr_src_read(f,regtype,regid) + elif (is_single(regid)): + if is_old_val(regtype, regid, tag): + genptr_src_read(f,regtype,regid) + elif is_new_val(regtype, regid, tag): + genptr_src_read_new(f,regtype,regid) + else: + print("Bad register parse: ",regtype,regid,toss,numregs) + else: + print("Bad register parse: ",regtype,regid,toss,numregs) + +def gen_helper_call_opn(f, tag, regtype, regid, toss, numregs, i): + if (i > 0): f.write(", ") + if (is_pair(regid)): + f.write("%s%sV" % (regtype,regid)) + elif (is_single(regid)): + if is_old_val(regtype, regid, tag): + f.write("%s%sV" % (regtype,regid)) + elif is_new_val(regtype, regid, tag): + f.write("%s%sN" % (regtype,regid)) + else: + print("Bad register parse: ",regtype,regid,toss,numregs) + else: + print("Bad register parse: ",regtype,regid,toss,numregs) + +def gen_helper_decl_imm(f,immlett): + f.write("DECL_TCG_IMM(tcgv_%s, %s);\n" % \ + (imm_name(immlett), imm_name(immlett))) + +def gen_helper_call_imm(f,immlett): + f.write(", tcgv_%s" % imm_name(immlett)) + +def gen_helper_free_imm(f,immlett): + f.write("FREE_TCG_IMM(tcgv_%s);\n" % imm_name(immlett)) + +def genptr_dst_write(f,regtype, regid): + macro = "WRITE_%sREG_%s" % (regtype, regid) + f.write("%s(%s%sN, %s%sV);\n" % (macro, regtype, regid, regtype, regid)) + +def genptr_dst_write_opn(f,regtype, regid, tag): + if (is_pair(regid)): + genptr_dst_write(f, regtype, regid) + elif (is_single(regid)): + genptr_dst_write(f, regtype, regid) + else: + print("Bad register parse: ",regtype,regid,toss,numregs) + +## +## Generate the TCG code to call the helper +## For A2_add: Rd32=add(Rs32,Rt32), { RdV=RsV+RtV;} +## We produce: +## { +## /* A2_add */ +## DECL_RREG_d(RdV, RdN, 0, 0); +## DECL_RREG_s(RsV, RsN, 1, 0); +## DECL_RREG_t(RtV, RtN, 2, 0); +## READ_RREG_s(RsV, RsN); +## READ_RREG_t(RtV, RtN); +## #ifdef fGEN_TCG_A2_add +## fGEN_TCG_A2_add({ RdV=RsV+RtV;}); +## #else +## gen_helper_A2_add(RdV, cpu_env, RsV, RtV); +## #endif +## WRITE_RREG_d(RdN, RdV); +## FREE_RREG_d(RdV); +## FREE_RREG_s(RsV); +## FREE_RREG_t(RtV); +## /* A2_add */ +## } +## +def gen_tcg_func(f, tag, regs, imms): + f.write('{\n') + f.write('/* %s */\n' % tag) + if need_ea(tag): gen_decl_ea_tcg(f) + i=0 + ## Declare all the operands (regs and immediates) + for regtype,regid,toss,numregs in regs: + genptr_decl_opn(f, tag, regtype, regid, toss, numregs, i) + i += 1 + for immlett,bits,immshift in imms: + genptr_decl_imm(f,immlett) + + if 'A_PRIV' in attribdict[tag]: + f.write('fCHECKFORPRIV();\n') + if 'A_GUEST' in attribdict[tag]: + f.write('fCHECKFORGUEST();\n') + if 'A_FPOP' in attribdict[tag]: + f.write('fFPOP_START();\n'); + + ## Read all the inputs + for regtype,regid,toss,numregs in regs: + if (is_read(regid)): + genptr_src_read_opn(f,regtype,regid,tag) + + f.write("#ifdef fGEN_TCG_%s\n" % tag) + f.write("fGEN_TCG_%s(%s);\n" % (tag, semdict[tag])) + f.write("#else\n") + ## Generate the call to the helper + f.write("do {\n") + for immlett,bits,immshift in imms: + gen_helper_decl_imm(f,immlett) + if need_part1(tag): f.write("PART1_WRAP(") + if need_slot(tag): f.write("SLOT_WRAP(") + f.write("gen_helper_%s(" % (tag)) + i=0 + ## If there is a scalar result, it is the return type + for regtype,regid,toss,numregs in regs: + if (is_written(regid)): + gen_helper_call_opn(f, tag, regtype, regid, toss, numregs, i) + i += 1 + if (i > 0): f.write(", ") + f.write("cpu_env") + i=1 + for regtype,regid,toss,numregs in regs: + if (is_read(regid)): + gen_helper_call_opn(f, tag, regtype, regid, toss, numregs, i) + i += 1 + for immlett,bits,immshift in imms: + gen_helper_call_imm(f,immlett) + + if need_slot(tag): f.write(", slot") + if need_part1(tag): f.write(", part1" ) + f.write(")") + if need_slot(tag): f.write(")") + if need_part1(tag): f.write(")") + f.write(";\n") + for immlett,bits,immshift in imms: + gen_helper_free_imm(f,immlett) + f.write("} while (0);\n") + f.write("#endif\n") + + ## Write all the outputs + for regtype,regid,toss,numregs in regs: + if (is_written(regid)): + genptr_dst_write_opn(f,regtype, regid, tag) + + if 'A_FPOP' in attribdict[tag]: + f.write('fFPOP_END();\n'); + + + ## Free all the operands (regs and immediates) + if need_ea(tag): gen_free_ea_tcg(f) + for regtype,regid,toss,numregs in regs: + genptr_free_opn(f,regtype,regid,i,tag) + i += 1 + for immlett,bits,immshift in imms: + genptr_free_imm(f,immlett) + + f.write("/* %s */\n" % tag) + f.write("}") + +def gen_def_tcg_func(f, tag, tagregs, tagimms): + regs = tagregs[tag] + imms = tagimms[tag] + + f.write('DEF_TCG_FUNC(%s, /* %s */\n' % (tag,semdict[tag])) + gen_tcg_func(f, tag, regs, imms) + f.write(")\n" ) + +def main(): + read_semantics_file(sys.argv[1]) + read_attribs_file(sys.argv[2]) + calculate_attribs() + tagregs = get_tagregs() + tagimms = get_tagimms() + + f = StringIO() + + f.write("#ifndef DEF_TCG_FUNC\n") + f.write("#define DEF_TCG_FUNC(TAG,GENFN) /* Nothing */\n") + f.write("#endif\n") + + for tag in tags: + ## Skip the priv instructions + if ( "A_PRIV" in attribdict[tag] ) : + continue + ## Skip the guest instructions + if ( "A_GUEST" in attribdict[tag] ) : + continue + ## Skip the diag instructions + if ( tag == "Y6_diag" ) : + continue + if ( tag == "Y6_diag0" ) : + continue + if ( tag == "Y6_diag1" ) : + continue + + gen_def_tcg_func(f, tag, tagregs, tagimms) + + f.write("#undef DEF_TCG_FUNC\n") + + realf = open('tcg_funcs_generated.h','w') + realf.write(f.getvalue()) + realf.close() + f.close() + +if __name__ == "__main__": + main() diff --git a/target/hexagon/hex_common.py b/target/hexagon/hex_common.py new file mode 100755 index 0000000..d45ffab --- /dev/null +++ b/target/hexagon/hex_common.py @@ -0,0 +1,204 @@ +#!/usr/bin/env python3 + +## +## Copyright(c) 2019-2020 Qualcomm Innovation Center, Inc. All Rights Reserved. +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, see <http://www.gnu.org/licenses/>. +## + +import sys +import re +import string +from io import StringIO + +behdict = {} # tag ->behavior +semdict = {} # tag -> semantics +attribdict = {} # tag -> attributes +macros = {} # macro -> macro information... +attribinfo = {} # Register information and misc +tags = [] # list of all tags + +# We should do this as a hash for performance, +# but to keep order let's keep it as a list. +def uniquify(seq): + seen = set() + seen_add = seen.add + return [x for x in seq if x not in seen and not seen_add(x)] + +regre = re.compile( + r"((?<!DUP)[MNORCPQXSGVZA])([stuvwxyzdefg]+)([.]?[LlHh]?)(\d+S?)") +immre = re.compile(r"[#]([rRsSuUm])(\d+)(?:[:](\d+))?") +reg_or_immre = \ + re.compile(r"(((?<!DUP)[MNRCOPQXSGVZA])([stuvwxyzdefg]+)" + \ + "([.]?[LlHh]?)(\d+S?))|([#]([rRsSuUm])(\d+)[:]?(\d+)?)") +relimmre = re.compile(r"[#]([rR])(\d+)(?:[:](\d+))?") +absimmre = re.compile(r"[#]([sSuUm])(\d+)(?:[:](\d+))?") + +finished_macros = set() + +def expand_macro_attribs(macro,allmac_re): + if macro.key not in finished_macros: + # Get a list of all things that might be macros + l = allmac_re.findall(macro.beh) + for submacro in l: + if not submacro: continue + if not macros[submacro]: + raise Exception("Couldn't find macro: <%s>" % l) + macro.attribs |= expand_macro_attribs( + macros[submacro], allmac_re) + finished_macros.add(macro.key) + return macro.attribs + +immextre = re.compile(r'f(MUST_)?IMMEXT[(]([UuSsRr])') +def calculate_attribs(): + # Recurse down macros, find attributes from sub-macros + macroValues = list(macros.values()) + allmacros_restr = "|".join(set([ m.re.pattern for m in macroValues ])) + allmacros_re = re.compile(allmacros_restr) + for macro in macroValues: + expand_macro_attribs(macro,allmacros_re) + # Append attributes to all instructions + for tag in tags: + for macname in allmacros_re.findall(semdict[tag]): + if not macname: continue + macro = macros[macname] + attribdict[tag] |= set(macro.attribs) + +def SEMANTICS(tag, beh, sem): + #print tag,beh,sem + behdict[tag] = beh + semdict[tag] = sem + attribdict[tag] = set() + tags.append(tag) # dicts have no order, this is for order + +def ATTRIBUTES(tag, attribstring): + attribstring = \ + attribstring.replace("ATTRIBS","").replace("(","").replace(")","") + if not attribstring: + return + attribs = attribstring.split(",") + for attrib in attribs: + attribdict[tag].add(attrib.strip()) + +class Macro(object): + __slots__ = ['key','name', 'beh', 'attribs', 're'] + def __init__(self, name, beh, attribs): + self.key = name + self.name = name + self.beh = beh + self.attribs = set(attribs) + self.re = re.compile("\\b" + name + "\\b") + +def MACROATTRIB(macname,beh,attribstring): + attribstring = attribstring.replace("(","").replace(")","") + if attribstring: + attribs = attribstring.split(",") + else: + attribs = [] + macros[macname] = Macro(macname,beh,attribs) + +def compute_tag_regs(tag): + return uniquify(regre.findall(behdict[tag])) + +def compute_tag_immediates(tag): + return uniquify(immre.findall(behdict[tag])) + +## +## tagregs is the main data structure we'll use +## tagregs[tag] will contain the registers used by an instruction +## Within each entry, we'll use the regtype and regid fields +## regtype can be one of the following +## C control register +## N new register value +## P predicate register +## R GPR register +## M modifier register +## regid can be one of the following +## d, e destination register +## dd destination register pair +## s, t, u, v, w source register +## ss, tt, uu, vv source register pair +## x, y read-write register +## xx, yy read-write register pair +## +def get_tagregs(): + return dict(zip(tags, list(map(compute_tag_regs, tags)))) + +def get_tagimms(): + return dict(zip(tags, list(map(compute_tag_immediates, tags)))) + +def is_pair(regid): + return len(regid) == 2 + +def is_single(regid): + return len(regid) == 1 + +def is_written(regid): + return regid[0] in "dexy" + +def is_writeonly(regid): + return regid[0] in "de" + +def is_read(regid): + return regid[0] in "stuvwxy" + +def is_readwrite(regid): + return regid[0] in "xy" + +def is_scalar_reg(regtype): + return regtype in "RPC" + +def is_old_val(regtype, regid, tag): + return regtype+regid+'V' in semdict[tag] + +def is_new_val(regtype, regid, tag): + return regtype+regid+'N' in semdict[tag] + +def need_slot(tag): + if ('A_CONDEXEC' in attribdict[tag] or + 'A_STORE' in attribdict[tag] or + 'A_LOAD' in attribdict[tag]): + return 1 + else: + return 0 + +def need_part1(tag): + return re.compile(r"fPART1").search(semdict[tag]) + +def need_ea(tag): + return re.compile(r"\bEA\b").search(semdict[tag]) + +def imm_name(immlett): + return "%siV" % immlett + +def read_semantics_file(name): + eval_line = "" + for line in open(name, 'rt').readlines(): + if not line.startswith("#"): + eval_line += line + if line.endswith("\\\n"): + eval_line.rstrip("\\\n") + else: + eval(eval_line.strip()) + eval_line = "" + +def read_attribs_file(name): + attribre = re.compile(r'DEF_ATTRIB\(([A-Za-z0-9_]+), ([^,]*), ' + + r'"([A-Za-z0-9_\.]*)", "([A-Za-z0-9_\.]*)"\)') + for line in open(sys.argv[2], 'rt').readlines(): + if not attribre.match(line): + continue + (attrib_base,descr,rreg,wreg) = attribre.findall(line)[0] + attrib_base = 'A_' + attrib_base + attribinfo[attrib_base] = {'rreg':rreg, 'wreg':wreg, 'descr':descr} -- 2.7.4