Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5564 | serge | 1 | /* |
2 | * Copyright (c) 2012 Rob Clark |
||
3 | * |
||
4 | * Permission is hereby granted, free of charge, to any person obtaining a |
||
5 | * copy of this software and associated documentation files (the "Software"), |
||
6 | * to deal in the Software without restriction, including without limitation |
||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||
8 | * and/or sell copies of the Software, and to permit persons to whom the |
||
9 | * Software is furnished to do so, subject to the following conditions: |
||
10 | * |
||
11 | * The above copyright notice and this permission notice (including the next |
||
12 | * paragraph) shall be included in all copies or substantial portions of the |
||
13 | * Software. |
||
14 | * |
||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||
20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||
21 | * SOFTWARE. |
||
22 | */ |
||
23 | |||
24 | #include |
||
25 | #include |
||
26 | #include |
||
27 | #include |
||
28 | #include |
||
29 | #include |
||
30 | #include |
||
31 | #include |
||
32 | |||
33 | #include "disasm.h" |
||
34 | #include "instr-a2xx.h" |
||
35 | |||
36 | static const char *levels[] = { |
||
37 | "\t", |
||
38 | "\t\t", |
||
39 | "\t\t\t", |
||
40 | "\t\t\t\t", |
||
41 | "\t\t\t\t\t", |
||
42 | "\t\t\t\t\t\t", |
||
43 | "\t\t\t\t\t\t\t", |
||
44 | "\t\t\t\t\t\t\t\t", |
||
45 | "\t\t\t\t\t\t\t\t\t", |
||
46 | "x", |
||
47 | "x", |
||
48 | "x", |
||
49 | "x", |
||
50 | "x", |
||
51 | "x", |
||
52 | }; |
||
53 | |||
54 | static enum debug_t debug; |
||
55 | |||
56 | /* |
||
57 | * ALU instructions: |
||
58 | */ |
||
59 | |||
60 | static const char chan_names[] = { |
||
61 | 'x', 'y', 'z', 'w', |
||
62 | /* these only apply to FETCH dst's: */ |
||
63 | '0', '1', '?', '_', |
||
64 | }; |
||
65 | |||
66 | static void print_srcreg(uint32_t num, uint32_t type, |
||
67 | uint32_t swiz, uint32_t negate, uint32_t abs) |
||
68 | { |
||
69 | if (negate) |
||
70 | printf("-"); |
||
71 | if (abs) |
||
72 | printf("|"); |
||
73 | printf("%c%u", type ? 'R' : 'C', num); |
||
74 | if (swiz) { |
||
75 | int i; |
||
76 | printf("."); |
||
77 | for (i = 0; i < 4; i++) { |
||
78 | printf("%c", chan_names[(swiz + i) & 0x3]); |
||
79 | swiz >>= 2; |
||
80 | } |
||
81 | } |
||
82 | if (abs) |
||
83 | printf("|"); |
||
84 | } |
||
85 | |||
86 | static void print_dstreg(uint32_t num, uint32_t mask, uint32_t dst_exp) |
||
87 | { |
||
88 | printf("%s%u", dst_exp ? "export" : "R", num); |
||
89 | if (mask != 0xf) { |
||
90 | int i; |
||
91 | printf("."); |
||
92 | for (i = 0; i < 4; i++) { |
||
93 | printf("%c", (mask & 0x1) ? chan_names[i] : '_'); |
||
94 | mask >>= 1; |
||
95 | } |
||
96 | } |
||
97 | } |
||
98 | |||
99 | static void print_export_comment(uint32_t num, enum shader_t type) |
||
100 | { |
||
101 | const char *name = NULL; |
||
102 | switch (type) { |
||
103 | case SHADER_VERTEX: |
||
104 | switch (num) { |
||
105 | case 62: name = "gl_Position"; break; |
||
106 | case 63: name = "gl_PointSize"; break; |
||
107 | } |
||
108 | break; |
||
109 | case SHADER_FRAGMENT: |
||
110 | switch (num) { |
||
111 | case 0: name = "gl_FragColor"; break; |
||
112 | } |
||
113 | break; |
||
114 | } |
||
115 | /* if we had a symbol table here, we could look |
||
116 | * up the name of the varying.. |
||
117 | */ |
||
118 | if (name) { |
||
119 | printf("\t; %s", name); |
||
120 | } |
||
121 | } |
||
122 | |||
123 | struct { |
||
124 | uint32_t num_srcs; |
||
125 | const char *name; |
||
126 | } vector_instructions[0x20] = { |
||
127 | #define INSTR(opc, num_srcs) [opc] = { num_srcs, #opc } |
||
128 | INSTR(ADDv, 2), |
||
129 | INSTR(MULv, 2), |
||
130 | INSTR(MAXv, 2), |
||
131 | INSTR(MINv, 2), |
||
132 | INSTR(SETEv, 2), |
||
133 | INSTR(SETGTv, 2), |
||
134 | INSTR(SETGTEv, 2), |
||
135 | INSTR(SETNEv, 2), |
||
136 | INSTR(FRACv, 1), |
||
137 | INSTR(TRUNCv, 1), |
||
138 | INSTR(FLOORv, 1), |
||
139 | INSTR(MULADDv, 3), |
||
140 | INSTR(CNDEv, 3), |
||
141 | INSTR(CNDGTEv, 3), |
||
142 | INSTR(CNDGTv, 3), |
||
143 | INSTR(DOT4v, 2), |
||
144 | INSTR(DOT3v, 2), |
||
145 | INSTR(DOT2ADDv, 3), // ??? |
||
146 | INSTR(CUBEv, 2), |
||
147 | INSTR(MAX4v, 1), |
||
148 | INSTR(PRED_SETE_PUSHv, 2), |
||
149 | INSTR(PRED_SETNE_PUSHv, 2), |
||
150 | INSTR(PRED_SETGT_PUSHv, 2), |
||
151 | INSTR(PRED_SETGTE_PUSHv, 2), |
||
152 | INSTR(KILLEv, 2), |
||
153 | INSTR(KILLGTv, 2), |
||
154 | INSTR(KILLGTEv, 2), |
||
155 | INSTR(KILLNEv, 2), |
||
156 | INSTR(DSTv, 2), |
||
157 | INSTR(MOVAv, 1), |
||
158 | }, scalar_instructions[0x40] = { |
||
159 | INSTR(ADDs, 1), |
||
160 | INSTR(ADD_PREVs, 1), |
||
161 | INSTR(MULs, 1), |
||
162 | INSTR(MUL_PREVs, 1), |
||
163 | INSTR(MUL_PREV2s, 1), |
||
164 | INSTR(MAXs, 1), |
||
165 | INSTR(MINs, 1), |
||
166 | INSTR(SETEs, 1), |
||
167 | INSTR(SETGTs, 1), |
||
168 | INSTR(SETGTEs, 1), |
||
169 | INSTR(SETNEs, 1), |
||
170 | INSTR(FRACs, 1), |
||
171 | INSTR(TRUNCs, 1), |
||
172 | INSTR(FLOORs, 1), |
||
173 | INSTR(EXP_IEEE, 1), |
||
174 | INSTR(LOG_CLAMP, 1), |
||
175 | INSTR(LOG_IEEE, 1), |
||
176 | INSTR(RECIP_CLAMP, 1), |
||
177 | INSTR(RECIP_FF, 1), |
||
178 | INSTR(RECIP_IEEE, 1), |
||
179 | INSTR(RECIPSQ_CLAMP, 1), |
||
180 | INSTR(RECIPSQ_FF, 1), |
||
181 | INSTR(RECIPSQ_IEEE, 1), |
||
182 | INSTR(MOVAs, 1), |
||
183 | INSTR(MOVA_FLOORs, 1), |
||
184 | INSTR(SUBs, 1), |
||
185 | INSTR(SUB_PREVs, 1), |
||
186 | INSTR(PRED_SETEs, 1), |
||
187 | INSTR(PRED_SETNEs, 1), |
||
188 | INSTR(PRED_SETGTs, 1), |
||
189 | INSTR(PRED_SETGTEs, 1), |
||
190 | INSTR(PRED_SET_INVs, 1), |
||
191 | INSTR(PRED_SET_POPs, 1), |
||
192 | INSTR(PRED_SET_CLRs, 1), |
||
193 | INSTR(PRED_SET_RESTOREs, 1), |
||
194 | INSTR(KILLEs, 1), |
||
195 | INSTR(KILLGTs, 1), |
||
196 | INSTR(KILLGTEs, 1), |
||
197 | INSTR(KILLNEs, 1), |
||
198 | INSTR(KILLONEs, 1), |
||
199 | INSTR(SQRT_IEEE, 1), |
||
200 | INSTR(MUL_CONST_0, 1), |
||
201 | INSTR(MUL_CONST_1, 1), |
||
202 | INSTR(ADD_CONST_0, 1), |
||
203 | INSTR(ADD_CONST_1, 1), |
||
204 | INSTR(SUB_CONST_0, 1), |
||
205 | INSTR(SUB_CONST_1, 1), |
||
206 | INSTR(SIN, 1), |
||
207 | INSTR(COS, 1), |
||
208 | INSTR(RETAIN_PREV, 1), |
||
209 | #undef INSTR |
||
210 | }; |
||
211 | |||
212 | static int disasm_alu(uint32_t *dwords, uint32_t alu_off, |
||
213 | int level, int sync, enum shader_t type) |
||
214 | { |
||
215 | instr_alu_t *alu = (instr_alu_t *)dwords; |
||
216 | |||
217 | printf("%s", levels[level]); |
||
218 | if (debug & PRINT_RAW) { |
||
219 | printf("%02x: %08x %08x %08x\t", alu_off, |
||
220 | dwords[0], dwords[1], dwords[2]); |
||
221 | } |
||
222 | |||
223 | printf(" %sALU:\t", sync ? "(S)" : " "); |
||
224 | |||
225 | printf("%s", vector_instructions[alu->vector_opc].name); |
||
226 | |||
227 | if (alu->pred_select & 0x2) { |
||
228 | /* seems to work similar to conditional execution in ARM instruction |
||
229 | * set, so let's use a similar syntax for now: |
||
230 | */ |
||
231 | printf((alu->pred_select & 0x1) ? "EQ" : "NE"); |
||
232 | } |
||
233 | |||
234 | printf("\t"); |
||
235 | |||
236 | print_dstreg(alu->vector_dest, alu->vector_write_mask, alu->export_data); |
||
237 | printf(" = "); |
||
238 | if (vector_instructions[alu->vector_opc].num_srcs == 3) { |
||
239 | print_srcreg(alu->src3_reg, alu->src3_sel, alu->src3_swiz, |
||
240 | alu->src3_reg_negate, alu->src3_reg_abs); |
||
241 | printf(", "); |
||
242 | } |
||
243 | print_srcreg(alu->src1_reg, alu->src1_sel, alu->src1_swiz, |
||
244 | alu->src1_reg_negate, alu->src1_reg_abs); |
||
245 | if (vector_instructions[alu->vector_opc].num_srcs > 1) { |
||
246 | printf(", "); |
||
247 | print_srcreg(alu->src2_reg, alu->src2_sel, alu->src2_swiz, |
||
248 | alu->src2_reg_negate, alu->src2_reg_abs); |
||
249 | } |
||
250 | |||
251 | if (alu->vector_clamp) |
||
252 | printf(" CLAMP"); |
||
253 | |||
254 | if (alu->export_data) |
||
255 | print_export_comment(alu->vector_dest, type); |
||
256 | |||
257 | printf("\n"); |
||
258 | |||
259 | if (alu->scalar_write_mask || !alu->vector_write_mask) { |
||
260 | /* 2nd optional scalar op: */ |
||
261 | |||
262 | printf("%s", levels[level]); |
||
263 | if (debug & PRINT_RAW) |
||
264 | printf(" \t"); |
||
265 | |||
266 | if (scalar_instructions[alu->scalar_opc].name) { |
||
267 | printf("\t \t%s\t", scalar_instructions[alu->scalar_opc].name); |
||
268 | } else { |
||
269 | printf("\t \tOP(%u)\t", alu->scalar_opc); |
||
270 | } |
||
271 | |||
272 | print_dstreg(alu->scalar_dest, alu->scalar_write_mask, alu->export_data); |
||
273 | printf(" = "); |
||
274 | print_srcreg(alu->src3_reg, alu->src3_sel, alu->src3_swiz, |
||
275 | alu->src3_reg_negate, alu->src3_reg_abs); |
||
276 | // TODO ADD/MUL must have another src?!? |
||
277 | if (alu->scalar_clamp) |
||
278 | printf(" CLAMP"); |
||
279 | if (alu->export_data) |
||
280 | print_export_comment(alu->scalar_dest, type); |
||
281 | printf("\n"); |
||
282 | } |
||
283 | |||
284 | return 0; |
||
285 | } |
||
286 | |||
287 | |||
288 | /* |
||
289 | * FETCH instructions: |
||
290 | */ |
||
291 | |||
292 | struct { |
||
293 | const char *name; |
||
294 | } fetch_types[0xff] = { |
||
295 | #define TYPE(id) [id] = { #id } |
||
296 | TYPE(FMT_1_REVERSE), |
||
297 | TYPE(FMT_32_FLOAT), |
||
298 | TYPE(FMT_32_32_FLOAT), |
||
299 | TYPE(FMT_32_32_32_FLOAT), |
||
300 | TYPE(FMT_32_32_32_32_FLOAT), |
||
301 | TYPE(FMT_16), |
||
302 | TYPE(FMT_16_16), |
||
303 | TYPE(FMT_16_16_16_16), |
||
304 | TYPE(FMT_8), |
||
305 | TYPE(FMT_8_8), |
||
306 | TYPE(FMT_8_8_8_8), |
||
307 | TYPE(FMT_32), |
||
308 | TYPE(FMT_32_32), |
||
309 | TYPE(FMT_32_32_32_32), |
||
310 | #undef TYPE |
||
311 | }; |
||
312 | |||
313 | static void print_fetch_dst(uint32_t dst_reg, uint32_t dst_swiz) |
||
314 | { |
||
315 | int i; |
||
316 | printf("\tR%u.", dst_reg); |
||
317 | for (i = 0; i < 4; i++) { |
||
318 | printf("%c", chan_names[dst_swiz & 0x7]); |
||
319 | dst_swiz >>= 3; |
||
320 | } |
||
321 | } |
||
322 | |||
323 | static void print_fetch_vtx(instr_fetch_t *fetch) |
||
324 | { |
||
325 | instr_fetch_vtx_t *vtx = &fetch->vtx; |
||
326 | |||
327 | if (vtx->pred_select) { |
||
328 | /* seems to work similar to conditional execution in ARM instruction |
||
329 | * set, so let's use a similar syntax for now: |
||
330 | */ |
||
331 | printf(vtx->pred_condition ? "EQ" : "NE"); |
||
332 | } |
||
333 | |||
334 | print_fetch_dst(vtx->dst_reg, vtx->dst_swiz); |
||
335 | printf(" = R%u.", vtx->src_reg); |
||
336 | printf("%c", chan_names[vtx->src_swiz & 0x3]); |
||
337 | if (fetch_types[vtx->format].name) { |
||
338 | printf(" %s", fetch_types[vtx->format].name); |
||
339 | } else { |
||
340 | printf(" TYPE(0x%x)", vtx->format); |
||
341 | } |
||
342 | printf(" %s", vtx->format_comp_all ? "SIGNED" : "UNSIGNED"); |
||
343 | if (!vtx->num_format_all) |
||
344 | printf(" NORMALIZED"); |
||
345 | printf(" STRIDE(%u)", vtx->stride); |
||
346 | if (vtx->offset) |
||
347 | printf(" OFFSET(%u)", vtx->offset); |
||
348 | printf(" CONST(%u, %u)", vtx->const_index, vtx->const_index_sel); |
||
349 | if (0) { |
||
350 | // XXX |
||
351 | printf(" src_reg_am=%u", vtx->src_reg_am); |
||
352 | printf(" dst_reg_am=%u", vtx->dst_reg_am); |
||
353 | printf(" num_format_all=%u", vtx->num_format_all); |
||
354 | printf(" signed_rf_mode_all=%u", vtx->signed_rf_mode_all); |
||
355 | printf(" exp_adjust_all=%u", vtx->exp_adjust_all); |
||
356 | } |
||
357 | } |
||
358 | |||
359 | static void print_fetch_tex(instr_fetch_t *fetch) |
||
360 | { |
||
361 | static const char *filter[] = { |
||
362 | [TEX_FILTER_POINT] = "POINT", |
||
363 | [TEX_FILTER_LINEAR] = "LINEAR", |
||
364 | [TEX_FILTER_BASEMAP] = "BASEMAP", |
||
365 | }; |
||
366 | static const char *aniso_filter[] = { |
||
367 | [ANISO_FILTER_DISABLED] = "DISABLED", |
||
368 | [ANISO_FILTER_MAX_1_1] = "MAX_1_1", |
||
369 | [ANISO_FILTER_MAX_2_1] = "MAX_2_1", |
||
370 | [ANISO_FILTER_MAX_4_1] = "MAX_4_1", |
||
371 | [ANISO_FILTER_MAX_8_1] = "MAX_8_1", |
||
372 | [ANISO_FILTER_MAX_16_1] = "MAX_16_1", |
||
373 | }; |
||
374 | static const char *arbitrary_filter[] = { |
||
375 | [ARBITRARY_FILTER_2X4_SYM] = "2x4_SYM", |
||
376 | [ARBITRARY_FILTER_2X4_ASYM] = "2x4_ASYM", |
||
377 | [ARBITRARY_FILTER_4X2_SYM] = "4x2_SYM", |
||
378 | [ARBITRARY_FILTER_4X2_ASYM] = "4x2_ASYM", |
||
379 | [ARBITRARY_FILTER_4X4_SYM] = "4x4_SYM", |
||
380 | [ARBITRARY_FILTER_4X4_ASYM] = "4x4_ASYM", |
||
381 | }; |
||
382 | static const char *sample_loc[] = { |
||
383 | [SAMPLE_CENTROID] = "CENTROID", |
||
384 | [SAMPLE_CENTER] = "CENTER", |
||
385 | }; |
||
386 | instr_fetch_tex_t *tex = &fetch->tex; |
||
387 | uint32_t src_swiz = tex->src_swiz; |
||
388 | int i; |
||
389 | |||
390 | if (tex->pred_select) { |
||
391 | /* seems to work similar to conditional execution in ARM instruction |
||
392 | * set, so let's use a similar syntax for now: |
||
393 | */ |
||
394 | printf(tex->pred_condition ? "EQ" : "NE"); |
||
395 | } |
||
396 | |||
397 | print_fetch_dst(tex->dst_reg, tex->dst_swiz); |
||
398 | printf(" = R%u.", tex->src_reg); |
||
399 | for (i = 0; i < 3; i++) { |
||
400 | printf("%c", chan_names[src_swiz & 0x3]); |
||
401 | src_swiz >>= 2; |
||
402 | } |
||
403 | printf(" CONST(%u)", tex->const_idx); |
||
404 | if (tex->fetch_valid_only) |
||
405 | printf(" VALID_ONLY"); |
||
406 | if (tex->tx_coord_denorm) |
||
407 | printf(" DENORM"); |
||
408 | if (tex->mag_filter != TEX_FILTER_USE_FETCH_CONST) |
||
409 | printf(" MAG(%s)", filter[tex->mag_filter]); |
||
410 | if (tex->min_filter != TEX_FILTER_USE_FETCH_CONST) |
||
411 | printf(" MIN(%s)", filter[tex->min_filter]); |
||
412 | if (tex->mip_filter != TEX_FILTER_USE_FETCH_CONST) |
||
413 | printf(" MIP(%s)", filter[tex->mip_filter]); |
||
414 | if (tex->aniso_filter != ANISO_FILTER_USE_FETCH_CONST) |
||
415 | printf(" ANISO(%s)", aniso_filter[tex->aniso_filter]); |
||
416 | if (tex->arbitrary_filter != ARBITRARY_FILTER_USE_FETCH_CONST) |
||
417 | printf(" ARBITRARY(%s)", arbitrary_filter[tex->arbitrary_filter]); |
||
418 | if (tex->vol_mag_filter != TEX_FILTER_USE_FETCH_CONST) |
||
419 | printf(" VOL_MAG(%s)", filter[tex->vol_mag_filter]); |
||
420 | if (tex->vol_min_filter != TEX_FILTER_USE_FETCH_CONST) |
||
421 | printf(" VOL_MIN(%s)", filter[tex->vol_min_filter]); |
||
422 | if (!tex->use_comp_lod) { |
||
423 | printf(" LOD(%u)", tex->use_comp_lod); |
||
424 | printf(" LOD_BIAS(%u)", tex->lod_bias); |
||
425 | } |
||
426 | if (tex->use_reg_gradients) |
||
427 | printf(" USE_REG_GRADIENTS"); |
||
428 | printf(" LOCATION(%s)", sample_loc[tex->sample_location]); |
||
429 | if (tex->offset_x || tex->offset_y || tex->offset_z) |
||
430 | printf(" OFFSET(%u,%u,%u)", tex->offset_x, tex->offset_y, tex->offset_z); |
||
431 | } |
||
432 | |||
433 | struct { |
||
434 | const char *name; |
||
435 | void (*fxn)(instr_fetch_t *cf); |
||
436 | } fetch_instructions[] = { |
||
437 | #define INSTR(opc, name, fxn) [opc] = { name, fxn } |
||
438 | INSTR(VTX_FETCH, "VERTEX", print_fetch_vtx), |
||
439 | INSTR(TEX_FETCH, "SAMPLE", print_fetch_tex), |
||
440 | INSTR(TEX_GET_BORDER_COLOR_FRAC, "?", print_fetch_tex), |
||
441 | INSTR(TEX_GET_COMP_TEX_LOD, "?", print_fetch_tex), |
||
442 | INSTR(TEX_GET_GRADIENTS, "?", print_fetch_tex), |
||
443 | INSTR(TEX_GET_WEIGHTS, "?", print_fetch_tex), |
||
444 | INSTR(TEX_SET_TEX_LOD, "SET_TEX_LOD", print_fetch_tex), |
||
445 | INSTR(TEX_SET_GRADIENTS_H, "?", print_fetch_tex), |
||
446 | INSTR(TEX_SET_GRADIENTS_V, "?", print_fetch_tex), |
||
447 | INSTR(TEX_RESERVED_4, "?", print_fetch_tex), |
||
448 | #undef INSTR |
||
449 | }; |
||
450 | |||
451 | static int disasm_fetch(uint32_t *dwords, uint32_t alu_off, int level, int sync) |
||
452 | { |
||
453 | instr_fetch_t *fetch = (instr_fetch_t *)dwords; |
||
454 | |||
455 | printf("%s", levels[level]); |
||
456 | if (debug & PRINT_RAW) { |
||
457 | printf("%02x: %08x %08x %08x\t", alu_off, |
||
458 | dwords[0], dwords[1], dwords[2]); |
||
459 | } |
||
460 | |||
461 | printf(" %sFETCH:\t", sync ? "(S)" : " "); |
||
462 | printf("%s", fetch_instructions[fetch->opc].name); |
||
463 | fetch_instructions[fetch->opc].fxn(fetch); |
||
464 | printf("\n"); |
||
465 | |||
466 | return 0; |
||
467 | } |
||
468 | |||
469 | /* |
||
470 | * CF instructions: |
||
471 | */ |
||
472 | |||
473 | static int cf_exec(instr_cf_t *cf) |
||
474 | { |
||
475 | return (cf->opc == EXEC) || |
||
476 | (cf->opc == EXEC_END) || |
||
477 | (cf->opc == COND_EXEC) || |
||
478 | (cf->opc == COND_EXEC_END) || |
||
479 | (cf->opc == COND_PRED_EXEC) || |
||
480 | (cf->opc == COND_PRED_EXEC_END) || |
||
481 | (cf->opc == COND_EXEC_PRED_CLEAN) || |
||
482 | (cf->opc == COND_EXEC_PRED_CLEAN_END); |
||
483 | } |
||
484 | |||
485 | static int cf_cond_exec(instr_cf_t *cf) |
||
486 | { |
||
487 | return (cf->opc == COND_EXEC) || |
||
488 | (cf->opc == COND_EXEC_END) || |
||
489 | (cf->opc == COND_PRED_EXEC) || |
||
490 | (cf->opc == COND_PRED_EXEC_END) || |
||
491 | (cf->opc == COND_EXEC_PRED_CLEAN) || |
||
492 | (cf->opc == COND_EXEC_PRED_CLEAN_END); |
||
493 | } |
||
494 | |||
495 | static void print_cf_nop(instr_cf_t *cf) |
||
496 | { |
||
497 | } |
||
498 | |||
499 | static void print_cf_exec(instr_cf_t *cf) |
||
500 | { |
||
501 | printf(" ADDR(0x%x) CNT(0x%x)", cf->exec.address, cf->exec.count); |
||
502 | if (cf->exec.yeild) |
||
503 | printf(" YIELD"); |
||
504 | if (cf->exec.vc) |
||
505 | printf(" VC(0x%x)", cf->exec.vc); |
||
506 | if (cf->exec.bool_addr) |
||
507 | printf(" BOOL_ADDR(0x%x)", cf->exec.bool_addr); |
||
508 | if (cf->exec.address_mode == ABSOLUTE_ADDR) |
||
509 | printf(" ABSOLUTE_ADDR"); |
||
510 | if (cf_cond_exec(cf)) |
||
511 | printf(" COND(%d)", cf->exec.condition); |
||
512 | } |
||
513 | |||
514 | static void print_cf_loop(instr_cf_t *cf) |
||
515 | { |
||
516 | printf(" ADDR(0x%x) LOOP_ID(%d)", cf->loop.address, cf->loop.loop_id); |
||
517 | if (cf->loop.address_mode == ABSOLUTE_ADDR) |
||
518 | printf(" ABSOLUTE_ADDR"); |
||
519 | } |
||
520 | |||
521 | static void print_cf_jmp_call(instr_cf_t *cf) |
||
522 | { |
||
523 | printf(" ADDR(0x%x) DIR(%d)", cf->jmp_call.address, cf->jmp_call.direction); |
||
524 | if (cf->jmp_call.force_call) |
||
525 | printf(" FORCE_CALL"); |
||
526 | if (cf->jmp_call.predicated_jmp) |
||
527 | printf(" COND(%d)", cf->jmp_call.condition); |
||
528 | if (cf->jmp_call.bool_addr) |
||
529 | printf(" BOOL_ADDR(0x%x)", cf->jmp_call.bool_addr); |
||
530 | if (cf->jmp_call.address_mode == ABSOLUTE_ADDR) |
||
531 | printf(" ABSOLUTE_ADDR"); |
||
532 | } |
||
533 | |||
534 | static void print_cf_alloc(instr_cf_t *cf) |
||
535 | { |
||
536 | static const char *bufname[] = { |
||
537 | [SQ_NO_ALLOC] = "NO ALLOC", |
||
538 | [SQ_POSITION] = "POSITION", |
||
539 | [SQ_PARAMETER_PIXEL] = "PARAM/PIXEL", |
||
540 | [SQ_MEMORY] = "MEMORY", |
||
541 | }; |
||
542 | printf(" %s SIZE(0x%x)", bufname[cf->alloc.buffer_select], cf->alloc.size); |
||
543 | if (cf->alloc.no_serial) |
||
544 | printf(" NO_SERIAL"); |
||
545 | if (cf->alloc.alloc_mode) // ??? |
||
546 | printf(" ALLOC_MODE"); |
||
547 | } |
||
548 | |||
549 | struct { |
||
550 | const char *name; |
||
551 | void (*fxn)(instr_cf_t *cf); |
||
552 | } cf_instructions[] = { |
||
553 | #define INSTR(opc, fxn) [opc] = { #opc, fxn } |
||
554 | INSTR(NOP, print_cf_nop), |
||
555 | INSTR(EXEC, print_cf_exec), |
||
556 | INSTR(EXEC_END, print_cf_exec), |
||
557 | INSTR(COND_EXEC, print_cf_exec), |
||
558 | INSTR(COND_EXEC_END, print_cf_exec), |
||
559 | INSTR(COND_PRED_EXEC, print_cf_exec), |
||
560 | INSTR(COND_PRED_EXEC_END, print_cf_exec), |
||
561 | INSTR(LOOP_START, print_cf_loop), |
||
562 | INSTR(LOOP_END, print_cf_loop), |
||
563 | INSTR(COND_CALL, print_cf_jmp_call), |
||
564 | INSTR(RETURN, print_cf_jmp_call), |
||
565 | INSTR(COND_JMP, print_cf_jmp_call), |
||
566 | INSTR(ALLOC, print_cf_alloc), |
||
567 | INSTR(COND_EXEC_PRED_CLEAN, print_cf_exec), |
||
568 | INSTR(COND_EXEC_PRED_CLEAN_END, print_cf_exec), |
||
569 | INSTR(MARK_VS_FETCH_DONE, print_cf_nop), // ?? |
||
570 | #undef INSTR |
||
571 | }; |
||
572 | |||
573 | static void print_cf(instr_cf_t *cf, int level) |
||
574 | { |
||
575 | printf("%s", levels[level]); |
||
576 | if (debug & PRINT_RAW) { |
||
577 | uint16_t *words = (uint16_t *)cf; |
||
578 | printf(" %04x %04x %04x \t", |
||
579 | words[0], words[1], words[2]); |
||
580 | } |
||
581 | printf("%s", cf_instructions[cf->opc].name); |
||
582 | cf_instructions[cf->opc].fxn(cf); |
||
583 | printf("\n"); |
||
584 | } |
||
585 | |||
586 | /* |
||
587 | * The adreno shader microcode consists of two parts: |
||
588 | * 1) A CF (control-flow) program, at the header of the compiled shader, |
||
589 | * which refers to ALU/FETCH instructions that follow it by address. |
||
590 | * 2) ALU and FETCH instructions |
||
591 | */ |
||
592 | |||
593 | int disasm_a2xx(uint32_t *dwords, int sizedwords, int level, enum shader_t type) |
||
594 | { |
||
595 | instr_cf_t *cfs = (instr_cf_t *)dwords; |
||
596 | int idx, max_idx; |
||
597 | |||
598 | for (idx = 0; ; idx++) { |
||
599 | instr_cf_t *cf = &cfs[idx]; |
||
600 | if (cf_exec(cf)) { |
||
601 | max_idx = 2 * cf->exec.address; |
||
602 | break; |
||
603 | } |
||
604 | } |
||
605 | |||
606 | for (idx = 0; idx < max_idx; idx++) { |
||
607 | instr_cf_t *cf = &cfs[idx]; |
||
608 | |||
609 | print_cf(cf, level); |
||
610 | |||
611 | if (cf_exec(cf)) { |
||
612 | uint32_t sequence = cf->exec.serialize; |
||
613 | uint32_t i; |
||
614 | for (i = 0; i < cf->exec.count; i++) { |
||
615 | uint32_t alu_off = (cf->exec.address + i); |
||
616 | if (sequence & 0x1) { |
||
617 | disasm_fetch(dwords + alu_off * 3, alu_off, level, sequence & 0x2); |
||
618 | } else { |
||
619 | disasm_alu(dwords + alu_off * 3, alu_off, level, sequence & 0x2, type); |
||
620 | } |
||
621 | sequence >>= 2; |
||
622 | } |
||
623 | } |
||
624 | } |
||
625 | |||
626 | return 0; |
||
627 | } |
||
628 | |||
629 | void disasm_set_debug(enum debug_t d) |
||
630 | { |
||
631 | debug = d; |
||
632 | }>>>>>> |