1bf215546Sopenharmony_ci/* Author(s): 2bf215546Sopenharmony_ci * Connor Abbott 3bf215546Sopenharmony_ci * Alyssa Rosenzweig 4bf215546Sopenharmony_ci * 5bf215546Sopenharmony_ci * Copyright (c) 2013 Connor Abbott (connor@abbott.cx) 6bf215546Sopenharmony_ci * Copyright (c) 2018 Alyssa Rosenzweig (alyssa@rosenzweig.io) 7bf215546Sopenharmony_ci * Copyright (C) 2019-2020 Collabora, Ltd. 8bf215546Sopenharmony_ci * 9bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy 10bf215546Sopenharmony_ci * of this software and associated documentation files (the "Software"), to deal 11bf215546Sopenharmony_ci * in the Software without restriction, including without limitation the rights 12bf215546Sopenharmony_ci * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13bf215546Sopenharmony_ci * copies of the Software, and to permit persons to whom the Software is 14bf215546Sopenharmony_ci * furnished to do so, subject to the following conditions: 15bf215546Sopenharmony_ci * 16bf215546Sopenharmony_ci * The above copyright notice and this permission notice shall be included in 17bf215546Sopenharmony_ci * all copies or substantial portions of the Software. 18bf215546Sopenharmony_ci * 19bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22bf215546Sopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24bf215546Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25bf215546Sopenharmony_ci * THE SOFTWARE. 26bf215546Sopenharmony_ci */ 27bf215546Sopenharmony_ci 28bf215546Sopenharmony_ci#include <stdio.h> 29bf215546Sopenharmony_ci#include <stdint.h> 30bf215546Sopenharmony_ci#include <stdlib.h> 31bf215546Sopenharmony_ci#include <assert.h> 32bf215546Sopenharmony_ci#include <inttypes.h> 33bf215546Sopenharmony_ci#include <ctype.h> 34bf215546Sopenharmony_ci#include <string.h> 35bf215546Sopenharmony_ci#include "midgard.h" 36bf215546Sopenharmony_ci#include "midgard_ops.h" 37bf215546Sopenharmony_ci#include "midgard_quirks.h" 38bf215546Sopenharmony_ci#include "disassemble.h" 39bf215546Sopenharmony_ci#include "helpers.h" 40bf215546Sopenharmony_ci#include "util/bitscan.h" 41bf215546Sopenharmony_ci#include "util/half_float.h" 42bf215546Sopenharmony_ci#include "util/u_math.h" 43bf215546Sopenharmony_ci 44bf215546Sopenharmony_ci#define DEFINE_CASE(define, str) case define: { fprintf(fp, str); break; } 45bf215546Sopenharmony_ci 46bf215546Sopenharmony_ci/* These are not mapped to hardware values, they just represent the possible 47bf215546Sopenharmony_ci * implicit arg modifiers that some midgard opcodes have, which can be decoded 48bf215546Sopenharmony_ci * from the opcodes via midgard_{alu,ldst,tex}_special_arg_mod() */ 49bf215546Sopenharmony_citypedef enum { 50bf215546Sopenharmony_ci midgard_arg_mod_none = 0, 51bf215546Sopenharmony_ci midgard_arg_mod_inv, 52bf215546Sopenharmony_ci midgard_arg_mod_x2, 53bf215546Sopenharmony_ci} midgard_special_arg_mod; 54bf215546Sopenharmony_ci 55bf215546Sopenharmony_citypedef struct { 56bf215546Sopenharmony_ci unsigned *midg_tags; 57bf215546Sopenharmony_ci struct midgard_disasm_stats midg_stats; 58bf215546Sopenharmony_ci 59bf215546Sopenharmony_ci /* For static analysis to ensure all registers are written at least once before 60bf215546Sopenharmony_ci * use along the source code path (TODO: does this break done for complex CF?) 61bf215546Sopenharmony_ci */ 62bf215546Sopenharmony_ci 63bf215546Sopenharmony_ci uint16_t midg_ever_written; 64bf215546Sopenharmony_ci} disassemble_context; 65bf215546Sopenharmony_ci 66bf215546Sopenharmony_ci/* Transform an expanded writemask (duplicated 8-bit format) into its condensed 67bf215546Sopenharmony_ci * form (one bit per component) */ 68bf215546Sopenharmony_ci 69bf215546Sopenharmony_cistatic inline unsigned 70bf215546Sopenharmony_cicondense_writemask(unsigned expanded_mask, 71bf215546Sopenharmony_ci unsigned bits_per_component) 72bf215546Sopenharmony_ci{ 73bf215546Sopenharmony_ci if (bits_per_component == 8) { 74bf215546Sopenharmony_ci /* Duplicate every bit to go from 8 to 16-channel wrmask */ 75bf215546Sopenharmony_ci unsigned omask = 0; 76bf215546Sopenharmony_ci 77bf215546Sopenharmony_ci for (unsigned i = 0; i < 8; ++i) { 78bf215546Sopenharmony_ci if (expanded_mask & (1 << i)) 79bf215546Sopenharmony_ci omask |= (3 << (2 * i)); 80bf215546Sopenharmony_ci } 81bf215546Sopenharmony_ci 82bf215546Sopenharmony_ci return omask; 83bf215546Sopenharmony_ci } 84bf215546Sopenharmony_ci 85bf215546Sopenharmony_ci unsigned slots_per_component = bits_per_component / 16; 86bf215546Sopenharmony_ci unsigned max_comp = (16 * 8) / bits_per_component; 87bf215546Sopenharmony_ci unsigned condensed_mask = 0; 88bf215546Sopenharmony_ci 89bf215546Sopenharmony_ci for (unsigned i = 0; i < max_comp; i++) { 90bf215546Sopenharmony_ci if (expanded_mask & (1 << (i * slots_per_component))) 91bf215546Sopenharmony_ci condensed_mask |= (1 << i); 92bf215546Sopenharmony_ci } 93bf215546Sopenharmony_ci 94bf215546Sopenharmony_ci return condensed_mask; 95bf215546Sopenharmony_ci} 96bf215546Sopenharmony_ci 97bf215546Sopenharmony_cistatic bool 98bf215546Sopenharmony_ciprint_alu_opcode(FILE *fp, midgard_alu_op op) 99bf215546Sopenharmony_ci{ 100bf215546Sopenharmony_ci if (alu_opcode_props[op].name) 101bf215546Sopenharmony_ci fprintf(fp, "%s", alu_opcode_props[op].name); 102bf215546Sopenharmony_ci else 103bf215546Sopenharmony_ci fprintf(fp, "alu_op_%02X", op); 104bf215546Sopenharmony_ci 105bf215546Sopenharmony_ci /* For constant analysis */ 106bf215546Sopenharmony_ci return midgard_is_integer_op(op); 107bf215546Sopenharmony_ci} 108bf215546Sopenharmony_ci 109bf215546Sopenharmony_cistatic void 110bf215546Sopenharmony_ciprint_ld_st_opcode(FILE *fp, midgard_load_store_op op) 111bf215546Sopenharmony_ci{ 112bf215546Sopenharmony_ci if (load_store_opcode_props[op].name) 113bf215546Sopenharmony_ci fprintf(fp, "%s", load_store_opcode_props[op].name); 114bf215546Sopenharmony_ci else 115bf215546Sopenharmony_ci fprintf(fp, "ldst_op_%02X", op); 116bf215546Sopenharmony_ci} 117bf215546Sopenharmony_ci 118bf215546Sopenharmony_cistatic void 119bf215546Sopenharmony_civalidate_sampler_type(enum mali_texture_op op, enum mali_sampler_type sampler_type) 120bf215546Sopenharmony_ci{ 121bf215546Sopenharmony_ci if (op == midgard_tex_op_mov || op == midgard_tex_op_barrier) 122bf215546Sopenharmony_ci assert(sampler_type == 0); 123bf215546Sopenharmony_ci else 124bf215546Sopenharmony_ci assert(sampler_type > 0); 125bf215546Sopenharmony_ci} 126bf215546Sopenharmony_ci 127bf215546Sopenharmony_cistatic void 128bf215546Sopenharmony_civalidate_expand_mode(midgard_src_expand_mode expand_mode, 129bf215546Sopenharmony_ci midgard_reg_mode reg_mode) 130bf215546Sopenharmony_ci{ 131bf215546Sopenharmony_ci switch (expand_mode) { 132bf215546Sopenharmony_ci case midgard_src_passthrough: 133bf215546Sopenharmony_ci break; 134bf215546Sopenharmony_ci 135bf215546Sopenharmony_ci case midgard_src_rep_low: 136bf215546Sopenharmony_ci assert(reg_mode == midgard_reg_mode_8 || 137bf215546Sopenharmony_ci reg_mode == midgard_reg_mode_16); 138bf215546Sopenharmony_ci break; 139bf215546Sopenharmony_ci 140bf215546Sopenharmony_ci case midgard_src_rep_high: 141bf215546Sopenharmony_ci assert(reg_mode == midgard_reg_mode_8 || 142bf215546Sopenharmony_ci reg_mode == midgard_reg_mode_16); 143bf215546Sopenharmony_ci break; 144bf215546Sopenharmony_ci 145bf215546Sopenharmony_ci case midgard_src_swap: 146bf215546Sopenharmony_ci assert(reg_mode == midgard_reg_mode_8 || 147bf215546Sopenharmony_ci reg_mode == midgard_reg_mode_16); 148bf215546Sopenharmony_ci break; 149bf215546Sopenharmony_ci 150bf215546Sopenharmony_ci case midgard_src_expand_low: 151bf215546Sopenharmony_ci assert(reg_mode != midgard_reg_mode_8); 152bf215546Sopenharmony_ci break; 153bf215546Sopenharmony_ci 154bf215546Sopenharmony_ci case midgard_src_expand_high: 155bf215546Sopenharmony_ci assert(reg_mode != midgard_reg_mode_8); 156bf215546Sopenharmony_ci break; 157bf215546Sopenharmony_ci 158bf215546Sopenharmony_ci case midgard_src_expand_low_swap: 159bf215546Sopenharmony_ci assert(reg_mode == midgard_reg_mode_16); 160bf215546Sopenharmony_ci break; 161bf215546Sopenharmony_ci 162bf215546Sopenharmony_ci case midgard_src_expand_high_swap: 163bf215546Sopenharmony_ci assert(reg_mode == midgard_reg_mode_16); 164bf215546Sopenharmony_ci break; 165bf215546Sopenharmony_ci 166bf215546Sopenharmony_ci default: 167bf215546Sopenharmony_ci unreachable("Invalid expand mode"); 168bf215546Sopenharmony_ci break; 169bf215546Sopenharmony_ci } 170bf215546Sopenharmony_ci} 171bf215546Sopenharmony_ci 172bf215546Sopenharmony_cistatic void 173bf215546Sopenharmony_ciprint_alu_reg(disassemble_context *ctx, FILE *fp, unsigned reg, bool is_write) 174bf215546Sopenharmony_ci{ 175bf215546Sopenharmony_ci unsigned uniform_reg = 23 - reg; 176bf215546Sopenharmony_ci bool is_uniform = false; 177bf215546Sopenharmony_ci 178bf215546Sopenharmony_ci /* For r8-r15, it could be a work or uniform. We distinguish based on 179bf215546Sopenharmony_ci * the fact work registers are ALWAYS written before use, but uniform 180bf215546Sopenharmony_ci * registers are NEVER written before use. */ 181bf215546Sopenharmony_ci 182bf215546Sopenharmony_ci if ((reg >= 8 && reg < 16) && !(ctx->midg_ever_written & (1 << reg))) 183bf215546Sopenharmony_ci is_uniform = true; 184bf215546Sopenharmony_ci 185bf215546Sopenharmony_ci /* r16-r23 are always uniform */ 186bf215546Sopenharmony_ci 187bf215546Sopenharmony_ci if (reg >= 16 && reg <= 23) 188bf215546Sopenharmony_ci is_uniform = true; 189bf215546Sopenharmony_ci 190bf215546Sopenharmony_ci /* Update the uniform count appropriately */ 191bf215546Sopenharmony_ci 192bf215546Sopenharmony_ci if (is_uniform) 193bf215546Sopenharmony_ci ctx->midg_stats.uniform_count = 194bf215546Sopenharmony_ci MAX2(uniform_reg + 1, ctx->midg_stats.uniform_count); 195bf215546Sopenharmony_ci 196bf215546Sopenharmony_ci if (reg == REGISTER_UNUSED || reg == REGISTER_UNUSED + 1) 197bf215546Sopenharmony_ci fprintf(fp, "TMP%u", reg - REGISTER_UNUSED); 198bf215546Sopenharmony_ci else if (reg == REGISTER_TEXTURE_BASE || reg == REGISTER_TEXTURE_BASE + 1) 199bf215546Sopenharmony_ci fprintf(fp, "%s%u", is_write ? "AT" : "TA", reg - REGISTER_TEXTURE_BASE); 200bf215546Sopenharmony_ci else if (reg == REGISTER_LDST_BASE || reg == REGISTER_LDST_BASE + 1) 201bf215546Sopenharmony_ci fprintf(fp, "AL%u", reg - REGISTER_LDST_BASE); 202bf215546Sopenharmony_ci else if (is_uniform) 203bf215546Sopenharmony_ci fprintf(fp, "U%u", uniform_reg); 204bf215546Sopenharmony_ci else if (reg == 31 && !is_write) 205bf215546Sopenharmony_ci fprintf(fp, "PC_SP"); 206bf215546Sopenharmony_ci else 207bf215546Sopenharmony_ci fprintf(fp, "R%u", reg); 208bf215546Sopenharmony_ci} 209bf215546Sopenharmony_ci 210bf215546Sopenharmony_cistatic void 211bf215546Sopenharmony_ciprint_ldst_write_reg(FILE *fp, unsigned reg) 212bf215546Sopenharmony_ci{ 213bf215546Sopenharmony_ci switch (reg) { 214bf215546Sopenharmony_ci case 26: 215bf215546Sopenharmony_ci case 27: 216bf215546Sopenharmony_ci fprintf(fp, "AL%u", reg - REGISTER_LDST_BASE); 217bf215546Sopenharmony_ci break; 218bf215546Sopenharmony_ci case 28: 219bf215546Sopenharmony_ci case 29: 220bf215546Sopenharmony_ci fprintf(fp, "AT%u", reg - REGISTER_TEXTURE_BASE); 221bf215546Sopenharmony_ci break; 222bf215546Sopenharmony_ci case 31: 223bf215546Sopenharmony_ci fprintf(fp, "PC_SP"); 224bf215546Sopenharmony_ci break; 225bf215546Sopenharmony_ci default: 226bf215546Sopenharmony_ci fprintf(fp, "R%d", reg); 227bf215546Sopenharmony_ci break; 228bf215546Sopenharmony_ci } 229bf215546Sopenharmony_ci} 230bf215546Sopenharmony_ci 231bf215546Sopenharmony_cistatic void 232bf215546Sopenharmony_ciprint_ldst_read_reg(FILE *fp, unsigned reg) 233bf215546Sopenharmony_ci{ 234bf215546Sopenharmony_ci switch (reg) { 235bf215546Sopenharmony_ci case 0: 236bf215546Sopenharmony_ci case 1: 237bf215546Sopenharmony_ci fprintf(fp, "AL%u", reg); 238bf215546Sopenharmony_ci break; 239bf215546Sopenharmony_ci case 2: 240bf215546Sopenharmony_ci fprintf(fp, "PC_SP"); 241bf215546Sopenharmony_ci break; 242bf215546Sopenharmony_ci case 3: 243bf215546Sopenharmony_ci fprintf(fp, "LOCAL_STORAGE_PTR"); 244bf215546Sopenharmony_ci break; 245bf215546Sopenharmony_ci case 4: 246bf215546Sopenharmony_ci fprintf(fp, "LOCAL_THREAD_ID"); 247bf215546Sopenharmony_ci break; 248bf215546Sopenharmony_ci case 5: 249bf215546Sopenharmony_ci fprintf(fp, "GROUP_ID"); 250bf215546Sopenharmony_ci break; 251bf215546Sopenharmony_ci case 6: 252bf215546Sopenharmony_ci fprintf(fp, "GLOBAL_THREAD_ID"); 253bf215546Sopenharmony_ci break; 254bf215546Sopenharmony_ci case 7: 255bf215546Sopenharmony_ci fprintf(fp, "0"); 256bf215546Sopenharmony_ci break; 257bf215546Sopenharmony_ci default: 258bf215546Sopenharmony_ci unreachable("Invalid load/store register read"); 259bf215546Sopenharmony_ci } 260bf215546Sopenharmony_ci} 261bf215546Sopenharmony_ci 262bf215546Sopenharmony_cistatic void 263bf215546Sopenharmony_ciprint_tex_reg(FILE *fp, unsigned reg, bool is_write) 264bf215546Sopenharmony_ci{ 265bf215546Sopenharmony_ci char *str = is_write ? "TA" : "AT"; 266bf215546Sopenharmony_ci int select = reg & 1; 267bf215546Sopenharmony_ci 268bf215546Sopenharmony_ci switch (reg) { 269bf215546Sopenharmony_ci case 0: 270bf215546Sopenharmony_ci case 1: 271bf215546Sopenharmony_ci fprintf(fp, "R%d", select); 272bf215546Sopenharmony_ci break; 273bf215546Sopenharmony_ci case 26: 274bf215546Sopenharmony_ci case 27: 275bf215546Sopenharmony_ci fprintf(fp, "AL%d", select); 276bf215546Sopenharmony_ci break; 277bf215546Sopenharmony_ci case 28: 278bf215546Sopenharmony_ci case 29: 279bf215546Sopenharmony_ci fprintf(fp, "%s%d", str, select); 280bf215546Sopenharmony_ci break; 281bf215546Sopenharmony_ci default: 282bf215546Sopenharmony_ci unreachable("Invalid texture register"); 283bf215546Sopenharmony_ci } 284bf215546Sopenharmony_ci} 285bf215546Sopenharmony_ci 286bf215546Sopenharmony_ci 287bf215546Sopenharmony_cistatic char *srcmod_names_int[4] = { 288bf215546Sopenharmony_ci ".sext", 289bf215546Sopenharmony_ci ".zext", 290bf215546Sopenharmony_ci ".replicate", 291bf215546Sopenharmony_ci ".lshift", 292bf215546Sopenharmony_ci}; 293bf215546Sopenharmony_ci 294bf215546Sopenharmony_cistatic char *argmod_names[3] = { 295bf215546Sopenharmony_ci "", 296bf215546Sopenharmony_ci ".inv", 297bf215546Sopenharmony_ci ".x2", 298bf215546Sopenharmony_ci}; 299bf215546Sopenharmony_ci 300bf215546Sopenharmony_cistatic char *index_format_names[4] = { 301bf215546Sopenharmony_ci "", 302bf215546Sopenharmony_ci ".u64", 303bf215546Sopenharmony_ci ".u32", 304bf215546Sopenharmony_ci ".s32" 305bf215546Sopenharmony_ci}; 306bf215546Sopenharmony_ci 307bf215546Sopenharmony_cistatic void 308bf215546Sopenharmony_ciprint_alu_outmod(FILE *fp, unsigned outmod, bool is_int, bool half) 309bf215546Sopenharmony_ci{ 310bf215546Sopenharmony_ci if (is_int && !half) { 311bf215546Sopenharmony_ci assert(outmod == midgard_outmod_keeplo); 312bf215546Sopenharmony_ci return; 313bf215546Sopenharmony_ci } 314bf215546Sopenharmony_ci 315bf215546Sopenharmony_ci if (!is_int && half) 316bf215546Sopenharmony_ci fprintf(fp, ".shrink"); 317bf215546Sopenharmony_ci 318bf215546Sopenharmony_ci mir_print_outmod(fp, outmod, is_int); 319bf215546Sopenharmony_ci} 320bf215546Sopenharmony_ci 321bf215546Sopenharmony_ci/* arg == 0 (dest), arg == 1 (src1), arg == 2 (src2) */ 322bf215546Sopenharmony_cistatic midgard_special_arg_mod 323bf215546Sopenharmony_cimidgard_alu_special_arg_mod(midgard_alu_op op, unsigned arg) { 324bf215546Sopenharmony_ci midgard_special_arg_mod mod = midgard_arg_mod_none; 325bf215546Sopenharmony_ci 326bf215546Sopenharmony_ci switch (op) { 327bf215546Sopenharmony_ci case midgard_alu_op_ishladd: 328bf215546Sopenharmony_ci case midgard_alu_op_ishlsub: 329bf215546Sopenharmony_ci if (arg == 1) mod = midgard_arg_mod_x2; 330bf215546Sopenharmony_ci break; 331bf215546Sopenharmony_ci 332bf215546Sopenharmony_ci default: 333bf215546Sopenharmony_ci break; 334bf215546Sopenharmony_ci } 335bf215546Sopenharmony_ci 336bf215546Sopenharmony_ci return mod; 337bf215546Sopenharmony_ci} 338bf215546Sopenharmony_ci 339bf215546Sopenharmony_cistatic void 340bf215546Sopenharmony_ciprint_quad_word(FILE *fp, uint32_t *words, unsigned tabs) 341bf215546Sopenharmony_ci{ 342bf215546Sopenharmony_ci unsigned i; 343bf215546Sopenharmony_ci 344bf215546Sopenharmony_ci for (i = 0; i < 4; i++) 345bf215546Sopenharmony_ci fprintf(fp, "0x%08X%s ", words[i], i == 3 ? "" : ","); 346bf215546Sopenharmony_ci 347bf215546Sopenharmony_ci fprintf(fp, "\n"); 348bf215546Sopenharmony_ci} 349bf215546Sopenharmony_ci 350bf215546Sopenharmony_cistatic const char components[16] = "xyzwefghijklmnop"; 351bf215546Sopenharmony_ci 352bf215546Sopenharmony_cistatic int 353bf215546Sopenharmony_cibits_for_mode(midgard_reg_mode mode) 354bf215546Sopenharmony_ci{ 355bf215546Sopenharmony_ci switch (mode) { 356bf215546Sopenharmony_ci case midgard_reg_mode_8: 357bf215546Sopenharmony_ci return 8; 358bf215546Sopenharmony_ci case midgard_reg_mode_16: 359bf215546Sopenharmony_ci return 16; 360bf215546Sopenharmony_ci case midgard_reg_mode_32: 361bf215546Sopenharmony_ci return 32; 362bf215546Sopenharmony_ci case midgard_reg_mode_64: 363bf215546Sopenharmony_ci return 64; 364bf215546Sopenharmony_ci default: 365bf215546Sopenharmony_ci unreachable("Invalid reg mode"); 366bf215546Sopenharmony_ci return 0; 367bf215546Sopenharmony_ci } 368bf215546Sopenharmony_ci} 369bf215546Sopenharmony_ci 370bf215546Sopenharmony_cistatic int 371bf215546Sopenharmony_cibits_for_mode_halved(midgard_reg_mode mode, bool half) 372bf215546Sopenharmony_ci{ 373bf215546Sopenharmony_ci unsigned bits = bits_for_mode(mode); 374bf215546Sopenharmony_ci 375bf215546Sopenharmony_ci if (half) 376bf215546Sopenharmony_ci bits >>= 1; 377bf215546Sopenharmony_ci 378bf215546Sopenharmony_ci return bits; 379bf215546Sopenharmony_ci} 380bf215546Sopenharmony_ci 381bf215546Sopenharmony_cistatic void 382bf215546Sopenharmony_ciprint_vec_selectors_64(FILE *fp, unsigned swizzle, 383bf215546Sopenharmony_ci midgard_reg_mode reg_mode, 384bf215546Sopenharmony_ci midgard_src_expand_mode expand_mode, 385bf215546Sopenharmony_ci unsigned selector_offset, uint8_t mask) 386bf215546Sopenharmony_ci{ 387bf215546Sopenharmony_ci bool expands = INPUT_EXPANDS(expand_mode); 388bf215546Sopenharmony_ci 389bf215546Sopenharmony_ci unsigned comp_skip = expands ? 1 : 2; 390bf215546Sopenharmony_ci unsigned mask_bit = 0; 391bf215546Sopenharmony_ci for (unsigned i = selector_offset; i < 4; i += comp_skip, mask_bit += 4) { 392bf215546Sopenharmony_ci if (!(mask & (1 << mask_bit))) continue; 393bf215546Sopenharmony_ci 394bf215546Sopenharmony_ci unsigned a = (swizzle >> (i * 2)) & 3; 395bf215546Sopenharmony_ci 396bf215546Sopenharmony_ci if (INPUT_EXPANDS(expand_mode)) { 397bf215546Sopenharmony_ci if (expand_mode == midgard_src_expand_high) 398bf215546Sopenharmony_ci a += 2; 399bf215546Sopenharmony_ci 400bf215546Sopenharmony_ci fprintf(fp, "%c", components[a / 2]); 401bf215546Sopenharmony_ci continue; 402bf215546Sopenharmony_ci } 403bf215546Sopenharmony_ci 404bf215546Sopenharmony_ci unsigned b = (swizzle >> ((i+1) * 2)) & 3; 405bf215546Sopenharmony_ci 406bf215546Sopenharmony_ci /* Normally we're adjacent, but if there's an issue, 407bf215546Sopenharmony_ci * don't make it ambiguous */ 408bf215546Sopenharmony_ci 409bf215546Sopenharmony_ci if (b == a + 1) 410bf215546Sopenharmony_ci fprintf(fp, "%c", a >> 1 ? 'Y' : 'X'); 411bf215546Sopenharmony_ci else 412bf215546Sopenharmony_ci fprintf(fp, "[%c%c]", components[a], components[b]); 413bf215546Sopenharmony_ci } 414bf215546Sopenharmony_ci} 415bf215546Sopenharmony_ci 416bf215546Sopenharmony_cistatic void 417bf215546Sopenharmony_ciprint_vec_selectors(FILE *fp, unsigned swizzle, 418bf215546Sopenharmony_ci midgard_reg_mode reg_mode, 419bf215546Sopenharmony_ci unsigned selector_offset, uint8_t mask, 420bf215546Sopenharmony_ci unsigned *mask_offset) 421bf215546Sopenharmony_ci{ 422bf215546Sopenharmony_ci assert(reg_mode != midgard_reg_mode_64); 423bf215546Sopenharmony_ci 424bf215546Sopenharmony_ci unsigned mask_skip = MAX2(bits_for_mode(reg_mode) / 16, 1); 425bf215546Sopenharmony_ci 426bf215546Sopenharmony_ci bool is_vec16 = reg_mode == midgard_reg_mode_8; 427bf215546Sopenharmony_ci 428bf215546Sopenharmony_ci for (unsigned i = 0; i < 4; i++, *mask_offset += mask_skip) { 429bf215546Sopenharmony_ci if (!(mask & (1 << *mask_offset))) continue; 430bf215546Sopenharmony_ci 431bf215546Sopenharmony_ci unsigned c = (swizzle >> (i * 2)) & 3; 432bf215546Sopenharmony_ci 433bf215546Sopenharmony_ci /* Vec16 has two components per swizzle selector. */ 434bf215546Sopenharmony_ci if (is_vec16) 435bf215546Sopenharmony_ci c *= 2; 436bf215546Sopenharmony_ci 437bf215546Sopenharmony_ci c += selector_offset; 438bf215546Sopenharmony_ci 439bf215546Sopenharmony_ci fprintf(fp, "%c", components[c]); 440bf215546Sopenharmony_ci if (is_vec16) 441bf215546Sopenharmony_ci fprintf(fp, "%c", components[c+1]); 442bf215546Sopenharmony_ci } 443bf215546Sopenharmony_ci} 444bf215546Sopenharmony_ci 445bf215546Sopenharmony_cistatic void 446bf215546Sopenharmony_ciprint_vec_swizzle(FILE *fp, unsigned swizzle, 447bf215546Sopenharmony_ci midgard_src_expand_mode expand, 448bf215546Sopenharmony_ci midgard_reg_mode mode, 449bf215546Sopenharmony_ci uint8_t mask) 450bf215546Sopenharmony_ci{ 451bf215546Sopenharmony_ci unsigned bits = bits_for_mode_halved(mode, INPUT_EXPANDS(expand)); 452bf215546Sopenharmony_ci 453bf215546Sopenharmony_ci /* Swizzle selectors are divided in two halves that are always 454bf215546Sopenharmony_ci * mirrored, the only difference is the starting component offset. 455bf215546Sopenharmony_ci * The number represents an offset into the components[] array. */ 456bf215546Sopenharmony_ci unsigned first_half = 0; 457bf215546Sopenharmony_ci unsigned second_half = (128 / bits) / 2; /* only used for 8 and 16-bit */ 458bf215546Sopenharmony_ci 459bf215546Sopenharmony_ci switch (expand) { 460bf215546Sopenharmony_ci case midgard_src_passthrough: 461bf215546Sopenharmony_ci if (swizzle == 0xE4) return; /* identity swizzle */ 462bf215546Sopenharmony_ci break; 463bf215546Sopenharmony_ci 464bf215546Sopenharmony_ci case midgard_src_expand_low: 465bf215546Sopenharmony_ci second_half /= 2; 466bf215546Sopenharmony_ci break; 467bf215546Sopenharmony_ci 468bf215546Sopenharmony_ci case midgard_src_expand_high: 469bf215546Sopenharmony_ci first_half = second_half; 470bf215546Sopenharmony_ci second_half += second_half / 2; 471bf215546Sopenharmony_ci break; 472bf215546Sopenharmony_ci 473bf215546Sopenharmony_ci /* The rest of the cases are only used for 8 and 16-bit */ 474bf215546Sopenharmony_ci 475bf215546Sopenharmony_ci case midgard_src_rep_low: 476bf215546Sopenharmony_ci second_half = 0; 477bf215546Sopenharmony_ci break; 478bf215546Sopenharmony_ci 479bf215546Sopenharmony_ci case midgard_src_rep_high: 480bf215546Sopenharmony_ci first_half = second_half; 481bf215546Sopenharmony_ci break; 482bf215546Sopenharmony_ci 483bf215546Sopenharmony_ci case midgard_src_swap: 484bf215546Sopenharmony_ci first_half = second_half; 485bf215546Sopenharmony_ci second_half = 0; 486bf215546Sopenharmony_ci break; 487bf215546Sopenharmony_ci 488bf215546Sopenharmony_ci case midgard_src_expand_low_swap: 489bf215546Sopenharmony_ci first_half = second_half / 2; 490bf215546Sopenharmony_ci second_half = 0; 491bf215546Sopenharmony_ci break; 492bf215546Sopenharmony_ci 493bf215546Sopenharmony_ci case midgard_src_expand_high_swap: 494bf215546Sopenharmony_ci first_half = second_half + second_half / 2; 495bf215546Sopenharmony_ci break; 496bf215546Sopenharmony_ci 497bf215546Sopenharmony_ci default: 498bf215546Sopenharmony_ci unreachable("Invalid expand mode"); 499bf215546Sopenharmony_ci break; 500bf215546Sopenharmony_ci } 501bf215546Sopenharmony_ci 502bf215546Sopenharmony_ci fprintf(fp, "."); 503bf215546Sopenharmony_ci 504bf215546Sopenharmony_ci /* Vec2 are weird so we use a separate function to simplify things. */ 505bf215546Sopenharmony_ci if (mode == midgard_reg_mode_64) { 506bf215546Sopenharmony_ci print_vec_selectors_64(fp, swizzle, mode, expand, first_half, mask); 507bf215546Sopenharmony_ci return; 508bf215546Sopenharmony_ci } 509bf215546Sopenharmony_ci 510bf215546Sopenharmony_ci unsigned mask_offs = 0; 511bf215546Sopenharmony_ci print_vec_selectors(fp, swizzle, mode, first_half, mask, &mask_offs); 512bf215546Sopenharmony_ci if (mode == midgard_reg_mode_8 || mode == midgard_reg_mode_16) 513bf215546Sopenharmony_ci print_vec_selectors(fp, swizzle, mode, second_half, mask, &mask_offs); 514bf215546Sopenharmony_ci} 515bf215546Sopenharmony_ci 516bf215546Sopenharmony_cistatic void 517bf215546Sopenharmony_ciprint_scalar_constant(FILE *fp, unsigned src_binary, 518bf215546Sopenharmony_ci const midgard_constants *consts, 519bf215546Sopenharmony_ci midgard_scalar_alu *alu) 520bf215546Sopenharmony_ci{ 521bf215546Sopenharmony_ci midgard_scalar_alu_src *src = (midgard_scalar_alu_src *)&src_binary; 522bf215546Sopenharmony_ci assert(consts != NULL); 523bf215546Sopenharmony_ci 524bf215546Sopenharmony_ci fprintf(fp, "#"); 525bf215546Sopenharmony_ci mir_print_constant_component(fp, consts, src->component, 526bf215546Sopenharmony_ci src->full ? 527bf215546Sopenharmony_ci midgard_reg_mode_32 : midgard_reg_mode_16, 528bf215546Sopenharmony_ci false, src->mod, alu->op); 529bf215546Sopenharmony_ci} 530bf215546Sopenharmony_ci 531bf215546Sopenharmony_cistatic void 532bf215546Sopenharmony_ciprint_vector_constants(FILE *fp, unsigned src_binary, 533bf215546Sopenharmony_ci const midgard_constants *consts, 534bf215546Sopenharmony_ci midgard_vector_alu *alu) 535bf215546Sopenharmony_ci{ 536bf215546Sopenharmony_ci midgard_vector_alu_src *src = (midgard_vector_alu_src *)&src_binary; 537bf215546Sopenharmony_ci bool expands = INPUT_EXPANDS(src->expand_mode); 538bf215546Sopenharmony_ci unsigned bits = bits_for_mode_halved(alu->reg_mode, expands); 539bf215546Sopenharmony_ci unsigned max_comp = (sizeof(*consts) * 8) / bits; 540bf215546Sopenharmony_ci unsigned comp_mask, num_comp = 0; 541bf215546Sopenharmony_ci 542bf215546Sopenharmony_ci assert(consts); 543bf215546Sopenharmony_ci assert(max_comp <= 16); 544bf215546Sopenharmony_ci 545bf215546Sopenharmony_ci comp_mask = effective_writemask(alu->op, condense_writemask(alu->mask, bits)); 546bf215546Sopenharmony_ci num_comp = util_bitcount(comp_mask); 547bf215546Sopenharmony_ci 548bf215546Sopenharmony_ci if (num_comp > 1) 549bf215546Sopenharmony_ci fprintf(fp, "<"); 550bf215546Sopenharmony_ci else 551bf215546Sopenharmony_ci fprintf(fp, "#"); 552bf215546Sopenharmony_ci 553bf215546Sopenharmony_ci bool first = true; 554bf215546Sopenharmony_ci 555bf215546Sopenharmony_ci for (unsigned i = 0; i < max_comp; ++i) { 556bf215546Sopenharmony_ci if (!(comp_mask & (1 << i))) continue; 557bf215546Sopenharmony_ci 558bf215546Sopenharmony_ci unsigned c = (src->swizzle >> (i * 2)) & 3; 559bf215546Sopenharmony_ci 560bf215546Sopenharmony_ci if (bits == 16 && !expands) { 561bf215546Sopenharmony_ci bool upper = i >= 4; 562bf215546Sopenharmony_ci 563bf215546Sopenharmony_ci switch (src->expand_mode) { 564bf215546Sopenharmony_ci case midgard_src_passthrough: 565bf215546Sopenharmony_ci c += upper * 4; 566bf215546Sopenharmony_ci break; 567bf215546Sopenharmony_ci case midgard_src_rep_low: 568bf215546Sopenharmony_ci break; 569bf215546Sopenharmony_ci case midgard_src_rep_high: 570bf215546Sopenharmony_ci c += 4; 571bf215546Sopenharmony_ci break; 572bf215546Sopenharmony_ci case midgard_src_swap: 573bf215546Sopenharmony_ci c += !upper * 4; 574bf215546Sopenharmony_ci break; 575bf215546Sopenharmony_ci default: 576bf215546Sopenharmony_ci unreachable("invalid expand mode"); 577bf215546Sopenharmony_ci break; 578bf215546Sopenharmony_ci } 579bf215546Sopenharmony_ci } else if (bits == 32 && !expands) { 580bf215546Sopenharmony_ci /* Implicitly ok */ 581bf215546Sopenharmony_ci } else if (bits == 64 && !expands) { 582bf215546Sopenharmony_ci /* Implicitly ok */ 583bf215546Sopenharmony_ci } else if (bits == 8 && !expands) { 584bf215546Sopenharmony_ci bool upper = i >= 8; 585bf215546Sopenharmony_ci 586bf215546Sopenharmony_ci unsigned index = (i >> 1) & 3; 587bf215546Sopenharmony_ci unsigned base = (src->swizzle >> (index * 2)) & 3; 588bf215546Sopenharmony_ci c = base * 2; 589bf215546Sopenharmony_ci 590bf215546Sopenharmony_ci switch (src->expand_mode) { 591bf215546Sopenharmony_ci case midgard_src_passthrough: 592bf215546Sopenharmony_ci c += upper * 8; 593bf215546Sopenharmony_ci break; 594bf215546Sopenharmony_ci case midgard_src_rep_low: 595bf215546Sopenharmony_ci break; 596bf215546Sopenharmony_ci case midgard_src_rep_high: 597bf215546Sopenharmony_ci c += 8; 598bf215546Sopenharmony_ci break; 599bf215546Sopenharmony_ci case midgard_src_swap: 600bf215546Sopenharmony_ci c += !upper * 8; 601bf215546Sopenharmony_ci break; 602bf215546Sopenharmony_ci default: 603bf215546Sopenharmony_ci unreachable("invalid expand mode"); 604bf215546Sopenharmony_ci break; 605bf215546Sopenharmony_ci } 606bf215546Sopenharmony_ci 607bf215546Sopenharmony_ci /* We work on twos, actually */ 608bf215546Sopenharmony_ci if (i & 1) 609bf215546Sopenharmony_ci c++; 610bf215546Sopenharmony_ci } 611bf215546Sopenharmony_ci 612bf215546Sopenharmony_ci if (first) 613bf215546Sopenharmony_ci first = false; 614bf215546Sopenharmony_ci else 615bf215546Sopenharmony_ci fprintf(fp, ", "); 616bf215546Sopenharmony_ci 617bf215546Sopenharmony_ci mir_print_constant_component(fp, consts, c, alu->reg_mode, 618bf215546Sopenharmony_ci expands, src->mod, alu->op); 619bf215546Sopenharmony_ci } 620bf215546Sopenharmony_ci 621bf215546Sopenharmony_ci if (num_comp > 1) 622bf215546Sopenharmony_ci fprintf(fp, ">"); 623bf215546Sopenharmony_ci} 624bf215546Sopenharmony_ci 625bf215546Sopenharmony_cistatic void 626bf215546Sopenharmony_ciprint_srcmod(FILE *fp, bool is_int, bool expands, unsigned mod, bool scalar) 627bf215546Sopenharmony_ci{ 628bf215546Sopenharmony_ci /* Modifiers change meaning depending on the op's context */ 629bf215546Sopenharmony_ci 630bf215546Sopenharmony_ci if (is_int) { 631bf215546Sopenharmony_ci if (expands) 632bf215546Sopenharmony_ci fprintf(fp, "%s", srcmod_names_int[mod]); 633bf215546Sopenharmony_ci } else { 634bf215546Sopenharmony_ci if (mod & MIDGARD_FLOAT_MOD_ABS) 635bf215546Sopenharmony_ci fprintf(fp, ".abs"); 636bf215546Sopenharmony_ci if (mod & MIDGARD_FLOAT_MOD_NEG) 637bf215546Sopenharmony_ci fprintf(fp, ".neg"); 638bf215546Sopenharmony_ci if (expands) 639bf215546Sopenharmony_ci fprintf(fp, ".widen"); 640bf215546Sopenharmony_ci } 641bf215546Sopenharmony_ci} 642bf215546Sopenharmony_ci 643bf215546Sopenharmony_cistatic void 644bf215546Sopenharmony_ciprint_vector_src(disassemble_context *ctx, FILE *fp, unsigned src_binary, 645bf215546Sopenharmony_ci midgard_reg_mode mode, unsigned reg, 646bf215546Sopenharmony_ci midgard_shrink_mode shrink_mode, 647bf215546Sopenharmony_ci uint8_t src_mask, bool is_int, 648bf215546Sopenharmony_ci midgard_special_arg_mod arg_mod) 649bf215546Sopenharmony_ci{ 650bf215546Sopenharmony_ci midgard_vector_alu_src *src = (midgard_vector_alu_src *)&src_binary; 651bf215546Sopenharmony_ci 652bf215546Sopenharmony_ci validate_expand_mode(src->expand_mode, mode); 653bf215546Sopenharmony_ci 654bf215546Sopenharmony_ci print_alu_reg(ctx, fp, reg, false); 655bf215546Sopenharmony_ci 656bf215546Sopenharmony_ci print_vec_swizzle(fp, src->swizzle, src->expand_mode, mode, src_mask); 657bf215546Sopenharmony_ci 658bf215546Sopenharmony_ci fprintf(fp, "%s", argmod_names[arg_mod]); 659bf215546Sopenharmony_ci 660bf215546Sopenharmony_ci print_srcmod(fp, is_int, INPUT_EXPANDS(src->expand_mode), src->mod, false); 661bf215546Sopenharmony_ci} 662bf215546Sopenharmony_ci 663bf215546Sopenharmony_cistatic uint16_t 664bf215546Sopenharmony_cidecode_vector_imm(unsigned src2_reg, unsigned imm) 665bf215546Sopenharmony_ci{ 666bf215546Sopenharmony_ci uint16_t ret; 667bf215546Sopenharmony_ci ret = src2_reg << 11; 668bf215546Sopenharmony_ci ret |= (imm & 0x7) << 8; 669bf215546Sopenharmony_ci ret |= (imm >> 3) & 0xFF; 670bf215546Sopenharmony_ci return ret; 671bf215546Sopenharmony_ci} 672bf215546Sopenharmony_ci 673bf215546Sopenharmony_cistatic void 674bf215546Sopenharmony_ciprint_immediate(FILE *fp, uint16_t imm, bool is_instruction_int) 675bf215546Sopenharmony_ci{ 676bf215546Sopenharmony_ci if (is_instruction_int) 677bf215546Sopenharmony_ci fprintf(fp, "#%u", imm); 678bf215546Sopenharmony_ci else 679bf215546Sopenharmony_ci fprintf(fp, "#%g", _mesa_half_to_float(imm)); 680bf215546Sopenharmony_ci} 681bf215546Sopenharmony_ci 682bf215546Sopenharmony_cistatic void 683bf215546Sopenharmony_ciupdate_dest(disassemble_context *ctx, unsigned reg) 684bf215546Sopenharmony_ci{ 685bf215546Sopenharmony_ci /* We should record writes as marking this as a work register. Store 686bf215546Sopenharmony_ci * the max register in work_count; we'll add one at the end */ 687bf215546Sopenharmony_ci 688bf215546Sopenharmony_ci if (reg < 16) { 689bf215546Sopenharmony_ci ctx->midg_stats.work_count = MAX2(reg, ctx->midg_stats.work_count); 690bf215546Sopenharmony_ci ctx->midg_ever_written |= (1 << reg); 691bf215546Sopenharmony_ci } 692bf215546Sopenharmony_ci} 693bf215546Sopenharmony_ci 694bf215546Sopenharmony_cistatic void 695bf215546Sopenharmony_ciprint_dest(disassemble_context *ctx, FILE *fp, unsigned reg) 696bf215546Sopenharmony_ci{ 697bf215546Sopenharmony_ci update_dest(ctx, reg); 698bf215546Sopenharmony_ci print_alu_reg(ctx, fp, reg, true); 699bf215546Sopenharmony_ci} 700bf215546Sopenharmony_ci 701bf215546Sopenharmony_ci/* For 16-bit+ masks, we read off from the 8-bit mask field. For 16-bit (vec8), 702bf215546Sopenharmony_ci * it's just one bit per channel, easy peasy. For 32-bit (vec4), it's one bit 703bf215546Sopenharmony_ci * per channel with one duplicate bit in the middle. For 64-bit (vec2), it's 704bf215546Sopenharmony_ci * one-bit per channel with _3_ duplicate bits in the middle. Basically, just 705bf215546Sopenharmony_ci * subdividing the 128-bit word in 16-bit increments. For 64-bit, we uppercase 706bf215546Sopenharmony_ci * the mask to make it obvious what happened */ 707bf215546Sopenharmony_ci 708bf215546Sopenharmony_cistatic void 709bf215546Sopenharmony_ciprint_alu_mask(FILE *fp, uint8_t mask, unsigned bits, midgard_shrink_mode shrink_mode) 710bf215546Sopenharmony_ci{ 711bf215546Sopenharmony_ci /* Skip 'complete' masks */ 712bf215546Sopenharmony_ci 713bf215546Sopenharmony_ci if (shrink_mode == midgard_shrink_mode_none && mask == 0xFF) 714bf215546Sopenharmony_ci return; 715bf215546Sopenharmony_ci 716bf215546Sopenharmony_ci fprintf(fp, "."); 717bf215546Sopenharmony_ci 718bf215546Sopenharmony_ci unsigned skip = MAX2(bits / 16, 1); 719bf215546Sopenharmony_ci bool tripped = false; 720bf215546Sopenharmony_ci 721bf215546Sopenharmony_ci /* To apply an upper destination shrink_mode, we "shift" the alphabet. 722bf215546Sopenharmony_ci * E.g. with an upper shrink_mode on 32-bit, instead of xyzw, print efgh. 723bf215546Sopenharmony_ci * For upper 16-bit, instead of xyzwefgh, print ijklmnop */ 724bf215546Sopenharmony_ci 725bf215546Sopenharmony_ci const char *alphabet = components; 726bf215546Sopenharmony_ci 727bf215546Sopenharmony_ci if (shrink_mode == midgard_shrink_mode_upper) { 728bf215546Sopenharmony_ci assert(bits != 8); 729bf215546Sopenharmony_ci alphabet += (128 / bits); 730bf215546Sopenharmony_ci } 731bf215546Sopenharmony_ci 732bf215546Sopenharmony_ci for (unsigned i = 0; i < 8; i += skip) { 733bf215546Sopenharmony_ci bool a = (mask & (1 << i)) != 0; 734bf215546Sopenharmony_ci 735bf215546Sopenharmony_ci for (unsigned j = 1; j < skip; ++j) { 736bf215546Sopenharmony_ci bool dupe = (mask & (1 << (i + j))) != 0; 737bf215546Sopenharmony_ci tripped |= (dupe != a); 738bf215546Sopenharmony_ci } 739bf215546Sopenharmony_ci 740bf215546Sopenharmony_ci if (a) { 741bf215546Sopenharmony_ci /* TODO: handle shrinking from 16-bit */ 742bf215546Sopenharmony_ci unsigned comp_idx = bits == 8 ? i * 2 : i; 743bf215546Sopenharmony_ci char c = alphabet[comp_idx / skip]; 744bf215546Sopenharmony_ci 745bf215546Sopenharmony_ci fprintf(fp, "%c", c); 746bf215546Sopenharmony_ci if (bits == 8) 747bf215546Sopenharmony_ci fprintf(fp, "%c", alphabet[comp_idx+1]); 748bf215546Sopenharmony_ci } 749bf215546Sopenharmony_ci } 750bf215546Sopenharmony_ci 751bf215546Sopenharmony_ci if (tripped) 752bf215546Sopenharmony_ci fprintf(fp, " /* %X */", mask); 753bf215546Sopenharmony_ci} 754bf215546Sopenharmony_ci 755bf215546Sopenharmony_ci/* TODO: 16-bit mode */ 756bf215546Sopenharmony_cistatic void 757bf215546Sopenharmony_ciprint_ldst_mask(FILE *fp, unsigned mask, unsigned swizzle) { 758bf215546Sopenharmony_ci fprintf(fp, "."); 759bf215546Sopenharmony_ci 760bf215546Sopenharmony_ci for (unsigned i = 0; i < 4; ++i) { 761bf215546Sopenharmony_ci bool write = (mask & (1 << i)) != 0; 762bf215546Sopenharmony_ci unsigned c = (swizzle >> (i * 2)) & 3; 763bf215546Sopenharmony_ci /* We can't omit the swizzle here since many ldst ops have a 764bf215546Sopenharmony_ci * combined swizzle/writemask, and it would be ambiguous to not 765bf215546Sopenharmony_ci * print the masked-out components. */ 766bf215546Sopenharmony_ci fprintf(fp, "%c", write ? components[c] : '~'); 767bf215546Sopenharmony_ci } 768bf215546Sopenharmony_ci} 769bf215546Sopenharmony_ci 770bf215546Sopenharmony_cistatic void 771bf215546Sopenharmony_ciprint_tex_mask(FILE *fp, unsigned mask, bool upper) 772bf215546Sopenharmony_ci{ 773bf215546Sopenharmony_ci if (mask == 0xF) { 774bf215546Sopenharmony_ci if (upper) 775bf215546Sopenharmony_ci fprintf(fp, "'"); 776bf215546Sopenharmony_ci 777bf215546Sopenharmony_ci return; 778bf215546Sopenharmony_ci } 779bf215546Sopenharmony_ci 780bf215546Sopenharmony_ci fprintf(fp, "."); 781bf215546Sopenharmony_ci 782bf215546Sopenharmony_ci for (unsigned i = 0; i < 4; ++i) { 783bf215546Sopenharmony_ci bool a = (mask & (1 << i)) != 0; 784bf215546Sopenharmony_ci if (a) 785bf215546Sopenharmony_ci fprintf(fp, "%c", components[i + (upper ? 4 : 0)]); 786bf215546Sopenharmony_ci } 787bf215546Sopenharmony_ci} 788bf215546Sopenharmony_ci 789bf215546Sopenharmony_cistatic void 790bf215546Sopenharmony_ciprint_vector_field(disassemble_context *ctx, FILE *fp, const char *name, 791bf215546Sopenharmony_ci uint16_t *words, uint16_t reg_word, 792bf215546Sopenharmony_ci const midgard_constants *consts, unsigned tabs, bool verbose) 793bf215546Sopenharmony_ci{ 794bf215546Sopenharmony_ci midgard_reg_info *reg_info = (midgard_reg_info *)®_word; 795bf215546Sopenharmony_ci midgard_vector_alu *alu_field = (midgard_vector_alu *) words; 796bf215546Sopenharmony_ci midgard_reg_mode mode = alu_field->reg_mode; 797bf215546Sopenharmony_ci midgard_alu_op op = alu_field->op; 798bf215546Sopenharmony_ci unsigned shrink_mode = alu_field->shrink_mode; 799bf215546Sopenharmony_ci bool is_int = midgard_is_integer_op(op); 800bf215546Sopenharmony_ci bool is_int_out = midgard_is_integer_out_op(op); 801bf215546Sopenharmony_ci 802bf215546Sopenharmony_ci if (verbose) 803bf215546Sopenharmony_ci fprintf(fp, "%s.", name); 804bf215546Sopenharmony_ci 805bf215546Sopenharmony_ci bool is_instruction_int = print_alu_opcode(fp, alu_field->op); 806bf215546Sopenharmony_ci 807bf215546Sopenharmony_ci /* Print lane width */ 808bf215546Sopenharmony_ci fprintf(fp, ".%c%d", is_int_out ? 'i' : 'f', bits_for_mode(mode)); 809bf215546Sopenharmony_ci 810bf215546Sopenharmony_ci fprintf(fp, " "); 811bf215546Sopenharmony_ci 812bf215546Sopenharmony_ci /* Mask denoting status of 8-lanes */ 813bf215546Sopenharmony_ci uint8_t mask = alu_field->mask; 814bf215546Sopenharmony_ci 815bf215546Sopenharmony_ci /* First, print the destination */ 816bf215546Sopenharmony_ci print_dest(ctx, fp, reg_info->out_reg); 817bf215546Sopenharmony_ci 818bf215546Sopenharmony_ci if (shrink_mode != midgard_shrink_mode_none) { 819bf215546Sopenharmony_ci bool shrinkable = (mode != midgard_reg_mode_8); 820bf215546Sopenharmony_ci bool known = shrink_mode != 0x3; /* Unused value */ 821bf215546Sopenharmony_ci 822bf215546Sopenharmony_ci if (!(shrinkable && known)) 823bf215546Sopenharmony_ci fprintf(fp, "/* do%u */ ", shrink_mode); 824bf215546Sopenharmony_ci } 825bf215546Sopenharmony_ci 826bf215546Sopenharmony_ci /* Instructions like fdot4 do *not* replicate, ensure the 827bf215546Sopenharmony_ci * mask is of only a single component */ 828bf215546Sopenharmony_ci 829bf215546Sopenharmony_ci unsigned rep = GET_CHANNEL_COUNT(alu_opcode_props[op].props); 830bf215546Sopenharmony_ci 831bf215546Sopenharmony_ci if (rep) { 832bf215546Sopenharmony_ci unsigned comp_mask = condense_writemask(mask, bits_for_mode(mode)); 833bf215546Sopenharmony_ci unsigned num_comp = util_bitcount(comp_mask); 834bf215546Sopenharmony_ci if (num_comp != 1) 835bf215546Sopenharmony_ci fprintf(fp, "/* err too many components */"); 836bf215546Sopenharmony_ci } 837bf215546Sopenharmony_ci print_alu_mask(fp, mask, bits_for_mode(mode), shrink_mode); 838bf215546Sopenharmony_ci 839bf215546Sopenharmony_ci /* Print output modifiers */ 840bf215546Sopenharmony_ci 841bf215546Sopenharmony_ci print_alu_outmod(fp, alu_field->outmod, is_int_out, shrink_mode != midgard_shrink_mode_none); 842bf215546Sopenharmony_ci 843bf215546Sopenharmony_ci /* Mask out unused components based on the writemask, but don't mask out 844bf215546Sopenharmony_ci * components that are used for interlane instructions like fdot3. */ 845bf215546Sopenharmony_ci uint8_t src_mask = 846bf215546Sopenharmony_ci rep ? expand_writemask(mask_of(rep), util_logbase2(128 / bits_for_mode(mode))) : mask; 847bf215546Sopenharmony_ci 848bf215546Sopenharmony_ci fprintf(fp, ", "); 849bf215546Sopenharmony_ci 850bf215546Sopenharmony_ci if (reg_info->src1_reg == REGISTER_CONSTANT) 851bf215546Sopenharmony_ci print_vector_constants(fp, alu_field->src1, consts, alu_field); 852bf215546Sopenharmony_ci else { 853bf215546Sopenharmony_ci midgard_special_arg_mod argmod = midgard_alu_special_arg_mod(op, 1); 854bf215546Sopenharmony_ci print_vector_src(ctx, fp, alu_field->src1, mode, reg_info->src1_reg, 855bf215546Sopenharmony_ci shrink_mode, src_mask, is_int, argmod); 856bf215546Sopenharmony_ci } 857bf215546Sopenharmony_ci 858bf215546Sopenharmony_ci fprintf(fp, ", "); 859bf215546Sopenharmony_ci 860bf215546Sopenharmony_ci if (reg_info->src2_imm) { 861bf215546Sopenharmony_ci uint16_t imm = decode_vector_imm(reg_info->src2_reg, alu_field->src2 >> 2); 862bf215546Sopenharmony_ci print_immediate(fp, imm, is_instruction_int); 863bf215546Sopenharmony_ci } else if (reg_info->src2_reg == REGISTER_CONSTANT) { 864bf215546Sopenharmony_ci print_vector_constants(fp, alu_field->src2, consts, alu_field); 865bf215546Sopenharmony_ci } else { 866bf215546Sopenharmony_ci midgard_special_arg_mod argmod = midgard_alu_special_arg_mod(op, 2); 867bf215546Sopenharmony_ci print_vector_src(ctx, fp, alu_field->src2, mode, reg_info->src2_reg, 868bf215546Sopenharmony_ci shrink_mode, src_mask, is_int, argmod); 869bf215546Sopenharmony_ci } 870bf215546Sopenharmony_ci 871bf215546Sopenharmony_ci ctx->midg_stats.instruction_count++; 872bf215546Sopenharmony_ci fprintf(fp, "\n"); 873bf215546Sopenharmony_ci} 874bf215546Sopenharmony_ci 875bf215546Sopenharmony_cistatic void 876bf215546Sopenharmony_ciprint_scalar_src(disassemble_context *ctx, FILE *fp, bool is_int, unsigned src_binary, unsigned reg) 877bf215546Sopenharmony_ci{ 878bf215546Sopenharmony_ci midgard_scalar_alu_src *src = (midgard_scalar_alu_src *)&src_binary; 879bf215546Sopenharmony_ci 880bf215546Sopenharmony_ci print_alu_reg(ctx, fp, reg, false); 881bf215546Sopenharmony_ci 882bf215546Sopenharmony_ci unsigned c = src->component; 883bf215546Sopenharmony_ci 884bf215546Sopenharmony_ci if (src->full) { 885bf215546Sopenharmony_ci assert((c & 1) == 0); 886bf215546Sopenharmony_ci c >>= 1; 887bf215546Sopenharmony_ci } 888bf215546Sopenharmony_ci 889bf215546Sopenharmony_ci fprintf(fp, ".%c", components[c]); 890bf215546Sopenharmony_ci 891bf215546Sopenharmony_ci print_srcmod(fp, is_int, !src->full, src->mod, true); 892bf215546Sopenharmony_ci} 893bf215546Sopenharmony_ci 894bf215546Sopenharmony_cistatic uint16_t 895bf215546Sopenharmony_cidecode_scalar_imm(unsigned src2_reg, unsigned imm) 896bf215546Sopenharmony_ci{ 897bf215546Sopenharmony_ci uint16_t ret; 898bf215546Sopenharmony_ci ret = src2_reg << 11; 899bf215546Sopenharmony_ci ret |= (imm & 3) << 9; 900bf215546Sopenharmony_ci ret |= (imm & 4) << 6; 901bf215546Sopenharmony_ci ret |= (imm & 0x38) << 2; 902bf215546Sopenharmony_ci ret |= imm >> 6; 903bf215546Sopenharmony_ci return ret; 904bf215546Sopenharmony_ci} 905bf215546Sopenharmony_ci 906bf215546Sopenharmony_cistatic void 907bf215546Sopenharmony_ciprint_scalar_field(disassemble_context *ctx, FILE *fp, const char *name, 908bf215546Sopenharmony_ci uint16_t *words, uint16_t reg_word, 909bf215546Sopenharmony_ci const midgard_constants *consts, unsigned tabs, bool verbose) 910bf215546Sopenharmony_ci{ 911bf215546Sopenharmony_ci midgard_reg_info *reg_info = (midgard_reg_info *)®_word; 912bf215546Sopenharmony_ci midgard_scalar_alu *alu_field = (midgard_scalar_alu *) words; 913bf215546Sopenharmony_ci bool is_int = midgard_is_integer_op(alu_field->op); 914bf215546Sopenharmony_ci bool is_int_out = midgard_is_integer_out_op(alu_field->op); 915bf215546Sopenharmony_ci bool full = alu_field->output_full; 916bf215546Sopenharmony_ci 917bf215546Sopenharmony_ci if (alu_field->reserved) 918bf215546Sopenharmony_ci fprintf(fp, "scalar ALU reserved bit set\n"); 919bf215546Sopenharmony_ci 920bf215546Sopenharmony_ci if (verbose) 921bf215546Sopenharmony_ci fprintf(fp, "%s.", name); 922bf215546Sopenharmony_ci 923bf215546Sopenharmony_ci bool is_instruction_int = print_alu_opcode(fp, alu_field->op); 924bf215546Sopenharmony_ci 925bf215546Sopenharmony_ci /* Print lane width, in this case the lane width is always 32-bit, but 926bf215546Sopenharmony_ci * we print it anyway to make it consistent with the other instructions. */ 927bf215546Sopenharmony_ci fprintf(fp, ".%c32", is_int_out ? 'i' : 'f'); 928bf215546Sopenharmony_ci 929bf215546Sopenharmony_ci fprintf(fp, " "); 930bf215546Sopenharmony_ci 931bf215546Sopenharmony_ci print_dest(ctx, fp, reg_info->out_reg); 932bf215546Sopenharmony_ci unsigned c = alu_field->output_component; 933bf215546Sopenharmony_ci 934bf215546Sopenharmony_ci if (full) { 935bf215546Sopenharmony_ci assert((c & 1) == 0); 936bf215546Sopenharmony_ci c >>= 1; 937bf215546Sopenharmony_ci } 938bf215546Sopenharmony_ci 939bf215546Sopenharmony_ci fprintf(fp, ".%c", components[c]); 940bf215546Sopenharmony_ci 941bf215546Sopenharmony_ci print_alu_outmod(fp, alu_field->outmod, is_int_out, !full); 942bf215546Sopenharmony_ci 943bf215546Sopenharmony_ci fprintf(fp, ", "); 944bf215546Sopenharmony_ci 945bf215546Sopenharmony_ci if (reg_info->src1_reg == REGISTER_CONSTANT) 946bf215546Sopenharmony_ci print_scalar_constant(fp, alu_field->src1, consts, alu_field); 947bf215546Sopenharmony_ci else 948bf215546Sopenharmony_ci print_scalar_src(ctx, fp, is_int, alu_field->src1, reg_info->src1_reg); 949bf215546Sopenharmony_ci 950bf215546Sopenharmony_ci fprintf(fp, ", "); 951bf215546Sopenharmony_ci 952bf215546Sopenharmony_ci if (reg_info->src2_imm) { 953bf215546Sopenharmony_ci uint16_t imm = decode_scalar_imm(reg_info->src2_reg, 954bf215546Sopenharmony_ci alu_field->src2); 955bf215546Sopenharmony_ci print_immediate(fp, imm, is_instruction_int); 956bf215546Sopenharmony_ci } else if (reg_info->src2_reg == REGISTER_CONSTANT) { 957bf215546Sopenharmony_ci print_scalar_constant(fp, alu_field->src2, consts, alu_field); 958bf215546Sopenharmony_ci } else 959bf215546Sopenharmony_ci print_scalar_src(ctx, fp, is_int, alu_field->src2, reg_info->src2_reg); 960bf215546Sopenharmony_ci 961bf215546Sopenharmony_ci ctx->midg_stats.instruction_count++; 962bf215546Sopenharmony_ci fprintf(fp, "\n"); 963bf215546Sopenharmony_ci} 964bf215546Sopenharmony_ci 965bf215546Sopenharmony_cistatic void 966bf215546Sopenharmony_ciprint_branch_op(FILE *fp, unsigned op) 967bf215546Sopenharmony_ci{ 968bf215546Sopenharmony_ci switch (op) { 969bf215546Sopenharmony_ci case midgard_jmp_writeout_op_branch_uncond: 970bf215546Sopenharmony_ci fprintf(fp, "uncond."); 971bf215546Sopenharmony_ci break; 972bf215546Sopenharmony_ci 973bf215546Sopenharmony_ci case midgard_jmp_writeout_op_branch_cond: 974bf215546Sopenharmony_ci fprintf(fp, "cond."); 975bf215546Sopenharmony_ci break; 976bf215546Sopenharmony_ci 977bf215546Sopenharmony_ci case midgard_jmp_writeout_op_writeout: 978bf215546Sopenharmony_ci fprintf(fp, "write."); 979bf215546Sopenharmony_ci break; 980bf215546Sopenharmony_ci 981bf215546Sopenharmony_ci case midgard_jmp_writeout_op_tilebuffer_pending: 982bf215546Sopenharmony_ci fprintf(fp, "tilebuffer."); 983bf215546Sopenharmony_ci break; 984bf215546Sopenharmony_ci 985bf215546Sopenharmony_ci case midgard_jmp_writeout_op_discard: 986bf215546Sopenharmony_ci fprintf(fp, "discard."); 987bf215546Sopenharmony_ci break; 988bf215546Sopenharmony_ci 989bf215546Sopenharmony_ci default: 990bf215546Sopenharmony_ci fprintf(fp, "unk%u.", op); 991bf215546Sopenharmony_ci break; 992bf215546Sopenharmony_ci } 993bf215546Sopenharmony_ci} 994bf215546Sopenharmony_ci 995bf215546Sopenharmony_cistatic void 996bf215546Sopenharmony_ciprint_branch_cond(FILE *fp, int cond) 997bf215546Sopenharmony_ci{ 998bf215546Sopenharmony_ci switch (cond) { 999bf215546Sopenharmony_ci case midgard_condition_write0: 1000bf215546Sopenharmony_ci fprintf(fp, "write0"); 1001bf215546Sopenharmony_ci break; 1002bf215546Sopenharmony_ci 1003bf215546Sopenharmony_ci case midgard_condition_false: 1004bf215546Sopenharmony_ci fprintf(fp, "false"); 1005bf215546Sopenharmony_ci break; 1006bf215546Sopenharmony_ci 1007bf215546Sopenharmony_ci case midgard_condition_true: 1008bf215546Sopenharmony_ci fprintf(fp, "true"); 1009bf215546Sopenharmony_ci break; 1010bf215546Sopenharmony_ci 1011bf215546Sopenharmony_ci case midgard_condition_always: 1012bf215546Sopenharmony_ci fprintf(fp, "always"); 1013bf215546Sopenharmony_ci break; 1014bf215546Sopenharmony_ci 1015bf215546Sopenharmony_ci default: 1016bf215546Sopenharmony_ci fprintf(fp, "unk%X", cond); 1017bf215546Sopenharmony_ci break; 1018bf215546Sopenharmony_ci } 1019bf215546Sopenharmony_ci} 1020bf215546Sopenharmony_ci 1021bf215546Sopenharmony_cistatic const char * 1022bf215546Sopenharmony_cifunction_call_mode(enum midgard_call_mode mode) 1023bf215546Sopenharmony_ci{ 1024bf215546Sopenharmony_ci switch (mode) { 1025bf215546Sopenharmony_ci case midgard_call_mode_default: return ""; 1026bf215546Sopenharmony_ci case midgard_call_mode_call: return ".call"; 1027bf215546Sopenharmony_ci case midgard_call_mode_return: return ".return"; 1028bf215546Sopenharmony_ci default: return ".reserved"; 1029bf215546Sopenharmony_ci } 1030bf215546Sopenharmony_ci} 1031bf215546Sopenharmony_ci 1032bf215546Sopenharmony_cistatic bool 1033bf215546Sopenharmony_ciprint_compact_branch_writeout_field(disassemble_context *ctx, FILE *fp, uint16_t word) 1034bf215546Sopenharmony_ci{ 1035bf215546Sopenharmony_ci midgard_jmp_writeout_op op = word & 0x7; 1036bf215546Sopenharmony_ci ctx->midg_stats.instruction_count++; 1037bf215546Sopenharmony_ci 1038bf215546Sopenharmony_ci switch (op) { 1039bf215546Sopenharmony_ci case midgard_jmp_writeout_op_branch_uncond: { 1040bf215546Sopenharmony_ci midgard_branch_uncond br_uncond; 1041bf215546Sopenharmony_ci memcpy((char *) &br_uncond, (char *) &word, sizeof(br_uncond)); 1042bf215546Sopenharmony_ci fprintf(fp, "br.uncond%s ", function_call_mode(br_uncond.call_mode)); 1043bf215546Sopenharmony_ci 1044bf215546Sopenharmony_ci if (br_uncond.offset >= 0) 1045bf215546Sopenharmony_ci fprintf(fp, "+"); 1046bf215546Sopenharmony_ci 1047bf215546Sopenharmony_ci fprintf(fp, "%d -> %s", br_uncond.offset, 1048bf215546Sopenharmony_ci midgard_tag_props[br_uncond.dest_tag].name); 1049bf215546Sopenharmony_ci fprintf(fp, "\n"); 1050bf215546Sopenharmony_ci 1051bf215546Sopenharmony_ci return br_uncond.offset >= 0; 1052bf215546Sopenharmony_ci } 1053bf215546Sopenharmony_ci 1054bf215546Sopenharmony_ci case midgard_jmp_writeout_op_branch_cond: 1055bf215546Sopenharmony_ci case midgard_jmp_writeout_op_writeout: 1056bf215546Sopenharmony_ci case midgard_jmp_writeout_op_discard: 1057bf215546Sopenharmony_ci default: { 1058bf215546Sopenharmony_ci midgard_branch_cond br_cond; 1059bf215546Sopenharmony_ci memcpy((char *) &br_cond, (char *) &word, sizeof(br_cond)); 1060bf215546Sopenharmony_ci 1061bf215546Sopenharmony_ci fprintf(fp, "br."); 1062bf215546Sopenharmony_ci 1063bf215546Sopenharmony_ci print_branch_op(fp, br_cond.op); 1064bf215546Sopenharmony_ci print_branch_cond(fp, br_cond.cond); 1065bf215546Sopenharmony_ci 1066bf215546Sopenharmony_ci fprintf(fp, " "); 1067bf215546Sopenharmony_ci 1068bf215546Sopenharmony_ci if (br_cond.offset >= 0) 1069bf215546Sopenharmony_ci fprintf(fp, "+"); 1070bf215546Sopenharmony_ci 1071bf215546Sopenharmony_ci fprintf(fp, "%d -> %s", br_cond.offset, 1072bf215546Sopenharmony_ci midgard_tag_props[br_cond.dest_tag].name); 1073bf215546Sopenharmony_ci fprintf(fp, "\n"); 1074bf215546Sopenharmony_ci 1075bf215546Sopenharmony_ci return br_cond.offset >= 0; 1076bf215546Sopenharmony_ci } 1077bf215546Sopenharmony_ci } 1078bf215546Sopenharmony_ci 1079bf215546Sopenharmony_ci return false; 1080bf215546Sopenharmony_ci} 1081bf215546Sopenharmony_ci 1082bf215546Sopenharmony_cistatic bool 1083bf215546Sopenharmony_ciprint_extended_branch_writeout_field(disassemble_context *ctx, FILE *fp, uint8_t *words, 1084bf215546Sopenharmony_ci unsigned next) 1085bf215546Sopenharmony_ci{ 1086bf215546Sopenharmony_ci midgard_branch_extended br; 1087bf215546Sopenharmony_ci memcpy((char *) &br, (char *) words, sizeof(br)); 1088bf215546Sopenharmony_ci 1089bf215546Sopenharmony_ci fprintf(fp, "brx%s.", function_call_mode(br.call_mode)); 1090bf215546Sopenharmony_ci 1091bf215546Sopenharmony_ci print_branch_op(fp, br.op); 1092bf215546Sopenharmony_ci 1093bf215546Sopenharmony_ci /* Condition codes are a LUT in the general case, but simply repeated 8 times for single-channel conditions.. Check this. */ 1094bf215546Sopenharmony_ci 1095bf215546Sopenharmony_ci bool single_channel = true; 1096bf215546Sopenharmony_ci 1097bf215546Sopenharmony_ci for (unsigned i = 0; i < 16; i += 2) { 1098bf215546Sopenharmony_ci single_channel &= (((br.cond >> i) & 0x3) == (br.cond & 0x3)); 1099bf215546Sopenharmony_ci } 1100bf215546Sopenharmony_ci 1101bf215546Sopenharmony_ci if (single_channel) 1102bf215546Sopenharmony_ci print_branch_cond(fp, br.cond & 0x3); 1103bf215546Sopenharmony_ci else 1104bf215546Sopenharmony_ci fprintf(fp, "lut%X", br.cond); 1105bf215546Sopenharmony_ci 1106bf215546Sopenharmony_ci fprintf(fp, " "); 1107bf215546Sopenharmony_ci 1108bf215546Sopenharmony_ci if (br.offset >= 0) 1109bf215546Sopenharmony_ci fprintf(fp, "+"); 1110bf215546Sopenharmony_ci 1111bf215546Sopenharmony_ci fprintf(fp, "%d -> %s\n", br.offset, 1112bf215546Sopenharmony_ci midgard_tag_props[br.dest_tag].name); 1113bf215546Sopenharmony_ci 1114bf215546Sopenharmony_ci unsigned I = next + br.offset * 4; 1115bf215546Sopenharmony_ci 1116bf215546Sopenharmony_ci if (ctx->midg_tags[I] && ctx->midg_tags[I] != br.dest_tag) { 1117bf215546Sopenharmony_ci fprintf(fp, "\t/* XXX TAG ERROR: jumping to %s but tagged %s \n", 1118bf215546Sopenharmony_ci midgard_tag_props[br.dest_tag].name, 1119bf215546Sopenharmony_ci midgard_tag_props[ctx->midg_tags[I]].name); 1120bf215546Sopenharmony_ci } 1121bf215546Sopenharmony_ci 1122bf215546Sopenharmony_ci ctx->midg_tags[I] = br.dest_tag; 1123bf215546Sopenharmony_ci 1124bf215546Sopenharmony_ci ctx->midg_stats.instruction_count++; 1125bf215546Sopenharmony_ci return br.offset >= 0; 1126bf215546Sopenharmony_ci} 1127bf215546Sopenharmony_ci 1128bf215546Sopenharmony_cistatic unsigned 1129bf215546Sopenharmony_cinum_alu_fields_enabled(uint32_t control_word) 1130bf215546Sopenharmony_ci{ 1131bf215546Sopenharmony_ci unsigned ret = 0; 1132bf215546Sopenharmony_ci 1133bf215546Sopenharmony_ci if ((control_word >> 17) & 1) 1134bf215546Sopenharmony_ci ret++; 1135bf215546Sopenharmony_ci 1136bf215546Sopenharmony_ci if ((control_word >> 19) & 1) 1137bf215546Sopenharmony_ci ret++; 1138bf215546Sopenharmony_ci 1139bf215546Sopenharmony_ci if ((control_word >> 21) & 1) 1140bf215546Sopenharmony_ci ret++; 1141bf215546Sopenharmony_ci 1142bf215546Sopenharmony_ci if ((control_word >> 23) & 1) 1143bf215546Sopenharmony_ci ret++; 1144bf215546Sopenharmony_ci 1145bf215546Sopenharmony_ci if ((control_word >> 25) & 1) 1146bf215546Sopenharmony_ci ret++; 1147bf215546Sopenharmony_ci 1148bf215546Sopenharmony_ci return ret; 1149bf215546Sopenharmony_ci} 1150bf215546Sopenharmony_ci 1151bf215546Sopenharmony_cistatic bool 1152bf215546Sopenharmony_ciprint_alu_word(disassemble_context *ctx, FILE *fp, uint32_t *words, 1153bf215546Sopenharmony_ci unsigned num_quad_words, unsigned tabs, unsigned next, 1154bf215546Sopenharmony_ci bool verbose) 1155bf215546Sopenharmony_ci{ 1156bf215546Sopenharmony_ci uint32_t control_word = words[0]; 1157bf215546Sopenharmony_ci uint16_t *beginning_ptr = (uint16_t *)(words + 1); 1158bf215546Sopenharmony_ci unsigned num_fields = num_alu_fields_enabled(control_word); 1159bf215546Sopenharmony_ci uint16_t *word_ptr = beginning_ptr + num_fields; 1160bf215546Sopenharmony_ci unsigned num_words = 2 + num_fields; 1161bf215546Sopenharmony_ci const midgard_constants *consts = NULL; 1162bf215546Sopenharmony_ci bool branch_forward = false; 1163bf215546Sopenharmony_ci 1164bf215546Sopenharmony_ci if ((control_word >> 17) & 1) 1165bf215546Sopenharmony_ci num_words += 3; 1166bf215546Sopenharmony_ci 1167bf215546Sopenharmony_ci if ((control_word >> 19) & 1) 1168bf215546Sopenharmony_ci num_words += 2; 1169bf215546Sopenharmony_ci 1170bf215546Sopenharmony_ci if ((control_word >> 21) & 1) 1171bf215546Sopenharmony_ci num_words += 3; 1172bf215546Sopenharmony_ci 1173bf215546Sopenharmony_ci if ((control_word >> 23) & 1) 1174bf215546Sopenharmony_ci num_words += 2; 1175bf215546Sopenharmony_ci 1176bf215546Sopenharmony_ci if ((control_word >> 25) & 1) 1177bf215546Sopenharmony_ci num_words += 3; 1178bf215546Sopenharmony_ci 1179bf215546Sopenharmony_ci if ((control_word >> 26) & 1) 1180bf215546Sopenharmony_ci num_words += 1; 1181bf215546Sopenharmony_ci 1182bf215546Sopenharmony_ci if ((control_word >> 27) & 1) 1183bf215546Sopenharmony_ci num_words += 3; 1184bf215546Sopenharmony_ci 1185bf215546Sopenharmony_ci if (num_quad_words > (num_words + 7) / 8) { 1186bf215546Sopenharmony_ci assert(num_quad_words == (num_words + 15) / 8); 1187bf215546Sopenharmony_ci //Assume that the extra quadword is constants 1188bf215546Sopenharmony_ci consts = (midgard_constants *)(words + (4 * num_quad_words - 4)); 1189bf215546Sopenharmony_ci } 1190bf215546Sopenharmony_ci 1191bf215546Sopenharmony_ci if ((control_word >> 16) & 1) 1192bf215546Sopenharmony_ci fprintf(fp, "unknown bit 16 enabled\n"); 1193bf215546Sopenharmony_ci 1194bf215546Sopenharmony_ci if ((control_word >> 17) & 1) { 1195bf215546Sopenharmony_ci print_vector_field(ctx, fp, "vmul", word_ptr, *beginning_ptr, consts, tabs, verbose); 1196bf215546Sopenharmony_ci beginning_ptr += 1; 1197bf215546Sopenharmony_ci word_ptr += 3; 1198bf215546Sopenharmony_ci } 1199bf215546Sopenharmony_ci 1200bf215546Sopenharmony_ci if ((control_word >> 18) & 1) 1201bf215546Sopenharmony_ci fprintf(fp, "unknown bit 18 enabled\n"); 1202bf215546Sopenharmony_ci 1203bf215546Sopenharmony_ci if ((control_word >> 19) & 1) { 1204bf215546Sopenharmony_ci print_scalar_field(ctx, fp, "sadd", word_ptr, *beginning_ptr, consts, tabs, verbose); 1205bf215546Sopenharmony_ci beginning_ptr += 1; 1206bf215546Sopenharmony_ci word_ptr += 2; 1207bf215546Sopenharmony_ci } 1208bf215546Sopenharmony_ci 1209bf215546Sopenharmony_ci if ((control_word >> 20) & 1) 1210bf215546Sopenharmony_ci fprintf(fp, "unknown bit 20 enabled\n"); 1211bf215546Sopenharmony_ci 1212bf215546Sopenharmony_ci if ((control_word >> 21) & 1) { 1213bf215546Sopenharmony_ci print_vector_field(ctx, fp, "vadd", word_ptr, *beginning_ptr, consts, tabs, verbose); 1214bf215546Sopenharmony_ci beginning_ptr += 1; 1215bf215546Sopenharmony_ci word_ptr += 3; 1216bf215546Sopenharmony_ci } 1217bf215546Sopenharmony_ci 1218bf215546Sopenharmony_ci if ((control_word >> 22) & 1) 1219bf215546Sopenharmony_ci fprintf(fp, "unknown bit 22 enabled\n"); 1220bf215546Sopenharmony_ci 1221bf215546Sopenharmony_ci if ((control_word >> 23) & 1) { 1222bf215546Sopenharmony_ci print_scalar_field(ctx, fp, "smul", word_ptr, *beginning_ptr, consts, tabs, verbose); 1223bf215546Sopenharmony_ci beginning_ptr += 1; 1224bf215546Sopenharmony_ci word_ptr += 2; 1225bf215546Sopenharmony_ci } 1226bf215546Sopenharmony_ci 1227bf215546Sopenharmony_ci if ((control_word >> 24) & 1) 1228bf215546Sopenharmony_ci fprintf(fp, "unknown bit 24 enabled\n"); 1229bf215546Sopenharmony_ci 1230bf215546Sopenharmony_ci if ((control_word >> 25) & 1) { 1231bf215546Sopenharmony_ci print_vector_field(ctx, fp, "lut", word_ptr, *beginning_ptr, consts, tabs, verbose); 1232bf215546Sopenharmony_ci word_ptr += 3; 1233bf215546Sopenharmony_ci } 1234bf215546Sopenharmony_ci 1235bf215546Sopenharmony_ci if ((control_word >> 26) & 1) { 1236bf215546Sopenharmony_ci branch_forward |= print_compact_branch_writeout_field(ctx, fp, *word_ptr); 1237bf215546Sopenharmony_ci word_ptr += 1; 1238bf215546Sopenharmony_ci } 1239bf215546Sopenharmony_ci 1240bf215546Sopenharmony_ci if ((control_word >> 27) & 1) { 1241bf215546Sopenharmony_ci branch_forward |= print_extended_branch_writeout_field(ctx, fp, (uint8_t *) word_ptr, next); 1242bf215546Sopenharmony_ci word_ptr += 3; 1243bf215546Sopenharmony_ci } 1244bf215546Sopenharmony_ci 1245bf215546Sopenharmony_ci if (consts) 1246bf215546Sopenharmony_ci fprintf(fp, "uconstants 0x%X, 0x%X, 0x%X, 0x%X\n", 1247bf215546Sopenharmony_ci consts->u32[0], consts->u32[1], 1248bf215546Sopenharmony_ci consts->u32[2], consts->u32[3]); 1249bf215546Sopenharmony_ci 1250bf215546Sopenharmony_ci return branch_forward; 1251bf215546Sopenharmony_ci} 1252bf215546Sopenharmony_ci 1253bf215546Sopenharmony_ci/* TODO: how can we use this now that we know that these params can't be known 1254bf215546Sopenharmony_ci * before run time in every single case? Maybe just use it in the cases we can? */ 1255bf215546Sopenharmony_ciUNUSED static void 1256bf215546Sopenharmony_ciprint_varying_parameters(FILE *fp, midgard_load_store_word *word) 1257bf215546Sopenharmony_ci{ 1258bf215546Sopenharmony_ci midgard_varying_params p = midgard_unpack_varying_params(*word); 1259bf215546Sopenharmony_ci 1260bf215546Sopenharmony_ci /* If a varying, there are qualifiers */ 1261bf215546Sopenharmony_ci if (p.flat_shading) 1262bf215546Sopenharmony_ci fprintf(fp, ".flat"); 1263bf215546Sopenharmony_ci 1264bf215546Sopenharmony_ci if (p.perspective_correction) 1265bf215546Sopenharmony_ci fprintf(fp, ".correction"); 1266bf215546Sopenharmony_ci 1267bf215546Sopenharmony_ci if (p.centroid_mapping) 1268bf215546Sopenharmony_ci fprintf(fp, ".centroid"); 1269bf215546Sopenharmony_ci 1270bf215546Sopenharmony_ci if (p.interpolate_sample) 1271bf215546Sopenharmony_ci fprintf(fp, ".sample"); 1272bf215546Sopenharmony_ci 1273bf215546Sopenharmony_ci switch (p.modifier) { 1274bf215546Sopenharmony_ci case midgard_varying_mod_perspective_y: 1275bf215546Sopenharmony_ci fprintf(fp, ".perspectivey"); 1276bf215546Sopenharmony_ci break; 1277bf215546Sopenharmony_ci case midgard_varying_mod_perspective_z: 1278bf215546Sopenharmony_ci fprintf(fp, ".perspectivez"); 1279bf215546Sopenharmony_ci break; 1280bf215546Sopenharmony_ci case midgard_varying_mod_perspective_w: 1281bf215546Sopenharmony_ci fprintf(fp, ".perspectivew"); 1282bf215546Sopenharmony_ci break; 1283bf215546Sopenharmony_ci default: 1284bf215546Sopenharmony_ci unreachable("invalid varying modifier"); 1285bf215546Sopenharmony_ci break; 1286bf215546Sopenharmony_ci } 1287bf215546Sopenharmony_ci} 1288bf215546Sopenharmony_ci 1289bf215546Sopenharmony_cistatic bool 1290bf215546Sopenharmony_ciis_op_varying(unsigned op) 1291bf215546Sopenharmony_ci{ 1292bf215546Sopenharmony_ci switch (op) { 1293bf215546Sopenharmony_ci case midgard_op_st_vary_16: 1294bf215546Sopenharmony_ci case midgard_op_st_vary_32: 1295bf215546Sopenharmony_ci case midgard_op_st_vary_32i: 1296bf215546Sopenharmony_ci case midgard_op_st_vary_32u: 1297bf215546Sopenharmony_ci case midgard_op_ld_vary_16: 1298bf215546Sopenharmony_ci case midgard_op_ld_vary_32: 1299bf215546Sopenharmony_ci case midgard_op_ld_vary_32i: 1300bf215546Sopenharmony_ci case midgard_op_ld_vary_32u: 1301bf215546Sopenharmony_ci return true; 1302bf215546Sopenharmony_ci } 1303bf215546Sopenharmony_ci 1304bf215546Sopenharmony_ci return false; 1305bf215546Sopenharmony_ci} 1306bf215546Sopenharmony_ci 1307bf215546Sopenharmony_cistatic bool 1308bf215546Sopenharmony_ciis_op_attribute(unsigned op) 1309bf215546Sopenharmony_ci{ 1310bf215546Sopenharmony_ci switch (op) { 1311bf215546Sopenharmony_ci case midgard_op_ld_attr_16: 1312bf215546Sopenharmony_ci case midgard_op_ld_attr_32: 1313bf215546Sopenharmony_ci case midgard_op_ld_attr_32i: 1314bf215546Sopenharmony_ci case midgard_op_ld_attr_32u: 1315bf215546Sopenharmony_ci return true; 1316bf215546Sopenharmony_ci } 1317bf215546Sopenharmony_ci 1318bf215546Sopenharmony_ci return false; 1319bf215546Sopenharmony_ci} 1320bf215546Sopenharmony_ci 1321bf215546Sopenharmony_ci/* Helper to print integer well-formatted, but only when non-zero. */ 1322bf215546Sopenharmony_cistatic void 1323bf215546Sopenharmony_cimidgard_print_sint(FILE *fp, int n) 1324bf215546Sopenharmony_ci{ 1325bf215546Sopenharmony_ci if (n > 0) 1326bf215546Sopenharmony_ci fprintf(fp, " + 0x%X", n); 1327bf215546Sopenharmony_ci else if (n < 0) 1328bf215546Sopenharmony_ci fprintf(fp, " - 0x%X", -n); 1329bf215546Sopenharmony_ci} 1330bf215546Sopenharmony_ci 1331bf215546Sopenharmony_cistatic void 1332bf215546Sopenharmony_ciupdate_stats(signed *stat, unsigned address) 1333bf215546Sopenharmony_ci{ 1334bf215546Sopenharmony_ci if (*stat >= 0) 1335bf215546Sopenharmony_ci *stat = MAX2(*stat, address + 1); 1336bf215546Sopenharmony_ci} 1337bf215546Sopenharmony_ci 1338bf215546Sopenharmony_cistatic void 1339bf215546Sopenharmony_ciprint_load_store_instr(disassemble_context *ctx, FILE *fp, uint64_t data, bool verbose) 1340bf215546Sopenharmony_ci{ 1341bf215546Sopenharmony_ci midgard_load_store_word *word = (midgard_load_store_word *) &data; 1342bf215546Sopenharmony_ci 1343bf215546Sopenharmony_ci print_ld_st_opcode(fp, word->op); 1344bf215546Sopenharmony_ci 1345bf215546Sopenharmony_ci if (word->op == midgard_op_trap) { 1346bf215546Sopenharmony_ci fprintf(fp, " 0x%X\n", word->signed_offset); 1347bf215546Sopenharmony_ci return; 1348bf215546Sopenharmony_ci } 1349bf215546Sopenharmony_ci 1350bf215546Sopenharmony_ci /* Print opcode modifiers */ 1351bf215546Sopenharmony_ci 1352bf215546Sopenharmony_ci if (OP_USES_ATTRIB(word->op)) { 1353bf215546Sopenharmony_ci /* Print non-default attribute tables */ 1354bf215546Sopenharmony_ci bool default_secondary = 1355bf215546Sopenharmony_ci (word->op == midgard_op_st_vary_32) || 1356bf215546Sopenharmony_ci (word->op == midgard_op_st_vary_16) || 1357bf215546Sopenharmony_ci (word->op == midgard_op_st_vary_32u) || 1358bf215546Sopenharmony_ci (word->op == midgard_op_st_vary_32i) || 1359bf215546Sopenharmony_ci (word->op == midgard_op_ld_vary_32) || 1360bf215546Sopenharmony_ci (word->op == midgard_op_ld_vary_16) || 1361bf215546Sopenharmony_ci (word->op == midgard_op_ld_vary_32u) || 1362bf215546Sopenharmony_ci (word->op == midgard_op_ld_vary_32i); 1363bf215546Sopenharmony_ci 1364bf215546Sopenharmony_ci bool default_primary = 1365bf215546Sopenharmony_ci (word->op == midgard_op_ld_attr_32) || 1366bf215546Sopenharmony_ci (word->op == midgard_op_ld_attr_16) || 1367bf215546Sopenharmony_ci (word->op == midgard_op_ld_attr_32u) || 1368bf215546Sopenharmony_ci (word->op == midgard_op_ld_attr_32i); 1369bf215546Sopenharmony_ci 1370bf215546Sopenharmony_ci bool has_default = (default_secondary || default_primary); 1371bf215546Sopenharmony_ci bool is_secondary = (word->index_format >> 1); 1372bf215546Sopenharmony_ci 1373bf215546Sopenharmony_ci if (has_default && (is_secondary != default_secondary)) 1374bf215546Sopenharmony_ci fprintf(fp, ".%s", is_secondary ? "secondary" : "primary"); 1375bf215546Sopenharmony_ci } else if (word->op == midgard_op_ld_cubemap_coords || OP_IS_PROJECTION(word->op)) 1376bf215546Sopenharmony_ci fprintf(fp, ".%s", word->bitsize_toggle ? "f32" : "f16"); 1377bf215546Sopenharmony_ci 1378bf215546Sopenharmony_ci fprintf(fp, " "); 1379bf215546Sopenharmony_ci 1380bf215546Sopenharmony_ci /* src/dest register */ 1381bf215546Sopenharmony_ci 1382bf215546Sopenharmony_ci if (!OP_IS_STORE(word->op)) { 1383bf215546Sopenharmony_ci print_ldst_write_reg(fp, word->reg); 1384bf215546Sopenharmony_ci 1385bf215546Sopenharmony_ci /* Some opcodes don't have a swizzable src register, and 1386bf215546Sopenharmony_ci * instead the swizzle is applied before the result is written 1387bf215546Sopenharmony_ci * to the dest reg. For these ops, we combine the writemask 1388bf215546Sopenharmony_ci * with the swizzle to display them in the disasm compactly. */ 1389bf215546Sopenharmony_ci unsigned swizzle = word->swizzle; 1390bf215546Sopenharmony_ci if ((OP_IS_REG2REG_LDST(word->op) && 1391bf215546Sopenharmony_ci word->op != midgard_op_lea && 1392bf215546Sopenharmony_ci word->op != midgard_op_lea_image) || OP_IS_ATOMIC(word->op)) 1393bf215546Sopenharmony_ci swizzle = 0xE4; 1394bf215546Sopenharmony_ci print_ldst_mask(fp, word->mask, swizzle); 1395bf215546Sopenharmony_ci } else { 1396bf215546Sopenharmony_ci uint8_t mask = 1397bf215546Sopenharmony_ci (word->mask & 0x1) | 1398bf215546Sopenharmony_ci ((word->mask & 0x2) << 1) | 1399bf215546Sopenharmony_ci ((word->mask & 0x4) << 2) | 1400bf215546Sopenharmony_ci ((word->mask & 0x8) << 3); 1401bf215546Sopenharmony_ci mask |= mask << 1; 1402bf215546Sopenharmony_ci print_ldst_read_reg(fp, word->reg); 1403bf215546Sopenharmony_ci print_vec_swizzle(fp, word->swizzle, midgard_src_passthrough, 1404bf215546Sopenharmony_ci midgard_reg_mode_32, mask); 1405bf215546Sopenharmony_ci } 1406bf215546Sopenharmony_ci 1407bf215546Sopenharmony_ci /* ld_ubo args */ 1408bf215546Sopenharmony_ci if (OP_IS_UBO_READ(word->op)) { 1409bf215546Sopenharmony_ci if (word->signed_offset & 1) { /* buffer index imm */ 1410bf215546Sopenharmony_ci unsigned imm = midgard_unpack_ubo_index_imm(*word); 1411bf215546Sopenharmony_ci fprintf(fp, ", %u", imm); 1412bf215546Sopenharmony_ci } else { /* buffer index from reg */ 1413bf215546Sopenharmony_ci fprintf(fp, ", "); 1414bf215546Sopenharmony_ci print_ldst_read_reg(fp, word->arg_reg); 1415bf215546Sopenharmony_ci fprintf(fp, ".%c", components[word->arg_comp]); 1416bf215546Sopenharmony_ci } 1417bf215546Sopenharmony_ci 1418bf215546Sopenharmony_ci fprintf(fp, ", "); 1419bf215546Sopenharmony_ci print_ldst_read_reg(fp, word->index_reg); 1420bf215546Sopenharmony_ci fprintf(fp, ".%c", components[word->index_comp]); 1421bf215546Sopenharmony_ci if (word->index_shift) 1422bf215546Sopenharmony_ci fprintf(fp, " << %u", word->index_shift); 1423bf215546Sopenharmony_ci midgard_print_sint(fp, UNPACK_LDST_UBO_OFS(word->signed_offset)); 1424bf215546Sopenharmony_ci } 1425bf215546Sopenharmony_ci 1426bf215546Sopenharmony_ci /* mem addr expression */ 1427bf215546Sopenharmony_ci if (OP_HAS_ADDRESS(word->op)) { 1428bf215546Sopenharmony_ci fprintf(fp, ", "); 1429bf215546Sopenharmony_ci bool first = true; 1430bf215546Sopenharmony_ci 1431bf215546Sopenharmony_ci /* Skip printing zero */ 1432bf215546Sopenharmony_ci if (word->arg_reg != 7 || verbose) { 1433bf215546Sopenharmony_ci print_ldst_read_reg(fp, word->arg_reg); 1434bf215546Sopenharmony_ci fprintf(fp, ".u%d.%c", 1435bf215546Sopenharmony_ci word->bitsize_toggle ? 64 : 32, components[word->arg_comp]); 1436bf215546Sopenharmony_ci first = false; 1437bf215546Sopenharmony_ci } 1438bf215546Sopenharmony_ci 1439bf215546Sopenharmony_ci if ((word->op < midgard_op_atomic_cmpxchg || 1440bf215546Sopenharmony_ci word->op > midgard_op_atomic_cmpxchg64_be) && 1441bf215546Sopenharmony_ci word->index_reg != 0x7) { 1442bf215546Sopenharmony_ci if (!first) 1443bf215546Sopenharmony_ci fprintf(fp, " + "); 1444bf215546Sopenharmony_ci 1445bf215546Sopenharmony_ci print_ldst_read_reg(fp, word->index_reg); 1446bf215546Sopenharmony_ci fprintf(fp, "%s.%c", 1447bf215546Sopenharmony_ci index_format_names[word->index_format], 1448bf215546Sopenharmony_ci components[word->index_comp]); 1449bf215546Sopenharmony_ci if (word->index_shift) 1450bf215546Sopenharmony_ci fprintf(fp, " << %u", word->index_shift); 1451bf215546Sopenharmony_ci } 1452bf215546Sopenharmony_ci 1453bf215546Sopenharmony_ci midgard_print_sint(fp, word->signed_offset); 1454bf215546Sopenharmony_ci } 1455bf215546Sopenharmony_ci 1456bf215546Sopenharmony_ci /* src reg for reg2reg ldst opcodes */ 1457bf215546Sopenharmony_ci if (OP_IS_REG2REG_LDST(word->op)) { 1458bf215546Sopenharmony_ci fprintf(fp, ", "); 1459bf215546Sopenharmony_ci print_ldst_read_reg(fp, word->arg_reg); 1460bf215546Sopenharmony_ci print_vec_swizzle(fp, word->swizzle, midgard_src_passthrough, 1461bf215546Sopenharmony_ci midgard_reg_mode_32, 0xFF); 1462bf215546Sopenharmony_ci } 1463bf215546Sopenharmony_ci 1464bf215546Sopenharmony_ci /* atomic ops encode the source arg where the ldst swizzle would be. */ 1465bf215546Sopenharmony_ci if (OP_IS_ATOMIC(word->op)) { 1466bf215546Sopenharmony_ci unsigned src = (word->swizzle >> 2) & 0x7; 1467bf215546Sopenharmony_ci unsigned src_comp = word->swizzle & 0x3; 1468bf215546Sopenharmony_ci fprintf(fp, ", "); 1469bf215546Sopenharmony_ci print_ldst_read_reg(fp, src); 1470bf215546Sopenharmony_ci fprintf(fp, ".%c", components[src_comp]); 1471bf215546Sopenharmony_ci } 1472bf215546Sopenharmony_ci 1473bf215546Sopenharmony_ci /* CMPXCHG encodes the extra comparison arg where the index reg would be. */ 1474bf215546Sopenharmony_ci if (word->op >= midgard_op_atomic_cmpxchg && 1475bf215546Sopenharmony_ci word->op <= midgard_op_atomic_cmpxchg64_be) { 1476bf215546Sopenharmony_ci fprintf(fp, ", "); 1477bf215546Sopenharmony_ci print_ldst_read_reg(fp, word->index_reg); 1478bf215546Sopenharmony_ci fprintf(fp, ".%c", components[word->index_comp]); 1479bf215546Sopenharmony_ci } 1480bf215546Sopenharmony_ci 1481bf215546Sopenharmony_ci /* index reg for attr/vary/images, selector for ld/st_special */ 1482bf215546Sopenharmony_ci if (OP_IS_SPECIAL(word->op) || OP_USES_ATTRIB(word->op)) { 1483bf215546Sopenharmony_ci fprintf(fp, ", "); 1484bf215546Sopenharmony_ci print_ldst_read_reg(fp, word->index_reg); 1485bf215546Sopenharmony_ci fprintf(fp, ".%c", components[word->index_comp]); 1486bf215546Sopenharmony_ci if (word->index_shift) 1487bf215546Sopenharmony_ci fprintf(fp, " << %u", word->index_shift); 1488bf215546Sopenharmony_ci midgard_print_sint(fp, UNPACK_LDST_ATTRIB_OFS(word->signed_offset)); 1489bf215546Sopenharmony_ci } 1490bf215546Sopenharmony_ci 1491bf215546Sopenharmony_ci /* vertex reg for attrib/varying ops, coord reg for image ops */ 1492bf215546Sopenharmony_ci if (OP_USES_ATTRIB(word->op)) { 1493bf215546Sopenharmony_ci fprintf(fp, ", "); 1494bf215546Sopenharmony_ci print_ldst_read_reg(fp, word->arg_reg); 1495bf215546Sopenharmony_ci 1496bf215546Sopenharmony_ci if (OP_IS_IMAGE(word->op)) 1497bf215546Sopenharmony_ci fprintf(fp, ".u%d", word->bitsize_toggle ? 64 : 32); 1498bf215546Sopenharmony_ci 1499bf215546Sopenharmony_ci fprintf(fp, ".%c", components[word->arg_comp]); 1500bf215546Sopenharmony_ci 1501bf215546Sopenharmony_ci if (word->bitsize_toggle && !OP_IS_IMAGE(word->op)) 1502bf215546Sopenharmony_ci midgard_print_sint(fp, UNPACK_LDST_VERTEX_OFS(word->signed_offset)); 1503bf215546Sopenharmony_ci } 1504bf215546Sopenharmony_ci 1505bf215546Sopenharmony_ci /* TODO: properly decode format specifier for PACK/UNPACK ops */ 1506bf215546Sopenharmony_ci if (OP_IS_PACK_COLOUR(word->op) || OP_IS_UNPACK_COLOUR(word->op)) { 1507bf215546Sopenharmony_ci fprintf(fp, ", "); 1508bf215546Sopenharmony_ci unsigned format_specifier = (word->signed_offset << 4) | word->index_shift; 1509bf215546Sopenharmony_ci fprintf(fp, "0x%X", format_specifier); 1510bf215546Sopenharmony_ci } 1511bf215546Sopenharmony_ci 1512bf215546Sopenharmony_ci fprintf(fp, "\n"); 1513bf215546Sopenharmony_ci 1514bf215546Sopenharmony_ci /* Debugging stuff */ 1515bf215546Sopenharmony_ci 1516bf215546Sopenharmony_ci if (is_op_varying(word->op)) { 1517bf215546Sopenharmony_ci /* Do some analysis: check if direct access */ 1518bf215546Sopenharmony_ci 1519bf215546Sopenharmony_ci if (word->index_reg == 0x7 && ctx->midg_stats.varying_count >= 0) 1520bf215546Sopenharmony_ci update_stats(&ctx->midg_stats.varying_count, 1521bf215546Sopenharmony_ci UNPACK_LDST_ATTRIB_OFS(word->signed_offset)); 1522bf215546Sopenharmony_ci else 1523bf215546Sopenharmony_ci ctx->midg_stats.varying_count = -16; 1524bf215546Sopenharmony_ci } else if (is_op_attribute(word->op)) { 1525bf215546Sopenharmony_ci if (word->index_reg == 0x7 && ctx->midg_stats.attribute_count >= 0) 1526bf215546Sopenharmony_ci update_stats(&ctx->midg_stats.attribute_count, 1527bf215546Sopenharmony_ci UNPACK_LDST_ATTRIB_OFS(word->signed_offset)); 1528bf215546Sopenharmony_ci else 1529bf215546Sopenharmony_ci ctx->midg_stats.attribute_count = -16; 1530bf215546Sopenharmony_ci } 1531bf215546Sopenharmony_ci 1532bf215546Sopenharmony_ci if (!OP_IS_STORE(word->op)) 1533bf215546Sopenharmony_ci update_dest(ctx, word->reg); 1534bf215546Sopenharmony_ci 1535bf215546Sopenharmony_ci if (OP_IS_UBO_READ(word->op)) 1536bf215546Sopenharmony_ci update_stats(&ctx->midg_stats.uniform_buffer_count, 1537bf215546Sopenharmony_ci UNPACK_LDST_UBO_OFS(word->signed_offset)); 1538bf215546Sopenharmony_ci 1539bf215546Sopenharmony_ci ctx->midg_stats.instruction_count++; 1540bf215546Sopenharmony_ci} 1541bf215546Sopenharmony_ci 1542bf215546Sopenharmony_cistatic void 1543bf215546Sopenharmony_ciprint_load_store_word(disassemble_context *ctx, FILE *fp, uint32_t *word, bool verbose) 1544bf215546Sopenharmony_ci{ 1545bf215546Sopenharmony_ci midgard_load_store *load_store = (midgard_load_store *) word; 1546bf215546Sopenharmony_ci 1547bf215546Sopenharmony_ci if (load_store->word1 != 3) { 1548bf215546Sopenharmony_ci print_load_store_instr(ctx, fp, load_store->word1, verbose); 1549bf215546Sopenharmony_ci } 1550bf215546Sopenharmony_ci 1551bf215546Sopenharmony_ci if (load_store->word2 != 3) { 1552bf215546Sopenharmony_ci print_load_store_instr(ctx, fp, load_store->word2, verbose); 1553bf215546Sopenharmony_ci } 1554bf215546Sopenharmony_ci} 1555bf215546Sopenharmony_ci 1556bf215546Sopenharmony_cistatic void 1557bf215546Sopenharmony_ciprint_texture_reg_select(FILE *fp, uint8_t u, unsigned base) 1558bf215546Sopenharmony_ci{ 1559bf215546Sopenharmony_ci midgard_tex_register_select sel; 1560bf215546Sopenharmony_ci memcpy(&sel, &u, sizeof(u)); 1561bf215546Sopenharmony_ci 1562bf215546Sopenharmony_ci print_tex_reg(fp, base + sel.select, false); 1563bf215546Sopenharmony_ci 1564bf215546Sopenharmony_ci unsigned component = sel.component; 1565bf215546Sopenharmony_ci 1566bf215546Sopenharmony_ci /* Use the upper half in half-reg mode */ 1567bf215546Sopenharmony_ci if (sel.upper) { 1568bf215546Sopenharmony_ci assert(!sel.full); 1569bf215546Sopenharmony_ci component += 4; 1570bf215546Sopenharmony_ci } 1571bf215546Sopenharmony_ci 1572bf215546Sopenharmony_ci fprintf(fp, ".%c.%d", components[component], sel.full ? 32 : 16); 1573bf215546Sopenharmony_ci 1574bf215546Sopenharmony_ci assert(sel.zero == 0); 1575bf215546Sopenharmony_ci} 1576bf215546Sopenharmony_ci 1577bf215546Sopenharmony_cistatic void 1578bf215546Sopenharmony_ciprint_texture_format(FILE *fp, int format) 1579bf215546Sopenharmony_ci{ 1580bf215546Sopenharmony_ci /* Act like a modifier */ 1581bf215546Sopenharmony_ci fprintf(fp, "."); 1582bf215546Sopenharmony_ci 1583bf215546Sopenharmony_ci switch (format) { 1584bf215546Sopenharmony_ci DEFINE_CASE(1, "1d"); 1585bf215546Sopenharmony_ci DEFINE_CASE(2, "2d"); 1586bf215546Sopenharmony_ci DEFINE_CASE(3, "3d"); 1587bf215546Sopenharmony_ci DEFINE_CASE(0, "cube"); 1588bf215546Sopenharmony_ci 1589bf215546Sopenharmony_ci default: 1590bf215546Sopenharmony_ci unreachable("Bad format"); 1591bf215546Sopenharmony_ci } 1592bf215546Sopenharmony_ci} 1593bf215546Sopenharmony_ci 1594bf215546Sopenharmony_cistatic bool 1595bf215546Sopenharmony_cimidgard_op_has_helpers(unsigned op) 1596bf215546Sopenharmony_ci{ 1597bf215546Sopenharmony_ci switch (op) { 1598bf215546Sopenharmony_ci case midgard_tex_op_normal: 1599bf215546Sopenharmony_ci case midgard_tex_op_derivative: 1600bf215546Sopenharmony_ci return true; 1601bf215546Sopenharmony_ci default: 1602bf215546Sopenharmony_ci return false; 1603bf215546Sopenharmony_ci } 1604bf215546Sopenharmony_ci} 1605bf215546Sopenharmony_ci 1606bf215546Sopenharmony_cistatic void 1607bf215546Sopenharmony_ciprint_texture_op(FILE *fp, unsigned op) 1608bf215546Sopenharmony_ci{ 1609bf215546Sopenharmony_ci if (tex_opcode_props[op].name) 1610bf215546Sopenharmony_ci fprintf(fp, "%s", tex_opcode_props[op].name); 1611bf215546Sopenharmony_ci else 1612bf215546Sopenharmony_ci fprintf(fp, "tex_op_%02X", op); 1613bf215546Sopenharmony_ci} 1614bf215546Sopenharmony_ci 1615bf215546Sopenharmony_cistatic bool 1616bf215546Sopenharmony_citexture_op_takes_bias(unsigned op) 1617bf215546Sopenharmony_ci{ 1618bf215546Sopenharmony_ci return op == midgard_tex_op_normal; 1619bf215546Sopenharmony_ci} 1620bf215546Sopenharmony_ci 1621bf215546Sopenharmony_cistatic char 1622bf215546Sopenharmony_cisampler_type_name(enum mali_sampler_type t) 1623bf215546Sopenharmony_ci{ 1624bf215546Sopenharmony_ci switch (t) { 1625bf215546Sopenharmony_ci case MALI_SAMPLER_FLOAT: 1626bf215546Sopenharmony_ci return 'f'; 1627bf215546Sopenharmony_ci case MALI_SAMPLER_UNSIGNED: 1628bf215546Sopenharmony_ci return 'u'; 1629bf215546Sopenharmony_ci case MALI_SAMPLER_SIGNED: 1630bf215546Sopenharmony_ci return 'i'; 1631bf215546Sopenharmony_ci default: 1632bf215546Sopenharmony_ci return '?'; 1633bf215546Sopenharmony_ci } 1634bf215546Sopenharmony_ci 1635bf215546Sopenharmony_ci} 1636bf215546Sopenharmony_ci 1637bf215546Sopenharmony_cistatic void 1638bf215546Sopenharmony_ciprint_texture_barrier(FILE *fp, uint32_t *word) 1639bf215546Sopenharmony_ci{ 1640bf215546Sopenharmony_ci midgard_texture_barrier_word *barrier = (midgard_texture_barrier_word *) word; 1641bf215546Sopenharmony_ci 1642bf215546Sopenharmony_ci if (barrier->type != TAG_TEXTURE_4_BARRIER) 1643bf215546Sopenharmony_ci fprintf(fp, "/* barrier tag %X != tex/bar */ ", barrier->type); 1644bf215546Sopenharmony_ci 1645bf215546Sopenharmony_ci if (!barrier->cont) 1646bf215546Sopenharmony_ci fprintf(fp, "/* cont missing? */"); 1647bf215546Sopenharmony_ci 1648bf215546Sopenharmony_ci if (!barrier->last) 1649bf215546Sopenharmony_ci fprintf(fp, "/* last missing? */"); 1650bf215546Sopenharmony_ci 1651bf215546Sopenharmony_ci if (barrier->zero1) 1652bf215546Sopenharmony_ci fprintf(fp, "/* zero1 = 0x%X */ ", barrier->zero1); 1653bf215546Sopenharmony_ci 1654bf215546Sopenharmony_ci if (barrier->zero2) 1655bf215546Sopenharmony_ci fprintf(fp, "/* zero2 = 0x%X */ ", barrier->zero2); 1656bf215546Sopenharmony_ci 1657bf215546Sopenharmony_ci if (barrier->zero3) 1658bf215546Sopenharmony_ci fprintf(fp, "/* zero3 = 0x%X */ ", barrier->zero3); 1659bf215546Sopenharmony_ci 1660bf215546Sopenharmony_ci if (barrier->zero4) 1661bf215546Sopenharmony_ci fprintf(fp, "/* zero4 = 0x%X */ ", barrier->zero4); 1662bf215546Sopenharmony_ci 1663bf215546Sopenharmony_ci if (barrier->zero5) 1664bf215546Sopenharmony_ci fprintf(fp, "/* zero4 = 0x%" PRIx64 " */ ", barrier->zero5); 1665bf215546Sopenharmony_ci 1666bf215546Sopenharmony_ci if (barrier->out_of_order) 1667bf215546Sopenharmony_ci fprintf(fp, ".ooo%u", barrier->out_of_order); 1668bf215546Sopenharmony_ci 1669bf215546Sopenharmony_ci fprintf(fp, "\n"); 1670bf215546Sopenharmony_ci} 1671bf215546Sopenharmony_ci 1672bf215546Sopenharmony_ci#undef DEFINE_CASE 1673bf215546Sopenharmony_ci 1674bf215546Sopenharmony_cistatic const char * 1675bf215546Sopenharmony_citexture_mode(enum mali_texture_mode mode) 1676bf215546Sopenharmony_ci{ 1677bf215546Sopenharmony_ci switch (mode) { 1678bf215546Sopenharmony_ci case TEXTURE_NORMAL: return ""; 1679bf215546Sopenharmony_ci case TEXTURE_SHADOW: return ".shadow"; 1680bf215546Sopenharmony_ci case TEXTURE_GATHER_SHADOW: return ".gather.shadow"; 1681bf215546Sopenharmony_ci case TEXTURE_GATHER_X: return ".gatherX"; 1682bf215546Sopenharmony_ci case TEXTURE_GATHER_Y: return ".gatherY"; 1683bf215546Sopenharmony_ci case TEXTURE_GATHER_Z: return ".gatherZ"; 1684bf215546Sopenharmony_ci case TEXTURE_GATHER_W: return ".gatherW"; 1685bf215546Sopenharmony_ci default: return "unk"; 1686bf215546Sopenharmony_ci } 1687bf215546Sopenharmony_ci} 1688bf215546Sopenharmony_ci 1689bf215546Sopenharmony_cistatic const char * 1690bf215546Sopenharmony_ciderivative_mode(enum mali_derivative_mode mode) 1691bf215546Sopenharmony_ci{ 1692bf215546Sopenharmony_ci switch (mode) { 1693bf215546Sopenharmony_ci case TEXTURE_DFDX: return ".x"; 1694bf215546Sopenharmony_ci case TEXTURE_DFDY: return ".y"; 1695bf215546Sopenharmony_ci default: return "unk"; 1696bf215546Sopenharmony_ci } 1697bf215546Sopenharmony_ci} 1698bf215546Sopenharmony_ci 1699bf215546Sopenharmony_cistatic const char * 1700bf215546Sopenharmony_cipartial_exection_mode(enum midgard_partial_execution mode) 1701bf215546Sopenharmony_ci{ 1702bf215546Sopenharmony_ci switch (mode) { 1703bf215546Sopenharmony_ci case MIDGARD_PARTIAL_EXECUTION_NONE: return ""; 1704bf215546Sopenharmony_ci case MIDGARD_PARTIAL_EXECUTION_SKIP: return ".skip"; 1705bf215546Sopenharmony_ci case MIDGARD_PARTIAL_EXECUTION_KILL: return ".kill"; 1706bf215546Sopenharmony_ci default: return ".reserved"; 1707bf215546Sopenharmony_ci } 1708bf215546Sopenharmony_ci} 1709bf215546Sopenharmony_ci 1710bf215546Sopenharmony_cistatic void 1711bf215546Sopenharmony_ciprint_texture_word(disassemble_context *ctx, FILE *fp, uint32_t *word, 1712bf215546Sopenharmony_ci unsigned tabs, unsigned in_reg_base, unsigned out_reg_base) 1713bf215546Sopenharmony_ci{ 1714bf215546Sopenharmony_ci midgard_texture_word *texture = (midgard_texture_word *) word; 1715bf215546Sopenharmony_ci ctx->midg_stats.helper_invocations |= midgard_op_has_helpers(texture->op); 1716bf215546Sopenharmony_ci validate_sampler_type(texture->op, texture->sampler_type); 1717bf215546Sopenharmony_ci 1718bf215546Sopenharmony_ci /* Broad category of texture operation in question */ 1719bf215546Sopenharmony_ci print_texture_op(fp, texture->op); 1720bf215546Sopenharmony_ci 1721bf215546Sopenharmony_ci /* Barriers use a dramatically different code path */ 1722bf215546Sopenharmony_ci if (texture->op == midgard_tex_op_barrier) { 1723bf215546Sopenharmony_ci print_texture_barrier(fp, word); 1724bf215546Sopenharmony_ci return; 1725bf215546Sopenharmony_ci } else if (texture->type == TAG_TEXTURE_4_BARRIER) 1726bf215546Sopenharmony_ci fprintf (fp, "/* nonbarrier had tex/bar tag */ "); 1727bf215546Sopenharmony_ci else if (texture->type == TAG_TEXTURE_4_VTX) 1728bf215546Sopenharmony_ci fprintf (fp, ".vtx"); 1729bf215546Sopenharmony_ci 1730bf215546Sopenharmony_ci if (texture->op == midgard_tex_op_derivative) 1731bf215546Sopenharmony_ci fprintf(fp, "%s", derivative_mode(texture->mode)); 1732bf215546Sopenharmony_ci else 1733bf215546Sopenharmony_ci fprintf(fp, "%s", texture_mode(texture->mode)); 1734bf215546Sopenharmony_ci 1735bf215546Sopenharmony_ci /* Specific format in question */ 1736bf215546Sopenharmony_ci print_texture_format(fp, texture->format); 1737bf215546Sopenharmony_ci 1738bf215546Sopenharmony_ci /* Instruction "modifiers" parallel the ALU instructions. */ 1739bf215546Sopenharmony_ci fputs(partial_exection_mode(texture->exec), fp); 1740bf215546Sopenharmony_ci 1741bf215546Sopenharmony_ci if (texture->out_of_order) 1742bf215546Sopenharmony_ci fprintf(fp, ".ooo%u", texture->out_of_order); 1743bf215546Sopenharmony_ci 1744bf215546Sopenharmony_ci fprintf(fp, " "); 1745bf215546Sopenharmony_ci print_tex_reg(fp, out_reg_base + texture->out_reg_select, true); 1746bf215546Sopenharmony_ci print_tex_mask(fp, texture->mask, texture->out_upper); 1747bf215546Sopenharmony_ci fprintf(fp, ".%c%d", texture->sampler_type == MALI_SAMPLER_FLOAT ? 'f' : 'i', 1748bf215546Sopenharmony_ci texture->out_full ? 32 : 16); 1749bf215546Sopenharmony_ci assert(!(texture->out_full && texture->out_upper)); 1750bf215546Sopenharmony_ci 1751bf215546Sopenharmony_ci /* Output modifiers are only valid for float texture operations */ 1752bf215546Sopenharmony_ci if (texture->sampler_type == MALI_SAMPLER_FLOAT) 1753bf215546Sopenharmony_ci mir_print_outmod(fp, texture->outmod, false); 1754bf215546Sopenharmony_ci 1755bf215546Sopenharmony_ci fprintf(fp, ", "); 1756bf215546Sopenharmony_ci 1757bf215546Sopenharmony_ci /* Depending on whether we read from textures directly or indirectly, 1758bf215546Sopenharmony_ci * we may be able to update our analysis */ 1759bf215546Sopenharmony_ci 1760bf215546Sopenharmony_ci if (texture->texture_register) { 1761bf215546Sopenharmony_ci fprintf(fp, "texture["); 1762bf215546Sopenharmony_ci print_texture_reg_select(fp, texture->texture_handle, in_reg_base); 1763bf215546Sopenharmony_ci fprintf(fp, "], "); 1764bf215546Sopenharmony_ci 1765bf215546Sopenharmony_ci /* Indirect, tut tut */ 1766bf215546Sopenharmony_ci ctx->midg_stats.texture_count = -16; 1767bf215546Sopenharmony_ci } else { 1768bf215546Sopenharmony_ci fprintf(fp, "texture%u, ", texture->texture_handle); 1769bf215546Sopenharmony_ci update_stats(&ctx->midg_stats.texture_count, texture->texture_handle); 1770bf215546Sopenharmony_ci } 1771bf215546Sopenharmony_ci 1772bf215546Sopenharmony_ci /* Print the type, GL style */ 1773bf215546Sopenharmony_ci fprintf(fp, "%csampler", sampler_type_name(texture->sampler_type)); 1774bf215546Sopenharmony_ci 1775bf215546Sopenharmony_ci if (texture->sampler_register) { 1776bf215546Sopenharmony_ci fprintf(fp, "["); 1777bf215546Sopenharmony_ci print_texture_reg_select(fp, texture->sampler_handle, in_reg_base); 1778bf215546Sopenharmony_ci fprintf(fp, "]"); 1779bf215546Sopenharmony_ci 1780bf215546Sopenharmony_ci ctx->midg_stats.sampler_count = -16; 1781bf215546Sopenharmony_ci } else { 1782bf215546Sopenharmony_ci fprintf(fp, "%u", texture->sampler_handle); 1783bf215546Sopenharmony_ci update_stats(&ctx->midg_stats.sampler_count, texture->sampler_handle); 1784bf215546Sopenharmony_ci } 1785bf215546Sopenharmony_ci 1786bf215546Sopenharmony_ci print_vec_swizzle(fp, texture->swizzle, midgard_src_passthrough, midgard_reg_mode_32, 0xFF); 1787bf215546Sopenharmony_ci 1788bf215546Sopenharmony_ci fprintf(fp, ", "); 1789bf215546Sopenharmony_ci 1790bf215546Sopenharmony_ci midgard_src_expand_mode exp = 1791bf215546Sopenharmony_ci texture->in_reg_upper ? midgard_src_expand_high : midgard_src_passthrough; 1792bf215546Sopenharmony_ci print_tex_reg(fp, in_reg_base + texture->in_reg_select, false); 1793bf215546Sopenharmony_ci print_vec_swizzle(fp, texture->in_reg_swizzle, exp, midgard_reg_mode_32, 0xFF); 1794bf215546Sopenharmony_ci fprintf(fp, ".%d", texture->in_reg_full ? 32 : 16); 1795bf215546Sopenharmony_ci assert(!(texture->in_reg_full && texture->in_reg_upper)); 1796bf215546Sopenharmony_ci 1797bf215546Sopenharmony_ci /* There is *always* an offset attached. Of 1798bf215546Sopenharmony_ci * course, that offset is just immediate #0 for a 1799bf215546Sopenharmony_ci * GLES call that doesn't take an offset. If there 1800bf215546Sopenharmony_ci * is a non-negative non-zero offset, this is 1801bf215546Sopenharmony_ci * specified in immediate offset mode, with the 1802bf215546Sopenharmony_ci * values in the offset_* fields as immediates. If 1803bf215546Sopenharmony_ci * this is a negative offset, we instead switch to 1804bf215546Sopenharmony_ci * a register offset mode, where the offset_* 1805bf215546Sopenharmony_ci * fields become register triplets */ 1806bf215546Sopenharmony_ci 1807bf215546Sopenharmony_ci if (texture->offset_register) { 1808bf215546Sopenharmony_ci fprintf(fp, " + "); 1809bf215546Sopenharmony_ci 1810bf215546Sopenharmony_ci bool full = texture->offset & 1; 1811bf215546Sopenharmony_ci bool select = texture->offset & 2; 1812bf215546Sopenharmony_ci bool upper = texture->offset & 4; 1813bf215546Sopenharmony_ci unsigned swizzle = texture->offset >> 3; 1814bf215546Sopenharmony_ci midgard_src_expand_mode exp = 1815bf215546Sopenharmony_ci upper ? midgard_src_expand_high : midgard_src_passthrough; 1816bf215546Sopenharmony_ci 1817bf215546Sopenharmony_ci print_tex_reg(fp, in_reg_base + select, false); 1818bf215546Sopenharmony_ci print_vec_swizzle(fp, swizzle, exp, midgard_reg_mode_32, 0xFF); 1819bf215546Sopenharmony_ci fprintf(fp, ".%d", full ? 32 : 16); 1820bf215546Sopenharmony_ci assert(!(texture->out_full && texture->out_upper)); 1821bf215546Sopenharmony_ci 1822bf215546Sopenharmony_ci fprintf(fp, ", "); 1823bf215546Sopenharmony_ci } else if (texture->offset) { 1824bf215546Sopenharmony_ci /* Only select ops allow negative immediate offsets, verify */ 1825bf215546Sopenharmony_ci 1826bf215546Sopenharmony_ci signed offset_x = (texture->offset & 0xF); 1827bf215546Sopenharmony_ci signed offset_y = ((texture->offset >> 4) & 0xF); 1828bf215546Sopenharmony_ci signed offset_z = ((texture->offset >> 8) & 0xF); 1829bf215546Sopenharmony_ci 1830bf215546Sopenharmony_ci bool neg_x = offset_x < 0; 1831bf215546Sopenharmony_ci bool neg_y = offset_y < 0; 1832bf215546Sopenharmony_ci bool neg_z = offset_z < 0; 1833bf215546Sopenharmony_ci bool any_neg = neg_x || neg_y || neg_z; 1834bf215546Sopenharmony_ci 1835bf215546Sopenharmony_ci if (any_neg && texture->op != midgard_tex_op_fetch) 1836bf215546Sopenharmony_ci fprintf(fp, "/* invalid negative */ "); 1837bf215546Sopenharmony_ci 1838bf215546Sopenharmony_ci /* Regardless, just print the immediate offset */ 1839bf215546Sopenharmony_ci 1840bf215546Sopenharmony_ci fprintf(fp, " + <%d, %d, %d>, ", offset_x, offset_y, offset_z); 1841bf215546Sopenharmony_ci } else { 1842bf215546Sopenharmony_ci fprintf(fp, ", "); 1843bf215546Sopenharmony_ci } 1844bf215546Sopenharmony_ci 1845bf215546Sopenharmony_ci char lod_operand = texture_op_takes_bias(texture->op) ? '+' : '='; 1846bf215546Sopenharmony_ci 1847bf215546Sopenharmony_ci if (texture->lod_register) { 1848bf215546Sopenharmony_ci fprintf(fp, "lod %c ", lod_operand); 1849bf215546Sopenharmony_ci print_texture_reg_select(fp, texture->bias, in_reg_base); 1850bf215546Sopenharmony_ci fprintf(fp, ", "); 1851bf215546Sopenharmony_ci 1852bf215546Sopenharmony_ci if (texture->bias_int) 1853bf215546Sopenharmony_ci fprintf(fp, " /* bias_int = 0x%X */", texture->bias_int); 1854bf215546Sopenharmony_ci } else if (texture->op == midgard_tex_op_fetch) { 1855bf215546Sopenharmony_ci /* For texel fetch, the int LOD is in the fractional place and 1856bf215546Sopenharmony_ci * there is no fraction. We *always* have an explicit LOD, even 1857bf215546Sopenharmony_ci * if it's zero. */ 1858bf215546Sopenharmony_ci 1859bf215546Sopenharmony_ci if (texture->bias_int) 1860bf215546Sopenharmony_ci fprintf(fp, " /* bias_int = 0x%X */ ", texture->bias_int); 1861bf215546Sopenharmony_ci 1862bf215546Sopenharmony_ci fprintf(fp, "lod = %u, ", texture->bias); 1863bf215546Sopenharmony_ci } else if (texture->bias || texture->bias_int) { 1864bf215546Sopenharmony_ci signed bias_int = texture->bias_int; 1865bf215546Sopenharmony_ci float bias_frac = texture->bias / 256.0f; 1866bf215546Sopenharmony_ci float bias = bias_int + bias_frac; 1867bf215546Sopenharmony_ci 1868bf215546Sopenharmony_ci bool is_bias = texture_op_takes_bias(texture->op); 1869bf215546Sopenharmony_ci char sign = (bias >= 0.0) ? '+' : '-'; 1870bf215546Sopenharmony_ci char operand = is_bias ? sign : '='; 1871bf215546Sopenharmony_ci 1872bf215546Sopenharmony_ci fprintf(fp, "lod %c %f, ", operand, fabsf(bias)); 1873bf215546Sopenharmony_ci } 1874bf215546Sopenharmony_ci 1875bf215546Sopenharmony_ci fprintf(fp, "\n"); 1876bf215546Sopenharmony_ci 1877bf215546Sopenharmony_ci /* While not zero in general, for these simple instructions the 1878bf215546Sopenharmony_ci * following unknowns are zero, so we don't include them */ 1879bf215546Sopenharmony_ci 1880bf215546Sopenharmony_ci if (texture->unknown4 || 1881bf215546Sopenharmony_ci texture->unknown8) { 1882bf215546Sopenharmony_ci fprintf(fp, "// unknown4 = 0x%x\n", texture->unknown4); 1883bf215546Sopenharmony_ci fprintf(fp, "// unknown8 = 0x%x\n", texture->unknown8); 1884bf215546Sopenharmony_ci } 1885bf215546Sopenharmony_ci 1886bf215546Sopenharmony_ci ctx->midg_stats.instruction_count++; 1887bf215546Sopenharmony_ci} 1888bf215546Sopenharmony_ci 1889bf215546Sopenharmony_cistruct midgard_disasm_stats 1890bf215546Sopenharmony_cidisassemble_midgard(FILE *fp, uint8_t *code, size_t size, unsigned gpu_id, bool verbose) 1891bf215546Sopenharmony_ci{ 1892bf215546Sopenharmony_ci uint32_t *words = (uint32_t *) code; 1893bf215546Sopenharmony_ci unsigned num_words = size / 4; 1894bf215546Sopenharmony_ci int tabs = 0; 1895bf215546Sopenharmony_ci 1896bf215546Sopenharmony_ci bool branch_forward = false; 1897bf215546Sopenharmony_ci 1898bf215546Sopenharmony_ci int last_next_tag = -1; 1899bf215546Sopenharmony_ci 1900bf215546Sopenharmony_ci unsigned i = 0; 1901bf215546Sopenharmony_ci 1902bf215546Sopenharmony_ci disassemble_context ctx = { 1903bf215546Sopenharmony_ci .midg_tags = calloc(sizeof(ctx.midg_tags[0]), num_words), 1904bf215546Sopenharmony_ci .midg_stats = {0}, 1905bf215546Sopenharmony_ci .midg_ever_written = 0, 1906bf215546Sopenharmony_ci }; 1907bf215546Sopenharmony_ci 1908bf215546Sopenharmony_ci while (i < num_words) { 1909bf215546Sopenharmony_ci unsigned tag = words[i] & 0xF; 1910bf215546Sopenharmony_ci unsigned next_tag = (words[i] >> 4) & 0xF; 1911bf215546Sopenharmony_ci unsigned num_quad_words = midgard_tag_props[tag].size; 1912bf215546Sopenharmony_ci 1913bf215546Sopenharmony_ci if (ctx.midg_tags[i] && ctx.midg_tags[i] != tag) { 1914bf215546Sopenharmony_ci fprintf(fp, "\t/* XXX: TAG ERROR branch, got %s expected %s */\n", 1915bf215546Sopenharmony_ci midgard_tag_props[tag].name, 1916bf215546Sopenharmony_ci midgard_tag_props[ctx.midg_tags[i]].name); 1917bf215546Sopenharmony_ci } 1918bf215546Sopenharmony_ci 1919bf215546Sopenharmony_ci ctx.midg_tags[i] = tag; 1920bf215546Sopenharmony_ci 1921bf215546Sopenharmony_ci /* Check the tag. The idea is to ensure that next_tag is 1922bf215546Sopenharmony_ci * *always* recoverable from the disassembly, such that we may 1923bf215546Sopenharmony_ci * safely omit printing next_tag. To show this, we first 1924bf215546Sopenharmony_ci * consider that next tags are semantically off-byone -- we end 1925bf215546Sopenharmony_ci * up parsing tag n during step n+1. So, we ensure after we're 1926bf215546Sopenharmony_ci * done disassembling the next tag of the final bundle is BREAK 1927bf215546Sopenharmony_ci * and warn otherwise. We also ensure that the next tag is 1928bf215546Sopenharmony_ci * never INVALID. Beyond that, since the last tag is checked 1929bf215546Sopenharmony_ci * outside the loop, we can check one tag prior. If equal to 1930bf215546Sopenharmony_ci * the current tag (which is unique), we're done. Otherwise, we 1931bf215546Sopenharmony_ci * print if that tag was > TAG_BREAK, which implies the tag was 1932bf215546Sopenharmony_ci * not TAG_BREAK or TAG_INVALID. But we already checked for 1933bf215546Sopenharmony_ci * TAG_INVALID, so it's just if the last tag was TAG_BREAK that 1934bf215546Sopenharmony_ci * we're silent. So we throw in a print for break-next on at 1935bf215546Sopenharmony_ci * the end of the bundle (if it's not the final bundle, which 1936bf215546Sopenharmony_ci * we already check for above), disambiguating this case as 1937bf215546Sopenharmony_ci * well. Hence in all cases we are unambiguous, QED. */ 1938bf215546Sopenharmony_ci 1939bf215546Sopenharmony_ci if (next_tag == TAG_INVALID) 1940bf215546Sopenharmony_ci fprintf(fp, "\t/* XXX: invalid next tag */\n"); 1941bf215546Sopenharmony_ci 1942bf215546Sopenharmony_ci if (last_next_tag > TAG_BREAK && last_next_tag != tag) { 1943bf215546Sopenharmony_ci fprintf(fp, "\t/* XXX: TAG ERROR sequence, got %s expexted %s */\n", 1944bf215546Sopenharmony_ci midgard_tag_props[tag].name, 1945bf215546Sopenharmony_ci midgard_tag_props[last_next_tag].name); 1946bf215546Sopenharmony_ci } 1947bf215546Sopenharmony_ci 1948bf215546Sopenharmony_ci last_next_tag = next_tag; 1949bf215546Sopenharmony_ci 1950bf215546Sopenharmony_ci /* Tags are unique in the following way: 1951bf215546Sopenharmony_ci * 1952bf215546Sopenharmony_ci * INVALID, BREAK, UNKNOWN_*: verbosely printed 1953bf215546Sopenharmony_ci * TEXTURE_4_BARRIER: verified by barrier/!barrier op 1954bf215546Sopenharmony_ci * TEXTURE_4_VTX: .vtx tag printed 1955bf215546Sopenharmony_ci * TEXTURE_4: tetxure lack of barriers or .vtx 1956bf215546Sopenharmony_ci * TAG_LOAD_STORE_4: only load/store 1957bf215546Sopenharmony_ci * TAG_ALU_4/8/12/16: by number of instructions/constants 1958bf215546Sopenharmony_ci * TAG_ALU_4_8/12/16_WRITEOUT: ^^ with .writeout tag 1959bf215546Sopenharmony_ci */ 1960bf215546Sopenharmony_ci 1961bf215546Sopenharmony_ci switch (tag) { 1962bf215546Sopenharmony_ci case TAG_TEXTURE_4_VTX ... TAG_TEXTURE_4_BARRIER: { 1963bf215546Sopenharmony_ci bool interpipe_aliasing = 1964bf215546Sopenharmony_ci midgard_get_quirks(gpu_id) & MIDGARD_INTERPIPE_REG_ALIASING; 1965bf215546Sopenharmony_ci 1966bf215546Sopenharmony_ci print_texture_word(&ctx, fp, &words[i], tabs, 1967bf215546Sopenharmony_ci interpipe_aliasing ? 0 : REG_TEX_BASE, 1968bf215546Sopenharmony_ci interpipe_aliasing ? REGISTER_LDST_BASE : REG_TEX_BASE); 1969bf215546Sopenharmony_ci break; 1970bf215546Sopenharmony_ci } 1971bf215546Sopenharmony_ci 1972bf215546Sopenharmony_ci case TAG_LOAD_STORE_4: 1973bf215546Sopenharmony_ci print_load_store_word(&ctx, fp, &words[i], verbose); 1974bf215546Sopenharmony_ci break; 1975bf215546Sopenharmony_ci 1976bf215546Sopenharmony_ci case TAG_ALU_4 ... TAG_ALU_16_WRITEOUT: 1977bf215546Sopenharmony_ci branch_forward = print_alu_word(&ctx, fp, &words[i], num_quad_words, tabs, i + 4*num_quad_words, verbose); 1978bf215546Sopenharmony_ci 1979bf215546Sopenharmony_ci /* TODO: infer/verify me */ 1980bf215546Sopenharmony_ci if (tag >= TAG_ALU_4_WRITEOUT) 1981bf215546Sopenharmony_ci fprintf(fp, "writeout\n"); 1982bf215546Sopenharmony_ci 1983bf215546Sopenharmony_ci break; 1984bf215546Sopenharmony_ci 1985bf215546Sopenharmony_ci default: 1986bf215546Sopenharmony_ci fprintf(fp, "Unknown word type %u:\n", words[i] & 0xF); 1987bf215546Sopenharmony_ci num_quad_words = 1; 1988bf215546Sopenharmony_ci print_quad_word(fp, &words[i], tabs); 1989bf215546Sopenharmony_ci fprintf(fp, "\n"); 1990bf215546Sopenharmony_ci break; 1991bf215546Sopenharmony_ci } 1992bf215546Sopenharmony_ci 1993bf215546Sopenharmony_ci /* We are parsing per bundle anyway. Add before we start 1994bf215546Sopenharmony_ci * breaking out so we don't miss the final bundle. */ 1995bf215546Sopenharmony_ci 1996bf215546Sopenharmony_ci ctx.midg_stats.bundle_count++; 1997bf215546Sopenharmony_ci ctx.midg_stats.quadword_count += num_quad_words; 1998bf215546Sopenharmony_ci 1999bf215546Sopenharmony_ci /* Include a synthetic "break" instruction at the end of the 2000bf215546Sopenharmony_ci * bundle to signify that if, absent a branch, the shader 2001bf215546Sopenharmony_ci * execution will stop here. Stop disassembly at such a break 2002bf215546Sopenharmony_ci * based on a heuristic */ 2003bf215546Sopenharmony_ci 2004bf215546Sopenharmony_ci if (next_tag == TAG_BREAK) { 2005bf215546Sopenharmony_ci if (branch_forward) { 2006bf215546Sopenharmony_ci fprintf(fp, "break\n"); 2007bf215546Sopenharmony_ci } else { 2008bf215546Sopenharmony_ci fprintf(fp, "\n"); 2009bf215546Sopenharmony_ci break; 2010bf215546Sopenharmony_ci } 2011bf215546Sopenharmony_ci } 2012bf215546Sopenharmony_ci 2013bf215546Sopenharmony_ci fprintf(fp, "\n"); 2014bf215546Sopenharmony_ci 2015bf215546Sopenharmony_ci i += 4 * num_quad_words; 2016bf215546Sopenharmony_ci } 2017bf215546Sopenharmony_ci 2018bf215546Sopenharmony_ci if (last_next_tag != TAG_BREAK) { 2019bf215546Sopenharmony_ci fprintf(fp, "/* XXX: shader ended with tag %s */\n", 2020bf215546Sopenharmony_ci midgard_tag_props[last_next_tag].name); 2021bf215546Sopenharmony_ci } 2022bf215546Sopenharmony_ci 2023bf215546Sopenharmony_ci free(ctx.midg_tags); 2024bf215546Sopenharmony_ci 2025bf215546Sopenharmony_ci /* We computed work_count as max_work_registers, so add one to get the 2026bf215546Sopenharmony_ci * count. If no work registers are written, you still have one work 2027bf215546Sopenharmony_ci * reported, which is exactly what the hardware expects */ 2028bf215546Sopenharmony_ci 2029bf215546Sopenharmony_ci ctx.midg_stats.work_count++; 2030bf215546Sopenharmony_ci 2031bf215546Sopenharmony_ci return ctx.midg_stats; 2032bf215546Sopenharmony_ci} 2033