xref: /aosp_15_r20/external/mesa3d/src/panfrost/compiler/gen_disasm.py (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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