xref: /aosp_15_r20/external/mesa3d/src/panfrost/compiler/valhall/disasm.py (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1#encoding=utf-8
2
3# Copyright (C) 2021 Collabora, Ltd.
4#
5# Permission is hereby granted, free of charge, to any person obtaining a
6# copy of this software and associated documentation files (the "Software"),
7# to deal in the Software without restriction, including without limitation
8# the rights to use, copy, modify, merge, publish, distribute, sublicense,
9# and/or sell copies of the Software, and to permit persons to whom the
10# Software is furnished to do so, subject to the following conditions:
11#
12# The above copyright notice and this permission notice (including the next
13# paragraph) shall be included in all copies or substantial portions of the
14# Software.
15#
16# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22# IN THE SOFTWARE.
23
24import sys
25from valhall import valhall_parse_isa
26from mako.template import Template
27from mako import exceptions
28
29(instructions, immediates, enums, typesize, safe_name) = valhall_parse_isa()
30
31template = """
32#include "disassemble.h"
33
34#define BIT(b)         (1ull << (b))
35#define MASK(count)    ((1ull << (count)) - 1)
36#define SEXT(b, count) ((b ^ BIT(count - 1)) - BIT(count - 1))
37#define UNUSED         __attribute__((unused))
38
39#define VA_SRC_UNIFORM_TYPE 0x2
40#define VA_SRC_IMM_TYPE     0x3
41
42% for name, en in ENUMS.items():
43UNUSED static const char *valhall_${name}[] = {
44% for v in en.values:
45    "${"" if v.default else "." + v.value}",
46% endfor
47};
48
49% endfor
50static const uint32_t va_immediates[32] = {
51% for imm in IMMEDIATES:
52    ${hex(imm)},
53% endfor
54};
55
56static inline void
57va_print_src(FILE *fp, uint8_t src, unsigned fau_page)
58{
59	unsigned type = (src >> 6);
60	unsigned value = (src & 0x3F);
61
62	if (type == VA_SRC_IMM_TYPE) {
63        if (value >= 32) {
64            if (fau_page == 0)
65                fputs(valhall_fau_special_page_0[(value - 0x20) >> 1] + 1, fp);
66            else if (fau_page == 1)
67                fputs(valhall_fau_special_page_1[(value - 0x20) >> 1] + 1, fp);
68            else if (fau_page == 3)
69                fputs(valhall_fau_special_page_3[(value - 0x20) >> 1] + 1, fp);
70            else
71                fprintf(fp, "reserved_page2");
72
73            fprintf(fp, ".w%u", value & 1);
74        } else {
75            fprintf(fp, "0x%X", va_immediates[value]);
76        }
77	} else if (type == VA_SRC_UNIFORM_TYPE) {
78		fprintf(fp, "u%u", value | (fau_page << 6));
79	} else {
80		bool discard = (type & 1);
81		fprintf(fp, "%sr%u", discard ? "^" : "", value);
82	}
83}
84
85static inline void
86va_print_float_src(FILE *fp, uint8_t src, unsigned fau_page, bool neg, bool abs)
87{
88	unsigned type = (src >> 6);
89	unsigned value = (src & 0x3F);
90
91	if (type == VA_SRC_IMM_TYPE) {
92        assert(value < 32 && "overflow in LUT");
93        fprintf(fp, "0x%X", va_immediates[value]);
94	} else {
95        va_print_src(fp, src, fau_page);
96    }
97
98	if (neg)
99		fprintf(fp, ".neg");
100
101	if (abs)
102		fprintf(fp, ".abs");
103}
104
105static inline void
106va_print_dest(FILE *fp, uint8_t dest, bool can_mask)
107{
108   unsigned mask = (dest >> 6);
109   unsigned value = (dest & 0x3F);
110   fprintf(fp, "r%u", value);
111
112   /* Should write at least one component */
113   //	assert(mask != 0);
114   //	assert(mask == 0x3 || can_mask);
115
116   if (mask != 0x3)
117      fprintf(fp, ".h%u", (mask == 1) ? 0 : 1);
118}
119
120void
121va_disasm_instr(FILE *fp, uint64_t instr)
122{
123   unsigned primary_opc = (instr >> 48) & MASK(9);
124   unsigned fau_page = (instr >> 57) & MASK(2);
125   unsigned secondary_opc = 0;
126
127   switch (primary_opc) {
128% for bucket in OPCODES:
129    <%
130        ops = OPCODES[bucket]
131        ambiguous = (len(ops) > 1)
132    %>
133% if len(ops) > 0:
134   case ${hex(bucket)}:
135% if ambiguous:
136	secondary_opc = (instr >> ${ops[0].secondary_shift}) & ${hex(ops[0].secondary_mask)};
137% endif
138% for op in ops:
139<% no_comma = True %>
140% if ambiguous:
141
142        if (secondary_opc == ${op.opcode2}) {
143% endif
144            fputs("${op.name}", fp);
145% for mod in op.modifiers:
146% if mod.name not in ["left", "memory_width", "descriptor_type", "staging_register_count", "staging_register_write_count"]:
147% if mod.is_enum:
148            fputs(valhall_${safe_name(mod.enum)}[(instr >> ${mod.start}) & ${hex((1 << mod.size) - 1)}], fp);
149% else:
150            if (instr & BIT(${mod.start})) fputs(".${mod.name}", fp);
151% endif
152% endif
153% endfor
154            assert((instr & (1ull << 63)) == 0 /* reserved */);
155            fprintf(fp, "%s ", valhall_flow[instr >> 59]);
156% if len(op.dests) > 0:
157<% no_comma = False %>
158            va_print_dest(fp, (instr >> 40), true);
159% endif
160% for index, sr in enumerate(op.staging):
161% if not no_comma:
162            fputs(", ", fp);
163% endif
164<%
165    no_comma = False
166
167    if sr.count != 0:
168        sr_count = sr.count
169    elif "staging_register_write_count" in [x.name for x in op.modifiers] and sr.write:
170        sr_count = "(((instr >> 36) & MASK(3)) + 1)"
171    elif "staging_register_count" in [x.name for x in op.modifiers]:
172        sr_count = "((instr >> 33) & MASK(3))"
173    else:
174        assert(0)
175%>
176//            assert(((instr >> ${sr.start}) & 0xC0) == ${sr.encoded_flags});
177            fprintf(fp, "@");
178            for (unsigned i = 0; i < ${sr_count}; ++i) {
179                fprintf(fp, "%sr%u", (i == 0) ? "" : ":",
180                        (uint32_t) (((instr >> ${sr.start}) & 0x3F) + i));
181            }
182% endfor
183% for i, src in enumerate(op.srcs):
184% if not no_comma:
185            fputs(", ", fp);
186% endif
187<% no_comma = False %>
188% if src.absneg:
189            va_print_float_src(fp, instr >> ${src.start}, fau_page,
190                    instr & BIT(${src.offset['neg']}),
191                    instr & BIT(${src.offset['abs']}));
192% elif src.is_float:
193            va_print_float_src(fp, instr >> ${src.start}, fau_page, false, false);
194% else:
195            va_print_src(fp, instr >> ${src.start}, fau_page);
196% endif
197% if src.swizzle:
198% if src.size == 32:
199            fputs(valhall_widen[(instr >> ${src.offset['swizzle']}) & 3], fp);
200% else:
201            fputs(valhall_swizzles_16_bit[(instr >> ${src.offset['swizzle']}) & 3], fp);
202% endif
203% endif
204% if src.lanes:
205            fputs(valhall_lanes_8_bit[(instr >> ${src.offset['widen']}) & 0xF], fp);
206% elif src.halfswizzle:
207            fputs(valhall_half_swizzles_8_bit[(instr >> ${src.offset['widen']}) & 0xF], fp);
208% elif src.widen:
209		    fputs(valhall_swizzles_${src.size}_bit[(instr >> ${src.offset['widen']}) & 0xF], fp);
210% elif src.combine:
211            fputs(valhall_combine[(instr >> ${src.offset['combine']}) & 0x7], fp);
212% endif
213% if src.lane:
214            fputs(valhall_lane_${src.size}_bit[(instr >> ${src.lane}) & 0x3], fp);
215% endif
216% if 'not' in src.offset:
217            if (instr & BIT(${src.offset['not']})) fputs(".not", fp);
218% endif
219% endfor
220% for imm in op.immediates:
221<%
222    prefix = "#" if imm.name == "constant" else imm.name + ":"
223    fmt = "%d" if imm.signed else "0x%X"
224%>
225            fprintf(fp, ", ${prefix}${fmt}", (uint32_t) ${"SEXT(" if imm.signed else ""}
226                    ((instr >> ${imm.start}) & MASK(${imm.size})) ${f", {imm.size})" if imm.signed else ""});
227% endfor
228% if ambiguous:
229        }
230% endif
231% endfor
232     break;
233
234% endif
235% endfor
236   }
237}
238
239void
240disassemble_valhall(FILE *fp, const void *code, size_t size, bool verbose)
241{
242   assert((size & 7) == 0);
243
244   const uint64_t *words = (const uint64_t *)code;
245
246   /* Segment into 8-byte instructions */
247   for (unsigned i = 0; i < (size / 8); ++i) {
248      uint64_t instr = words[i];
249
250      if (instr == 0) {
251         fprintf(fp, "\\n");
252         return;
253      }
254
255      if (verbose) {
256         /* Print byte pattern */
257         for (unsigned j = 0; j < 8; ++j)
258            fprintf(fp, "%02x ", (uint8_t)(instr >> (j * 8)));
259
260         fprintf(fp, "   ");
261      } else {
262         /* Print whitespace */
263         fprintf(fp, "   ");
264      }
265
266      va_disasm_instr(fp, instr);
267      fprintf(fp, "\\n");
268
269      /* Detect branches */
270      uint64_t opcode = (instr >> 48) & MASK(9);
271      bool branchz = (opcode == 0x1F);
272      bool branchzi = (opcode == 0x2F);
273
274      /* Separate blocks visually by inserting whitespace after branches */
275      if (branchz || branchzi)
276         fprintf(fp, "\\n");
277   }
278
279   fprintf(fp, "\\n");
280}
281"""
282
283# Bucket by opcode for hierarchical disassembly
284OPCODE_BUCKETS = {}
285for ins in instructions:
286    opc = ins.opcode
287    OPCODE_BUCKETS[opc] = OPCODE_BUCKETS.get(opc, []) + [ins]
288
289# Check that each bucket may be disambiguated
290for op in OPCODE_BUCKETS:
291    bucket = OPCODE_BUCKETS[op]
292
293    # Nothing to disambiguate
294    if len(bucket) < 2:
295        continue
296
297    SECONDARY = {}
298    for ins in bucket:
299        # Number of sources determines opcode2 placement, must be consistent
300        assert(len(ins.srcs) == len(bucket[0].srcs))
301
302        # Must not repeat, else we're ambiguous
303        assert(ins.opcode2 not in SECONDARY)
304        SECONDARY[ins.opcode2] = ins
305
306try:
307    print(Template(template).render(OPCODES = OPCODE_BUCKETS, IMMEDIATES = immediates, ENUMS = enums, typesize = typesize, safe_name = safe_name))
308except:
309    print(exceptions.text_error_template().render())
310