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