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
PRINTF(struct debug_stream * stream,const char * fmt,...)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
print_reg_type_nr(struct debug_stream * stream,unsigned type,unsigned nr)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
print_reg_neg_swizzle(struct debug_stream * stream,unsigned reg)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
print_src_reg(struct debug_stream * stream,unsigned dword)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
print_dest_reg(struct debug_stream * stream,unsigned dword)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
print_arith_op(struct debug_stream * stream,unsigned opcode,const unsigned * program)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
print_tex_op(struct debug_stream * stream,unsigned opcode,const unsigned * program)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
print_texkil_op(struct debug_stream * stream,unsigned opcode,const unsigned * program)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
print_dcl_op(struct debug_stream * stream,unsigned opcode,const unsigned * program)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
i915_disassemble_program(struct debug_stream * stream,const unsigned * program,unsigned sz)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