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