1/************************************************************************** 2 * 3 * Copyright 2003 VMware, Inc. 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 **************************************************************************/ 27 28#include "util/log.h" 29#include "util/ralloc.h" 30#include "util/u_debug.h" 31#include "i915_debug.h" 32#include "i915_debug_private.h" 33#include "i915_reg.h" 34 35#define PRINTF ralloc_asprintf_append 36 37static const char *opcodes[0x20] = { 38 "NOP", "ADD", "MOV", "MUL", "MAD", "DP2ADD", "DP3", "DP4", 39 "FRC", "RCP", "RSQ", "EXP", "LOG", "CMP", "MIN", "MAX", 40 "FLR", "MOD", "TRC", "SGE", "SLT", "TEXLD", "TEXLDP", "TEXLDB", 41 "TEXKILL", "DCL", "0x1a", "0x1b", "0x1c", "0x1d", "0x1e", "0x1f", 42}; 43 44static const int args[0x20] = { 45 0, /* 0 nop */ 46 2, /* 1 add */ 47 1, /* 2 mov */ 48 2, /* 3 m ul */ 49 3, /* 4 mad */ 50 3, /* 5 dp2add */ 51 2, /* 6 dp3 */ 52 2, /* 7 dp4 */ 53 1, /* 8 frc */ 54 1, /* 9 rcp */ 55 1, /* a rsq */ 56 1, /* b exp */ 57 1, /* c log */ 58 3, /* d cmp */ 59 2, /* e min */ 60 2, /* f max */ 61 1, /* 10 flr */ 62 1, /* 11 mod */ 63 1, /* 12 trc */ 64 2, /* 13 sge */ 65 2, /* 14 slt */ 66 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 67}; 68 69static const char *regname[0x8] = { 70 "R", "T", "CONST", "S", "OC", "OD", "U", "UNKNOWN", 71}; 72 73static void 74print_reg_type_nr(char **stream, unsigned type, unsigned nr) 75{ 76 switch (type) { 77 case REG_TYPE_T: 78 switch (nr) { 79 case T_DIFFUSE: 80 PRINTF(stream, "T_DIFFUSE"); 81 return; 82 case T_SPECULAR: 83 PRINTF(stream, "T_SPECULAR"); 84 return; 85 case T_FOG_W: 86 PRINTF(stream, "T_FOG_W"); 87 return; 88 default: 89 PRINTF(stream, "T_TEX%d", nr); 90 return; 91 } 92 case REG_TYPE_OC: 93 if (nr == 0) { 94 PRINTF(stream, "oC"); 95 return; 96 } 97 break; 98 case REG_TYPE_OD: 99 if (nr == 0) { 100 PRINTF(stream, "oD"); 101 return; 102 } 103 break; 104 default: 105 break; 106 } 107 108 PRINTF(stream, "%s[%d]", regname[type], nr); 109} 110 111#define REG_SWIZZLE_MASK 0x7777 112#define REG_NEGATE_MASK 0x8888 113 114#define REG_SWIZZLE_XYZW \ 115 ((SRC_X << A2_SRC2_CHANNEL_X_SHIFT) | (SRC_Y << A2_SRC2_CHANNEL_Y_SHIFT) | \ 116 (SRC_Z << A2_SRC2_CHANNEL_Z_SHIFT) | (SRC_W << A2_SRC2_CHANNEL_W_SHIFT)) 117 118static void 119print_reg_neg_swizzle(char **stream, unsigned reg) 120{ 121 int i; 122 123 if ((reg & REG_SWIZZLE_MASK) == REG_SWIZZLE_XYZW && 124 (reg & REG_NEGATE_MASK) == 0) 125 return; 126 127 PRINTF(stream, "."); 128 129 for (i = 3; i >= 0; i--) { 130 if (reg & (1 << ((i * 4) + 3))) 131 PRINTF(stream, "-"); 132 133 switch ((reg >> (i * 4)) & 0x7) { 134 case 0: 135 PRINTF(stream, "x"); 136 break; 137 case 1: 138 PRINTF(stream, "y"); 139 break; 140 case 2: 141 PRINTF(stream, "z"); 142 break; 143 case 3: 144 PRINTF(stream, "w"); 145 break; 146 case 4: 147 PRINTF(stream, "0"); 148 break; 149 case 5: 150 PRINTF(stream, "1"); 151 break; 152 default: 153 PRINTF(stream, "?"); 154 break; 155 } 156 } 157} 158 159static void 160print_src_reg(char **stream, unsigned dword) 161{ 162 unsigned nr = (dword >> A2_SRC2_NR_SHIFT) & REG_NR_MASK; 163 unsigned type = (dword >> A2_SRC2_TYPE_SHIFT) & REG_TYPE_MASK; 164 print_reg_type_nr(stream, type, nr); 165 print_reg_neg_swizzle(stream, dword); 166} 167 168static void 169print_dest_reg(char **stream, unsigned dword) 170{ 171 unsigned nr = (dword >> A0_DEST_NR_SHIFT) & REG_NR_MASK; 172 unsigned type = (dword >> A0_DEST_TYPE_SHIFT) & REG_TYPE_MASK; 173 print_reg_type_nr(stream, type, nr); 174 if ((dword & A0_DEST_CHANNEL_ALL) == A0_DEST_CHANNEL_ALL) 175 return; 176 PRINTF(stream, "."); 177 if (dword & A0_DEST_CHANNEL_X) 178 PRINTF(stream, "x"); 179 if (dword & A0_DEST_CHANNEL_Y) 180 PRINTF(stream, "y"); 181 if (dword & A0_DEST_CHANNEL_Z) 182 PRINTF(stream, "z"); 183 if (dword & A0_DEST_CHANNEL_W) 184 PRINTF(stream, "w"); 185} 186 187#define GET_SRC0_REG(r0, r1) ((r0 << 14) | (r1 >> A1_SRC0_CHANNEL_W_SHIFT)) 188#define GET_SRC1_REG(r0, r1) ((r0 << 8) | (r1 >> A2_SRC1_CHANNEL_W_SHIFT)) 189#define GET_SRC2_REG(r) (r) 190 191static void 192print_arith_op(char **stream, unsigned opcode, const unsigned *program) 193{ 194 if (opcode != A0_NOP) { 195 print_dest_reg(stream, program[0]); 196 if (program[0] & A0_DEST_SATURATE) 197 PRINTF(stream, " = SATURATE "); 198 else 199 PRINTF(stream, " = "); 200 } 201 202 PRINTF(stream, "%s ", opcodes[opcode]); 203 204 print_src_reg(stream, GET_SRC0_REG(program[0], program[1])); 205 if (args[opcode] == 1) 206 return; 207 208 PRINTF(stream, ", "); 209 print_src_reg(stream, GET_SRC1_REG(program[1], program[2])); 210 if (args[opcode] == 2) 211 return; 212 213 PRINTF(stream, ", "); 214 print_src_reg(stream, GET_SRC2_REG(program[2])); 215 return; 216} 217 218static void 219print_tex_op(char **stream, unsigned opcode, const unsigned *program) 220{ 221 print_dest_reg(stream, program[0] | A0_DEST_CHANNEL_ALL); 222 PRINTF(stream, " = "); 223 224 PRINTF(stream, "%s ", opcodes[opcode]); 225 226 PRINTF(stream, "S[%d],", program[0] & T0_SAMPLER_NR_MASK); 227 228 print_reg_type_nr(stream, 229 (program[1] >> T1_ADDRESS_REG_TYPE_SHIFT) & REG_TYPE_MASK, 230 (program[1] >> T1_ADDRESS_REG_NR_SHIFT) & REG_NR_MASK); 231} 232 233static void 234print_texkil_op(char **stream, unsigned opcode, const unsigned *program) 235{ 236 PRINTF(stream, "TEXKIL "); 237 238 print_reg_type_nr(stream, 239 (program[1] >> T1_ADDRESS_REG_TYPE_SHIFT) & REG_TYPE_MASK, 240 (program[1] >> T1_ADDRESS_REG_NR_SHIFT) & REG_NR_MASK); 241} 242 243static void 244print_dcl_op(char **stream, unsigned opcode, const unsigned *program) 245{ 246 unsigned type = (program[0] >> D0_TYPE_SHIFT) & REG_TYPE_MASK; 247 248 PRINTF(stream, "%s ", opcodes[opcode]); 249 250 unsigned dest_dword = program[0]; 251 if (type == REG_TYPE_S) 252 dest_dword |= A0_DEST_CHANNEL_ALL; 253 print_dest_reg(stream, dest_dword); 254 255 if (type == REG_TYPE_S) { 256 switch (program[0] & D0_SAMPLE_TYPE_MASK) { 257 case D0_SAMPLE_TYPE_2D: 258 PRINTF(stream, " 2D"); 259 break; 260 case D0_SAMPLE_TYPE_VOLUME: 261 PRINTF(stream, " 3D"); 262 break; 263 case D0_SAMPLE_TYPE_CUBE: 264 PRINTF(stream, " CUBE"); 265 break; 266 default: 267 PRINTF(stream, " XXX bad type"); 268 break; 269 } 270 } 271} 272 273void 274i915_disassemble_program(const unsigned *program, unsigned sz) 275{ 276 unsigned i; 277 278 mesa_logi("\t\tBEGIN"); 279 280 assert((program[0] & 0x1ff) + 2 == sz); 281 282 program++; 283 for (i = 1; i < sz; i += 3, program += 3) { 284 unsigned opcode = program[0] & (0x1f << 24); 285 286 char *stream = ralloc_strdup(NULL, ""); 287 if ((int)opcode >= A0_NOP && opcode <= A0_SLT) 288 print_arith_op(&stream, opcode >> 24, program); 289 else if (opcode >= T0_TEXLD && opcode < T0_TEXKILL) 290 print_tex_op(&stream, opcode >> 24, program); 291 else if (opcode == T0_TEXKILL) 292 print_texkil_op(&stream, opcode >> 24, program); 293 else if (opcode == D0_DCL) 294 print_dcl_op(&stream, opcode >> 24, program); 295 else 296 ralloc_asprintf_append(&stream, "\t\t Unknown opcode 0x%x\n", opcode); 297 298 mesa_logi("\t\t %s ", stream); 299 ralloc_free(stream); 300 } 301 302 mesa_logi("\t\tEND"); 303} 304