| #!/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 <http://www.gnu.org/licenses/>. |
| ## |
| |
| 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'((?<!DUP)[MNORCPQXSGVZA])([stuvwxyzdefg]+)([.]?[LlHh]?)(\d+S?)') |
| immre = re.compile(r'[#]([rRsSuUm])(\d+)(?:[:](\d+))?') |
| |
| def ordered_unique(l): |
| return sorted(set(l), key=l.index) |
| |
| implicit_registers = { |
| 'SP' : 29, |
| 'FP' : 30, |
| 'LR' : 31 |
| } |
| |
| num_registers = { |
| 'R' : 32, |
| 'V' : 32 |
| } |
| |
| def print_op_info(f): |
| for tag in sorted(encs.keys(), key=iset.tags.index): |
| enc = encs[tag] |
| print(file=f) |
| print('DECODE_OPINFO({},'.format(tag), file=f) |
| regs = ordered_unique(regre.findall(iset.iset[tag]['syntax'])) |
| imms = ordered_unique(immre.findall(iset.iset[tag]['syntax'])) |
| regno = 0 |
| for reg in regs: |
| reg_type = reg[0] |
| reg_letter = reg[1][0] |
| reg_num_choices = int(reg[3].rstrip('S')) |
| reg_mapping = reg[0] + ''.join(['_' for letter in reg[1]]) + reg[3] |
| reg_enc_fields = re.findall(reg_letter + '+', enc) |
| if len(reg_enc_fields) == 0: |
| raise Exception('Tag "{}" missing register field!'.format(tag)) |
| if len(reg_enc_fields) > 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) |