Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Copyright (c) 2013 Rob Clark <robdclark@gmail.com>
  3.  *
  4.  * Permission is hereby granted, free of charge, to any person obtaining a
  5.  * copy of this software and associated documentation files (the "Software"),
  6.  * to deal in the Software without restriction, including without limitation
  7.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8.  * and/or sell copies of the Software, and to permit persons to whom the
  9.  * Software is furnished to do so, subject to the following conditions:
  10.  *
  11.  * The above copyright notice and this permission notice (including the next
  12.  * paragraph) shall be included in all copies or substantial portions of the
  13.  * Software.
  14.  *
  15.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  18.  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19.  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20.  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  21.  * SOFTWARE.
  22.  */
  23.  
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <stdint.h>
  27. #include <string.h>
  28. #include <assert.h>
  29.  
  30. #include <util/u_debug.h>
  31.  
  32. #include "disasm.h"
  33. #include "instr-a3xx.h"
  34.  
  35. static enum debug_t debug;
  36.  
  37. #define printf debug_printf
  38.  
  39. static const char *levels[] = {
  40.                 "",
  41.                 "\t",
  42.                 "\t\t",
  43.                 "\t\t\t",
  44.                 "\t\t\t\t",
  45.                 "\t\t\t\t\t",
  46.                 "\t\t\t\t\t\t",
  47.                 "\t\t\t\t\t\t\t",
  48.                 "\t\t\t\t\t\t\t\t",
  49.                 "\t\t\t\t\t\t\t\t\t",
  50.                 "x",
  51.                 "x",
  52.                 "x",
  53.                 "x",
  54.                 "x",
  55.                 "x",
  56. };
  57.  
  58. static const char *component = "xyzw";
  59.  
  60. static const char *type[] = {
  61.                 [TYPE_F16] = "f16",
  62.                 [TYPE_F32] = "f32",
  63.                 [TYPE_U16] = "u16",
  64.                 [TYPE_U32] = "u32",
  65.                 [TYPE_S16] = "s16",
  66.                 [TYPE_S32] = "s32",
  67.                 [TYPE_U8]  = "u8",
  68.                 [TYPE_S8]  = "s8",
  69. };
  70.  
  71. static void print_reg(reg_t reg, bool full, bool r, bool c, bool im,
  72.                 bool neg, bool abs, bool addr_rel)
  73. {
  74.         const char type = c ? 'c' : 'r';
  75.  
  76.         // XXX I prefer - and || for neg/abs, but preserving format used
  77.         // by libllvm-a3xx for easy diffing..
  78.  
  79.         if (abs && neg)
  80.                 printf("(absneg)");
  81.         else if (neg)
  82.                 printf("(neg)");
  83.         else if (abs)
  84.                 printf("(abs)");
  85.  
  86.         if (r)
  87.                 printf("(r)");
  88.  
  89.         if (im) {
  90.                 printf("%d", reg.iim_val);
  91.         } else if (addr_rel) {
  92.                 /* I would just use %+d but trying to make it diff'able with
  93.                  * libllvm-a3xx...
  94.                  */
  95.                 if (reg.iim_val < 0)
  96.                         printf("%s%c<a0.x - %d>", full ? "" : "h", type, -reg.iim_val);
  97.                 else if (reg.iim_val > 0)
  98.                         printf("%s%c<a0.x + %d>", full ? "" : "h", type, reg.iim_val);
  99.                 else
  100.                         printf("%s%c<a0.x>", full ? "" : "h", type);
  101.         } else if ((reg.num == REG_A0) && !c) {
  102.                 printf("a0.%c", component[reg.comp]);
  103.         } else if ((reg.num == REG_P0) && !c) {
  104.                 printf("p0.%c", component[reg.comp]);
  105.         } else {
  106.                 printf("%s%c%d.%c", full ? "" : "h", type, reg.num, component[reg.comp]);
  107.         }
  108. }
  109.  
  110. /* Tracking for registers used, read-before-write (input), and
  111.  * write-after-read (output.. but not 100%)..
  112.  */
  113.  
  114. #define MAX_REG 128
  115.  
  116. typedef struct {
  117.         uint8_t full[MAX_REG/8];
  118.         uint8_t half[MAX_REG/8];
  119. } regmask_t;
  120.  
  121. static void regmask_set(regmask_t *regmask, unsigned num, bool full, unsigned val)
  122. {
  123.         unsigned i = num / 8;
  124.         unsigned j = num % 8;
  125.         assert(num < MAX_REG);
  126.         if (full) {
  127.                 regmask->full[i] = (regmask->full[i] & ~(1 << j)) | (val << j);
  128.         } else {
  129.                 regmask->half[i] = (regmask->half[i] & ~(1 << j)) | (val << j);
  130.         }
  131. }
  132.  
  133. static unsigned regmask_get(regmask_t *regmask, unsigned num, bool full)
  134. {
  135.         unsigned i = num / 8;
  136.         unsigned j = num % 8;
  137.         assert(num < MAX_REG);
  138.         if (full) {
  139.                 return (regmask->full[i] >> j) & 0x1;
  140.         } else {
  141.                 return (regmask->half[i] >> j) & 0x1;
  142.         }
  143. }
  144.  
  145. static unsigned regidx(reg_t reg)
  146. {
  147.         return (4 * reg.num) + reg.comp;
  148. }
  149.  
  150. static struct {
  151.         regmask_t used;
  152.         regmask_t rbw;      /* read before write */
  153.         regmask_t war;      /* write after read */
  154.         regmask_t cnst;     /* used consts */
  155. } regs;
  156.  
  157. static void print_regs(regmask_t *regmask, bool full)
  158. {
  159.         int num, max = 0, cnt = 0;
  160.         int first, last;
  161.  
  162.         void print_sequence(void)
  163.         {
  164.                 if (first != MAX_REG) {
  165.                         if (first == last) {
  166.                                 printf(" %d", first);
  167.                         } else {
  168.                                 printf(" %d-%d", first, last);
  169.                         }
  170.                 }
  171.         }
  172.  
  173.         first = last = MAX_REG;
  174.  
  175.         for (num = 0; num < MAX_REG; num++) {
  176.                 if (regmask_get(regmask, num, full)) {
  177.                         if (num != (last + 1)) {
  178.                                 print_sequence();
  179.                                 first = num;
  180.                         }
  181.                         last = num;
  182.                         max = num;
  183.                         cnt++;
  184.                 }
  185.         }
  186.  
  187.         print_sequence();
  188.  
  189.         printf(" (cnt=%d, max=%d)", cnt, max);
  190. }
  191.  
  192. static void print_reg_stats(int level)
  193. {
  194.         printf("%sRegister Stats:\n", levels[level]);
  195.         printf("%s- used (half):", levels[level]);
  196.         print_regs(&regs.used, false);
  197.         printf("\n");
  198.         printf("%s- used (full):", levels[level]);
  199.         print_regs(&regs.used, true);
  200.         printf("\n");
  201.         printf("%s- input (half):", levels[level]);
  202.         print_regs(&regs.rbw, false);
  203.         printf("\n");
  204.         printf("%s- input (full):", levels[level]);
  205.         print_regs(&regs.rbw, true);
  206.         printf("\n");
  207.         printf("%s- const (half):", levels[level]);
  208.         print_regs(&regs.cnst, false);
  209.         printf("\n");
  210.         printf("%s- const (full):", levels[level]);
  211.         print_regs(&regs.cnst, true);
  212.         printf("\n");
  213.         printf("%s- output (half):", levels[level]);
  214.         print_regs(&regs.war, false);
  215.         printf("  (estimated)\n");
  216.         printf("%s- output (full):", levels[level]);
  217.         print_regs(&regs.war, true);
  218.         printf("  (estimated)\n");
  219. }
  220.  
  221. /* we have to process the dst register after src to avoid tripping up
  222.  * the read-before-write detection
  223.  */
  224. static unsigned last_dst;
  225. static bool last_dst_full;
  226. static bool last_dst_valid = false;
  227.  
  228. /* current instruction repeat flag: */
  229. static unsigned repeat;
  230.  
  231. static void process_reg_dst(void)
  232. {
  233.         int i;
  234.  
  235.         if (!last_dst_valid)
  236.                 return;
  237.  
  238.         for (i = 0; i <= repeat; i++) {
  239.                 unsigned dst = last_dst + i;
  240.  
  241.                 regmask_set(&regs.war, dst, last_dst_full, 1);
  242.                 regmask_set(&regs.used, dst, last_dst_full, 1);
  243.         }
  244.  
  245.         last_dst_valid = false;
  246. }
  247.  
  248. static void print_reg_dst(reg_t reg, bool full, bool addr_rel)
  249. {
  250.         /* presumably the special registers a0.c and p0.c don't count.. */
  251.         if (!(addr_rel || reg_special(reg))) {
  252.                 last_dst = regidx(reg);
  253.                 last_dst_full = full;
  254.                 last_dst_valid = true;
  255.         }
  256.         print_reg(reg, full, false, false, false, false, false, addr_rel);
  257. }
  258.  
  259. static void print_reg_src(reg_t reg, bool full, bool r, bool c, bool im,
  260.                 bool neg, bool abs, bool addr_rel)
  261. {
  262.         /* presumably the special registers a0.c and p0.c don't count.. */
  263.         if (!(addr_rel || c || im || reg_special(reg))) {
  264.                 int i, num = regidx(reg);
  265.                 for (i = 0; i <= repeat; i++) {
  266.                         unsigned src = num + i;
  267.  
  268.                         if (!regmask_get(&regs.used, src, full))
  269.                                 regmask_set(&regs.rbw, src, full, 1);
  270.  
  271.                         regmask_set(&regs.war, src, full, 0);
  272.                         regmask_set(&regs.used, src, full, 1);
  273.  
  274.                         if (!r)
  275.                                 break;
  276.                 }
  277.         } else if (c) {
  278.                 int i, num = regidx(reg);
  279.                 for (i = 0; i <= repeat; i++) {
  280.                         unsigned src = num + i;
  281.  
  282.                         regmask_set(&regs.cnst, src, full, 1);
  283.  
  284.                         if (!r)
  285.                                 break;
  286.                 }
  287.         }
  288.  
  289.         print_reg(reg, full, r, c, im, neg, abs, addr_rel);
  290. }
  291.  
  292.  
  293. static void print_instr_cat0(instr_t *instr)
  294. {
  295.         instr_cat0_t *cat0 = &instr->cat0;
  296.  
  297.         switch (cat0->opc) {
  298.         case OPC_KILL:
  299.                 printf(" %sp0.%c", cat0->inv ? "!" : "",
  300.                                 component[cat0->comp]);
  301.                 break;
  302.         case OPC_BR:
  303.                 printf(" %sp0.%c, #%d", cat0->inv ? "!" : "",
  304.                                 component[cat0->comp], cat0->immed);
  305.                 break;
  306.         case OPC_JUMP:
  307.         case OPC_CALL:
  308.                 printf(" #%d", cat0->immed);
  309.                 break;
  310.         }
  311.  
  312.         if ((debug & PRINT_VERBOSE) && (cat0->dummy1|cat0->dummy2|cat0->dummy3|cat0->dummy4))
  313.                 printf("\t{0: %x,%x,%x,%x}", cat0->dummy1, cat0->dummy2, cat0->dummy3, cat0->dummy4);
  314. }
  315.  
  316. static void print_instr_cat1(instr_t *instr)
  317. {
  318.         instr_cat1_t *cat1 = &instr->cat1;
  319.  
  320.         // XXX maybe a bug in libllvm disassembler?
  321.         if (cat1->src_rel)
  322.                 printf("(ul)");
  323.  
  324.         if (cat1->src_type == cat1->dst_type) {
  325.                 if ((cat1->src_type == TYPE_S16) && (((reg_t)cat1->dst).num == REG_A0)) {
  326.                         /* special case (nmemonic?): */
  327.                         printf("mova");
  328.                 } else {
  329.                         printf("mov.%s%s", type[cat1->src_type], type[cat1->dst_type]);
  330.                 }
  331.         } else {
  332.                 printf("cov.%s%s", type[cat1->src_type], type[cat1->dst_type]);
  333.         }
  334.  
  335.         printf(" ");
  336.  
  337.         if (cat1->even)
  338.                 printf("(even)");
  339.  
  340.         if (cat1->pos_inf)
  341.                 printf("(pos_infinity)");
  342.  
  343.         print_reg_dst((reg_t)(cat1->dst), type_size(cat1->dst_type) == 32,
  344.                         cat1->dst_rel);
  345.  
  346.         printf(", ");
  347.  
  348.         /* ugg, have to special case this.. vs print_reg().. */
  349.         if (cat1->src_im) {
  350.                 if (type_float(cat1->src_type))
  351.                         printf("(%f)", cat1->fim_val);
  352.                 else
  353.                         printf("%d", cat1->iim_val);
  354.         } else if (cat1->src_rel && !cat1->src_c) {
  355.                 /* I would just use %+d but trying to make it diff'able with
  356.                  * libllvm-a3xx...
  357.                  */
  358.                 if (cat1->off < 0)
  359.                         printf("c<a0.x - %d>", -cat1->off);
  360.                 else if (cat1->off > 0)
  361.                         printf("c<a0.x + %d>", cat1->off);
  362.                 else
  363.                         printf("c<a0.x>");
  364.         } else {
  365.                 print_reg_src((reg_t)(cat1->src), type_size(cat1->src_type) == 32,
  366.                                 cat1->src_r, cat1->src_c, cat1->src_im, false, false, false);
  367.         }
  368.  
  369.         if ((debug & PRINT_VERBOSE) && (cat1->must_be_0))
  370.                 printf("\t{1: %x}", cat1->must_be_0);
  371. }
  372.  
  373. static void print_instr_cat2(instr_t *instr)
  374. {
  375.         instr_cat2_t *cat2 = &instr->cat2;
  376.         static const char *cond[] = {
  377.                         "lt",
  378.                         "le",
  379.                         "gt",
  380.                         "ge",
  381.                         "eq",
  382.                         "ne",
  383.                         "?6?",
  384.         };
  385.  
  386.         switch (cat2->opc) {
  387.         case OPC_CMPS_F:
  388.         case OPC_CMPS_U:
  389.         case OPC_CMPS_S:
  390.         case OPC_CMPV_F:
  391.         case OPC_CMPV_U:
  392.         case OPC_CMPV_S:
  393.                 printf(".%s", cond[cat2->cond]);
  394.                 break;
  395.         }
  396.  
  397.         printf(" ");
  398.         if (cat2->ei)
  399.                 printf("(ei)");
  400.         print_reg_dst((reg_t)(cat2->dst), cat2->full ^ cat2->dst_half, false);
  401.         printf(", ");
  402.         print_reg_src((reg_t)(cat2->src1), cat2->full, cat2->src1_r,
  403.                         cat2->src1_c, cat2->src1_im, cat2->src1_neg,
  404.                         cat2->src1_abs, cat2->src1_rel);
  405.         switch (cat2->opc) {
  406.         case OPC_ABSNEG_F:
  407.         case OPC_ABSNEG_S:
  408.         case OPC_CLZ_B:
  409.         case OPC_CLZ_S:
  410.         case OPC_SIGN_F:
  411.         case OPC_FLOOR_F:
  412.         case OPC_CEIL_F:
  413.         case OPC_RNDNE_F:
  414.         case OPC_RNDAZ_F:
  415.         case OPC_TRUNC_F:
  416.         case OPC_NOT_B:
  417.         case OPC_BFREV_B:
  418.         case OPC_SETRM:
  419.         case OPC_CBITS_B:
  420.                 /* these only have one src reg */
  421.                 break;
  422.         default:
  423.                 printf(", ");
  424.                 print_reg_src((reg_t)(cat2->src2), cat2->full, cat2->src2_r,
  425.                                 cat2->src2_c, cat2->src2_im, cat2->src2_neg,
  426.                                 cat2->src2_abs, cat2->src2_rel);
  427.                 break;
  428.         }
  429. }
  430.  
  431. static void print_instr_cat3(instr_t *instr)
  432. {
  433.         instr_cat3_t *cat3 = &instr->cat3;
  434.         bool full = true;
  435.  
  436.         // XXX is this based on opc or some other bit?
  437.         switch (cat3->opc) {
  438.         case OPC_MAD_F16:
  439.         case OPC_MAD_U16:
  440.         case OPC_MAD_S16:
  441.         case OPC_SEL_B16:
  442.         case OPC_SEL_S16:
  443.         case OPC_SEL_F16:
  444.         case OPC_SAD_S16:
  445.         case OPC_SAD_S32:  // really??
  446.                 full = false;
  447.                 break;
  448.         }
  449.  
  450.         printf(" ");
  451.         print_reg_dst((reg_t)(cat3->dst), full ^ cat3->dst_half, false);
  452.         printf(", ");
  453.         print_reg_src((reg_t)(cat3->src1), full,
  454.                         cat3->src1_r, cat3->src1_c, false, cat3->src1_neg,
  455.                         false, cat3->src1_rel);
  456.         printf(", ");
  457.         print_reg_src((reg_t)cat3->src2, full,
  458.                         cat3->src2_r, cat3->src2_c, false, cat3->src2_neg,
  459.                         false, false);
  460.         printf(", ");
  461.         print_reg_src((reg_t)(cat3->src3), full,
  462.                         cat3->src3_r, cat3->src3_c, false, cat3->src3_neg,
  463.                         false, cat3->src3_rel);
  464. }
  465.  
  466. static void print_instr_cat4(instr_t *instr)
  467. {
  468.         instr_cat4_t *cat4 = &instr->cat4;
  469.  
  470.         printf(" ");
  471.         print_reg_dst((reg_t)(cat4->dst), cat4->full ^ cat4->dst_half, false);
  472.         printf(", ");
  473.         print_reg_src((reg_t)(cat4->src), cat4->full,
  474.                         cat4->src_r, cat4->src_c, cat4->src_im,
  475.                         cat4->src_neg, cat4->src_abs, cat4->src_rel);
  476.  
  477.         if ((debug & PRINT_VERBOSE) && (cat4->dummy1|cat4->dummy2))
  478.                 printf("\t{4: %x,%x}", cat4->dummy1, cat4->dummy2);
  479. }
  480.  
  481. static void print_instr_cat5(instr_t *instr)
  482. {
  483.         static const struct {
  484.                 bool src1, src2, samp, tex;
  485.         } info[0x1f] = {
  486.                         [OPC_ISAM]     = { true,  false, true,  true,  },
  487.                         [OPC_ISAML]    = { true,  true,  true,  true,  },
  488.                         [OPC_ISAMM]    = { true,  false, true,  true,  },
  489.                         [OPC_SAM]      = { true,  false, true,  true,  },
  490.                         [OPC_SAMB]     = { true,  true,  true,  true,  },
  491.                         [OPC_SAML]     = { true,  true,  true,  true,  },
  492.                         [OPC_SAMGQ]    = { true,  false, true,  true,  },
  493.                         [OPC_GETLOD]   = { true,  false, true,  true,  },
  494.                         [OPC_CONV]     = { true,  true,  true,  true,  },
  495.                         [OPC_CONVM]    = { true,  true,  true,  true,  },
  496.                         [OPC_GETSIZE]  = { true,  false, false, true,  },
  497.                         [OPC_GETBUF]   = { false, false, false, true,  },
  498.                         [OPC_GETPOS]   = { true,  false, false, true,  },
  499.                         [OPC_GETINFO]  = { false, false, false, true,  },
  500.                         [OPC_DSX]      = { true,  false, false, false, },
  501.                         [OPC_DSY]      = { true,  false, false, false, },
  502.                         [OPC_GATHER4R] = { true,  false, true,  true,  },
  503.                         [OPC_GATHER4G] = { true,  false, true,  true,  },
  504.                         [OPC_GATHER4B] = { true,  false, true,  true,  },
  505.                         [OPC_GATHER4A] = { true,  false, true,  true,  },
  506.                         [OPC_SAMGP0]   = { true,  false, true,  true,  },
  507.                         [OPC_SAMGP1]   = { true,  false, true,  true,  },
  508.                         [OPC_SAMGP2]   = { true,  false, true,  true,  },
  509.                         [OPC_SAMGP3]   = { true,  false, true,  true,  },
  510.                         [OPC_DSXPP_1]  = { true,  false, false, false, },
  511.                         [OPC_DSYPP_1]  = { true,  false, false, false, },
  512.                         [OPC_RGETPOS]  = { false, false, false, false, },
  513.                         [OPC_RGETINFO] = { false, false, false, false, },
  514.         };
  515.         instr_cat5_t *cat5 = &instr->cat5;
  516.         int i;
  517.  
  518.         if (cat5->is_3d)   printf(".3d");
  519.         if (cat5->is_a)    printf(".a");
  520.         if (cat5->is_o)    printf(".o");
  521.         if (cat5->is_p)    printf(".p");
  522.         if (cat5->is_s)    printf(".s");
  523.         if (cat5->is_s2en) printf(".s2en");
  524.  
  525.         printf(" ");
  526.  
  527.         switch (cat5->opc) {
  528.         case OPC_DSXPP_1:
  529.         case OPC_DSYPP_1:
  530.                 break;
  531.         default:
  532.                 printf("(%s)", type[cat5->type]);
  533.                 break;
  534.         }
  535.  
  536.         printf("(");
  537.         for (i = 0; i < 4; i++)
  538.                 if (cat5->wrmask & (1 << i))
  539.                         printf("%c", "xyzw"[i]);
  540.         printf(")");
  541.  
  542.         print_reg_dst((reg_t)(cat5->dst), type_size(cat5->type) == 32, false);
  543.  
  544.         if (info[cat5->opc].src1) {
  545.                 printf(", ");
  546.                 print_reg_src((reg_t)(cat5->src1), cat5->full, false, false, false,
  547.                                 false, false, false);
  548.         }
  549.  
  550.         if (cat5->is_s2en) {
  551.                 printf(", ");
  552.                 print_reg_src((reg_t)(cat5->s2en.src2), cat5->full, false, false, false,
  553.                                 false, false, false);
  554.                 printf(", ");
  555.                 print_reg_src((reg_t)(cat5->s2en.src3), false, false, false, false,
  556.                                 false, false, false);
  557.         } else {
  558.                 if (cat5->is_o || info[cat5->opc].src2) {
  559.                         printf(", ");
  560.                         print_reg_src((reg_t)(cat5->norm.src2), cat5->full,
  561.                                         false, false, false, false, false, false);
  562.                 }
  563.                 if (info[cat5->opc].samp)
  564.                         printf(", s#%d", cat5->norm.samp);
  565.                 if (info[cat5->opc].tex)
  566.                         printf(", t#%d", cat5->norm.tex);
  567.         }
  568.  
  569.         if (debug & PRINT_VERBOSE) {
  570.                 if (cat5->is_s2en) {
  571.                         if ((debug & PRINT_VERBOSE) && (cat5->s2en.dummy1|cat5->s2en.dummy2|cat5->dummy2))
  572.                                 printf("\t{5: %x,%x,%x}", cat5->s2en.dummy1, cat5->s2en.dummy2, cat5->dummy2);
  573.                 } else {
  574.                         if ((debug & PRINT_VERBOSE) && (cat5->norm.dummy1|cat5->dummy2))
  575.                                 printf("\t{5: %x,%x}", cat5->norm.dummy1, cat5->dummy2);
  576.                 }
  577.         }
  578. }
  579.  
  580. static int32_t u2i(uint32_t val, int nbits)
  581. {
  582.         return ((val >> (nbits-1)) * ~((1 << nbits) - 1)) | val;
  583. }
  584.  
  585. static void print_instr_cat6(instr_t *instr)
  586. {
  587.         instr_cat6_t *cat6 = &instr->cat6;
  588.  
  589.         printf(".%s ", type[cat6->type]);
  590.  
  591.         switch (cat6->opc) {
  592.         case OPC_LDG:
  593.         case OPC_LDP:
  594.         case OPC_LDL:
  595.         case OPC_LDLW:
  596.         case OPC_LDLV:
  597.                 /* load instructions: */
  598.                 print_reg_dst((reg_t)(cat6->a.dst), type_size(cat6->type) == 32, false);
  599.                 printf(",");
  600.                 switch (cat6->opc) {
  601.                 case OPC_LDG:
  602.                         printf("g");
  603.                         break;
  604.                 case OPC_LDP:
  605.                         printf("p");
  606.                         break;
  607.                 case OPC_LDL:
  608.                 case OPC_LDLW:
  609.                 case OPC_LDLV:
  610.                         printf("l");
  611.                         break;
  612.                 }
  613.                 printf("[");
  614.                 print_reg_src((reg_t)(cat6->a.src), true,
  615.                                 false, false, false, false, false, false);
  616.                 if (cat6->a.off)
  617.                         printf("%+d", cat6->a.off);
  618.                 printf("]");
  619.                 break;
  620.         case OPC_PREFETCH:
  621.                 /* similar to load instructions: */
  622.                 printf("g[");
  623.                 print_reg_src((reg_t)(cat6->a.src), true,
  624.                                 false, false, false, false, false, false);
  625.                 if (cat6->a.off)
  626.                         printf("%+d", cat6->a.off);
  627.                 printf("]");
  628.                 break;
  629.         case OPC_STG:
  630.         case OPC_STP:
  631.         case OPC_STL:
  632.         case OPC_STLW:
  633.                 /* store instructions: */
  634.                 switch (cat6->opc) {
  635.                 case OPC_STG:
  636.                         printf("g");
  637.                         break;
  638.                 case OPC_STP:
  639.                         printf("p");
  640.                         break;
  641.                 case OPC_STL:
  642.                 case OPC_STLW:
  643.                         printf("l");
  644.                         break;
  645.                 }
  646.                 printf("[");
  647.                 print_reg_dst((reg_t)(cat6->b.dst), true, false);
  648.                 if (cat6->b.off || cat6->b.off_hi)
  649.                         printf("%+d", u2i((cat6->b.off_hi << 8) | cat6->b.off, 13));
  650.                 printf("]");
  651.                 printf(",");
  652.                 print_reg_src((reg_t)(cat6->b.src), type_size(cat6->type) == 32,
  653.                                 false, false, false, false, false, false);
  654.  
  655.                 break;
  656.         case OPC_STI:
  657.                 /* sti has same encoding as other store instructions, but
  658.                  * slightly different syntax:
  659.                  */
  660.                 print_reg_dst((reg_t)(cat6->b.dst), false /* XXX is it always half? */, false);
  661.                 if (cat6->b.off || cat6->b.off_hi)
  662.                         printf("%+d", u2i((cat6->b.off_hi << 8) | cat6->b.off, 13));
  663.                 printf(",");
  664.                 print_reg_src((reg_t)(cat6->b.src), type_size(cat6->type) == 32,
  665.                                 false, false, false, false, false, false);
  666.                 break;
  667.         }
  668.  
  669.         printf(", %d", cat6->iim_val);
  670.  
  671.         if (debug & PRINT_VERBOSE) {
  672.                 switch (cat6->opc) {
  673.                 case OPC_LDG:
  674.                 case OPC_LDP:
  675.                         /* load instructions: */
  676.                         if (cat6->a.dummy1|cat6->a.dummy2|cat6->a.dummy3)
  677.                                 printf("\t{6: %x,%x,%x}", cat6->a.dummy1, cat6->a.dummy2, cat6->a.dummy3);
  678.                         if ((cat6->a.must_be_one1 != 1) || (cat6->a.must_be_one2 != 1))
  679.                                 printf("{?? %d,%d ??}", cat6->a.must_be_one1, cat6->a.must_be_one2);
  680.                         break;
  681.                 case OPC_STG:
  682.                 case OPC_STP:
  683.                 case OPC_STI:
  684.                         /* store instructions: */
  685.                         if (cat6->b.dummy1|cat6->b.dummy2)
  686.                                 printf("\t{6: %x,%x}", cat6->b.dummy1, cat6->b.dummy2);
  687.                         if ((cat6->b.must_be_one1 != 1) || (cat6->b.must_be_one2 != 1) ||
  688.                                         (cat6->b.must_be_zero1 != 0))
  689.                                 printf("{?? %d,%d,%d ??}", cat6->b.must_be_one1, cat6->b.must_be_one2,
  690.                                                 cat6->b.must_be_zero1);
  691.                         break;
  692.                 }
  693.         }
  694. }
  695.  
  696. /* size of largest OPC field of all the instruction categories: */
  697. #define NOPC_BITS 6
  698.  
  699. struct opc_info {
  700.         uint16_t cat;
  701.         uint16_t opc;
  702.         const char *name;
  703.         void (*print)(instr_t *instr);
  704. } opcs[1 << (3+NOPC_BITS)] = {
  705. #define OPC(cat, opc, name) [((cat) << NOPC_BITS) | (opc)] = { (cat), (opc), #name, print_instr_cat##cat }
  706.         /* category 0: */
  707.         OPC(0, OPC_NOP,          nop),
  708.         OPC(0, OPC_BR,           br),
  709.         OPC(0, OPC_JUMP,         jump),
  710.         OPC(0, OPC_CALL,         call),
  711.         OPC(0, OPC_RET,          ret),
  712.         OPC(0, OPC_KILL,         kill),
  713.         OPC(0, OPC_END,          end),
  714.         OPC(0, OPC_EMIT,         emit),
  715.         OPC(0, OPC_CUT,          cut),
  716.         OPC(0, OPC_CHMASK,       chmask),
  717.         OPC(0, OPC_CHSH,         chsh),
  718.         OPC(0, OPC_FLOW_REV,     flow_rev),
  719.  
  720.         /* category 1: */
  721.         OPC(1, 0, ),
  722.  
  723.         /* category 2: */
  724.         OPC(2, OPC_ADD_F,        add.f),
  725.         OPC(2, OPC_MIN_F,        min.f),
  726.         OPC(2, OPC_MAX_F,        max.f),
  727.         OPC(2, OPC_MUL_F,        mul.f),
  728.         OPC(2, OPC_SIGN_F,       sign.f),
  729.         OPC(2, OPC_CMPS_F,       cmps.f),
  730.         OPC(2, OPC_ABSNEG_F,     absneg.f),
  731.         OPC(2, OPC_CMPV_F,       cmpv.f),
  732.         OPC(2, OPC_FLOOR_F,      floor.f),
  733.         OPC(2, OPC_CEIL_F,       ceil.f),
  734.         OPC(2, OPC_RNDNE_F,      rndne.f),
  735.         OPC(2, OPC_RNDAZ_F,      rndaz.f),
  736.         OPC(2, OPC_TRUNC_F,      trunc.f),
  737.         OPC(2, OPC_ADD_U,        add.u),
  738.         OPC(2, OPC_ADD_S,        add.s),
  739.         OPC(2, OPC_SUB_U,        sub.u),
  740.         OPC(2, OPC_SUB_S,        sub.s),
  741.         OPC(2, OPC_CMPS_U,       cmps.u),
  742.         OPC(2, OPC_CMPS_S,       cmps.s),
  743.         OPC(2, OPC_MIN_U,        min.u),
  744.         OPC(2, OPC_MIN_S,        min.s),
  745.         OPC(2, OPC_MAX_U,        max.u),
  746.         OPC(2, OPC_MAX_S,        max.s),
  747.         OPC(2, OPC_ABSNEG_S,     absneg.s),
  748.         OPC(2, OPC_AND_B,        and.b),
  749.         OPC(2, OPC_OR_B,         or.b),
  750.         OPC(2, OPC_NOT_B,        not.b),
  751.         OPC(2, OPC_XOR_B,        xor.b),
  752.         OPC(2, OPC_CMPV_U,       cmpv.u),
  753.         OPC(2, OPC_CMPV_S,       cmpv.s),
  754.         OPC(2, OPC_MUL_U,        mul.u),
  755.         OPC(2, OPC_MUL_S,        mul.s),
  756.         OPC(2, OPC_MULL_U,       mull.u),
  757.         OPC(2, OPC_BFREV_B,      bfrev.b),
  758.         OPC(2, OPC_CLZ_S,        clz.s),
  759.         OPC(2, OPC_CLZ_B,        clz.b),
  760.         OPC(2, OPC_SHL_B,        shl.b),
  761.         OPC(2, OPC_SHR_B,        shr.b),
  762.         OPC(2, OPC_ASHR_B,       ashr.b),
  763.         OPC(2, OPC_BARY_F,       bary.f),
  764.         OPC(2, OPC_MGEN_B,       mgen.b),
  765.         OPC(2, OPC_GETBIT_B,     getbit.b),
  766.         OPC(2, OPC_SETRM,        setrm),
  767.         OPC(2, OPC_CBITS_B,      cbits.b),
  768.         OPC(2, OPC_SHB,          shb),
  769.         OPC(2, OPC_MSAD,         msad),
  770.  
  771.         /* category 3: */
  772.         OPC(3, OPC_MAD_U16,      mad.u16),
  773.         OPC(3, OPC_MADSH_U16,    madsh.u16),
  774.         OPC(3, OPC_MAD_S16,      mad.s16),
  775.         OPC(3, OPC_MADSH_M16,    madsh.m16),
  776.         OPC(3, OPC_MAD_U24,      mad.u24),
  777.         OPC(3, OPC_MAD_S24,      mad.s24),
  778.         OPC(3, OPC_MAD_F16,      mad.f16),
  779.         OPC(3, OPC_MAD_F32,      mad.f32),
  780.         OPC(3, OPC_SEL_B16,      sel.b16),
  781.         OPC(3, OPC_SEL_B32,      sel.b32),
  782.         OPC(3, OPC_SEL_S16,      sel.s16),
  783.         OPC(3, OPC_SEL_S32,      sel.s32),
  784.         OPC(3, OPC_SEL_F16,      sel.f16),
  785.         OPC(3, OPC_SEL_F32,      sel.f32),
  786.         OPC(3, OPC_SAD_S16,      sad.s16),
  787.         OPC(3, OPC_SAD_S32,      sad.s32),
  788.  
  789.         /* category 4: */
  790.         OPC(4, OPC_RCP,          rcp),
  791.         OPC(4, OPC_RSQ,          rsq),
  792.         OPC(4, OPC_LOG2,         log2),
  793.         OPC(4, OPC_EXP2,         exp2),
  794.         OPC(4, OPC_SIN,          sin),
  795.         OPC(4, OPC_COS,          cos),
  796.         OPC(4, OPC_SQRT,         sqrt),
  797.  
  798.         /* category 5: */
  799.         OPC(5, OPC_ISAM,         isam),
  800.         OPC(5, OPC_ISAML,        isaml),
  801.         OPC(5, OPC_ISAMM,        isamm),
  802.         OPC(5, OPC_SAM,          sam),
  803.         OPC(5, OPC_SAMB,         samb),
  804.         OPC(5, OPC_SAML,         saml),
  805.         OPC(5, OPC_SAMGQ,        samgq),
  806.         OPC(5, OPC_GETLOD,       getlod),
  807.         OPC(5, OPC_CONV,         conv),
  808.         OPC(5, OPC_CONVM,        convm),
  809.         OPC(5, OPC_GETSIZE,      getsize),
  810.         OPC(5, OPC_GETBUF,       getbuf),
  811.         OPC(5, OPC_GETPOS,       getpos),
  812.         OPC(5, OPC_GETINFO,      getinfo),
  813.         OPC(5, OPC_DSX,          dsx),
  814.         OPC(5, OPC_DSY,          dsy),
  815.         OPC(5, OPC_GATHER4R,     gather4r),
  816.         OPC(5, OPC_GATHER4G,     gather4g),
  817.         OPC(5, OPC_GATHER4B,     gather4b),
  818.         OPC(5, OPC_GATHER4A,     gather4a),
  819.         OPC(5, OPC_SAMGP0,       samgp0),
  820.         OPC(5, OPC_SAMGP1,       samgp1),
  821.         OPC(5, OPC_SAMGP2,       samgp2),
  822.         OPC(5, OPC_SAMGP3,       samgp3),
  823.         OPC(5, OPC_DSXPP_1,      dsxpp.1),
  824.         OPC(5, OPC_DSYPP_1,      dsypp.1),
  825.         OPC(5, OPC_RGETPOS,      rgetpos),
  826.         OPC(5, OPC_RGETINFO,     rgetinfo),
  827.  
  828.  
  829.         /* category 6: */
  830.         OPC(6, OPC_LDG,          ldg),
  831.         OPC(6, OPC_LDL,          ldl),
  832.         OPC(6, OPC_LDP,          ldp),
  833.         OPC(6, OPC_STG,          stg),
  834.         OPC(6, OPC_STL,          stl),
  835.         OPC(6, OPC_STP,          stp),
  836.         OPC(6, OPC_STI,          sti),
  837.         OPC(6, OPC_G2L,          g2l),
  838.         OPC(6, OPC_L2G,          l2g),
  839.         OPC(6, OPC_PREFETCH,     prefetch),
  840.         OPC(6, OPC_LDLW,         ldlw),
  841.         OPC(6, OPC_STLW,         stlw),
  842.         OPC(6, OPC_RESFMT,       resfmt),
  843.         OPC(6, OPC_RESINFO,      resinf),
  844.         OPC(6, OPC_ATOMIC_ADD_L,     atomic.add.l),
  845.         OPC(6, OPC_ATOMIC_SUB_L,     atomic.sub.l),
  846.         OPC(6, OPC_ATOMIC_XCHG_L,    atomic.xchg.l),
  847.         OPC(6, OPC_ATOMIC_INC_L,     atomic.inc.l),
  848.         OPC(6, OPC_ATOMIC_DEC_L,     atomic.dec.l),
  849.         OPC(6, OPC_ATOMIC_CMPXCHG_L, atomic.cmpxchg.l),
  850.         OPC(6, OPC_ATOMIC_MIN_L,     atomic.min.l),
  851.         OPC(6, OPC_ATOMIC_MAX_L,     atomic.max.l),
  852.         OPC(6, OPC_ATOMIC_AND_L,     atomic.and.l),
  853.         OPC(6, OPC_ATOMIC_OR_L,      atomic.or.l),
  854.         OPC(6, OPC_ATOMIC_XOR_L,     atomic.xor.l),
  855.         OPC(6, OPC_LDGB_TYPED_4D,    ldgb.typed.4d),
  856.         OPC(6, OPC_STGB_4D_4,    stgb.4d.4),
  857.         OPC(6, OPC_STIB,         stib),
  858.         OPC(6, OPC_LDC_4,        ldc.4),
  859.         OPC(6, OPC_LDLV,         ldlv),
  860.  
  861.  
  862. #undef OPC
  863. };
  864.  
  865. #define GETINFO(instr) (&(opcs[((instr)->opc_cat << NOPC_BITS) | getopc(instr)]))
  866.  
  867. static uint32_t getopc(instr_t *instr)
  868. {
  869.         switch (instr->opc_cat) {
  870.         case 0:  return instr->cat0.opc;
  871.         case 1:  return 0;
  872.         case 2:  return instr->cat2.opc;
  873.         case 3:  return instr->cat3.opc;
  874.         case 4:  return instr->cat4.opc;
  875.         case 5:  return instr->cat5.opc;
  876.         case 6:  return instr->cat6.opc;
  877.         default: return 0;
  878.         }
  879. }
  880.  
  881. static void print_instr(uint32_t *dwords, int level, int n)
  882. {
  883.         instr_t *instr = (instr_t *)dwords;
  884.         uint32_t opc = getopc(instr);
  885.         const char *name;
  886.  
  887.         printf("%s%04d[%08xx_%08xx] ", levels[level], n, dwords[1], dwords[0]);
  888.  
  889. #if 0
  890.         /* print unknown bits: */
  891.         if (debug & PRINT_RAW)
  892.                 printf("[%08xx_%08xx] ", dwords[1] & 0x001ff800, dwords[0] & 0x00000000);
  893.  
  894.         if (debug & PRINT_VERBOSE)
  895.                 printf("%d,%02d ", instr->opc_cat, opc);
  896. #endif
  897.  
  898.         /* NOTE: order flags are printed is a bit fugly.. but for now I
  899.          * try to match the order in llvm-a3xx disassembler for easy
  900.          * diff'ing..
  901.          */
  902.  
  903.         if (instr->sync)
  904.                 printf("(sy)");
  905.         if (instr->ss && (instr->opc_cat <= 4))
  906.                 printf("(ss)");
  907.         if (instr->jmp_tgt)
  908.                 printf("(jp)");
  909.         if (instr->repeat && (instr->opc_cat <= 4)) {
  910.                 printf("(rpt%d)", instr->repeat);
  911.                 repeat = instr->repeat;
  912.         } else {
  913.                 repeat = 0;
  914.         }
  915.         if (instr->ul && ((2 <= instr->opc_cat) && (instr->opc_cat <= 4)))
  916.                 printf("(ul)");
  917.  
  918.         name = GETINFO(instr)->name;
  919.  
  920.         if (name) {
  921.                 printf("%s", name);
  922.                 GETINFO(instr)->print(instr);
  923.         } else {
  924.                 printf("unknown(%d,%d)", instr->opc_cat, opc);
  925.         }
  926.  
  927.         printf("\n");
  928.  
  929.         process_reg_dst();
  930. }
  931.  
  932. int disasm_a3xx(uint32_t *dwords, int sizedwords, int level, enum shader_t type)
  933. {
  934.         int i;
  935.  
  936.         assert((sizedwords % 2) == 0);
  937.  
  938.         memset(&regs, 0, sizeof(regs));
  939.  
  940.         for (i = 0; i < sizedwords; i += 2)
  941.                 print_instr(&dwords[i], level, i/2);
  942.  
  943.         print_reg_stats(level);
  944.  
  945.         return 0;
  946. }
  947.