diff options
author | Alyssa Rosenzweig <[email protected]> | 2019-01-30 01:11:31 +0000 |
---|---|---|
committer | Alyssa Rosenzweig <[email protected]> | 2019-02-05 01:26:28 +0000 |
commit | e67e0726372ab65f410411e607701be4673ff6ef (patch) | |
tree | 039d895a9740c272b45aafd3e0c87914ca733262 /src/gallium/drivers/panfrost/midgard/disassemble.c | |
parent | 61d3ae6e0bde93c5601278d1a60c44be655a7cb5 (diff) |
panfrost: Implement Midgard shader toolchain
This patch implements the free Midgard shader toolchain: the assembler,
the disassembler, and the NIR-based compiler. The assembler is a
standalone inaccessible Python script for reference purposes. The
disassembler and the compiler are implemented in C, accessible via the
standalone `midgard_compiler` binary. Later patches will use these
interfaces from the driver for online compilation.
Signed-off-by: Alyssa Rosenzweig <[email protected]>
Acked-by: Jason Ekstrand <[email protected]>
Acked-by: Rob Clark <[email protected]>
Acked-by: Eric Anholt <[email protected]>
Acked-by: Emil Velikov <[email protected]>
Diffstat (limited to 'src/gallium/drivers/panfrost/midgard/disassemble.c')
-rw-r--r-- | src/gallium/drivers/panfrost/midgard/disassemble.c | 986 |
1 files changed, 986 insertions, 0 deletions
diff --git a/src/gallium/drivers/panfrost/midgard/disassemble.c b/src/gallium/drivers/panfrost/midgard/disassemble.c new file mode 100644 index 00000000000..afde3fdbbcd --- /dev/null +++ b/src/gallium/drivers/panfrost/midgard/disassemble.c @@ -0,0 +1,986 @@ +/* Author(s): + * Connor Abbott + * Alyssa Rosenzweig + * + * Copyright (c) 2013 Connor Abbott ([email protected]) + * Copyright (c) 2018 Alyssa Rosenzweig ([email protected]) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <stdio.h> +#include <stdint.h> +#include <assert.h> +#include <inttypes.h> +#include <string.h> +#include "midgard.h" +#include "midgard-parse.h" +#include "disassemble.h" +#include "util/half_float.h" + +#define DEFINE_CASE(define, str) case define: { printf(str); break; } + +static bool is_instruction_int = false; + +static void +print_alu_opcode(midgard_alu_op op) +{ + bool int_op = false; + + if (alu_opcode_names[op]) { + printf("%s", alu_opcode_names[op]); + + int_op = alu_opcode_names[op][0] == 'i'; + } else + printf("alu_op_%02X", op); + + /* For constant analysis */ + is_instruction_int = int_op; +} + +static void +print_ld_st_opcode(midgard_load_store_op op) +{ + if (load_store_opcode_names[op]) + printf("%s", load_store_opcode_names[op]); + else + printf("ldst_op_%02X", op); +} + +static bool is_embedded_constant_half = false; +static bool is_embedded_constant_int = false; + +static void +print_reg(unsigned reg, bool half) +{ + /* Perform basic static analysis for expanding constants correctly */ + + if (half && (reg >> 1) == 26) { + is_embedded_constant_half = true; + is_embedded_constant_int = is_instruction_int; + } else if (!half && reg == 26) { + is_embedded_constant_int = is_instruction_int; + } + + if (half) + printf("h"); + + printf("r%u", reg); +} + +static char *outmod_names[4] = { + "", + ".pos", + "", + ".sat" +}; + +static void +print_outmod(midgard_outmod outmod) +{ + printf("%s", outmod_names[outmod]); +} + +static void +print_quad_word(uint32_t *words, unsigned tabs) +{ + unsigned i; + + for (i = 0; i < 4; i++) + printf("0x%08X%s ", words[i], i == 3 ? "" : ","); + + printf("\n"); +} + +static void +print_vector_src(unsigned src_binary, bool out_high, + bool out_half, unsigned reg) +{ + midgard_vector_alu_src *src = (midgard_vector_alu_src *)&src_binary; + + if (src->negate) + printf("-"); + + if (src->abs) + printf("abs("); + + //register + + if (out_half) { + if (src->half) + printf(" /* half */ "); + + unsigned half_reg; + + if (out_high) { + if (src->rep_low) + half_reg = reg * 2; + else + half_reg = reg * 2 + 1; + + if (src->rep_high) + printf(" /* rep_high */ "); + } else { + if (src->rep_high) + half_reg = reg * 2 + 1; + else + half_reg = reg * 2; + + if (src->rep_low) + printf(" /* rep_low */ "); + } + + print_reg(half_reg, true); + } else { + if (src->rep_high) + printf(" /* rep_high */ "); + + if (src->half) + print_reg(reg * 2 + src->rep_low, true); + else { + if (src->rep_low) + printf(" /* rep_low */ "); + + print_reg(reg, false); + } + } + + //swizzle + + if (src->swizzle != 0xE4) { //default swizzle + unsigned i; + static const char c[4] = "xyzw"; + + printf("."); + + for (i = 0; i < 4; i++) + printf("%c", c[(src->swizzle >> (i * 2)) & 3]); + } + + if (src->abs) + printf(")"); +} + +static uint16_t +decode_vector_imm(unsigned src2_reg, unsigned imm) +{ + uint16_t ret; + ret = src2_reg << 11; + ret |= (imm & 0x7) << 8; + ret |= (imm >> 3) & 0xFF; + return ret; +} + +static void +print_immediate(uint16_t imm) +{ + if (is_instruction_int) + printf("#%d", imm); + else + printf("#%g", _mesa_half_to_float(imm)); +} + +static void +print_vector_field(const char *name, uint16_t *words, uint16_t reg_word, + unsigned tabs) +{ + midgard_reg_info *reg_info = (midgard_reg_info *)®_word; + midgard_vector_alu *alu_field = (midgard_vector_alu *) words; + + if (alu_field->reg_mode != midgard_reg_mode_half && + alu_field->reg_mode != midgard_reg_mode_full) { + printf("unknown reg mode %u\n", alu_field->reg_mode); + } + + /* For now, prefix instruction names with their unit, until we + * understand how this works on a deeper level */ + printf("%s.", name); + + print_alu_opcode(alu_field->op); + print_outmod(alu_field->outmod); + printf(" "); + + bool half, out_half, out_high = false; + unsigned mask; + + half = (alu_field->reg_mode == midgard_reg_mode_half); + + if (half) { + if (alu_field->mask & 0xF) { + out_high = false; + + if ((alu_field->mask & 0xF0)) + printf("/* %X */ ", alu_field->mask); + + mask = alu_field->mask; + } else { + out_high = true; + mask = alu_field->mask >> 4; + } + } else { + mask = alu_field->mask & 1; + mask |= (alu_field->mask & 4) >> 1; + mask |= (alu_field->mask & 16) >> 2; + mask |= (alu_field->mask & 64) >> 3; + } + + out_half = half; + + if (alu_field->dest_override != midgard_dest_override_none) { + if (out_half) + printf("/* half */ "); + + out_half = true; + + if (alu_field->dest_override == midgard_dest_override_lower) + out_high = false; + else if (alu_field->dest_override == midgard_dest_override_upper) + out_high = true; + else + assert(0); + } + + if (out_half) { + if (out_high) + print_reg(2 * reg_info->out_reg + 1, true); + else + print_reg(2 * reg_info->out_reg, true); + } else + print_reg(reg_info->out_reg, false); + + if (mask != 0xF) { + unsigned i; + static const char c[4] = "xyzw"; + + printf("."); + + for (i = 0; i < 4; i++) + if (mask & (1 << i)) + printf("%c", c[i]); + } + + printf(", "); + + print_vector_src(alu_field->src1, out_high, half, reg_info->src1_reg); + + printf(", "); + + if (reg_info->src2_imm) { + uint16_t imm = decode_vector_imm(reg_info->src2_reg, alu_field->src2 >> 2); + print_immediate(imm); + } else { + print_vector_src(alu_field->src2, out_high, half, + reg_info->src2_reg); + } + + printf("\n"); +} + +static void +print_scalar_src(unsigned src_binary, unsigned reg) +{ + midgard_scalar_alu_src *src = (midgard_scalar_alu_src *)&src_binary; + + if (src->negate) + printf("-"); + + if (src->abs) + printf("abs("); + + if (src->full) + print_reg(reg, false); + else + print_reg(reg * 2 + (src->component >> 2), true); + + static const char c[4] = "xyzw"; + \ + printf(".%c", c[src->full ? src->component >> 1 : src->component & 3]); + + if (src->abs) + printf(")"); + +} + +static uint16_t +decode_scalar_imm(unsigned src2_reg, unsigned imm) +{ + uint16_t ret; + ret = src2_reg << 11; + ret |= (imm & 3) << 9; + ret |= (imm & 4) << 6; + ret |= (imm & 0x38) << 2; + ret |= imm >> 6; + return ret; +} + +static void +print_scalar_field(const char *name, uint16_t *words, uint16_t reg_word, + unsigned tabs) +{ + midgard_reg_info *reg_info = (midgard_reg_info *)®_word; + midgard_scalar_alu *alu_field = (midgard_scalar_alu *) words; + + if (alu_field->unknown) + printf("scalar ALU unknown bit set\n"); + + printf("%s.", name); + print_alu_opcode(alu_field->op); + print_outmod(alu_field->outmod); + printf(" "); + + if (alu_field->output_full) + print_reg(reg_info->out_reg, false); + else + print_reg(reg_info->out_reg * 2 + (alu_field->output_component >> 2), + true); + + static const char c[4] = "xyzw"; + printf(".%c, ", + c[alu_field->output_full ? alu_field->output_component >> 1 : + alu_field->output_component & 3]); + + print_scalar_src(alu_field->src1, reg_info->src1_reg); + + printf(", "); + + if (reg_info->src2_imm) { + uint16_t imm = decode_scalar_imm(reg_info->src2_reg, + alu_field->src2); + print_immediate(imm); + } else + print_scalar_src(alu_field->src2, reg_info->src2_reg); + + printf("\n"); +} + +static void +print_branch_op(int op) +{ + switch (op) { + case midgard_jmp_writeout_op_branch_cond: + printf("cond."); + break; + + case midgard_jmp_writeout_op_writeout: + printf("write."); + break; + + case midgard_jmp_writeout_op_discard: + printf("discard."); + break; + + default: + printf("unk%d.", op); + break; + } +} + +static void +print_branch_cond(int cond) +{ + switch (cond) { + case midgard_condition_write0: + printf("write0"); + break; + + case midgard_condition_false: + printf("false"); + break; + + case midgard_condition_true: + printf("true"); + break; + + case midgard_condition_always: + printf("always"); + break; + + default: + break; + } +} + +static void +print_compact_branch_writeout_field(uint16_t word) +{ + midgard_jmp_writeout_op op = word & 0x7; + + switch (op) { + case midgard_jmp_writeout_op_branch_uncond: { + midgard_branch_uncond br_uncond; + memcpy((char *) &br_uncond, (char *) &word, sizeof(br_uncond)); + printf("br.uncond "); + + if (br_uncond.unknown != 1) + printf("unknown:%d, ", br_uncond.unknown); + + if (br_uncond.offset >= 0) + printf("+"); + + printf("%d", br_uncond.offset); + + printf(" -> %X\n", br_uncond.dest_tag); + break; + } + + case midgard_jmp_writeout_op_branch_cond: + case midgard_jmp_writeout_op_writeout: + case midgard_jmp_writeout_op_discard: + default: { + midgard_branch_cond br_cond; + memcpy((char *) &br_cond, (char *) &word, sizeof(br_cond)); + + printf("br."); + + print_branch_op(br_cond.op); + print_branch_cond(br_cond.cond); + + printf(" "); + + if (br_cond.offset >= 0) + printf("+"); + + printf("%d", br_cond.offset); + + printf(" -> %X\n", br_cond.dest_tag); + break; + } + } +} + +static void +print_extended_branch_writeout_field(uint8_t *words) +{ + midgard_branch_extended br; + memcpy((char *) &br, (char *) words, sizeof(br)); + + printf("br."); + + print_branch_op(br.op); + print_branch_cond(br.cond); + + /* XXX: This can't be right */ + if (br.unknown) + printf(".unknown%d\n", br.unknown); + + if (br.zero) + printf(".zero%d\n", br.zero); + + printf(" "); + + if (br.offset >= 0) + printf("+"); + + printf("%d", br.offset); + + printf(" -> %X\n", br.dest_tag); +} + +static unsigned +num_alu_fields_enabled(uint32_t control_word) +{ + unsigned ret = 0; + + if ((control_word >> 17) & 1) + ret++; + + if ((control_word >> 19) & 1) + ret++; + + if ((control_word >> 21) & 1) + ret++; + + if ((control_word >> 23) & 1) + ret++; + + if ((control_word >> 25) & 1) + ret++; + + return ret; +} + +static float +float_bitcast(uint32_t integer) +{ + union { + uint32_t i; + float f; + } v; + + v.i = integer; + return v.f; +} + +static void +print_alu_word(uint32_t *words, unsigned num_quad_words, + unsigned tabs) +{ + uint32_t control_word = words[0]; + uint16_t *beginning_ptr = (uint16_t *)(words + 1); + unsigned num_fields = num_alu_fields_enabled(control_word); + uint16_t *word_ptr = beginning_ptr + num_fields; + unsigned num_words = 2 + num_fields; + + if ((control_word >> 16) & 1) + printf("unknown bit 16 enabled\n"); + + if ((control_word >> 17) & 1) { + print_vector_field("vmul", word_ptr, *beginning_ptr, tabs); + beginning_ptr += 1; + word_ptr += 3; + num_words += 3; + } + + if ((control_word >> 18) & 1) + printf("unknown bit 18 enabled\n"); + + if ((control_word >> 19) & 1) { + print_scalar_field("sadd", word_ptr, *beginning_ptr, tabs); + beginning_ptr += 1; + word_ptr += 2; + num_words += 2; + } + + if ((control_word >> 20) & 1) + printf("unknown bit 20 enabled\n"); + + if ((control_word >> 21) & 1) { + print_vector_field("vadd", word_ptr, *beginning_ptr, tabs); + beginning_ptr += 1; + word_ptr += 3; + num_words += 3; + } + + if ((control_word >> 22) & 1) + printf("unknown bit 22 enabled\n"); + + if ((control_word >> 23) & 1) { + print_scalar_field("smul", word_ptr, *beginning_ptr, tabs); + beginning_ptr += 1; + word_ptr += 2; + num_words += 2; + } + + if ((control_word >> 24) & 1) + printf("unknown bit 24 enabled\n"); + + if ((control_word >> 25) & 1) { + print_vector_field("lut", word_ptr, *beginning_ptr, tabs); + beginning_ptr += 1; + word_ptr += 3; + num_words += 3; + } + + if ((control_word >> 26) & 1) { + print_compact_branch_writeout_field(*word_ptr); + word_ptr += 1; + num_words += 1; + } + + if ((control_word >> 27) & 1) { + print_extended_branch_writeout_field((uint8_t *) word_ptr); + word_ptr += 3; + num_words += 3; + } + + if (num_quad_words > (num_words + 7) / 8) { + assert(num_quad_words == (num_words + 15) / 8); + //Assume that the extra quadword is constants + void *consts = words + (4 * num_quad_words - 4); + + if (is_embedded_constant_int) { + if (is_embedded_constant_half) { + int16_t *sconsts = (int16_t *) consts; + printf("sconstants %d, %d, %d, %d\n", + sconsts[0], + sconsts[1], + sconsts[2], + sconsts[3]); + } else { + int32_t *iconsts = (int32_t *) consts; + printf("iconstants %d, %d, %d, %d\n", + iconsts[0], + iconsts[1], + iconsts[2], + iconsts[3]); + } + } else { + if (is_embedded_constant_half) { + uint16_t *hconsts = (uint16_t *) consts; + printf("hconstants %g, %g, %g, %g\n", + _mesa_half_to_float(hconsts[0]), + _mesa_half_to_float(hconsts[1]), + _mesa_half_to_float(hconsts[2]), + _mesa_half_to_float(hconsts[3])); + } else { + uint32_t *fconsts = (uint32_t *) consts; + printf("fconstants %g, %g, %g, %g\n", + float_bitcast(fconsts[0]), + float_bitcast(fconsts[1]), + float_bitcast(fconsts[2]), + float_bitcast(fconsts[3])); + } + + } + } +} + +/* Swizzle/mask formats are common between load/store ops and texture ops, it + * looks like... */ + +static void +print_swizzle(uint32_t swizzle) +{ + unsigned i; + + if (swizzle != 0xE4) { + printf("."); + + for (i = 0; i < 4; i++) + printf("%c", "xyzw"[(swizzle >> (2 * i)) & 3]); + } +} + +static void +print_mask(uint32_t mask) +{ + unsigned i; + + if (mask != 0xF) { + printf("."); + + for (i = 0; i < 4; i++) + if (mask & (1 << i)) + printf("%c", "xyzw"[i]); + + /* Handle degenerate case */ + if (mask == 0) + printf("0"); + } +} + +static void +print_varying_parameters(midgard_load_store_word *word) +{ + midgard_varying_parameter param; + unsigned v = word->varying_parameters; + memcpy(¶m, &v, sizeof(param)); + + if (param.is_varying) { + /* If a varying, there are qualifiers */ + if (param.flat) + printf(".flat"); + + if (param.interpolation != midgard_interp_default) { + if (param.interpolation == midgard_interp_centroid) + printf(".centroid"); + else + printf(".interp%d", param.interpolation); + } + } else if (param.flat || param.interpolation) { + printf(" /* is_varying not set but varying metadata attached */"); + } + + if (param.zero1 || param.zero2) + printf(" /* zero tripped, %d %d */ ", param.zero1, param.zero2); +} + +static bool +is_op_varying(unsigned op) +{ + switch (op) { + case midgard_op_store_vary_16: + case midgard_op_store_vary_32: + case midgard_op_load_vary_16: + case midgard_op_load_vary_32: + return true; + } + + return false; +} + +static void +print_load_store_instr(uint64_t data, + unsigned tabs) +{ + midgard_load_store_word *word = (midgard_load_store_word *) &data; + + print_ld_st_opcode(word->op); + + if (is_op_varying(word->op)) + print_varying_parameters(word); + + printf(" r%d", word->reg); + print_mask(word->mask); + + int address = word->address; + + if (word->op == midgard_op_load_uniform_32) { + /* Uniforms use their own addressing scheme */ + + int lo = word->varying_parameters >> 7; + int hi = word->address; + + /* TODO: Combine fields logically */ + address = (hi << 3) | lo; + } + + printf(", %d", address); + + print_swizzle(word->swizzle); + + printf(", 0x%X\n", word->unknown); +} + +static void +print_load_store_word(uint32_t *word, unsigned tabs) +{ + midgard_load_store *load_store = (midgard_load_store *) word; + + if (load_store->word1 != 3) { + print_load_store_instr(load_store->word1, tabs); + } + + if (load_store->word2 != 3) { + print_load_store_instr(load_store->word2, tabs); + } +} + +static void +print_texture_reg(bool full, bool select, bool upper) +{ + if (full) + printf("r%d", REG_TEX_BASE + select); + else + printf("hr%d", (REG_TEX_BASE + select) * 2 + upper); + + if (full && upper) + printf("// error: out full / upper mutually exclusive\n"); + +} + +static void +print_texture_format(int format) +{ + /* Act like a modifier */ + printf("."); + + switch (format) { + DEFINE_CASE(TEXTURE_2D, "2d"); + DEFINE_CASE(TEXTURE_3D, "3d"); + + default: + printf("fmt_%d", format); + break; + } +} + +static void +print_texture_op(int format) +{ + /* Act like a modifier */ + printf("."); + + switch (format) { + DEFINE_CASE(TEXTURE_OP_NORMAL, "normal"); + DEFINE_CASE(TEXTURE_OP_TEXEL_FETCH, "texelfetch"); + + default: + printf("op_%d", format); + break; + } +} + +#undef DEFINE_CASE + +static void +print_texture_word(uint32_t *word, unsigned tabs) +{ + midgard_texture_word *texture = (midgard_texture_word *) word; + + /* Instruction family, like ALU words have theirs */ + printf("texture"); + + /* Broad category of texture operation in question */ + print_texture_op(texture->op); + + /* Specific format in question */ + print_texture_format(texture->format); + + /* Instruction "modifiers" parallel the ALU instructions. First group + * are modifiers that act alone */ + + if (!texture->filter) + printf(".raw"); + + if (texture->shadow) + printf(".shadow"); + + if (texture->cont) + printf(".cont"); + + if (texture->last) + printf(".last"); + + /* Second set are modifiers which take an extra argument each */ + + if (texture->has_offset) + printf(".offset"); + + if (texture->bias) + printf(".bias"); + + printf(" "); + + print_texture_reg(texture->out_full, texture->out_reg_select, texture->out_upper); + print_mask(texture->mask); + printf(", "); + + printf("texture%d, ", texture->texture_handle); + + printf("sampler%d", texture->sampler_handle); + print_swizzle(texture->swizzle); + printf(", "); + + print_texture_reg(/*texture->in_reg_full*/true, texture->in_reg_select, texture->in_reg_upper); + printf(".%c%c, ", "xyzw"[texture->in_reg_swizzle_left], + "xyzw"[texture->in_reg_swizzle_right]); + + /* TODO: can offsets be full words? */ + if (texture->has_offset) { + print_texture_reg(false, texture->offset_reg_select, texture->offset_reg_upper); + printf(", "); + } + + if (texture->bias) + printf("%f, ", texture->bias / 256.0f); + + printf("\n"); + + /* While not zero in general, for these simple instructions the + * following unknowns are zero, so we don't include them */ + + if (texture->unknown1 || + texture->unknown2 || + texture->unknown3 || + texture->unknown4 || + texture->unknownA || + texture->unknownB || + texture->unknown8 || + texture->unknown9) { + printf("// unknown1 = 0x%x\n", texture->unknown1); + printf("// unknown2 = 0x%x\n", texture->unknown2); + printf("// unknown3 = 0x%x\n", texture->unknown3); + printf("// unknown4 = 0x%x\n", texture->unknown4); + printf("// unknownA = 0x%x\n", texture->unknownA); + printf("// unknownB = 0x%x\n", texture->unknownB); + printf("// unknown8 = 0x%x\n", texture->unknown8); + printf("// unknown9 = 0x%x\n", texture->unknown9); + } + + /* Similarly, if no offset is applied, these are zero. If an offset + * -is- applied, or gradients are used, etc, these are nonzero but + * largely unknown still. */ + + if (texture->offset_unknown1 || + texture->offset_reg_select || + texture->offset_reg_upper || + texture->offset_unknown4 || + texture->offset_unknown5 || + texture->offset_unknown6 || + texture->offset_unknown7 || + texture->offset_unknown8 || + texture->offset_unknown9) { + printf("// offset_unknown1 = 0x%x\n", texture->offset_unknown1); + printf("// offset_reg_select = 0x%x\n", texture->offset_reg_select); + printf("// offset_reg_upper = 0x%x\n", texture->offset_reg_upper); + printf("// offset_unknown4 = 0x%x\n", texture->offset_unknown4); + printf("// offset_unknown5 = 0x%x\n", texture->offset_unknown5); + printf("// offset_unknown6 = 0x%x\n", texture->offset_unknown6); + printf("// offset_unknown7 = 0x%x\n", texture->offset_unknown7); + printf("// offset_unknown8 = 0x%x\n", texture->offset_unknown8); + printf("// offset_unknown9 = 0x%x\n", texture->offset_unknown9); + } + + /* Don't blow up */ + if (texture->unknown7 != 0x1) + printf("// (!) unknown7 = %d\n", texture->unknown7); +} + +void +disassemble_midgard(uint8_t *code, size_t size) +{ + uint32_t *words = (uint32_t *) code; + unsigned num_words = size / 4; + int tabs = 0; + + bool prefetch_flag = false; + + unsigned i = 0; + + while (i < num_words) { + unsigned num_quad_words = midgard_word_size[words[i] & 0xF]; + + switch (midgard_word_types[words[i] & 0xF]) { + case midgard_word_type_texture: + print_texture_word(&words[i], tabs); + break; + + case midgard_word_type_load_store: + print_load_store_word(&words[i], tabs); + break; + + case midgard_word_type_alu: + print_alu_word(&words[i], num_quad_words, tabs); + + if (prefetch_flag) + return; + + /* Reset word static analysis state */ + is_embedded_constant_half = false; + is_embedded_constant_int = false; + + break; + + default: + printf("Unknown word type %u:\n", words[i] & 0xF); + num_quad_words = 1; + print_quad_word(&words[i], tabs); + printf("\n"); + break; + } + + printf("\n"); + + unsigned next = (words[i] & 0xF0) >> 4; + + i += 4 * num_quad_words; + + /* Break based on instruction prefetch flag */ + + if (i < num_words && next == 1) { + prefetch_flag = true; + + if (midgard_word_types[words[i] & 0xF] != midgard_word_type_alu) + return; + } + } + + return; +} |