/************************************************************************** * * Copyright 2003 VMware, Inc. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sub license, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial portions * of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * **************************************************************************/ #include "i915_reg.h" #include "i915_debug.h" #include "i915_debug_private.h" #include "util/u_debug.h" static void PRINTF( struct debug_stream *stream, const char *fmt, ... ) { va_list args; va_start( args, fmt ); debug_vprintf( fmt, args ); va_end( args ); } static const char *opcodes[0x20] = { "NOP", "ADD", "MOV", "MUL", "MAD", "DP2ADD", "DP3", "DP4", "FRC", "RCP", "RSQ", "EXP", "LOG", "CMP", "MIN", "MAX", "FLR", "MOD", "TRC", "SGE", "SLT", "TEXLD", "TEXLDP", "TEXLDB", "TEXKILL", "DCL", "0x1a", "0x1b", "0x1c", "0x1d", "0x1e", "0x1f", }; static const int args[0x20] = { 0, /* 0 nop */ 2, /* 1 add */ 1, /* 2 mov */ 2, /* 3 m ul */ 3, /* 4 mad */ 3, /* 5 dp2add */ 2, /* 6 dp3 */ 2, /* 7 dp4 */ 1, /* 8 frc */ 1, /* 9 rcp */ 1, /* a rsq */ 1, /* b exp */ 1, /* c log */ 3, /* d cmp */ 2, /* e min */ 2, /* f max */ 1, /* 10 flr */ 1, /* 11 mod */ 1, /* 12 trc */ 2, /* 13 sge */ 2, /* 14 slt */ 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, }; static const char *regname[0x8] = { "R", "T", "CONST", "S", "OC", "OD", "U", "UNKNOWN", }; static void print_reg_type_nr(struct debug_stream *stream, unsigned type, unsigned nr) { switch (type) { case REG_TYPE_T: switch (nr) { case T_DIFFUSE: PRINTF(stream, "T_DIFFUSE"); return; case T_SPECULAR: PRINTF(stream, "T_SPECULAR"); return; case T_FOG_W: PRINTF(stream, "T_FOG_W"); return; default: PRINTF(stream, "T_TEX%d", nr); return; } case REG_TYPE_OC: if (nr == 0) { PRINTF(stream, "oC"); return; } break; case REG_TYPE_OD: if (nr == 0) { PRINTF(stream, "oD"); return; } break; default: break; } PRINTF(stream, "%s[%d]", regname[type], nr); } #define REG_SWIZZLE_MASK 0x7777 #define REG_NEGATE_MASK 0x8888 #define REG_SWIZZLE_XYZW ((SRC_X << A2_SRC2_CHANNEL_X_SHIFT) | \ (SRC_Y << A2_SRC2_CHANNEL_Y_SHIFT) | \ (SRC_Z << A2_SRC2_CHANNEL_Z_SHIFT) | \ (SRC_W << A2_SRC2_CHANNEL_W_SHIFT)) static void print_reg_neg_swizzle(struct debug_stream *stream, unsigned reg) { int i; if ((reg & REG_SWIZZLE_MASK) == REG_SWIZZLE_XYZW && (reg & REG_NEGATE_MASK) == 0) return; PRINTF(stream, "."); for (i = 3; i >= 0; i--) { if (reg & (1 << ((i * 4) + 3))) PRINTF(stream, "-"); switch ((reg >> (i * 4)) & 0x7) { case 0: PRINTF(stream, "x"); break; case 1: PRINTF(stream, "y"); break; case 2: PRINTF(stream, "z"); break; case 3: PRINTF(stream, "w"); break; case 4: PRINTF(stream, "0"); break; case 5: PRINTF(stream, "1"); break; default: PRINTF(stream, "?"); break; } } } static void print_src_reg(struct debug_stream *stream, unsigned dword) { unsigned nr = (dword >> A2_SRC2_NR_SHIFT) & REG_NR_MASK; unsigned type = (dword >> A2_SRC2_TYPE_SHIFT) & REG_TYPE_MASK; print_reg_type_nr(stream, type, nr); print_reg_neg_swizzle(stream, dword); } static void print_dest_reg(struct debug_stream *stream, unsigned dword) { unsigned nr = (dword >> A0_DEST_NR_SHIFT) & REG_NR_MASK; unsigned type = (dword >> A0_DEST_TYPE_SHIFT) & REG_TYPE_MASK; print_reg_type_nr(stream, type, nr); if ((dword & A0_DEST_CHANNEL_ALL) == A0_DEST_CHANNEL_ALL) return; PRINTF(stream, "."); if (dword & A0_DEST_CHANNEL_X) PRINTF(stream, "x"); if (dword & A0_DEST_CHANNEL_Y) PRINTF(stream, "y"); if (dword & A0_DEST_CHANNEL_Z) PRINTF(stream, "z"); if (dword & A0_DEST_CHANNEL_W) PRINTF(stream, "w"); } #define GET_SRC0_REG(r0, r1) ((r0<<14)|(r1>>A1_SRC0_CHANNEL_W_SHIFT)) #define GET_SRC1_REG(r0, r1) ((r0<<8)|(r1>>A2_SRC1_CHANNEL_W_SHIFT)) #define GET_SRC2_REG(r) (r) static void print_arith_op(struct debug_stream *stream, unsigned opcode, const unsigned * program) { if (opcode != A0_NOP) { print_dest_reg(stream, program[0]); if (program[0] & A0_DEST_SATURATE) PRINTF(stream, " = SATURATE "); else PRINTF(stream, " = "); } PRINTF(stream, "%s ", opcodes[opcode]); print_src_reg(stream, GET_SRC0_REG(program[0], program[1])); if (args[opcode] == 1) { PRINTF(stream, "\n"); return; } PRINTF(stream, ", "); print_src_reg(stream, GET_SRC1_REG(program[1], program[2])); if (args[opcode] == 2) { PRINTF(stream, "\n"); return; } PRINTF(stream, ", "); print_src_reg(stream, GET_SRC2_REG(program[2])); PRINTF(stream, "\n"); return; } static void print_tex_op(struct debug_stream *stream, unsigned opcode, const unsigned * program) { print_dest_reg(stream, program[0] | A0_DEST_CHANNEL_ALL); PRINTF(stream, " = "); PRINTF(stream, "%s ", opcodes[opcode]); PRINTF(stream, "S[%d],", program[0] & T0_SAMPLER_NR_MASK); print_reg_type_nr(stream, (program[1] >> T1_ADDRESS_REG_TYPE_SHIFT) & REG_TYPE_MASK, (program[1] >> T1_ADDRESS_REG_NR_SHIFT) & REG_NR_MASK); PRINTF(stream, "\n"); } static void print_texkil_op(struct debug_stream *stream, unsigned opcode, const unsigned * program) { PRINTF(stream, "TEXKIL "); print_reg_type_nr(stream, (program[1] >> T1_ADDRESS_REG_TYPE_SHIFT) & REG_TYPE_MASK, (program[1] >> T1_ADDRESS_REG_NR_SHIFT) & REG_NR_MASK); PRINTF(stream, "\n"); } static void print_dcl_op(struct debug_stream *stream, unsigned opcode, const unsigned * program) { PRINTF(stream, "%s ", opcodes[opcode]); print_dest_reg(stream, program[0] | A0_DEST_CHANNEL_ALL); PRINTF(stream, "\n"); } void i915_disassemble_program(struct debug_stream *stream, const unsigned * program, unsigned sz) { unsigned i; PRINTF(stream, "\t\tBEGIN\n"); assert((program[0] & 0x1ff) + 2 == sz); for (i = 1; i < sz; i += 3, program += 3) { unsigned opcode = program[0] & (0x1f << 24); PRINTF(stream, "\t\t"); if ((int) opcode >= A0_NOP && opcode <= A0_SLT) print_arith_op(stream, opcode >> 24, program); else if (opcode >= T0_TEXLD && opcode < T0_TEXKILL) print_tex_op(stream, opcode >> 24, program); else if (opcode == T0_TEXKILL) print_texkil_op(stream, opcode >> 24, program); else if (opcode == D0_DCL) print_dcl_op(stream, opcode >> 24, program); else PRINTF(stream, "Unknown opcode 0x%x\n", opcode); } PRINTF(stream, "\t\tEND\n\n"); }