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