#!/usr/bin/env python3 ## ## Copyright(c) 2019-2023 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 . ## import io import re import sys import iset encs = { tag: "".join(reversed(iset.iset[tag]["enc"].replace(" ", ""))) for tag in iset.tags if iset.iset[tag]["enc"] != "MISSING ENCODING" } enc_classes = set([iset.iset[tag]["enc_class"] for tag in encs.keys()]) subinsn_enc_classes = set( [enc_class for enc_class in enc_classes if enc_class.startswith("SUBINSN_")] ) ext_enc_classes = set( [ enc_class for enc_class in enc_classes if enc_class not in ("NORMAL", "16BIT") and not enc_class.startswith("SUBINSN_") ] ) try: subinsn_groupings = iset.subinsn_groupings except AttributeError: subinsn_groupings = {} for tag, subinsn_grouping in subinsn_groupings.items(): encs[tag] = "".join(reversed(subinsn_grouping["enc"].replace(" ", ""))) dectree_normal = {"leaves": set()} dectree_16bit = {"leaves": set()} dectree_subinsn_groupings = {"leaves": set()} dectree_subinsns = {name: {"leaves": set()} for name in subinsn_enc_classes} dectree_extensions = {name: {"leaves": set()} for name in ext_enc_classes} for tag in encs.keys(): if tag in subinsn_groupings: dectree_subinsn_groupings["leaves"].add(tag) continue enc_class = iset.iset[tag]["enc_class"] if enc_class.startswith("SUBINSN_"): if len(encs[tag]) != 32: encs[tag] = encs[tag] + "0" * (32 - len(encs[tag])) dectree_subinsns[enc_class]["leaves"].add(tag) elif enc_class == "16BIT": if len(encs[tag]) != 16: raise Exception( 'Tag "{}" has enc_class "{}" and not an encoding ' + "width of 16 bits!".format(tag, enc_class) ) dectree_16bit["leaves"].add(tag) else: if len(encs[tag]) != 32: raise Exception( 'Tag "{}" has enc_class "{}" and not an encoding ' + "width of 32 bits!".format(tag, enc_class) ) if enc_class == "NORMAL": dectree_normal["leaves"].add(tag) else: dectree_extensions[enc_class]["leaves"].add(tag) faketags = set() for tag, enc in iset.enc_ext_spaces.items(): faketags.add(tag) encs[tag] = "".join(reversed(enc.replace(" ", ""))) dectree_normal["leaves"].add(tag) faketags |= set(subinsn_groupings.keys()) def every_bit_counts(bitset): for i in range(1, len(next(iter(bitset)))): if len(set([bits[:i] + bits[i + 1 :] for bits in bitset])) == len(bitset): return False return True def auto_separate(node): tags = node["leaves"] if len(tags) <= 1: return enc_width = len(encs[next(iter(tags))]) opcode_bit_for_all = [ all([encs[tag][i] in "01" for tag in tags]) for i in range(enc_width) ] opcode_bit_is_0_for_all = [ opcode_bit_for_all[i] and all([encs[tag][i] == "0" for tag in tags]) for i in range(enc_width) ] opcode_bit_is_1_for_all = [ opcode_bit_for_all[i] and all([encs[tag][i] == "1" for tag in tags]) for i in range(enc_width) ] differentiator_opcode_bit = [ opcode_bit_for_all[i] and not (opcode_bit_is_0_for_all[i] or opcode_bit_is_1_for_all[i]) for i in range(enc_width) ] best_width = 0 for width in range(4, 0, -1): for lsb in range(enc_width - width, -1, -1): bitset = set([encs[tag][lsb : lsb + width] for tag in tags]) if all(differentiator_opcode_bit[lsb : lsb + width]) and ( len(bitset) == len(tags) or every_bit_counts(bitset) ): best_width = width best_lsb = lsb caught_all_tags = len(bitset) == len(tags) break if best_width != 0: break if best_width == 0: raise Exception( "Could not find a way to differentiate the encodings " + "of the following tags:\n{}".format("\n".join(tags)) ) if caught_all_tags: for width in range(1, best_width): for lsb in range(enc_width - width, -1, -1): bitset = set([encs[tag][lsb : lsb + width] for tag in tags]) if all(differentiator_opcode_bit[lsb : lsb + width]) and len( bitset ) == len(tags): best_width = width best_lsb = lsb break else: continue break node["separator_lsb"] = best_lsb node["separator_width"] = best_width node["children"] = [] for value in range(2**best_width): child = {} bits = "".join(reversed("{:0{}b}".format(value, best_width))) child["leaves"] = set( [tag for tag in tags if encs[tag][best_lsb : best_lsb + best_width] == bits] ) node["children"].append(child) for child in node["children"]: auto_separate(child) auto_separate(dectree_normal) auto_separate(dectree_16bit) if subinsn_groupings: auto_separate(dectree_subinsn_groupings) for dectree_subinsn in dectree_subinsns.values(): auto_separate(dectree_subinsn) for dectree_ext in dectree_extensions.values(): auto_separate(dectree_ext) for tag in faketags: del encs[tag] def table_name(parents, node): path = parents + [node] root = path[0] tag = next(iter(node["leaves"])) if tag in subinsn_groupings: enc_width = len(subinsn_groupings[tag]["enc"].replace(" ", "")) else: tag = next(iter(node["leaves"] - faketags)) enc_width = len(encs[tag]) determining_bits = ["_"] * enc_width for parent, child in zip(path[:-1], path[1:]): lsb = parent["separator_lsb"] width = parent["separator_width"] value = parent["children"].index(child) determining_bits[lsb : lsb + width] = list( reversed("{:0{}b}".format(value, width)) ) if tag in subinsn_groupings: name = "DECODE_ROOT_EE" else: enc_class = iset.iset[tag]["enc_class"] if enc_class in ext_enc_classes: name = "DECODE_EXT_{}".format(enc_class) elif enc_class in subinsn_enc_classes: name = "DECODE_SUBINSN_{}".format(enc_class) else: name = "DECODE_ROOT_{}".format(enc_width) if node != root: name += "_" + "".join(reversed(determining_bits)) return name def print_node(f, node, parents): if len(node["leaves"]) <= 1: return name = table_name(parents, node) lsb = node["separator_lsb"] width = node["separator_width"] print( "DECODE_NEW_TABLE({},{},DECODE_SEPARATOR_BITS({},{}))".format( name, 2**width, lsb, width ), file=f, ) for child in node["children"]: if len(child["leaves"]) == 0: print("INVALID()", file=f) elif len(child["leaves"]) == 1: (tag,) = child["leaves"] if tag in subinsn_groupings: class_a = subinsn_groupings[tag]["class_a"] class_b = subinsn_groupings[tag]["class_b"] enc = subinsn_groupings[tag]["enc"].replace(" ", "") if "RESERVED" in tag: print("INVALID()", file=f) else: print( 'SUBINSNS({},{},{},"{}")'.format(tag, class_a, class_b, enc), file=f, ) elif tag in iset.enc_ext_spaces: enc = iset.enc_ext_spaces[tag].replace(" ", "") print('EXTSPACE({},"{}")'.format(tag, enc), file=f) else: enc = "".join(reversed(encs[tag])) print('TERMINAL({},"{}")'.format(tag, enc), file=f) else: print("TABLE_LINK({})".format(table_name(parents + [node], child)), file=f) print( "DECODE_END_TABLE({},{},DECODE_SEPARATOR_BITS({},{}))".format( name, 2**width, lsb, width ), file=f, ) print(file=f) parents.append(node) for child in node["children"]: print_node(f, child, parents) parents.pop() def print_tree(f, tree): print_node(f, tree, []) def print_match_info(f): for tag in sorted(encs.keys(), key=iset.tags.index): enc = "".join(reversed(encs[tag])) mask = int(re.sub(r"[^1]", r"0", enc.replace("0", "1")), 2) match = int(re.sub(r"[^01]", r"0", enc), 2) suffix = "" print( "DECODE{}_MATCH_INFO({},0x{:x}U,0x{:x}U)".format(suffix, tag, mask, match), file=f, ) regre = re.compile(r"((? 1: raise Exception('Tag "{}" has split register field!'.format(tag)) reg_enc_field = reg_enc_fields[0] if 2 ** len(reg_enc_field) != reg_num_choices: raise Exception( 'Tag "{}" has incorrect register field width!'.format(tag) ) print( " DECODE_REG({},{},{})".format( regno, len(reg_enc_field), enc.index(reg_enc_field) ), file=f, ) if reg_type in num_registers and reg_num_choices != num_registers[reg_type]: print( " DECODE_MAPPED_REG({},{})".format(regno, reg_mapping), file=f, ) regno += 1 def implicit_register_key(reg): return implicit_registers[reg] for reg in sorted( set( [ r for r in ( iset.iset[tag]["rregs"].split(",") + iset.iset[tag]["wregs"].split(",") ) if r in implicit_registers ] ), key=implicit_register_key, ): print( " DECODE_IMPL_REG({},{})".format(regno, implicit_registers[reg]), file=f, ) regno += 1 if imms and imms[0][0].isupper(): imms = reversed(imms) for imm in imms: if imm[0].isupper(): immno = 1 else: immno = 0 imm_type = imm[0] imm_width = int(imm[1]) imm_shift = imm[2] if imm_shift: imm_shift = int(imm_shift) else: imm_shift = 0 if imm_type.islower(): imm_letter = "i" else: imm_letter = "I" remainder = imm_width for m in reversed(list(re.finditer(imm_letter + "+", enc))): remainder -= m.end() - m.start() print( " DECODE_IMM({},{},{},{})".format( immno, m.end() - m.start(), m.start(), remainder ), file=f, ) if remainder != 0: if imm[2]: imm[2] = ":" + imm[2] raise Exception( 'Tag "{}" has an incorrect number of ' + 'encoding bits for immediate "{}"'.format(tag, "".join(imm)) ) if imm_type.lower() in "sr": print(" DECODE_IMM_SXT({},{})".format(immno, imm_width), file=f) if imm_type.lower() == "n": print(" DECODE_IMM_NEG({},{})".format(immno, imm_width), file=f) if imm_shift: print( " DECODE_IMM_SHIFT({},{})".format(immno, imm_shift), file=f ) print(")", file=f) if __name__ == "__main__": with open(sys.argv[1], "w") as f: print_tree(f, dectree_normal) print_tree(f, dectree_16bit) if subinsn_groupings: print_tree(f, dectree_subinsn_groupings) for name, dectree_subinsn in sorted(dectree_subinsns.items()): print_tree(f, dectree_subinsn) for name, dectree_ext in sorted(dectree_extensions.items()): print_tree(f, dectree_ext) print_match_info(f) print_op_info(f)