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