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