1 /************************************************************************** 2 * 3 * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. 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 TUNGSTEN GRAPHICS 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 29 #include "i915_reg.h" 30 #include "i915_debug.h" 31 #include "i915_debug_private.h" 32 #include "util/u_debug.h" 33 34 35 static void 36 PRINTF( 37 struct debug_stream *stream, 38 const char *fmt, 39 ... ) 40 { 41 va_list args; 42 43 va_start( args, fmt ); 44 debug_vprintf( fmt, args ); 45 va_end( args ); 46 } 47 48 49 static const char *opcodes[0x20] = { 50 "NOP", 51 "ADD", 52 "MOV", 53 "MUL", 54 "MAD", 55 "DP2ADD", 56 "DP3", 57 "DP4", 58 "FRC", 59 "RCP", 60 "RSQ", 61 "EXP", 62 "LOG", 63 "CMP", 64 "MIN", 65 "MAX", 66 "FLR", 67 "MOD", 68 "TRC", 69 "SGE", 70 "SLT", 71 "TEXLD", 72 "TEXLDP", 73 "TEXLDB", 74 "TEXKILL", 75 "DCL", 76 "0x1a", 77 "0x1b", 78 "0x1c", 79 "0x1d", 80 "0x1e", 81 "0x1f", 82 }; 83 84 85 static const int args[0x20] = { 86 0, /* 0 nop */ 87 2, /* 1 add */ 88 1, /* 2 mov */ 89 2, /* 3 m ul */ 90 3, /* 4 mad */ 91 3, /* 5 dp2add */ 92 2, /* 6 dp3 */ 93 2, /* 7 dp4 */ 94 1, /* 8 frc */ 95 1, /* 9 rcp */ 96 1, /* a rsq */ 97 1, /* b exp */ 98 1, /* c log */ 99 3, /* d cmp */ 100 2, /* e min */ 101 2, /* f max */ 102 1, /* 10 flr */ 103 1, /* 11 mod */ 104 1, /* 12 trc */ 105 2, /* 13 sge */ 106 2, /* 14 slt */ 107 1, 108 1, 109 1, 110 1, 111 0, 112 0, 113 0, 114 0, 115 0, 116 0, 117 0, 118 }; 119 120 121 static const char *regname[0x8] = { 122 "R", 123 "T", 124 "CONST", 125 "S", 126 "OC", 127 "OD", 128 "U", 129 "UNKNOWN", 130 }; 131 132 static void 133 print_reg_type_nr(struct debug_stream *stream, unsigned type, unsigned nr) 134 { 135 switch (type) { 136 case REG_TYPE_T: 137 switch (nr) { 138 case T_DIFFUSE: 139 PRINTF(stream, "T_DIFFUSE"); 140 return; 141 case T_SPECULAR: 142 PRINTF(stream, "T_SPECULAR"); 143 return; 144 case T_FOG_W: 145 PRINTF(stream, "T_FOG_W"); 146 return; 147 default: 148 PRINTF(stream, "T_TEX%d", nr); 149 return; 150 } 151 case REG_TYPE_OC: 152 if (nr == 0) { 153 PRINTF(stream, "oC"); 154 return; 155 } 156 break; 157 case REG_TYPE_OD: 158 if (nr == 0) { 159 PRINTF(stream, "oD"); 160 return; 161 } 162 break; 163 default: 164 break; 165 } 166 167 PRINTF(stream, "%s[%d]", regname[type], nr); 168 } 169 170 #define REG_SWIZZLE_MASK 0x7777 171 #define REG_NEGATE_MASK 0x8888 172 173 #define REG_SWIZZLE_XYZW ((SRC_X << A2_SRC2_CHANNEL_X_SHIFT) | \ 174 (SRC_Y << A2_SRC2_CHANNEL_Y_SHIFT) | \ 175 (SRC_Z << A2_SRC2_CHANNEL_Z_SHIFT) | \ 176 (SRC_W << A2_SRC2_CHANNEL_W_SHIFT)) 177 178 179 static void 180 print_reg_neg_swizzle(struct debug_stream *stream, unsigned reg) 181 { 182 int i; 183 184 if ((reg & REG_SWIZZLE_MASK) == REG_SWIZZLE_XYZW && 185 (reg & REG_NEGATE_MASK) == 0) 186 return; 187 188 PRINTF(stream, "."); 189 190 for (i = 3; i >= 0; i--) { 191 if (reg & (1 << ((i * 4) + 3))) 192 PRINTF(stream, "-"); 193 194 switch ((reg >> (i * 4)) & 0x7) { 195 case 0: 196 PRINTF(stream, "x"); 197 break; 198 case 1: 199 PRINTF(stream, "y"); 200 break; 201 case 2: 202 PRINTF(stream, "z"); 203 break; 204 case 3: 205 PRINTF(stream, "w"); 206 break; 207 case 4: 208 PRINTF(stream, "0"); 209 break; 210 case 5: 211 PRINTF(stream, "1"); 212 break; 213 default: 214 PRINTF(stream, "?"); 215 break; 216 } 217 } 218 } 219 220 221 static void 222 print_src_reg(struct debug_stream *stream, unsigned dword) 223 { 224 unsigned nr = (dword >> A2_SRC2_NR_SHIFT) & REG_NR_MASK; 225 unsigned type = (dword >> A2_SRC2_TYPE_SHIFT) & REG_TYPE_MASK; 226 print_reg_type_nr(stream, type, nr); 227 print_reg_neg_swizzle(stream, dword); 228 } 229 230 231 static void 232 print_dest_reg(struct debug_stream *stream, unsigned dword) 233 { 234 unsigned nr = (dword >> A0_DEST_NR_SHIFT) & REG_NR_MASK; 235 unsigned type = (dword >> A0_DEST_TYPE_SHIFT) & REG_TYPE_MASK; 236 print_reg_type_nr(stream, type, nr); 237 if ((dword & A0_DEST_CHANNEL_ALL) == A0_DEST_CHANNEL_ALL) 238 return; 239 PRINTF(stream, "."); 240 if (dword & A0_DEST_CHANNEL_X) 241 PRINTF(stream, "x"); 242 if (dword & A0_DEST_CHANNEL_Y) 243 PRINTF(stream, "y"); 244 if (dword & A0_DEST_CHANNEL_Z) 245 PRINTF(stream, "z"); 246 if (dword & A0_DEST_CHANNEL_W) 247 PRINTF(stream, "w"); 248 } 249 250 251 #define GET_SRC0_REG(r0, r1) ((r0<<14)|(r1>>A1_SRC0_CHANNEL_W_SHIFT)) 252 #define GET_SRC1_REG(r0, r1) ((r0<<8)|(r1>>A2_SRC1_CHANNEL_W_SHIFT)) 253 #define GET_SRC2_REG(r) (r) 254 255 256 static void 257 print_arith_op(struct debug_stream *stream, 258 unsigned opcode, const unsigned * program) 259 { 260 if (opcode != A0_NOP) { 261 print_dest_reg(stream, program[0]); 262 if (program[0] & A0_DEST_SATURATE) 263 PRINTF(stream, " = SATURATE "); 264 else 265 PRINTF(stream, " = "); 266 } 267 268 PRINTF(stream, "%s ", opcodes[opcode]); 269 270 print_src_reg(stream, GET_SRC0_REG(program[0], program[1])); 271 if (args[opcode] == 1) { 272 PRINTF(stream, "\n"); 273 return; 274 } 275 276 PRINTF(stream, ", "); 277 print_src_reg(stream, GET_SRC1_REG(program[1], program[2])); 278 if (args[opcode] == 2) { 279 PRINTF(stream, "\n"); 280 return; 281 } 282 283 PRINTF(stream, ", "); 284 print_src_reg(stream, GET_SRC2_REG(program[2])); 285 PRINTF(stream, "\n"); 286 return; 287 } 288 289 290 static void 291 print_tex_op(struct debug_stream *stream, 292 unsigned opcode, const unsigned * program) 293 { 294 print_dest_reg(stream, program[0] | A0_DEST_CHANNEL_ALL); 295 PRINTF(stream, " = "); 296 297 PRINTF(stream, "%s ", opcodes[opcode]); 298 299 PRINTF(stream, "S[%d],", program[0] & T0_SAMPLER_NR_MASK); 300 301 print_reg_type_nr(stream, 302 (program[1] >> T1_ADDRESS_REG_TYPE_SHIFT) & 303 REG_TYPE_MASK, 304 (program[1] >> T1_ADDRESS_REG_NR_SHIFT) & REG_NR_MASK); 305 PRINTF(stream, "\n"); 306 } 307 308 static void 309 print_texkil_op(struct debug_stream *stream, 310 unsigned opcode, const unsigned * program) 311 { 312 PRINTF(stream, "TEXKIL "); 313 314 print_reg_type_nr(stream, 315 (program[1] >> T1_ADDRESS_REG_TYPE_SHIFT) & 316 REG_TYPE_MASK, 317 (program[1] >> T1_ADDRESS_REG_NR_SHIFT) & REG_NR_MASK); 318 PRINTF(stream, "\n"); 319 } 320 321 static void 322 print_dcl_op(struct debug_stream *stream, 323 unsigned opcode, const unsigned * program) 324 { 325 PRINTF(stream, "%s ", opcodes[opcode]); 326 print_dest_reg(stream, 327 program[0] | A0_DEST_CHANNEL_ALL); 328 PRINTF(stream, "\n"); 329 } 330 331 332 void 333 i915_disassemble_program(struct debug_stream *stream, 334 const unsigned * program, unsigned sz) 335 { 336 unsigned i; 337 338 PRINTF(stream, "\t\tBEGIN\n"); 339 340 assert((program[0] & 0x1ff) + 2 == sz); 341 342 program++; 343 for (i = 1; i < sz; i += 3, program += 3) { 344 unsigned opcode = program[0] & (0x1f << 24); 345 346 PRINTF(stream, "\t\t"); 347 348 if ((int) opcode >= A0_NOP && opcode <= A0_SLT) 349 print_arith_op(stream, opcode >> 24, program); 350 else if (opcode >= T0_TEXLD && opcode < T0_TEXKILL) 351 print_tex_op(stream, opcode >> 24, program); 352 else if (opcode == T0_TEXKILL) 353 print_texkil_op(stream, opcode >> 24, program); 354 else if (opcode == D0_DCL) 355 print_dcl_op(stream, opcode >> 24, program); 356 else 357 PRINTF(stream, "Unknown opcode 0x%x\n", opcode); 358 } 359 360 PRINTF(stream, "\t\tEND\n\n"); 361 } 362 363 364