17ec681f3Smrg/* 27ec681f3Smrg * Copyright (c) 2012 Rob Clark <robdclark@gmail.com> 37ec681f3Smrg * 47ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a 57ec681f3Smrg * copy of this software and associated documentation files (the "Software"), 67ec681f3Smrg * to deal in the Software without restriction, including without limitation 77ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 87ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the 97ec681f3Smrg * Software is furnished to do so, subject to the following conditions: 107ec681f3Smrg * 117ec681f3Smrg * The above copyright notice and this permission notice (including the next 127ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the 137ec681f3Smrg * Software. 147ec681f3Smrg * 157ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 167ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 177ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 187ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 197ec681f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 207ec681f3Smrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 217ec681f3Smrg * SOFTWARE. 227ec681f3Smrg */ 237ec681f3Smrg 247ec681f3Smrg#include <fcntl.h> 257ec681f3Smrg#include <stdint.h> 267ec681f3Smrg#include <stdio.h> 277ec681f3Smrg#include <stdlib.h> 287ec681f3Smrg#include <string.h> 297ec681f3Smrg#include <unistd.h> 307ec681f3Smrg#include <sys/stat.h> 317ec681f3Smrg#include <sys/types.h> 327ec681f3Smrg 337ec681f3Smrg#include "disasm.h" 347ec681f3Smrg#include "instr-a2xx.h" 357ec681f3Smrg 367ec681f3Smrgstatic const char *levels[] = { 377ec681f3Smrg "\t", 387ec681f3Smrg "\t\t", 397ec681f3Smrg "\t\t\t", 407ec681f3Smrg "\t\t\t\t", 417ec681f3Smrg "\t\t\t\t\t", 427ec681f3Smrg "\t\t\t\t\t\t", 437ec681f3Smrg "\t\t\t\t\t\t\t", 447ec681f3Smrg "\t\t\t\t\t\t\t\t", 457ec681f3Smrg "\t\t\t\t\t\t\t\t\t", 467ec681f3Smrg "x", 477ec681f3Smrg "x", 487ec681f3Smrg "x", 497ec681f3Smrg "x", 507ec681f3Smrg "x", 517ec681f3Smrg "x", 527ec681f3Smrg}; 537ec681f3Smrg 547ec681f3Smrgstatic enum debug_t debug; 557ec681f3Smrg 567ec681f3Smrg/* 577ec681f3Smrg * ALU instructions: 587ec681f3Smrg */ 597ec681f3Smrg 607ec681f3Smrgstatic const char chan_names[] = { 617ec681f3Smrg 'x', 627ec681f3Smrg 'y', 637ec681f3Smrg 'z', 647ec681f3Smrg 'w', 657ec681f3Smrg /* these only apply to FETCH dst's: */ 667ec681f3Smrg '0', 677ec681f3Smrg '1', 687ec681f3Smrg '?', 697ec681f3Smrg '_', 707ec681f3Smrg}; 717ec681f3Smrg 727ec681f3Smrgstatic void 737ec681f3Smrgprint_srcreg(uint32_t num, uint32_t type, uint32_t swiz, uint32_t negate, 747ec681f3Smrg uint32_t abs) 757ec681f3Smrg{ 767ec681f3Smrg if (negate) 777ec681f3Smrg printf("-"); 787ec681f3Smrg if (abs) 797ec681f3Smrg printf("|"); 807ec681f3Smrg printf("%c%u", type ? 'R' : 'C', num); 817ec681f3Smrg if (swiz) { 827ec681f3Smrg int i; 837ec681f3Smrg printf("."); 847ec681f3Smrg for (i = 0; i < 4; i++) { 857ec681f3Smrg printf("%c", chan_names[(swiz + i) & 0x3]); 867ec681f3Smrg swiz >>= 2; 877ec681f3Smrg } 887ec681f3Smrg } 897ec681f3Smrg if (abs) 907ec681f3Smrg printf("|"); 917ec681f3Smrg} 927ec681f3Smrg 937ec681f3Smrgstatic void 947ec681f3Smrgprint_dstreg(uint32_t num, uint32_t mask, uint32_t dst_exp) 957ec681f3Smrg{ 967ec681f3Smrg printf("%s%u", dst_exp ? "export" : "R", num); 977ec681f3Smrg if (mask != 0xf) { 987ec681f3Smrg int i; 997ec681f3Smrg printf("."); 1007ec681f3Smrg for (i = 0; i < 4; i++) { 1017ec681f3Smrg printf("%c", (mask & 0x1) ? chan_names[i] : '_'); 1027ec681f3Smrg mask >>= 1; 1037ec681f3Smrg } 1047ec681f3Smrg } 1057ec681f3Smrg} 1067ec681f3Smrg 1077ec681f3Smrgstatic void 1087ec681f3Smrgprint_export_comment(uint32_t num, gl_shader_stage type) 1097ec681f3Smrg{ 1107ec681f3Smrg const char *name = NULL; 1117ec681f3Smrg switch (type) { 1127ec681f3Smrg case MESA_SHADER_VERTEX: 1137ec681f3Smrg switch (num) { 1147ec681f3Smrg case 62: 1157ec681f3Smrg name = "gl_Position"; 1167ec681f3Smrg break; 1177ec681f3Smrg case 63: 1187ec681f3Smrg name = "gl_PointSize"; 1197ec681f3Smrg break; 1207ec681f3Smrg } 1217ec681f3Smrg break; 1227ec681f3Smrg case MESA_SHADER_FRAGMENT: 1237ec681f3Smrg switch (num) { 1247ec681f3Smrg case 0: 1257ec681f3Smrg name = "gl_FragColor"; 1267ec681f3Smrg break; 1277ec681f3Smrg } 1287ec681f3Smrg break; 1297ec681f3Smrg default: 1307ec681f3Smrg assert(!"not reached"); 1317ec681f3Smrg } 1327ec681f3Smrg /* if we had a symbol table here, we could look 1337ec681f3Smrg * up the name of the varying.. 1347ec681f3Smrg */ 1357ec681f3Smrg if (name) { 1367ec681f3Smrg printf("\t; %s", name); 1377ec681f3Smrg } 1387ec681f3Smrg} 1397ec681f3Smrg 1407ec681f3Smrgstruct { 1417ec681f3Smrg uint32_t num_srcs; 1427ec681f3Smrg const char *name; 1437ec681f3Smrg} vector_instructions[0x20] = { 1447ec681f3Smrg#define INSTR(opc, num_srcs) [opc] = {num_srcs, #opc} 1457ec681f3Smrg INSTR(ADDv, 2), 1467ec681f3Smrg INSTR(MULv, 2), 1477ec681f3Smrg INSTR(MAXv, 2), 1487ec681f3Smrg INSTR(MINv, 2), 1497ec681f3Smrg INSTR(SETEv, 2), 1507ec681f3Smrg INSTR(SETGTv, 2), 1517ec681f3Smrg INSTR(SETGTEv, 2), 1527ec681f3Smrg INSTR(SETNEv, 2), 1537ec681f3Smrg INSTR(FRACv, 1), 1547ec681f3Smrg INSTR(TRUNCv, 1), 1557ec681f3Smrg INSTR(FLOORv, 1), 1567ec681f3Smrg INSTR(MULADDv, 3), 1577ec681f3Smrg INSTR(CNDEv, 3), 1587ec681f3Smrg INSTR(CNDGTEv, 3), 1597ec681f3Smrg INSTR(CNDGTv, 3), 1607ec681f3Smrg INSTR(DOT4v, 2), 1617ec681f3Smrg INSTR(DOT3v, 2), 1627ec681f3Smrg INSTR(DOT2ADDv, 3), // ??? 1637ec681f3Smrg INSTR(CUBEv, 2), 1647ec681f3Smrg INSTR(MAX4v, 1), 1657ec681f3Smrg INSTR(PRED_SETE_PUSHv, 2), 1667ec681f3Smrg INSTR(PRED_SETNE_PUSHv, 2), 1677ec681f3Smrg INSTR(PRED_SETGT_PUSHv, 2), 1687ec681f3Smrg INSTR(PRED_SETGTE_PUSHv, 2), 1697ec681f3Smrg INSTR(KILLEv, 2), 1707ec681f3Smrg INSTR(KILLGTv, 2), 1717ec681f3Smrg INSTR(KILLGTEv, 2), 1727ec681f3Smrg INSTR(KILLNEv, 2), 1737ec681f3Smrg INSTR(DSTv, 2), 1747ec681f3Smrg INSTR(MOVAv, 1), 1757ec681f3Smrg}, scalar_instructions[0x40] = { 1767ec681f3Smrg INSTR(ADDs, 1), 1777ec681f3Smrg INSTR(ADD_PREVs, 1), 1787ec681f3Smrg INSTR(MULs, 1), 1797ec681f3Smrg INSTR(MUL_PREVs, 1), 1807ec681f3Smrg INSTR(MUL_PREV2s, 1), 1817ec681f3Smrg INSTR(MAXs, 1), 1827ec681f3Smrg INSTR(MINs, 1), 1837ec681f3Smrg INSTR(SETEs, 1), 1847ec681f3Smrg INSTR(SETGTs, 1), 1857ec681f3Smrg INSTR(SETGTEs, 1), 1867ec681f3Smrg INSTR(SETNEs, 1), 1877ec681f3Smrg INSTR(FRACs, 1), 1887ec681f3Smrg INSTR(TRUNCs, 1), 1897ec681f3Smrg INSTR(FLOORs, 1), 1907ec681f3Smrg INSTR(EXP_IEEE, 1), 1917ec681f3Smrg INSTR(LOG_CLAMP, 1), 1927ec681f3Smrg INSTR(LOG_IEEE, 1), 1937ec681f3Smrg INSTR(RECIP_CLAMP, 1), 1947ec681f3Smrg INSTR(RECIP_FF, 1), 1957ec681f3Smrg INSTR(RECIP_IEEE, 1), 1967ec681f3Smrg INSTR(RECIPSQ_CLAMP, 1), 1977ec681f3Smrg INSTR(RECIPSQ_FF, 1), 1987ec681f3Smrg INSTR(RECIPSQ_IEEE, 1), 1997ec681f3Smrg INSTR(MOVAs, 1), 2007ec681f3Smrg INSTR(MOVA_FLOORs, 1), 2017ec681f3Smrg INSTR(SUBs, 1), 2027ec681f3Smrg INSTR(SUB_PREVs, 1), 2037ec681f3Smrg INSTR(PRED_SETEs, 1), 2047ec681f3Smrg INSTR(PRED_SETNEs, 1), 2057ec681f3Smrg INSTR(PRED_SETGTs, 1), 2067ec681f3Smrg INSTR(PRED_SETGTEs, 1), 2077ec681f3Smrg INSTR(PRED_SET_INVs, 1), 2087ec681f3Smrg INSTR(PRED_SET_POPs, 1), 2097ec681f3Smrg INSTR(PRED_SET_CLRs, 1), 2107ec681f3Smrg INSTR(PRED_SET_RESTOREs, 1), 2117ec681f3Smrg INSTR(KILLEs, 1), 2127ec681f3Smrg INSTR(KILLGTs, 1), 2137ec681f3Smrg INSTR(KILLGTEs, 1), 2147ec681f3Smrg INSTR(KILLNEs, 1), 2157ec681f3Smrg INSTR(KILLONEs, 1), 2167ec681f3Smrg INSTR(SQRT_IEEE, 1), 2177ec681f3Smrg INSTR(MUL_CONST_0, 1), 2187ec681f3Smrg INSTR(MUL_CONST_1, 1), 2197ec681f3Smrg INSTR(ADD_CONST_0, 1), 2207ec681f3Smrg INSTR(ADD_CONST_1, 1), 2217ec681f3Smrg INSTR(SUB_CONST_0, 1), 2227ec681f3Smrg INSTR(SUB_CONST_1, 1), 2237ec681f3Smrg INSTR(SIN, 1), 2247ec681f3Smrg INSTR(COS, 1), 2257ec681f3Smrg INSTR(RETAIN_PREV, 1), 2267ec681f3Smrg#undef INSTR 2277ec681f3Smrg}; 2287ec681f3Smrg 2297ec681f3Smrgstatic int 2307ec681f3Smrgdisasm_alu(uint32_t *dwords, uint32_t alu_off, int level, int sync, 2317ec681f3Smrg gl_shader_stage type) 2327ec681f3Smrg{ 2337ec681f3Smrg instr_alu_t *alu = (instr_alu_t *)dwords; 2347ec681f3Smrg 2357ec681f3Smrg printf("%s", levels[level]); 2367ec681f3Smrg if (debug & PRINT_RAW) { 2377ec681f3Smrg printf("%02x: %08x %08x %08x\t", alu_off, dwords[0], dwords[1], 2387ec681f3Smrg dwords[2]); 2397ec681f3Smrg } 2407ec681f3Smrg 2417ec681f3Smrg printf(" %sALU:\t", sync ? "(S)" : " "); 2427ec681f3Smrg 2437ec681f3Smrg printf("%s", vector_instructions[alu->vector_opc].name); 2447ec681f3Smrg 2457ec681f3Smrg if (alu->pred_select & 0x2) { 2467ec681f3Smrg /* seems to work similar to conditional execution in ARM instruction 2477ec681f3Smrg * set, so let's use a similar syntax for now: 2487ec681f3Smrg */ 2497ec681f3Smrg printf((alu->pred_select & 0x1) ? "EQ" : "NE"); 2507ec681f3Smrg } 2517ec681f3Smrg 2527ec681f3Smrg printf("\t"); 2537ec681f3Smrg 2547ec681f3Smrg print_dstreg(alu->vector_dest, alu->vector_write_mask, alu->export_data); 2557ec681f3Smrg printf(" = "); 2567ec681f3Smrg if (vector_instructions[alu->vector_opc].num_srcs == 3) { 2577ec681f3Smrg print_srcreg(alu->src3_reg, alu->src3_sel, alu->src3_swiz, 2587ec681f3Smrg alu->src3_reg_negate, alu->src3_reg_abs); 2597ec681f3Smrg printf(", "); 2607ec681f3Smrg } 2617ec681f3Smrg print_srcreg(alu->src1_reg, alu->src1_sel, alu->src1_swiz, 2627ec681f3Smrg alu->src1_reg_negate, alu->src1_reg_abs); 2637ec681f3Smrg if (vector_instructions[alu->vector_opc].num_srcs > 1) { 2647ec681f3Smrg printf(", "); 2657ec681f3Smrg print_srcreg(alu->src2_reg, alu->src2_sel, alu->src2_swiz, 2667ec681f3Smrg alu->src2_reg_negate, alu->src2_reg_abs); 2677ec681f3Smrg } 2687ec681f3Smrg 2697ec681f3Smrg if (alu->vector_clamp) 2707ec681f3Smrg printf(" CLAMP"); 2717ec681f3Smrg 2727ec681f3Smrg if (alu->export_data) 2737ec681f3Smrg print_export_comment(alu->vector_dest, type); 2747ec681f3Smrg 2757ec681f3Smrg printf("\n"); 2767ec681f3Smrg 2777ec681f3Smrg if (alu->scalar_write_mask || !alu->vector_write_mask) { 2787ec681f3Smrg /* 2nd optional scalar op: */ 2797ec681f3Smrg 2807ec681f3Smrg printf("%s", levels[level]); 2817ec681f3Smrg if (debug & PRINT_RAW) 2827ec681f3Smrg printf(" \t"); 2837ec681f3Smrg 2847ec681f3Smrg if (scalar_instructions[alu->scalar_opc].name) { 2857ec681f3Smrg printf("\t \t%s\t", scalar_instructions[alu->scalar_opc].name); 2867ec681f3Smrg } else { 2877ec681f3Smrg printf("\t \tOP(%u)\t", alu->scalar_opc); 2887ec681f3Smrg } 2897ec681f3Smrg 2907ec681f3Smrg print_dstreg(alu->scalar_dest, alu->scalar_write_mask, alu->export_data); 2917ec681f3Smrg printf(" = "); 2927ec681f3Smrg print_srcreg(alu->src3_reg, alu->src3_sel, alu->src3_swiz, 2937ec681f3Smrg alu->src3_reg_negate, alu->src3_reg_abs); 2947ec681f3Smrg // TODO ADD/MUL must have another src?!? 2957ec681f3Smrg if (alu->scalar_clamp) 2967ec681f3Smrg printf(" CLAMP"); 2977ec681f3Smrg if (alu->export_data) 2987ec681f3Smrg print_export_comment(alu->scalar_dest, type); 2997ec681f3Smrg printf("\n"); 3007ec681f3Smrg } 3017ec681f3Smrg 3027ec681f3Smrg return 0; 3037ec681f3Smrg} 3047ec681f3Smrg 3057ec681f3Smrg/* 3067ec681f3Smrg * FETCH instructions: 3077ec681f3Smrg */ 3087ec681f3Smrg 3097ec681f3Smrgstruct { 3107ec681f3Smrg const char *name; 3117ec681f3Smrg} fetch_types[0xff] = { 3127ec681f3Smrg#define TYPE(id) [id] = {#id} 3137ec681f3Smrg TYPE(FMT_1_REVERSE), 3147ec681f3Smrg TYPE(FMT_32_FLOAT), 3157ec681f3Smrg TYPE(FMT_32_32_FLOAT), 3167ec681f3Smrg TYPE(FMT_32_32_32_FLOAT), 3177ec681f3Smrg TYPE(FMT_32_32_32_32_FLOAT), 3187ec681f3Smrg TYPE(FMT_16), 3197ec681f3Smrg TYPE(FMT_16_16), 3207ec681f3Smrg TYPE(FMT_16_16_16_16), 3217ec681f3Smrg TYPE(FMT_8), 3227ec681f3Smrg TYPE(FMT_8_8), 3237ec681f3Smrg TYPE(FMT_8_8_8_8), 3247ec681f3Smrg TYPE(FMT_32), 3257ec681f3Smrg TYPE(FMT_32_32), 3267ec681f3Smrg TYPE(FMT_32_32_32_32), 3277ec681f3Smrg#undef TYPE 3287ec681f3Smrg}; 3297ec681f3Smrg 3307ec681f3Smrgstatic void 3317ec681f3Smrgprint_fetch_dst(uint32_t dst_reg, uint32_t dst_swiz) 3327ec681f3Smrg{ 3337ec681f3Smrg int i; 3347ec681f3Smrg printf("\tR%u.", dst_reg); 3357ec681f3Smrg for (i = 0; i < 4; i++) { 3367ec681f3Smrg printf("%c", chan_names[dst_swiz & 0x7]); 3377ec681f3Smrg dst_swiz >>= 3; 3387ec681f3Smrg } 3397ec681f3Smrg} 3407ec681f3Smrg 3417ec681f3Smrgstatic void 3427ec681f3Smrgprint_fetch_vtx(instr_fetch_t *fetch) 3437ec681f3Smrg{ 3447ec681f3Smrg instr_fetch_vtx_t *vtx = &fetch->vtx; 3457ec681f3Smrg 3467ec681f3Smrg if (vtx->pred_select) { 3477ec681f3Smrg /* seems to work similar to conditional execution in ARM instruction 3487ec681f3Smrg * set, so let's use a similar syntax for now: 3497ec681f3Smrg */ 3507ec681f3Smrg printf(vtx->pred_condition ? "EQ" : "NE"); 3517ec681f3Smrg } 3527ec681f3Smrg 3537ec681f3Smrg print_fetch_dst(vtx->dst_reg, vtx->dst_swiz); 3547ec681f3Smrg printf(" = R%u.", vtx->src_reg); 3557ec681f3Smrg printf("%c", chan_names[vtx->src_swiz & 0x3]); 3567ec681f3Smrg if (fetch_types[vtx->format].name) { 3577ec681f3Smrg printf(" %s", fetch_types[vtx->format].name); 3587ec681f3Smrg } else { 3597ec681f3Smrg printf(" TYPE(0x%x)", vtx->format); 3607ec681f3Smrg } 3617ec681f3Smrg printf(" %s", vtx->format_comp_all ? "SIGNED" : "UNSIGNED"); 3627ec681f3Smrg if (!vtx->num_format_all) 3637ec681f3Smrg printf(" NORMALIZED"); 3647ec681f3Smrg printf(" STRIDE(%u)", vtx->stride); 3657ec681f3Smrg if (vtx->offset) 3667ec681f3Smrg printf(" OFFSET(%u)", vtx->offset); 3677ec681f3Smrg printf(" CONST(%u, %u)", vtx->const_index, vtx->const_index_sel); 3687ec681f3Smrg if (0) { 3697ec681f3Smrg // XXX 3707ec681f3Smrg printf(" src_reg_am=%u", vtx->src_reg_am); 3717ec681f3Smrg printf(" dst_reg_am=%u", vtx->dst_reg_am); 3727ec681f3Smrg printf(" num_format_all=%u", vtx->num_format_all); 3737ec681f3Smrg printf(" signed_rf_mode_all=%u", vtx->signed_rf_mode_all); 3747ec681f3Smrg printf(" exp_adjust_all=%u", vtx->exp_adjust_all); 3757ec681f3Smrg } 3767ec681f3Smrg} 3777ec681f3Smrg 3787ec681f3Smrgstatic void 3797ec681f3Smrgprint_fetch_tex(instr_fetch_t *fetch) 3807ec681f3Smrg{ 3817ec681f3Smrg static const char *filter[] = { 3827ec681f3Smrg [TEX_FILTER_POINT] = "POINT", 3837ec681f3Smrg [TEX_FILTER_LINEAR] = "LINEAR", 3847ec681f3Smrg [TEX_FILTER_BASEMAP] = "BASEMAP", 3857ec681f3Smrg }; 3867ec681f3Smrg static const char *aniso_filter[] = { 3877ec681f3Smrg [ANISO_FILTER_DISABLED] = "DISABLED", 3887ec681f3Smrg [ANISO_FILTER_MAX_1_1] = "MAX_1_1", 3897ec681f3Smrg [ANISO_FILTER_MAX_2_1] = "MAX_2_1", 3907ec681f3Smrg [ANISO_FILTER_MAX_4_1] = "MAX_4_1", 3917ec681f3Smrg [ANISO_FILTER_MAX_8_1] = "MAX_8_1", 3927ec681f3Smrg [ANISO_FILTER_MAX_16_1] = "MAX_16_1", 3937ec681f3Smrg }; 3947ec681f3Smrg static const char *arbitrary_filter[] = { 3957ec681f3Smrg [ARBITRARY_FILTER_2X4_SYM] = "2x4_SYM", 3967ec681f3Smrg [ARBITRARY_FILTER_2X4_ASYM] = "2x4_ASYM", 3977ec681f3Smrg [ARBITRARY_FILTER_4X2_SYM] = "4x2_SYM", 3987ec681f3Smrg [ARBITRARY_FILTER_4X2_ASYM] = "4x2_ASYM", 3997ec681f3Smrg [ARBITRARY_FILTER_4X4_SYM] = "4x4_SYM", 4007ec681f3Smrg [ARBITRARY_FILTER_4X4_ASYM] = "4x4_ASYM", 4017ec681f3Smrg }; 4027ec681f3Smrg static const char *sample_loc[] = { 4037ec681f3Smrg [SAMPLE_CENTROID] = "CENTROID", 4047ec681f3Smrg [SAMPLE_CENTER] = "CENTER", 4057ec681f3Smrg }; 4067ec681f3Smrg instr_fetch_tex_t *tex = &fetch->tex; 4077ec681f3Smrg uint32_t src_swiz = tex->src_swiz; 4087ec681f3Smrg int i; 4097ec681f3Smrg 4107ec681f3Smrg if (tex->pred_select) { 4117ec681f3Smrg /* seems to work similar to conditional execution in ARM instruction 4127ec681f3Smrg * set, so let's use a similar syntax for now: 4137ec681f3Smrg */ 4147ec681f3Smrg printf(tex->pred_condition ? "EQ" : "NE"); 4157ec681f3Smrg } 4167ec681f3Smrg 4177ec681f3Smrg print_fetch_dst(tex->dst_reg, tex->dst_swiz); 4187ec681f3Smrg printf(" = R%u.", tex->src_reg); 4197ec681f3Smrg for (i = 0; i < 3; i++) { 4207ec681f3Smrg printf("%c", chan_names[src_swiz & 0x3]); 4217ec681f3Smrg src_swiz >>= 2; 4227ec681f3Smrg } 4237ec681f3Smrg printf(" CONST(%u)", tex->const_idx); 4247ec681f3Smrg if (tex->fetch_valid_only) 4257ec681f3Smrg printf(" VALID_ONLY"); 4267ec681f3Smrg if (tex->tx_coord_denorm) 4277ec681f3Smrg printf(" DENORM"); 4287ec681f3Smrg if (tex->mag_filter != TEX_FILTER_USE_FETCH_CONST) 4297ec681f3Smrg printf(" MAG(%s)", filter[tex->mag_filter]); 4307ec681f3Smrg if (tex->min_filter != TEX_FILTER_USE_FETCH_CONST) 4317ec681f3Smrg printf(" MIN(%s)", filter[tex->min_filter]); 4327ec681f3Smrg if (tex->mip_filter != TEX_FILTER_USE_FETCH_CONST) 4337ec681f3Smrg printf(" MIP(%s)", filter[tex->mip_filter]); 4347ec681f3Smrg if (tex->aniso_filter != ANISO_FILTER_USE_FETCH_CONST) 4357ec681f3Smrg printf(" ANISO(%s)", aniso_filter[tex->aniso_filter]); 4367ec681f3Smrg if (tex->arbitrary_filter != ARBITRARY_FILTER_USE_FETCH_CONST) 4377ec681f3Smrg printf(" ARBITRARY(%s)", arbitrary_filter[tex->arbitrary_filter]); 4387ec681f3Smrg if (tex->vol_mag_filter != TEX_FILTER_USE_FETCH_CONST) 4397ec681f3Smrg printf(" VOL_MAG(%s)", filter[tex->vol_mag_filter]); 4407ec681f3Smrg if (tex->vol_min_filter != TEX_FILTER_USE_FETCH_CONST) 4417ec681f3Smrg printf(" VOL_MIN(%s)", filter[tex->vol_min_filter]); 4427ec681f3Smrg if (!tex->use_comp_lod) { 4437ec681f3Smrg printf(" LOD(%u)", tex->use_comp_lod); 4447ec681f3Smrg printf(" LOD_BIAS(%u)", tex->lod_bias); 4457ec681f3Smrg } 4467ec681f3Smrg if (tex->use_reg_lod) { 4477ec681f3Smrg printf(" REG_LOD(%u)", tex->use_reg_lod); 4487ec681f3Smrg } 4497ec681f3Smrg if (tex->use_reg_gradients) 4507ec681f3Smrg printf(" USE_REG_GRADIENTS"); 4517ec681f3Smrg printf(" LOCATION(%s)", sample_loc[tex->sample_location]); 4527ec681f3Smrg if (tex->offset_x || tex->offset_y || tex->offset_z) 4537ec681f3Smrg printf(" OFFSET(%u,%u,%u)", tex->offset_x, tex->offset_y, tex->offset_z); 4547ec681f3Smrg} 4557ec681f3Smrg 4567ec681f3Smrgstruct { 4577ec681f3Smrg const char *name; 4587ec681f3Smrg void (*fxn)(instr_fetch_t *cf); 4597ec681f3Smrg} fetch_instructions[] = { 4607ec681f3Smrg#define INSTR(opc, name, fxn) [opc] = {name, fxn} 4617ec681f3Smrg INSTR(VTX_FETCH, "VERTEX", print_fetch_vtx), 4627ec681f3Smrg INSTR(TEX_FETCH, "SAMPLE", print_fetch_tex), 4637ec681f3Smrg INSTR(TEX_GET_BORDER_COLOR_FRAC, "?", print_fetch_tex), 4647ec681f3Smrg INSTR(TEX_GET_COMP_TEX_LOD, "?", print_fetch_tex), 4657ec681f3Smrg INSTR(TEX_GET_GRADIENTS, "?", print_fetch_tex), 4667ec681f3Smrg INSTR(TEX_GET_WEIGHTS, "?", print_fetch_tex), 4677ec681f3Smrg INSTR(TEX_SET_TEX_LOD, "SET_TEX_LOD", print_fetch_tex), 4687ec681f3Smrg INSTR(TEX_SET_GRADIENTS_H, "?", print_fetch_tex), 4697ec681f3Smrg INSTR(TEX_SET_GRADIENTS_V, "?", print_fetch_tex), 4707ec681f3Smrg INSTR(TEX_RESERVED_4, "?", print_fetch_tex), 4717ec681f3Smrg#undef INSTR 4727ec681f3Smrg}; 4737ec681f3Smrg 4747ec681f3Smrgstatic int 4757ec681f3Smrgdisasm_fetch(uint32_t *dwords, uint32_t alu_off, int level, int sync) 4767ec681f3Smrg{ 4777ec681f3Smrg instr_fetch_t *fetch = (instr_fetch_t *)dwords; 4787ec681f3Smrg 4797ec681f3Smrg printf("%s", levels[level]); 4807ec681f3Smrg if (debug & PRINT_RAW) { 4817ec681f3Smrg printf("%02x: %08x %08x %08x\t", alu_off, dwords[0], dwords[1], 4827ec681f3Smrg dwords[2]); 4837ec681f3Smrg } 4847ec681f3Smrg 4857ec681f3Smrg printf(" %sFETCH:\t", sync ? "(S)" : " "); 4867ec681f3Smrg printf("%s", fetch_instructions[fetch->opc].name); 4877ec681f3Smrg fetch_instructions[fetch->opc].fxn(fetch); 4887ec681f3Smrg printf("\n"); 4897ec681f3Smrg 4907ec681f3Smrg return 0; 4917ec681f3Smrg} 4927ec681f3Smrg 4937ec681f3Smrg/* 4947ec681f3Smrg * CF instructions: 4957ec681f3Smrg */ 4967ec681f3Smrg 4977ec681f3Smrgstatic int 4987ec681f3Smrgcf_exec(instr_cf_t *cf) 4997ec681f3Smrg{ 5007ec681f3Smrg return (cf->opc == EXEC) || (cf->opc == EXEC_END) || 5017ec681f3Smrg (cf->opc == COND_EXEC) || (cf->opc == COND_EXEC_END) || 5027ec681f3Smrg (cf->opc == COND_PRED_EXEC) || (cf->opc == COND_PRED_EXEC_END) || 5037ec681f3Smrg (cf->opc == COND_EXEC_PRED_CLEAN) || 5047ec681f3Smrg (cf->opc == COND_EXEC_PRED_CLEAN_END); 5057ec681f3Smrg} 5067ec681f3Smrg 5077ec681f3Smrgstatic int 5087ec681f3Smrgcf_cond_exec(instr_cf_t *cf) 5097ec681f3Smrg{ 5107ec681f3Smrg return (cf->opc == COND_EXEC) || (cf->opc == COND_EXEC_END) || 5117ec681f3Smrg (cf->opc == COND_PRED_EXEC) || (cf->opc == COND_PRED_EXEC_END) || 5127ec681f3Smrg (cf->opc == COND_EXEC_PRED_CLEAN) || 5137ec681f3Smrg (cf->opc == COND_EXEC_PRED_CLEAN_END); 5147ec681f3Smrg} 5157ec681f3Smrg 5167ec681f3Smrgstatic void 5177ec681f3Smrgprint_cf_nop(instr_cf_t *cf) 5187ec681f3Smrg{ 5197ec681f3Smrg} 5207ec681f3Smrg 5217ec681f3Smrgstatic void 5227ec681f3Smrgprint_cf_exec(instr_cf_t *cf) 5237ec681f3Smrg{ 5247ec681f3Smrg printf(" ADDR(0x%x) CNT(0x%x)", cf->exec.address, cf->exec.count); 5257ec681f3Smrg if (cf->exec.yeild) 5267ec681f3Smrg printf(" YIELD"); 5277ec681f3Smrg if (cf->exec.vc) 5287ec681f3Smrg printf(" VC(0x%x)", cf->exec.vc); 5297ec681f3Smrg if (cf->exec.bool_addr) 5307ec681f3Smrg printf(" BOOL_ADDR(0x%x)", cf->exec.bool_addr); 5317ec681f3Smrg if (cf->exec.address_mode == ABSOLUTE_ADDR) 5327ec681f3Smrg printf(" ABSOLUTE_ADDR"); 5337ec681f3Smrg if (cf_cond_exec(cf)) 5347ec681f3Smrg printf(" COND(%d)", cf->exec.condition); 5357ec681f3Smrg} 5367ec681f3Smrg 5377ec681f3Smrgstatic void 5387ec681f3Smrgprint_cf_loop(instr_cf_t *cf) 5397ec681f3Smrg{ 5407ec681f3Smrg printf(" ADDR(0x%x) LOOP_ID(%d)", cf->loop.address, cf->loop.loop_id); 5417ec681f3Smrg if (cf->loop.address_mode == ABSOLUTE_ADDR) 5427ec681f3Smrg printf(" ABSOLUTE_ADDR"); 5437ec681f3Smrg} 5447ec681f3Smrg 5457ec681f3Smrgstatic void 5467ec681f3Smrgprint_cf_jmp_call(instr_cf_t *cf) 5477ec681f3Smrg{ 5487ec681f3Smrg printf(" ADDR(0x%x) DIR(%d)", cf->jmp_call.address, cf->jmp_call.direction); 5497ec681f3Smrg if (cf->jmp_call.force_call) 5507ec681f3Smrg printf(" FORCE_CALL"); 5517ec681f3Smrg if (cf->jmp_call.predicated_jmp) 5527ec681f3Smrg printf(" COND(%d)", cf->jmp_call.condition); 5537ec681f3Smrg if (cf->jmp_call.bool_addr) 5547ec681f3Smrg printf(" BOOL_ADDR(0x%x)", cf->jmp_call.bool_addr); 5557ec681f3Smrg if (cf->jmp_call.address_mode == ABSOLUTE_ADDR) 5567ec681f3Smrg printf(" ABSOLUTE_ADDR"); 5577ec681f3Smrg} 5587ec681f3Smrg 5597ec681f3Smrgstatic void 5607ec681f3Smrgprint_cf_alloc(instr_cf_t *cf) 5617ec681f3Smrg{ 5627ec681f3Smrg static const char *bufname[] = { 5637ec681f3Smrg [SQ_NO_ALLOC] = "NO ALLOC", 5647ec681f3Smrg [SQ_POSITION] = "POSITION", 5657ec681f3Smrg [SQ_PARAMETER_PIXEL] = "PARAM/PIXEL", 5667ec681f3Smrg [SQ_MEMORY] = "MEMORY", 5677ec681f3Smrg }; 5687ec681f3Smrg printf(" %s SIZE(0x%x)", bufname[cf->alloc.buffer_select], cf->alloc.size); 5697ec681f3Smrg if (cf->alloc.no_serial) 5707ec681f3Smrg printf(" NO_SERIAL"); 5717ec681f3Smrg if (cf->alloc.alloc_mode) // ??? 5727ec681f3Smrg printf(" ALLOC_MODE"); 5737ec681f3Smrg} 5747ec681f3Smrg 5757ec681f3Smrgstruct { 5767ec681f3Smrg const char *name; 5777ec681f3Smrg void (*fxn)(instr_cf_t *cf); 5787ec681f3Smrg} cf_instructions[] = { 5797ec681f3Smrg#define INSTR(opc, fxn) [opc] = {#opc, fxn} 5807ec681f3Smrg INSTR(NOP, print_cf_nop), 5817ec681f3Smrg INSTR(EXEC, print_cf_exec), 5827ec681f3Smrg INSTR(EXEC_END, print_cf_exec), 5837ec681f3Smrg INSTR(COND_EXEC, print_cf_exec), 5847ec681f3Smrg INSTR(COND_EXEC_END, print_cf_exec), 5857ec681f3Smrg INSTR(COND_PRED_EXEC, print_cf_exec), 5867ec681f3Smrg INSTR(COND_PRED_EXEC_END, print_cf_exec), 5877ec681f3Smrg INSTR(LOOP_START, print_cf_loop), 5887ec681f3Smrg INSTR(LOOP_END, print_cf_loop), 5897ec681f3Smrg INSTR(COND_CALL, print_cf_jmp_call), 5907ec681f3Smrg INSTR(RETURN, print_cf_jmp_call), 5917ec681f3Smrg INSTR(COND_JMP, print_cf_jmp_call), 5927ec681f3Smrg INSTR(ALLOC, print_cf_alloc), 5937ec681f3Smrg INSTR(COND_EXEC_PRED_CLEAN, print_cf_exec), 5947ec681f3Smrg INSTR(COND_EXEC_PRED_CLEAN_END, print_cf_exec), 5957ec681f3Smrg INSTR(MARK_VS_FETCH_DONE, print_cf_nop), // ?? 5967ec681f3Smrg#undef INSTR 5977ec681f3Smrg}; 5987ec681f3Smrg 5997ec681f3Smrgstatic void 6007ec681f3Smrgprint_cf(instr_cf_t *cf, int level) 6017ec681f3Smrg{ 6027ec681f3Smrg printf("%s", levels[level]); 6037ec681f3Smrg if (debug & PRINT_RAW) { 6047ec681f3Smrg uint16_t words[3]; 6057ec681f3Smrg memcpy(&words, cf, sizeof(words)); 6067ec681f3Smrg printf(" %04x %04x %04x \t", words[0], words[1], words[2]); 6077ec681f3Smrg } 6087ec681f3Smrg printf("%s", cf_instructions[cf->opc].name); 6097ec681f3Smrg cf_instructions[cf->opc].fxn(cf); 6107ec681f3Smrg printf("\n"); 6117ec681f3Smrg} 6127ec681f3Smrg 6137ec681f3Smrg/* 6147ec681f3Smrg * The adreno shader microcode consists of two parts: 6157ec681f3Smrg * 1) A CF (control-flow) program, at the header of the compiled shader, 6167ec681f3Smrg * which refers to ALU/FETCH instructions that follow it by address. 6177ec681f3Smrg * 2) ALU and FETCH instructions 6187ec681f3Smrg */ 6197ec681f3Smrg 6207ec681f3Smrgint 6217ec681f3Smrgdisasm_a2xx(uint32_t *dwords, int sizedwords, int level, gl_shader_stage type) 6227ec681f3Smrg{ 6237ec681f3Smrg instr_cf_t *cfs = (instr_cf_t *)dwords; 6247ec681f3Smrg int idx, max_idx; 6257ec681f3Smrg 6267ec681f3Smrg for (idx = 0;; idx++) { 6277ec681f3Smrg instr_cf_t *cf = &cfs[idx]; 6287ec681f3Smrg if (cf_exec(cf)) { 6297ec681f3Smrg max_idx = 2 * cf->exec.address; 6307ec681f3Smrg break; 6317ec681f3Smrg } 6327ec681f3Smrg } 6337ec681f3Smrg 6347ec681f3Smrg for (idx = 0; idx < max_idx; idx++) { 6357ec681f3Smrg instr_cf_t *cf = &cfs[idx]; 6367ec681f3Smrg 6377ec681f3Smrg print_cf(cf, level); 6387ec681f3Smrg 6397ec681f3Smrg if (cf_exec(cf)) { 6407ec681f3Smrg uint32_t sequence = cf->exec.serialize; 6417ec681f3Smrg uint32_t i; 6427ec681f3Smrg for (i = 0; i < cf->exec.count; i++) { 6437ec681f3Smrg uint32_t alu_off = (cf->exec.address + i); 6447ec681f3Smrg if (sequence & 0x1) { 6457ec681f3Smrg disasm_fetch(dwords + alu_off * 3, alu_off, level, 6467ec681f3Smrg sequence & 0x2); 6477ec681f3Smrg } else { 6487ec681f3Smrg disasm_alu(dwords + alu_off * 3, alu_off, level, sequence & 0x2, 6497ec681f3Smrg type); 6507ec681f3Smrg } 6517ec681f3Smrg sequence >>= 2; 6527ec681f3Smrg } 6537ec681f3Smrg } 6547ec681f3Smrg } 6557ec681f3Smrg 6567ec681f3Smrg return 0; 6577ec681f3Smrg} 6587ec681f3Smrg 6597ec681f3Smrgvoid 6607ec681f3Smrgdisasm_a2xx_set_debug(enum debug_t d) 6617ec681f3Smrg{ 6627ec681f3Smrg debug = d; 6637ec681f3Smrg} 664