Example #1
0
 def emit_sail_ast(self, previous_clauses, file):
     for enc in self.encs:
         enc_name, enc_iset, enc_fields, enc_asl, enc_asm = enc
         fields = [(nm, hi - lo + 1) for (hi, lo, nm, split, consts,
                                          actual_consts) in enc_fields
                   if nm != '_']
         typed_fields = [
             '/* {} : */ bits({})'.format(name, length)
             for (name, length) in fields
         ]
         if len(typed_fields) < 1:
             clause = 'union clause ast = ' + sanitize(enc_name) + ' : unit'
         else:
             clause = 'union clause ast = ' + sanitize(
                 enc_name) + ' : (' + ', '.join(typed_fields) + ')'
         if clause not in previous_clauses:
             print(clause, file=file)
             previous_clauses.add(clause)
Example #2
0
def generate_alternative_explanation(instr_name, enc_name, explanations, types,
                                     children1, children2):
    els_args1 = [
        process_element(instr_name, enc_name, explanations, types,
                        child.children[0]) for child in children1
    ]
    elements1 = list(
        itertools.chain.from_iterable([el_arg[0]
                                       for el_arg in els_args1]))  # flatten
    args1 = list(
        itertools.chain.from_iterable([el_arg[1]
                                       for el_arg in els_args1]))  # flatten
    links1 = list(
        itertools.chain.from_iterable([el_arg[2]
                                       for el_arg in els_args1]))  # flatten

    els_args2 = [
        process_element(instr_name, enc_name, explanations, types,
                        child.children[0]) for child in children2
    ]
    elements2 = list(
        itertools.chain.from_iterable([el_arg[0]
                                       for el_arg in els_args2]))  # flatten
    args2 = list(
        itertools.chain.from_iterable([el_arg[1]
                                       for el_arg in els_args2]))  # flatten
    links2 = list(
        itertools.chain.from_iterable([el_arg[2]
                                       for el_arg in els_args2]))  # flatten

    if args1[0].split('@') == args2:
        args1 = args2
    elif args1 == args2[0].split('@'):
        args2 = args1

    assert args1 == args2
    # what to do about links? they're almost certainly different

    values = [
        ('({})'.format(', '.join(type_bitconcat(types, arg)
                                 for arg in args1)), ' ^ '.join(elements1)),
        ('({})'.format(', '.join(type_bitconcat(types, arg)
                                 for arg in args2)), ' ^ '.join(elements2)),
    ]
    props = {
        'encoded_in':
        '({})'.format(', '.join(args1)),
        'arg_type':
        '({})'.format(', '.join(
            'bits({})'.format(get_bitconcat_n_bits(types, arg))
            for arg in args1)),
    }
    name = '{}_alternative_{}'.format(enc_name, sanitize('_'.join(args1)))
    assert name not in explanations
    explanations[name] = Explanation('TABLE', props, values)
    return (name, args1, links1)
Example #3
0
def generate_presence_explanation(instr_name, enc_name, explanations, types,
                                  el):
    link = el.string + '_' + enc_name
    el_exp = explanations[link]

    values = [
        ('0b0', '"" if false /* hack */'),
        ('0b1', '"{}"'.format(el_exp.props['constant'])),
        ('0b0', '""'),
    ]
    props = {
        'encoded_in':
        '({})'.format(', '.join(el_exp.props['encoded_in'])),
        'arg_type':
        'bits({})'.format(
            get_bitconcat_n_bits(types, el_exp.props['encoded_in'])),
    }
    name = '{}_presence_{}'.format(enc_name,
                                   sanitize(el_exp.props['encoded_in']))
    assert name not in explanations
    explanations[name] = Explanation('TABLE', props, values)
    return (name, [el_exp.props['encoded_in']], [link])
Example #4
0
def generate_optional_explanation(instr_name, enc_name, explanations, types,
                                  children):
    els_args = [
        process_element(instr_name, enc_name, explanations, types,
                        child.children[0]) for child in children[1].children
    ]
    elements = list(
        itertools.chain.from_iterable([el_arg[0]
                                       for el_arg in els_args]))  # flatten
    args = list(
        itertools.chain.from_iterable([el_arg[1]
                                       for el_arg in els_args]))  # flatten
    links = list(
        itertools.chain.from_iterable([el_arg[2]
                                       for el_arg in els_args]))  # flatten

    values = [
        ('({})'.format(', '.join(
            default_clause(explanations, types, arg, link)
            for arg, link in zip(args, links))), '"" if false /* hack */'),
        ('({})'.format(', '.join(type_bitconcat(types, arg)
                                 for arg in args)), ' ^ '.join(elements)),
        ('({})'.format(', '.join(
            default_clause(explanations, types, arg, link)
            for arg, link in zip(args, links))), '""'),
    ]
    props = {
        'encoded_in':
        '({})'.format(', '.join(args)),
        'arg_type':
        '({})'.format(', '.join(
            'bits({})'.format(get_bitconcat_n_bits(types, arg))
            for arg in args)) if len(args) > 0 else 'unit',
    }
    name = '{}_optional_{}'.format(enc_name, sanitize('_'.join(args)))
    assert name not in explanations
    explanations[name] = Explanation('TABLE', props, values)
    return (name, args, links)
