1*61046927SAndroid Build Coastguard Worker# 2*61046927SAndroid Build Coastguard Worker# Copyright (C) 2020 Collabora, Ltd. 3*61046927SAndroid Build Coastguard Worker# 4*61046927SAndroid Build Coastguard Worker# Permission is hereby granted, free of charge, to any person obtaining a 5*61046927SAndroid Build Coastguard Worker# copy of this software and associated documentation files (the "Software"), 6*61046927SAndroid Build Coastguard Worker# to deal in the Software without restriction, including without limitation 7*61046927SAndroid Build Coastguard Worker# the rights to use, copy, modify, merge, publish, distribute, sublicense, 8*61046927SAndroid Build Coastguard Worker# and/or sell copies of the Software, and to permit persons to whom the 9*61046927SAndroid Build Coastguard Worker# Software is furnished to do so, subject to the following conditions: 10*61046927SAndroid Build Coastguard Worker# 11*61046927SAndroid Build Coastguard Worker# The above copyright notice and this permission notice (including the next 12*61046927SAndroid Build Coastguard Worker# paragraph) shall be included in all copies or substantial portions of the 13*61046927SAndroid Build Coastguard Worker# Software. 14*61046927SAndroid Build Coastguard Worker# 15*61046927SAndroid Build Coastguard Worker# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16*61046927SAndroid Build Coastguard Worker# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17*61046927SAndroid Build Coastguard Worker# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18*61046927SAndroid Build Coastguard Worker# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19*61046927SAndroid Build Coastguard Worker# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20*61046927SAndroid Build Coastguard Worker# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21*61046927SAndroid Build Coastguard Worker# IN THE SOFTWARE. 22*61046927SAndroid Build Coastguard Worker 23*61046927SAndroid Build Coastguard Workerimport sys 24*61046927SAndroid Build Coastguard Workerimport itertools 25*61046927SAndroid Build Coastguard Workerfrom bifrost_isa import parse_instructions, opname_to_c, expand_states 26*61046927SAndroid Build Coastguard Workerfrom mako.template import Template 27*61046927SAndroid Build Coastguard Worker 28*61046927SAndroid Build Coastguard Workerinstructions = parse_instructions(sys.argv[1], include_unused = True) 29*61046927SAndroid Build Coastguard Worker 30*61046927SAndroid Build Coastguard Worker# Constructs a reserved mask for a derived to cull impossible encodings 31*61046927SAndroid Build Coastguard Worker 32*61046927SAndroid Build Coastguard Workerdef reserved_mask(derived): 33*61046927SAndroid Build Coastguard Worker ((pos, width), opts) = derived 34*61046927SAndroid Build Coastguard Worker reserved = [x is None for x in opts] 35*61046927SAndroid Build Coastguard Worker mask = sum([(y << x) for x, y in enumerate(reserved)]) 36*61046927SAndroid Build Coastguard Worker return (pos, width, mask) 37*61046927SAndroid Build Coastguard Worker 38*61046927SAndroid Build Coastguard Workerdef reserved_masks(op): 39*61046927SAndroid Build Coastguard Worker masks = [reserved_mask(m) for m in op[2].get("derived", [])] 40*61046927SAndroid Build Coastguard Worker return [m for m in masks if m[2] != 0] 41*61046927SAndroid Build Coastguard Worker 42*61046927SAndroid Build Coastguard Worker# To decode instructions, pattern match based on the rules: 43*61046927SAndroid Build Coastguard Worker# 44*61046927SAndroid Build Coastguard Worker# 1. Execution unit (FMA or ADD) must line up. 45*61046927SAndroid Build Coastguard Worker# 2. All exact bits must match. 46*61046927SAndroid Build Coastguard Worker# 3. No fields should be reserved in a legal encoding. 47*61046927SAndroid Build Coastguard Worker# 4. Tiebreaker: Longer exact masks (greater unsigned bitwise inverses) win. 48*61046927SAndroid Build Coastguard Worker# 49*61046927SAndroid Build Coastguard Worker# To implement, filter the execution unit and check for exact bits in 50*61046927SAndroid Build Coastguard Worker# descending order of exact mask length. Check for reserved fields per 51*61046927SAndroid Build Coastguard Worker# candidate and succeed if it matches. 52*61046927SAndroid Build Coastguard Worker# found. 53*61046927SAndroid Build Coastguard Worker 54*61046927SAndroid Build Coastguard Workerdef decode_op(instructions, is_fma): 55*61046927SAndroid Build Coastguard Worker # Filter out the desired execution unit 56*61046927SAndroid Build Coastguard Worker options = [n for n in instructions.keys() if (n[0] == '*') == is_fma] 57*61046927SAndroid Build Coastguard Worker 58*61046927SAndroid Build Coastguard Worker # Sort by exact masks, descending 59*61046927SAndroid Build Coastguard Worker MAX_MASK = (1 << (23 if is_fma else 20)) - 1 60*61046927SAndroid Build Coastguard Worker options.sort(key = lambda n: (MAX_MASK ^ instructions[n][2]["exact"][0])) 61*61046927SAndroid Build Coastguard Worker 62*61046927SAndroid Build Coastguard Worker # Map to what we need to template 63*61046927SAndroid Build Coastguard Worker mapped = [(opname_to_c(op), instructions[op][2]["exact"], reserved_masks(instructions[op])) for op in options] 64*61046927SAndroid Build Coastguard Worker 65*61046927SAndroid Build Coastguard Worker # Generate checks in order 66*61046927SAndroid Build Coastguard Worker template = """void 67*61046927SAndroid Build Coastguard Workerbi_disasm_${unit}(FILE *fp, unsigned bits, struct bifrost_regs *srcs, struct bifrost_regs *next_regs, unsigned staging_register, unsigned branch_offset, struct bi_constants *consts, bool last) 68*61046927SAndroid Build Coastguard Worker{ 69*61046927SAndroid Build Coastguard Worker fputs(" ", fp); 70*61046927SAndroid Build Coastguard Worker 71*61046927SAndroid Build Coastguard Worker% for (i, (name, (emask, ebits), derived)) in enumerate(options): 72*61046927SAndroid Build Coastguard Worker% if len(derived) > 0: 73*61046927SAndroid Build Coastguard Worker ${"else " if i > 0 else ""}if (unlikely(((bits & ${hex(emask)}) == ${hex(ebits)}) 74*61046927SAndroid Build Coastguard Worker% for (pos, width, reserved) in derived: 75*61046927SAndroid Build Coastguard Worker && !(${hex(reserved)} & (1 << _BITS(bits, ${pos}, ${width}))) 76*61046927SAndroid Build Coastguard Worker% endfor 77*61046927SAndroid Build Coastguard Worker )) 78*61046927SAndroid Build Coastguard Worker% else: 79*61046927SAndroid Build Coastguard Worker ${"else " if i > 0 else ""}if (unlikely(((bits & ${hex(emask)}) == ${hex(ebits)}))) 80*61046927SAndroid Build Coastguard Worker% endif 81*61046927SAndroid Build Coastguard Worker bi_disasm_${name}(fp, bits, srcs, next_regs, staging_register, branch_offset, consts, last); 82*61046927SAndroid Build Coastguard Worker% endfor 83*61046927SAndroid Build Coastguard Worker else 84*61046927SAndroid Build Coastguard Worker fprintf(fp, "INSTR_INVALID_ENC ${unit} %X", bits); 85*61046927SAndroid Build Coastguard Worker 86*61046927SAndroid Build Coastguard Worker fputs("\\n", fp); 87*61046927SAndroid Build Coastguard Worker}""" 88*61046927SAndroid Build Coastguard Worker 89*61046927SAndroid Build Coastguard Worker return Template(template).render(options = mapped, unit = "fma" if is_fma else "add") 90*61046927SAndroid Build Coastguard Worker 91*61046927SAndroid Build Coastguard Worker# Decoding emits a series of function calls to e.g. `fma_fadd_v2f16`. We need to 92*61046927SAndroid Build Coastguard Worker# emit functions to disassemble a single decoded instruction in a particular 93*61046927SAndroid Build Coastguard Worker# state. Sync prototypes to avoid moves when calling. 94*61046927SAndroid Build Coastguard Worker 95*61046927SAndroid Build Coastguard Workerdisasm_op_template = Template("""static void 96*61046927SAndroid Build Coastguard Workerbi_disasm_${c_name}(FILE *fp, unsigned bits, struct bifrost_regs *srcs, struct bifrost_regs *next_regs, unsigned staging_register, unsigned branch_offset, struct bi_constants *consts, bool last) 97*61046927SAndroid Build Coastguard Worker{ 98*61046927SAndroid Build Coastguard Worker ${body.strip()} 99*61046927SAndroid Build Coastguard Worker} 100*61046927SAndroid Build Coastguard Worker""") 101*61046927SAndroid Build Coastguard Worker 102*61046927SAndroid Build Coastguard Workerlut_template_only = Template(""" static const char *${field}[] = { 103*61046927SAndroid Build Coastguard Worker ${", ".join(['"' + x + '"' for x in table])} 104*61046927SAndroid Build Coastguard Worker }; 105*61046927SAndroid Build Coastguard Worker""") 106*61046927SAndroid Build Coastguard Worker 107*61046927SAndroid Build Coastguard Worker# Given a lookup table written logically, generate an accessor 108*61046927SAndroid Build Coastguard Workerlut_template = Template(""" static const char *${field}_table[] = { 109*61046927SAndroid Build Coastguard Worker ${", ".join(['"' + x + '"' for x in table])} 110*61046927SAndroid Build Coastguard Worker }; 111*61046927SAndroid Build Coastguard Worker 112*61046927SAndroid Build Coastguard Worker const char *${field} = ${field}_table[_BITS(bits, ${pos}, ${width})]; 113*61046927SAndroid Build Coastguard Worker""") 114*61046927SAndroid Build Coastguard Worker 115*61046927SAndroid Build Coastguard Worker# Helpers for decoding follow. pretty_mods applies dot syntax 116*61046927SAndroid Build Coastguard Worker 117*61046927SAndroid Build Coastguard Workerdef pretty_mods(opts, default): 118*61046927SAndroid Build Coastguard Worker return [('.' + (opt or 'reserved') if opt != default else '') for opt in opts] 119*61046927SAndroid Build Coastguard Worker 120*61046927SAndroid Build Coastguard Worker# Recursively searches for the set of free variables required by an expression 121*61046927SAndroid Build Coastguard Worker 122*61046927SAndroid Build Coastguard Workerdef find_context_keys_expr(expr): 123*61046927SAndroid Build Coastguard Worker if isinstance(expr, list): 124*61046927SAndroid Build Coastguard Worker return set.union(*[find_context_keys_expr(x) for x in expr[1:]]) 125*61046927SAndroid Build Coastguard Worker elif expr[0] == '#': 126*61046927SAndroid Build Coastguard Worker return set() 127*61046927SAndroid Build Coastguard Worker else: 128*61046927SAndroid Build Coastguard Worker return set([expr]) 129*61046927SAndroid Build Coastguard Worker 130*61046927SAndroid Build Coastguard Workerdef find_context_keys(desc, test): 131*61046927SAndroid Build Coastguard Worker keys = set() 132*61046927SAndroid Build Coastguard Worker 133*61046927SAndroid Build Coastguard Worker if len(test) > 0: 134*61046927SAndroid Build Coastguard Worker keys |= find_context_keys_expr(test) 135*61046927SAndroid Build Coastguard Worker 136*61046927SAndroid Build Coastguard Worker for i, (_, vals) in enumerate(desc.get('derived', [])): 137*61046927SAndroid Build Coastguard Worker for j, val in enumerate(vals): 138*61046927SAndroid Build Coastguard Worker if val is not None: 139*61046927SAndroid Build Coastguard Worker keys |= find_context_keys_expr(val) 140*61046927SAndroid Build Coastguard Worker 141*61046927SAndroid Build Coastguard Worker return keys 142*61046927SAndroid Build Coastguard Worker 143*61046927SAndroid Build Coastguard Worker# Compiles a logic expression to Python expression, ctx -> { T, F } 144*61046927SAndroid Build Coastguard Worker 145*61046927SAndroid Build Coastguard WorkerEVALUATORS = { 146*61046927SAndroid Build Coastguard Worker 'and': ' and ', 147*61046927SAndroid Build Coastguard Worker 'or': ' or ', 148*61046927SAndroid Build Coastguard Worker 'eq': ' == ', 149*61046927SAndroid Build Coastguard Worker 'neq': ' != ', 150*61046927SAndroid Build Coastguard Worker} 151*61046927SAndroid Build Coastguard Worker 152*61046927SAndroid Build Coastguard Workerdef compile_derived_inner(expr, keys): 153*61046927SAndroid Build Coastguard Worker if expr == []: 154*61046927SAndroid Build Coastguard Worker return 'True' 155*61046927SAndroid Build Coastguard Worker elif expr is None or expr[0] == 'alias': 156*61046927SAndroid Build Coastguard Worker return 'False' 157*61046927SAndroid Build Coastguard Worker elif isinstance(expr, list): 158*61046927SAndroid Build Coastguard Worker args = [compile_derived_inner(arg, keys) for arg in expr[1:]] 159*61046927SAndroid Build Coastguard Worker return '(' + EVALUATORS[expr[0]].join(args) + ')' 160*61046927SAndroid Build Coastguard Worker elif expr[0] == '#': 161*61046927SAndroid Build Coastguard Worker return "'{}'".format(expr[1:]) 162*61046927SAndroid Build Coastguard Worker elif expr == 'ordering': 163*61046927SAndroid Build Coastguard Worker return expr 164*61046927SAndroid Build Coastguard Worker else: 165*61046927SAndroid Build Coastguard Worker return "ctx[{}]".format(keys.index(expr)) 166*61046927SAndroid Build Coastguard Worker 167*61046927SAndroid Build Coastguard Workerdef compile_derived(expr, keys): 168*61046927SAndroid Build Coastguard Worker return eval('lambda ctx, ordering: ' + compile_derived_inner(expr, keys)) 169*61046927SAndroid Build Coastguard Worker 170*61046927SAndroid Build Coastguard Worker# Generate all possible combinations of values and evaluate the derived values 171*61046927SAndroid Build Coastguard Worker# by bruteforce evaluation to generate a forward mapping (values -> deriveds) 172*61046927SAndroid Build Coastguard Worker 173*61046927SAndroid Build Coastguard Workerdef evaluate_forward_derived(vals, ctx, ordering): 174*61046927SAndroid Build Coastguard Worker for j, expr in enumerate(vals): 175*61046927SAndroid Build Coastguard Worker if expr(ctx, ordering): 176*61046927SAndroid Build Coastguard Worker return j 177*61046927SAndroid Build Coastguard Worker 178*61046927SAndroid Build Coastguard Worker return None 179*61046927SAndroid Build Coastguard Worker 180*61046927SAndroid Build Coastguard Workerdef evaluate_forward(keys, derivf, testf, ctx, ordering): 181*61046927SAndroid Build Coastguard Worker if not testf(ctx, ordering): 182*61046927SAndroid Build Coastguard Worker return None 183*61046927SAndroid Build Coastguard Worker 184*61046927SAndroid Build Coastguard Worker deriv = [] 185*61046927SAndroid Build Coastguard Worker 186*61046927SAndroid Build Coastguard Worker for vals in derivf: 187*61046927SAndroid Build Coastguard Worker evaled = evaluate_forward_derived(vals, ctx, ordering) 188*61046927SAndroid Build Coastguard Worker 189*61046927SAndroid Build Coastguard Worker if evaled is None: 190*61046927SAndroid Build Coastguard Worker return None 191*61046927SAndroid Build Coastguard Worker 192*61046927SAndroid Build Coastguard Worker deriv.append(evaled) 193*61046927SAndroid Build Coastguard Worker 194*61046927SAndroid Build Coastguard Worker return deriv 195*61046927SAndroid Build Coastguard Worker 196*61046927SAndroid Build Coastguard Workerdef evaluate_forwards(keys, derivf, testf, mod_vals, ordered): 197*61046927SAndroid Build Coastguard Worker orderings = ["lt", "gt"] if ordered else [None] 198*61046927SAndroid Build Coastguard Worker return [[evaluate_forward(keys, derivf, testf, i, order) for i in itertools.product(*mod_vals)] for order in orderings] 199*61046927SAndroid Build Coastguard Worker 200*61046927SAndroid Build Coastguard Worker# Invert the forward mapping (values -> deriveds) of finite sets to produce a 201*61046927SAndroid Build Coastguard Worker# backwards mapping (deriveds -> values), suitable for disassembly. This is 202*61046927SAndroid Build Coastguard Worker# possible since the encoding is unambiguous, so this mapping is a bijection 203*61046927SAndroid Build Coastguard Worker# (after reserved/impossible encodings) 204*61046927SAndroid Build Coastguard Worker 205*61046927SAndroid Build Coastguard Workerdef invert_lut(value_size, forward, derived, mod_map, keys, mod_vals): 206*61046927SAndroid Build Coastguard Worker backwards = [None] * (1 << value_size) 207*61046927SAndroid Build Coastguard Worker for (i, deriveds), ctx in zip(enumerate(forward), itertools.product(*mod_vals)): 208*61046927SAndroid Build Coastguard Worker # Skip reserved 209*61046927SAndroid Build Coastguard Worker if deriveds == None: 210*61046927SAndroid Build Coastguard Worker continue 211*61046927SAndroid Build Coastguard Worker 212*61046927SAndroid Build Coastguard Worker shift = 0 213*61046927SAndroid Build Coastguard Worker param = 0 214*61046927SAndroid Build Coastguard Worker for j, ((x, width), y) in enumerate(derived): 215*61046927SAndroid Build Coastguard Worker param += (deriveds[j] << shift) 216*61046927SAndroid Build Coastguard Worker shift += width 217*61046927SAndroid Build Coastguard Worker 218*61046927SAndroid Build Coastguard Worker assert(param not in backwards) 219*61046927SAndroid Build Coastguard Worker backwards[param] = ctx 220*61046927SAndroid Build Coastguard Worker 221*61046927SAndroid Build Coastguard Worker return backwards 222*61046927SAndroid Build Coastguard Worker 223*61046927SAndroid Build Coastguard Worker# Compute the value of all indirectly specified modifiers by using the 224*61046927SAndroid Build Coastguard Worker# backwards mapping (deriveds -> values) as a run-time lookup table. 225*61046927SAndroid Build Coastguard Worker 226*61046927SAndroid Build Coastguard Workerdef build_lut(mnemonic, desc, test): 227*61046927SAndroid Build Coastguard Worker # Construct the system 228*61046927SAndroid Build Coastguard Worker facts = [] 229*61046927SAndroid Build Coastguard Worker 230*61046927SAndroid Build Coastguard Worker mod_map = {} 231*61046927SAndroid Build Coastguard Worker 232*61046927SAndroid Build Coastguard Worker for ((name, pos, width), default, values) in desc.get('modifiers', []): 233*61046927SAndroid Build Coastguard Worker mod_map[name] = (width, values, pos, default) 234*61046927SAndroid Build Coastguard Worker 235*61046927SAndroid Build Coastguard Worker derived = desc.get('derived', []) 236*61046927SAndroid Build Coastguard Worker 237*61046927SAndroid Build Coastguard Worker # Find the keys and impose an order 238*61046927SAndroid Build Coastguard Worker key_set = find_context_keys(desc, test) 239*61046927SAndroid Build Coastguard Worker ordered = 'ordering' in key_set 240*61046927SAndroid Build Coastguard Worker key_set.discard('ordering') 241*61046927SAndroid Build Coastguard Worker keys = sorted(list(key_set)) 242*61046927SAndroid Build Coastguard Worker 243*61046927SAndroid Build Coastguard Worker # Evaluate the deriveds for every possible state, forming a (state -> deriveds) map 244*61046927SAndroid Build Coastguard Worker testf = compile_derived(test, keys) 245*61046927SAndroid Build Coastguard Worker derivf = [[compile_derived(expr, keys) for expr in v] for (_, v) in derived] 246*61046927SAndroid Build Coastguard Worker mod_vals = [mod_map[k][1] for k in keys] 247*61046927SAndroid Build Coastguard Worker forward = evaluate_forwards(keys, derivf, testf, mod_vals, ordered) 248*61046927SAndroid Build Coastguard Worker 249*61046927SAndroid Build Coastguard Worker # Now invert that map to get a (deriveds -> state) map 250*61046927SAndroid Build Coastguard Worker value_size = sum([width for ((x, width), y) in derived]) 251*61046927SAndroid Build Coastguard Worker backwards = [invert_lut(value_size, f, derived, mod_map, keys, mod_vals) for f in forward] 252*61046927SAndroid Build Coastguard Worker 253*61046927SAndroid Build Coastguard Worker # From that map, we can generate LUTs 254*61046927SAndroid Build Coastguard Worker output = "" 255*61046927SAndroid Build Coastguard Worker 256*61046927SAndroid Build Coastguard Worker if ordered: 257*61046927SAndroid Build Coastguard Worker output += "bool ordering = (_BITS(bits, {}, 3) > _BITS(bits, {}, 3));\n".format(desc["srcs"][0][0], desc["srcs"][1][0]) 258*61046927SAndroid Build Coastguard Worker 259*61046927SAndroid Build Coastguard Worker for j, key in enumerate(keys): 260*61046927SAndroid Build Coastguard Worker # Only generate tables for indirect specifiers 261*61046927SAndroid Build Coastguard Worker if mod_map[key][2] is not None: 262*61046927SAndroid Build Coastguard Worker continue 263*61046927SAndroid Build Coastguard Worker 264*61046927SAndroid Build Coastguard Worker idx_parts = [] 265*61046927SAndroid Build Coastguard Worker shift = 0 266*61046927SAndroid Build Coastguard Worker 267*61046927SAndroid Build Coastguard Worker for ((pos, width), _) in derived: 268*61046927SAndroid Build Coastguard Worker idx_parts.append("(_BITS(bits, {}, {}) << {})".format(pos, width, shift)) 269*61046927SAndroid Build Coastguard Worker shift += width 270*61046927SAndroid Build Coastguard Worker 271*61046927SAndroid Build Coastguard Worker built_idx = (" | ".join(idx_parts)) if len(idx_parts) > 0 else "0" 272*61046927SAndroid Build Coastguard Worker 273*61046927SAndroid Build Coastguard Worker default = mod_map[key][3] 274*61046927SAndroid Build Coastguard Worker 275*61046927SAndroid Build Coastguard Worker if ordered: 276*61046927SAndroid Build Coastguard Worker for i, order in enumerate(backwards): 277*61046927SAndroid Build Coastguard Worker options = [ctx[j] if ctx is not None and ctx[j] is not None else "reserved" for ctx in order] 278*61046927SAndroid Build Coastguard Worker output += lut_template_only.render(field = key + "_" + str(i), table = pretty_mods(options, default)) 279*61046927SAndroid Build Coastguard Worker 280*61046927SAndroid Build Coastguard Worker output += " const char *{} = ordering ? {}_1[{}] : {}_0[{}];\n".format(key, key, built_idx, key, built_idx) 281*61046927SAndroid Build Coastguard Worker else: 282*61046927SAndroid Build Coastguard Worker options = [ctx[j] if ctx is not None and ctx[j] is not None else "reserved" for ctx in backwards[0]] 283*61046927SAndroid Build Coastguard Worker output += lut_template_only.render(field = key + "_table", table = pretty_mods(options, default)) 284*61046927SAndroid Build Coastguard Worker output += " const char *{} = {}_table[{}];\n".format(key, key, built_idx) 285*61046927SAndroid Build Coastguard Worker 286*61046927SAndroid Build Coastguard Worker return output 287*61046927SAndroid Build Coastguard Worker 288*61046927SAndroid Build Coastguard Workerdef disasm_mod(mod, skip_mods): 289*61046927SAndroid Build Coastguard Worker if mod[0][0] in skip_mods: 290*61046927SAndroid Build Coastguard Worker return '' 291*61046927SAndroid Build Coastguard Worker else: 292*61046927SAndroid Build Coastguard Worker return ' fputs({}, fp);\n'.format(mod[0][0]) 293*61046927SAndroid Build Coastguard Worker 294*61046927SAndroid Build Coastguard Workerdef disasm_op(name, op): 295*61046927SAndroid Build Coastguard Worker (mnemonic, test, desc) = op 296*61046927SAndroid Build Coastguard Worker is_fma = mnemonic[0] == '*' 297*61046927SAndroid Build Coastguard Worker 298*61046927SAndroid Build Coastguard Worker # Modifiers may be either direct (pos is not None) or indirect (pos is 299*61046927SAndroid Build Coastguard Worker # None). If direct, we just do the bit lookup. If indirect, we use a LUT. 300*61046927SAndroid Build Coastguard Worker 301*61046927SAndroid Build Coastguard Worker body = "" 302*61046927SAndroid Build Coastguard Worker skip_mods = [] 303*61046927SAndroid Build Coastguard Worker 304*61046927SAndroid Build Coastguard Worker body += build_lut(mnemonic, desc, test) 305*61046927SAndroid Build Coastguard Worker 306*61046927SAndroid Build Coastguard Worker for ((mod, pos, width), default, opts) in desc.get('modifiers', []): 307*61046927SAndroid Build Coastguard Worker if pos is not None: 308*61046927SAndroid Build Coastguard Worker body += lut_template.render(field = mod, table = pretty_mods(opts, default), pos = pos, width = width) + "\n" 309*61046927SAndroid Build Coastguard Worker 310*61046927SAndroid Build Coastguard Worker # Mnemonic, followed by modifiers 311*61046927SAndroid Build Coastguard Worker body += ' fputs("{}", fp);\n'.format(mnemonic) 312*61046927SAndroid Build Coastguard Worker 313*61046927SAndroid Build Coastguard Worker srcs = desc.get('srcs', []) 314*61046927SAndroid Build Coastguard Worker 315*61046927SAndroid Build Coastguard Worker for mod in desc.get('modifiers', []): 316*61046927SAndroid Build Coastguard Worker # Skip per-source until next block 317*61046927SAndroid Build Coastguard Worker if mod[0][0][-1] in "0123" and int(mod[0][0][-1]) < len(srcs): 318*61046927SAndroid Build Coastguard Worker continue 319*61046927SAndroid Build Coastguard Worker 320*61046927SAndroid Build Coastguard Worker body += disasm_mod(mod, skip_mods) 321*61046927SAndroid Build Coastguard Worker 322*61046927SAndroid Build Coastguard Worker body += ' fputs(" ", fp);\n' 323*61046927SAndroid Build Coastguard Worker body += ' bi_disasm_dest_{}(fp, next_regs, last);\n'.format('fma' if is_fma else 'add') 324*61046927SAndroid Build Coastguard Worker 325*61046927SAndroid Build Coastguard Worker # Next up, each source. Source modifiers are inserterd here 326*61046927SAndroid Build Coastguard Worker 327*61046927SAndroid Build Coastguard Worker for i, (pos, mask) in enumerate(srcs): 328*61046927SAndroid Build Coastguard Worker body += ' fputs(", ", fp);\n' 329*61046927SAndroid Build Coastguard Worker body += ' dump_src(fp, _BITS(bits, {}, 3), *srcs, branch_offset, consts, {});\n'.format(pos, "true" if is_fma else "false") 330*61046927SAndroid Build Coastguard Worker 331*61046927SAndroid Build Coastguard Worker # Error check if needed 332*61046927SAndroid Build Coastguard Worker if (mask != 0xFF): 333*61046927SAndroid Build Coastguard Worker body += ' if (!({} & (1 << _BITS(bits, {}, 3)))) fputs("(INVALID)", fp);\n'.format(hex(mask), pos, 3) 334*61046927SAndroid Build Coastguard Worker 335*61046927SAndroid Build Coastguard Worker # Print modifiers suffixed with this src number (e.g. abs0 for src0) 336*61046927SAndroid Build Coastguard Worker for mod in desc.get('modifiers', []): 337*61046927SAndroid Build Coastguard Worker if mod[0][0][-1] == str(i): 338*61046927SAndroid Build Coastguard Worker body += disasm_mod(mod, skip_mods) 339*61046927SAndroid Build Coastguard Worker 340*61046927SAndroid Build Coastguard Worker # And each immediate 341*61046927SAndroid Build Coastguard Worker for (imm, pos, width) in desc.get('immediates', []): 342*61046927SAndroid Build Coastguard Worker body += ' fprintf(fp, ", {}:%u", _BITS(bits, {}, {}));\n'.format(imm, pos, width) 343*61046927SAndroid Build Coastguard Worker 344*61046927SAndroid Build Coastguard Worker # Attach a staging register if one is used 345*61046927SAndroid Build Coastguard Worker if desc.get('staging'): 346*61046927SAndroid Build Coastguard Worker body += ' fprintf(fp, ", @r%u", staging_register);\n' 347*61046927SAndroid Build Coastguard Worker 348*61046927SAndroid Build Coastguard Worker return disasm_op_template.render(c_name = opname_to_c(name), body = body) 349*61046927SAndroid Build Coastguard Worker 350*61046927SAndroid Build Coastguard Workerprint('#include "util/macros.h"') 351*61046927SAndroid Build Coastguard Workerprint('#include "bifrost/disassemble.h"') 352*61046927SAndroid Build Coastguard Workerprint('#include "bifrost/bi_disasm.h"') 353*61046927SAndroid Build Coastguard Workerprint('#include "bifrost.h"') 354*61046927SAndroid Build Coastguard Worker 355*61046927SAndroid Build Coastguard Workerstates = expand_states(instructions) 356*61046927SAndroid Build Coastguard Workerprint('#define _BITS(bits, pos, width) (((bits) >> (pos)) & ((1 << (width)) - 1))') 357*61046927SAndroid Build Coastguard Worker 358*61046927SAndroid Build Coastguard Workerfor st in states: 359*61046927SAndroid Build Coastguard Worker print(disasm_op(st, states[st])) 360*61046927SAndroid Build Coastguard Worker 361*61046927SAndroid Build Coastguard Workerprint(decode_op(states, True)) 362*61046927SAndroid Build Coastguard Workerprint(decode_op(states, False)) 363