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