Example #5
0
def emit_sail_asm(file, enc):
    enc_name, enc_iset, enc_fields, enc_asl, enc_asms = enc
    for (gs, rhs) in enc_asms:
        pos_guards, neg_guards = parse_guards(gs)
        fields = [
            name_or_const(pos_guards, *f) for f in enc_fields if f[2] != '_'
        ]
        lhs = '{}({})'.format(sanitize(enc_name), ', '.join(fields))

        pos_guards = {k: expand_dontcares(v) for k, v in pos_guards.items()}
        neg_guards = {k: expand_dontcares(v) for k, v in neg_guards.items()}
        pos_sail_guards = ' & '.join([
            '(' + ' | '.join('{} == 0b{}'.format(k, v) for v in vs) + ')'
            for k, vs in pos_guards.items()
        ])
        neg_sail_guards = ' & '.join([
            '(' + ' & '.join('{} != 0b{}'.format(k, v) for v in vs) + ')'
            for k, vs in neg_guards.items()
        ])

        clause = 'mapping clause assembly = {}{}{} <-> {}'.format(
            lhs, ' if ' if neg_sail_guards else '', neg_sail_guards,
            rhs.replace(':', '@'))
        print(clause, file=file)
Example #6
0
def readEncoding(iclass, names, exec_name, exps, decode, sailhack):
    encoding = iclass.find('regdiagram')
    isT16 = encoding.attrib['form'] == "16"
    insn_set = "T16" if isT16 else iclass.attrib['isa']

    fields = []
    for b in encoding.findall('box'):
        wd = int(b.attrib.get('width', '1'))
        hi = int(b.attrib['hibit'])
        # normalise T16 encoding bit numbers
        if isT16: hi = hi - 16
        lo = hi - wd + 1
        nm = b.attrib.get('name', '_') if b.attrib.get('usename',
                                                       '0') == '1' else '_'
        # workaround for Sail
        if sailhack and nm == 'type': nm = 'typ'
        ignore = 'psbits' in b.attrib and b.attrib['psbits'] == 'x' * wd
        actual_consts = ''.join([
            'x' *
            int(c.attrib.get('colspan', '1')) if c.text is None else c.text
            for c in b.findall('c')
        ])
        consts = actual_consts
        if ignore:
            consts = 'x' * wd

        # workaround: add explicit slicing to LDM/STM register_list fields
        if nm == "register_list" and wd == 13: nm = nm + "<12:0>"

        # if adjacent entries are two parts of same field, join them
        # e.g., imm8<7:1> and imm8<0> or opcode[5:2] and opcode[1:0]
        m = re.match('^(\w+)[<[]', nm)
        if m:
            nm = m.group(1)
            split = True
            if fields[-1][3] and fields[-1][2] == nm:
                (hi1, lo1, _, _, c1) = fields.pop()
                assert (lo1 == hi + 1)  # must be adjacent
                hi = hi1
                consts = c1 + consts
        else:
            split = False

        # discard != information because it is better obtained elsewhere in spec
        if consts.startswith('!='): consts = 'x' * wd

        fields.append((hi, lo, nm, split, consts, actual_consts))

    # workaround: avoid use of overloaded field names
    fields2 = []
    for (hi, lo, nm, split, consts, actual_consts) in fields:
        if (nm in ["SP", "mask", "opcode"] and 'x' not in consts
                and exec_name not in [
                    "aarch64/float/convert/fix", "aarch64/float/convert/int"
                ]):
            # workaround: avoid use of overloaded field name
            nm = '_'
        fields2.append((hi, lo, nm, split, consts, actual_consts))

    asm_types = {
        nm: 'bits({})'.format(hi - lo + 1)
        for hi, lo, nm, _, _, _ in fields if nm != '_'
    }
    asm_encodings = [
        asm.read_asm_encoding(sanitize(exec_name), exps, asm_types, e)
        for e in iclass.findall('.//encoding/asmtemplate/..')
    ]

    dec_asl_ps = iclass.find('ps_section/ps')
    if dec_asl_ps is None:
        dec_asl = None
    else:
        dec_asl = readASL(iclass.find('ps_section/ps'))
        if decode: dec_asl.code = decode + "\n" + dec_asl.code
        dec_asl.patchDependencies(names)

    if insn_set in ['T16', 'T32', 'A32']:
        assert dec_asl
    name = dec_asl.name if insn_set in ["T16", "T32", "A32"
                                        ] else encoding.attrib['psname']

    return (name, insn_set, fields2, dec_asl, asm_encodings)
