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)
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)
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])
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)
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)
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)
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
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)