#!/usr/bin/env python3 ## ## Copyright(c) 2019-2021 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)