Example #7
0
def process_element(instr_name, enc_name, explanations, types, el):
    if type(el.element) is Token and str(el.element) in '{}()':
        return ([], [])
    elif el.element.name == 'text':
        els = ['"{}"'.format(el.string)]
        return (els, [], [])
    elif el.element.name == 'doublespace':
        return (['spc()'], [], [])
    elif el.element.name == 'space':
        return (['def_spc()'], [], [])
    elif el.element.name == 'link':
        link = el.string + '_' + enc_name
        exp = explanations[link]
        if (exp.type == 'asm_immediate' or exp.type == 'asm_signed_immediate'):
            n_bits = get_bitconcat_n_bits(types, exp.props['encoded_in'])
            return ([
                'hex_bits_{}({})'.format(n_bits, exp.props['encoded_in'])
            ], [exp.props['encoded_in']], [link])
        # TODO FIXME SIGNED
        # elif exp.type == 'asm_signed_immediate':
        #     n_bits = get_bitconcat_n_bits(types, exp.props['encoded_in'])
        #     return (['hex_bits_{}({})'.format(n_bits, exp.props['enc
        elif exp.type == 'asm_extendedreg_hack_oneSP_64':
            return (['asm_extendedreg_hack_oneSP_64(Rn, option, Rm, imm3)'],
                    ['Rn', 'option', 'Rm', 'imm3'], [link])
        elif exp.type == 'asm_extendedreg_hack_twoSP_64':
            return ([
                'asm_extendedreg_hack_twoSP_64(Rd, Rn, option, Rm, imm3)'
            ], ['Rd', 'Rn', 'option', 'Rm', 'imm3'], [link])
        elif exp.type == 'asm_extendedreg_hack_oneSP_32':
            return (['asm_extendedreg_hack_oneSP_32(Rn, option, Rm, imm3)'],
                    ['Rn', 'option', 'Rm', 'imm3'], [link])
        elif exp.type == 'asm_extendedreg_hack_twoSP_32':
            return ([
                'asm_extendedreg_hack_twoSP_32(Rd, Rn, option, Rm, imm3)'
            ], ['Rd', 'Rn', 'option', 'Rm', 'imm3'], [link])
        elif exp.type == 'lsl_shift_hack_32':
            return (['lsl_shift_hack_32(immr, imms)'], ['immr',
                                                        'imms'], [link])
        elif exp.type == 'lsl_shift_hack_64':
            return (['lsl_shift_hack_64(immr, imms)'], ['immr',
                                                        'imms'], [link])


