• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1from valhall import instructions, immediates, enums, typesize, safe_name
2from mako.template import Template
3from mako import exceptions
4
5template = """
6#include "disassemble.h"
7
8% for name, en in ENUMS.items():
9UNUSED static const char *valhall_${name}[] = {
10% for v in en.values:
11    "${"" if v.default else "." + v.value}",
12% endfor
13};
14
15% endfor
16static const uint32_t va_immediates[32] = {
17% for imm in IMMEDIATES:
18    ${hex(imm)},
19% endfor
20};
21
22/* Byte 7 has instruction metadata, analogous to Bifrost's clause header */
23struct va_metadata {
24	bool opcode_high : 1;
25    unsigned immediate_mode : 2;
26    unsigned action : 3;
27	bool do_action : 1;
28	bool unk3 : 1;
29} __attribute__((packed));
30
31static inline void
32va_print_metadata(FILE *fp, uint8_t meta)
33{
34	struct va_metadata m;
35	memcpy(&m, &meta, 1);
36
37    fputs(valhall_immediate_mode[m.immediate_mode], fp);
38
39	if (m.do_action) {
40        fputs(valhall_action[m.action], fp);
41	} else if (m.action) {
42		fprintf(fp, ".wait%s%s%s",
43				m.action & (1 << 0) ? "0" : "",
44				m.action & (1 << 1) ? "1" : "",
45				m.action & (1 << 2) ? "2" : "");
46	}
47
48	if (m.unk3)
49		fprintf(fp, ".unk3");
50}
51
52static inline void
53va_print_src(FILE *fp, uint8_t src, unsigned imm_mode)
54{
55	unsigned type = (src >> 6);
56	unsigned value = (src & 0x3F);
57
58	if (type == VA_SRC_IMM_TYPE) {
59        if (value >= 32) {
60            if (imm_mode == 0) {
61                if (value >= 0x30)
62                    fprintf(fp, "blend_descriptor_%u_%c", (value - 0x30) >> 1, value & 1 ? 'y' : 'x');
63                else if (value == 0x2A)
64                    fprintf(fp, "atest_datum");
65                else
66                    fprintf(fp, "unk:%X", value);
67            } else if (imm_mode == 1) {
68                if (value < 0x28)
69                    fputs(valhall_thread_storage_pointers[value - 0x20] + 1, fp);
70                else
71                    fprintf(fp, "unk:%X", value);
72            } else if (imm_mode == 3) {
73                if (value < 0x40)
74                    fputs(valhall_thread_identification[value - 0x20] + 1, fp);
75                else
76                    fprintf(fp, "unk:%X", value);
77            } else {
78                    fprintf(fp, "unk:%X", value);
79            }
80        } else {
81            fprintf(fp, "0x%X", va_immediates[value]);
82        }
83	} else if (type == VA_SRC_UNIFORM_TYPE) {
84		fprintf(fp, "u%u", value);
85	} else {
86		bool discard = (type & 1);
87		fprintf(fp, "%sr%u", discard ? "`" : "", value);
88	}
89}
90
91static inline void
92va_print_float_src(FILE *fp, uint8_t src, unsigned imm_mode, bool neg, bool abs)
93{
94	unsigned type = (src >> 6);
95	unsigned value = (src & 0x3F);
96
97	if (type == VA_SRC_IMM_TYPE) {
98        assert(value < 32 && "overflow in LUT");
99        fprintf(fp, "0x%X", va_immediates[value]);
100	} else {
101        va_print_src(fp, src, imm_mode);
102    }
103
104	if (neg)
105		fprintf(fp, ".neg");
106
107	if (abs)
108		fprintf(fp, ".abs");
109}
110
111void
112va_disasm_instr(FILE *fp, uint64_t instr)
113{
114   unsigned primary_opc = (instr >> 48) & MASK(9);
115   unsigned imm_mode = (instr >> 57) & MASK(2);
116   unsigned secondary_opc = 0;
117
118   switch (primary_opc) {
119% for bucket in OPCODES:
120    <%
121        ops = OPCODES[bucket]
122        ambiguous = (len(ops) > 1)
123    %>
124% if len(ops) > 0:
125   case ${hex(bucket)}:
126% if ambiguous:
127	secondary_opc = (instr >> ${ops[0].secondary_shift}) & ${hex(ops[0].secondary_mask)};
128% endif
129% for op in ops:
130<% no_comma = True %>
131% if ambiguous:
132
133        if (secondary_opc == ${op.opcode2}) {
134% endif
135            fputs("${op.name}", fp);
136% for mod in op.modifiers:
137% if mod.name not in ["left", "staging_register_count"]:
138% if mod.size == 1:
139            if (instr & BIT(${mod.start})) fputs(".${mod.name}", fp);
140% else:
141            fputs(valhall_${safe_name(mod.name)}[(instr >> ${mod.start}) & ${hex((1 << mod.size) - 1)}], fp);
142% endif
143% endif
144% endfor
145            va_print_metadata(fp, instr >> 56);
146            fputs(" ", fp);
147% if len(op.dests) > 0:
148<% no_comma = False %>
149            va_print_dest(fp, (instr >> 40), true);
150% endif
151% for index, sr in enumerate(op.staging):
152% if not no_comma:
153            fputs(", ", fp);
154% endif
155<%
156    no_comma = False
157    sr_count = "((instr >> 33) & MASK(3))" if sr.count == 0 else sr.count
158%>
159//            assert(((instr >> ${sr.start}) & 0xC0) == ${sr.encoded_flags});
160            for (unsigned i = 0; i < ${sr_count}; ++i) {
161                fprintf(fp, "%sr%u", (i == 0) ? "@" : ":",
162                        (uint32_t) (((instr >> ${sr.start}) & 0x3F) + i));
163            }
164% endfor
165% for i, src in enumerate(op.srcs):
166% if not no_comma:
167            fputs(", ", fp);
168% endif
169<% no_comma = False %>
170% if src.absneg:
171            va_print_float_src(fp, instr >> ${8 * i}, imm_mode,
172                    instr & BIT(${src.offset['neg']}),
173                    instr & BIT(${src.offset['abs']}));
174% elif src.is_float:
175            va_print_float_src(fp, instr >> ${8 * i}, imm_mode, false, false);
176% else:
177            va_print_src(fp, instr >> ${8 * i}, imm_mode);
178% endif
179% if src.swizzle:
180% if src.size == 32:
181            fputs(valhall_widen[(instr >> ${src.offset['swizzle']}) & 3], fp);
182% else:
183            fputs(valhall_swizzles_16_bit[(instr >> ${src.offset['swizzle']}) & 3], fp);
184% endif
185% endif
186% if src.lanes:
187            fputs(valhall_lanes_8_bit[(instr >> ${src.offset['widen']}) & 0xF], fp);
188% elif src.widen:
189		    fputs(valhall_swizzles_${src.size}_bit[(instr >> ${src.offset['widen']}) & 0xF], fp);
190% endif
191% if src.lane:
192            fputs(valhall_lane_${src.size}_bit[(instr >> ${src.lane}) & 0x3], fp);
193% endif
194% if 'not' in src.offset:
195            if (instr & BIT(${src.offset['not']})) fputs(".not", fp);
196% endif
197% endfor
198% for imm in op.immediates:
199<%
200    prefix = "#" if imm.name == "constant" else imm.name + ":"
201    fmt = "%d" if imm.signed else "0x%X"
202%>
203            fprintf(fp, ", ${prefix}${fmt}", (uint32_t) ${"SEXT(" if imm.signed else ""}
204                    ((instr >> ${imm.start}) & MASK(${imm.size})) ${f", {imm.size})" if imm.signed else ""});
205% endfor
206% if ambiguous:
207        }
208% endif
209% endfor
210     break;
211
212% endif
213% endfor
214   }
215}
216"""
217
218# Bucket by opcode for hierarchical disassembly
219OPCODE_BUCKETS = {}
220for ins in instructions:
221    opc = ins.opcode
222    OPCODE_BUCKETS[opc] = OPCODE_BUCKETS.get(opc, []) + [ins]
223
224# Check that each bucket may be disambiguated
225for op in OPCODE_BUCKETS:
226    bucket = OPCODE_BUCKETS[op]
227
228    # Nothing to disambiguate
229    if len(bucket) < 2:
230        continue
231
232    SECONDARY = {}
233    for ins in bucket:
234        # Number of sources determines opcode2 placement, must be consistent
235        assert(len(ins.srcs) == len(bucket[0].srcs))
236
237        # Must not repeat, else we're ambiguous
238        assert(ins.opcode2 not in SECONDARY)
239        SECONDARY[ins.opcode2] = ins
240
241try:
242    print(Template(template).render(OPCODES = OPCODE_BUCKETS, IMMEDIATES = immediates, ENUMS = enums, typesize = typesize, safe_name = safe_name))
243except:
244    print(exceptions.text_error_template().render())
245