#        elif exp.type == 'lsb_width_hack_32':
#           return (['lsb_width_hack_32(immr, imms)'], ['immr', 'imms'], [link])
        elif exp.type == 'lsb_width_hack':
            return (['lsb_width_hack(immr, imms)'], ['immr', 'imms'], [link])
        elif exp.type == 'lsb_mod_hack_32':
            return (['lsb_mod_hack_32(immr, imms)'], ['immr', 'imms'], [link])
        elif exp.type == 'lsb_mod_hack_64':
            return (['lsb_mod_hack_64(immr, imms)'], ['immr', 'imms'], [link])
        elif exp.type == 'matching_Wn':
            return (['matching_Wn(Rn, Rm)'], ['Rn', 'Rm'], [link])
        elif exp.type == 'matching_Xn':
            return (['matching_Xn(Rn, Rm)'], ['Rn', 'Rm'], [link])
        elif exp.type == 'movewide_imm_hack_32':
            return (['movewide_imm_hack_32(imm16, hw)'], ['imm16',
                                                          'hw'], [link])
        elif exp.type == 'movewide_imm_hack_64':
            return (['movewide_imm_hack_64(imm16, hw)'], ['imm16',
                                                          'hw'], [link])
        elif exp.type == 'movewide_inverted_imm_hack_32':
            return (['movewide_inverted_imm_hack_32(imm16, hw)'],
                    ['imm16', 'hw'], [link])
        elif exp.type == 'movewide_inverted_imm_hack_64':
            return (['movewide_inverted_imm_hack_64(imm16, hw)'],
                    ['imm16', 'hw'], [link])
        elif 'expr' in exp.props and exp.type == 'asm_constant' and exp.props[
                'expr'] == 'PRESENCE':
            name, args, links = generate_presence_explanation(
                instr_name, enc_name, explanations, types, el)
            return (['{}({})'.format(name, ', '.join(args))], args, links)
        elif exp.type == 'TABLE':
            return (['{}({})'.format(sanitize(link), exp.props['encoded_in'])],
                    [exp.props['encoded_in']], [link])
        else:
            return (['{}({})'.format(exp.type, exp.props['encoded_in'])],
                    [exp.props['encoded_in']], [link])
    elif el.element.name == 'bracket_alternative':
        name, args, links = generate_alternative_explanation(
            instr_name, enc_name, explanations, types, el.children[1].children,
            el.children[3].children)
        return (['{}({})'.format(name, ', '.join(args))], args, links)
    elif el.element.name == 'optional_alternative':
        name, args, links = generate_optional_alternative_explanation(
            instr_name, enc_name, explanations, types, el.children[1].children,
            el.children[3].children)
        return (['{}({})'.format(name, ', '.join(args))], args, links)
    elif el.element.name == 'optional':
        name, args, links = generate_optional_explanation(
            instr_name, enc_name, explanations, types, el.children)
        return (['{}({})'.format(name, ', '.join(args))], args, links)
    else:
        assert False, 'unknown element name in grammar for asm: ' + el.element.name
Example #8
0
def generate_optional_alternative_explanation(instr_name, enc_name,
                                              explanations, types, children1,
                                              children2):
    els_args1 = [
        process_element(instr_name, enc_name, explanations, types,
                        child.children[0]) for child in children1
    ]
    elements1 = list(
        itertools.chain.from_iterable([el_arg[0]
                                       for el_arg in els_args1]))  # flatten
    args1 = list(
        itertools.chain.from_iterable([el_arg[1]
                                       for el_arg in els_args1]))  # flatten
    links1 = list(
        itertools.chain.from_iterable([el_arg[2]
                                       for el_arg in els_args1]))  # flatten

    els_args2 = [
        process_element(instr_name, enc_name, explanations, types,
                        child.children[0]) for child in children2
    ]
    elements2 = list(
        itertools.chain.from_iterable([el_arg[0]
                                       for el_arg in els_args2]))  # flatten
    args2 = list(
        itertools.chain.from_iterable([el_arg[1]
                                       for el_arg in els_args2]))  # flatten
    links2 = list(
        itertools.chain.from_iterable([el_arg[2]
                                       for el_arg in els_args2]))  # flatten

    alt_name, alt_args, alt_links = generate_alternative_explanation(
        instr_name, enc_name, explanations, types, children1, children2)

    assert args1 == args2 == alt_args
    # what to do about links? they're almost certainly different

    # see if either side has a default
    try:
        default_args = [
            default_clause(explanations, types, arg, link)
            for arg, link in zip(args1, links1)
        ]
        values = [
            ('({})'.format(', '.join(default_args)), '"" if false /* hack */'),
            ('({})'.format(', '.join(
                type_bitconcat(types, arg)
                for arg in args1)), '{}({})'.format(alt_name,
                                                    ', '.join(args1))),
            ('({})'.format(', '.join(default_args)), '""'),
        ]
        props = {
            'encoded_in':
            '({})'.format(', '.join(args1)),
            'arg_type':
            '({})'.format(', '.join(
                'bits({})'.format(get_bitconcat_n_bits(types, arg))
                for arg in args1)),
        }
    except NoDefaultException:
        default_args = [
            default_clause(explanations, types, arg, link)
            for arg, link in zip(args2, links2)
        ]
        values = [
            ('({})'.format(', '.join(default_args)), '"" if false /* hack */'),
            ('({})'.format(', '.join(
                type_bitconcat(types, arg)
                for arg in args2)), '{}({})'.format(alt_name,
                                                    ', '.join(args2))),
            ('({})'.format(', '.join(default_args)), '""'),
        ]
        props = {
            'encoded_in':
            '({})'.format(', '.join(args2)),
            'arg_type':
            '({})'.format(', '.join(
                'bits({})'.format(get_bitconcat_n_bits(types, arg))
                for arg in args2)),
        }
    name = '{}_optional_{}'.format(enc_name, sanitize('_'.join(args1)))
    assert name not in explanations
    explanations[name] = Explanation('TABLE', props, values)
    return (name, args1, links1)