1/* Author(s):
2 *   Connor Abbott
3 *   Alyssa Rosenzweig
4 *
5 * Copyright (c) 2013 Connor Abbott (connor@abbott.cx)
6 * Copyright (c) 2018 Alyssa Rosenzweig (alyssa@rosenzweig.io)
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 * THE SOFTWARE.
25 */
26
27#include <stdio.h>
28#include <stdint.h>
29#include <assert.h>
30#include <inttypes.h>
31#include <string.h>
32#include "midgard.h"
33#include "midgard-parse.h"
34#include "disassemble.h"
35#include "helpers.h"
36#include "util/half_float.h"
37
38#define DEFINE_CASE(define, str) case define: { printf(str); break; }
39
40static bool is_instruction_int = false;
41
42static void
43print_alu_opcode(midgard_alu_op op)
44{
45        bool int_op = false;
46
47        if (alu_opcode_props[op].name) {
48                printf("%s", alu_opcode_props[op].name);
49
50                int_op = midgard_is_integer_op(op);
51        } else
52                printf("alu_op_%02X", op);
53
54        /* For constant analysis */
55        is_instruction_int = int_op;
56}
57
58static void
59print_ld_st_opcode(midgard_load_store_op op)
60{
61        if (load_store_opcode_names[op])
62                printf("%s", load_store_opcode_names[op]);
63        else
64                printf("ldst_op_%02X", op);
65}
66
67static bool is_embedded_constant_half = false;
68static bool is_embedded_constant_int = false;
69
70static char
71prefix_for_bits(unsigned bits)
72{
73        switch (bits) {
74                case 8:
75                        return 'q';
76                case 16:
77                        return 'h';
78                case 64:
79                        return 'd';
80                default:
81                        return 0;
82        }
83}
84
85static void
86print_reg(unsigned reg, unsigned bits)
87{
88        /* Perform basic static analysis for expanding constants correctly */
89
90        if ((bits == 16) && (reg >> 1) == 26) {
91                is_embedded_constant_half = true;
92                is_embedded_constant_int = is_instruction_int;
93        } else if ((bits == 32) && reg == 26) {
94                is_embedded_constant_int = is_instruction_int;
95        } else if (bits == 8) {
96                /* TODO */
97        } else if (bits == 64) {
98                /* TODO */
99        }
100
101        char prefix = prefix_for_bits(bits);
102
103        if (prefix)
104                putchar(prefix);
105
106        printf("r%u", reg);
107}
108
109static char *outmod_names[4] = {
110        "",
111        ".pos",
112        ".int",
113        ".sat"
114};
115
116static void
117print_outmod(midgard_outmod outmod)
118{
119        printf("%s", outmod_names[outmod]);
120}
121
122static void
123print_quad_word(uint32_t *words, unsigned tabs)
124{
125        unsigned i;
126
127        for (i = 0; i < 4; i++)
128                printf("0x%08X%s ", words[i], i == 3 ? "" : ",");
129
130        printf("\n");
131}
132
133static void
134print_vector_src(unsigned src_binary, bool out_high,
135                 midgard_reg_mode mode, unsigned reg,
136                 bool is_int)
137{
138        midgard_vector_alu_src *src = (midgard_vector_alu_src *)&src_binary;
139
140        /* Modifiers change meaning depending on the op's context */
141
142        midgard_int_mod int_mod = src->mod;
143
144        if (is_int) {
145                switch (int_mod) {
146                        case midgard_int_sign_extend:
147                                printf("sext(");
148                                break;
149                        case midgard_int_zero_extend:
150                                printf("zext(");
151                                break;
152                        case midgard_int_reserved:
153                                printf("unk(");
154                                break;
155                        case midgard_int_normal:
156                                /* Implicit */
157                                break;
158                }
159        } else {
160                if (src->mod & MIDGARD_FLOAT_MOD_NEG)
161                        printf("-");
162
163                if (src->mod & MIDGARD_FLOAT_MOD_ABS)
164                        printf("abs(");
165        }
166
167        //register
168
169        if (mode == midgard_reg_mode_8) {
170                if (src->half)
171                        printf(" /* half */ ");
172
173                unsigned quarter_reg = reg * 2;
174
175                if (out_high) {
176                        if (!src->rep_low)
177                                quarter_reg++;
178
179                        if (src->rep_high)
180                                printf(" /* rep_high */ ");
181                } else {
182                        if (src->rep_high)
183                                quarter_reg++;
184
185                        if (src->rep_low)
186                                printf(" /* rep_low */ ");
187                }
188
189                print_reg(quarter_reg, 8);
190        } else if (mode == midgard_reg_mode_16) {
191                if (src->half)
192                        printf(" /* half */ ");
193
194                unsigned half_reg = reg * 2;
195
196                if (out_high) {
197                        if (!src->rep_low)
198                                half_reg++;
199
200                        if (src->rep_high)
201                                printf(" /* rep_high */ ");
202                } else {
203                        if (src->rep_high)
204                                half_reg++;
205
206                        if (src->rep_low)
207                                printf(" /* rep_low */ ");
208                }
209
210                print_reg(half_reg, 16);
211        } else if (mode == midgard_reg_mode_32) {
212                if (src->rep_high)
213                        printf(" /* rep_high */ ");
214
215                if (src->half)
216                        print_reg(reg * 2 + src->rep_low, 16);
217                else {
218                        if (src->rep_low)
219                                printf(" /* rep_low */ ");
220
221                        print_reg(reg, 32);
222                }
223        } else if (mode == midgard_reg_mode_64) {
224                if (src->rep_high)
225                        printf(" /* rep_high */ ");
226
227                if (src->rep_low)
228                        printf(" /* rep_low */ ");
229
230                if (src->half)
231                        printf(" /* half */ ");
232
233                if (out_high)
234                        printf(" /* out_high */ ");
235
236                print_reg(reg, 64);
237        }
238
239        //swizzle
240
241        if (src->swizzle != 0xE4) { //default swizzle
242                unsigned i;
243                static const char c[4] = "xyzw";
244
245                printf(".");
246
247                for (i = 0; i < 4; i++)
248                        printf("%c", c[(src->swizzle >> (i * 2)) & 3]);
249        }
250
251        /* Since we wrapped with a function-looking thing */
252
253        if ((is_int && (int_mod != midgard_int_normal))
254                        || (!is_int && src->mod & MIDGARD_FLOAT_MOD_ABS))
255                printf(")");
256}
257
258static uint16_t
259decode_vector_imm(unsigned src2_reg, unsigned imm)
260{
261        uint16_t ret;
262        ret = src2_reg << 11;
263        ret |= (imm & 0x7) << 8;
264        ret |= (imm >> 3) & 0xFF;
265        return ret;
266}
267
268static void
269print_immediate(uint16_t imm)
270{
271        if (is_instruction_int)
272                printf("#%d", imm);
273        else
274                printf("#%g", _mesa_half_to_float(imm));
275}
276
277static int
278bits_for_mode(midgard_reg_mode mode)
279{
280        switch (mode) {
281                case midgard_reg_mode_8:
282                        return 8;
283                case midgard_reg_mode_16:
284                        return 16;
285                case midgard_reg_mode_32:
286                        return 32;
287                case midgard_reg_mode_64:
288                        return 64;
289                default:
290                        return 0;
291        }
292}
293
294static void
295print_dest(unsigned reg, midgard_reg_mode mode, midgard_dest_override override, bool out_high)
296{
297        bool overriden = override != midgard_dest_override_none;
298        bool overriden_up = override == midgard_dest_override_upper;
299
300        /* Depending on the mode and override, we determine the type of
301         * destination addressed. Absent an override, we address just the
302         * type of the operation itself, directly at the out_reg register
303         * (scaled if necessary to disambiguate, raised if necessary) */
304
305        unsigned bits = bits_for_mode(mode);
306
307        if (overriden)
308                bits /= 2;
309
310        /* Sanity check the override */
311
312        if (overriden) {
313                bool modeable = (mode == midgard_reg_mode_32) || (mode == midgard_reg_mode_16);
314                bool known = override != 0x3; /* Unused value */
315                bool uppable = !overriden_up || (mode == midgard_reg_mode_32);
316
317                if (!(modeable && known && uppable))
318                        printf("/* do%d */ ", override);
319        }
320
321        switch (mode) {
322                case midgard_reg_mode_8:
323                case midgard_reg_mode_16:
324                        reg = reg * 2 + out_high;
325                        break;
326
327                case midgard_reg_mode_32:
328                        if (overriden) {
329                                reg = (reg * 2) + overriden_up;
330                        }
331
332                        break;
333
334                default:
335                        break;
336        }
337
338        print_reg(reg, bits);
339}
340
341static void
342print_vector_field(const char *name, uint16_t *words, uint16_t reg_word,
343                   unsigned tabs)
344{
345        midgard_reg_info *reg_info = (midgard_reg_info *)&reg_word;
346        midgard_vector_alu *alu_field = (midgard_vector_alu *) words;
347        midgard_reg_mode mode = alu_field->reg_mode;
348
349        /* For now, prefix instruction names with their unit, until we
350         * understand how this works on a deeper level */
351        printf("%s.", name);
352
353        print_alu_opcode(alu_field->op);
354        print_outmod(alu_field->outmod);
355        printf(" ");
356
357        bool out_high = false;
358        unsigned mask;
359
360        if (mode == midgard_reg_mode_16
361                || mode == midgard_reg_mode_8) {
362
363                /* For partial views, the mask denotes which adjacent register
364                 * is used as the window into the larger register */
365
366                if (alu_field->mask & 0xF) {
367                        out_high = false;
368
369                        if ((alu_field->mask & 0xF0))
370                                printf("/* %X */ ", alu_field->mask);
371
372                        mask = alu_field->mask;
373                } else {
374                        out_high = true;
375                        mask = alu_field->mask >> 4;
376                }
377        } else {
378                /* For full 32-bit, every other bit is duplicated, so we only
379                 * pick every other to find the effective mask */
380
381                mask = alu_field->mask & 1;
382                mask |= (alu_field->mask & 4) >> 1;
383                mask |= (alu_field->mask & 16) >> 2;
384                mask |= (alu_field->mask & 64) >> 3;
385
386                /* ... but verify! */
387
388                unsigned checked = alu_field->mask & 0x55;
389                unsigned opposite = alu_field->mask & 0xAA;
390
391                if ((checked << 1) != opposite)
392                        printf("/* %X */ ", alu_field->mask);
393        }
394
395        /* First, print the destination */
396        print_dest(reg_info->out_reg, mode, alu_field->dest_override, out_high);
397
398        /* The semantics here are not totally grokked yet */
399        if (alu_field->dest_override == midgard_dest_override_upper)
400                out_high = true;
401
402        if (mask != 0xF) {
403                unsigned i;
404                static const char c[4] = "xyzw";
405
406                printf(".");
407
408                for (i = 0; i < 4; i++)
409                        if (mask & (1 << i))
410                                printf("%c", c[i]);
411        }
412
413        printf(", ");
414
415        bool is_int = midgard_is_integer_op(alu_field->op);
416        print_vector_src(alu_field->src1, out_high, mode, reg_info->src1_reg, is_int);
417
418        printf(", ");
419
420        if (reg_info->src2_imm) {
421                uint16_t imm = decode_vector_imm(reg_info->src2_reg, alu_field->src2 >> 2);
422                print_immediate(imm);
423        } else {
424                print_vector_src(alu_field->src2, out_high, mode,
425                                 reg_info->src2_reg, is_int);
426        }
427
428        printf("\n");
429}
430
431static void
432print_scalar_src(unsigned src_binary, unsigned reg)
433{
434        midgard_scalar_alu_src *src = (midgard_scalar_alu_src *)&src_binary;
435
436        if (src->negate)
437                printf("-");
438
439        if (src->abs)
440                printf("abs(");
441
442        if (src->full)
443                print_reg(reg, 32);
444        else
445                print_reg(reg * 2 + (src->component >> 2), 16);
446
447        static const char c[4] = "xyzw";
448        \
449        printf(".%c", c[src->full ? src->component >> 1 : src->component & 3]);
450
451        if (src->abs)
452                printf(")");
453
454}
455
456static uint16_t
457decode_scalar_imm(unsigned src2_reg, unsigned imm)
458{
459        uint16_t ret;
460        ret = src2_reg << 11;
461        ret |= (imm & 3) << 9;
462        ret |= (imm & 4) << 6;
463        ret |= (imm & 0x38) << 2;
464        ret |= imm >> 6;
465        return ret;
466}
467
468static void
469print_scalar_field(const char *name, uint16_t *words, uint16_t reg_word,
470                   unsigned tabs)
471{
472        midgard_reg_info *reg_info = (midgard_reg_info *)&reg_word;
473        midgard_scalar_alu *alu_field = (midgard_scalar_alu *) words;
474
475        if (alu_field->unknown)
476                printf("scalar ALU unknown bit set\n");
477
478        printf("%s.", name);
479        print_alu_opcode(alu_field->op);
480        print_outmod(alu_field->outmod);
481        printf(" ");
482
483        if (alu_field->output_full)
484                print_reg(reg_info->out_reg, 32);
485        else
486                print_reg(reg_info->out_reg * 2 + (alu_field->output_component >> 2),
487                          16);
488
489        static const char c[4] = "xyzw";
490        printf(".%c, ",
491               c[alu_field->output_full ? alu_field->output_component >> 1 :
492                                        alu_field->output_component & 3]);
493
494        print_scalar_src(alu_field->src1, reg_info->src1_reg);
495
496        printf(", ");
497
498        if (reg_info->src2_imm) {
499                uint16_t imm = decode_scalar_imm(reg_info->src2_reg,
500                                                 alu_field->src2);
501                print_immediate(imm);
502        } else
503                print_scalar_src(alu_field->src2, reg_info->src2_reg);
504
505        printf("\n");
506}
507
508static void
509print_branch_op(int op)
510{
511        switch (op) {
512        case midgard_jmp_writeout_op_branch_uncond:
513                printf("uncond.");
514                break;
515
516        case midgard_jmp_writeout_op_branch_cond:
517                printf("cond.");
518                break;
519
520        case midgard_jmp_writeout_op_writeout:
521                printf("write.");
522                break;
523
524        case midgard_jmp_writeout_op_tilebuffer_pending:
525                printf("tilebuffer.");
526                break;
527
528        case midgard_jmp_writeout_op_discard:
529                printf("discard.");
530                break;
531
532        default:
533                printf("unk%d.", op);
534                break;
535        }
536}
537
538static void
539print_branch_cond(int cond)
540{
541        switch (cond) {
542        case midgard_condition_write0:
543                printf("write0");
544                break;
545
546        case midgard_condition_false:
547                printf("false");
548                break;
549
550        case midgard_condition_true:
551                printf("true");
552                break;
553
554        case midgard_condition_always:
555                printf("always");
556                break;
557
558        default:
559                printf("unk%X", cond);
560                break;
561        }
562}
563
564static void
565print_compact_branch_writeout_field(uint16_t word)
566{
567        midgard_jmp_writeout_op op = word & 0x7;
568
569        switch (op) {
570        case midgard_jmp_writeout_op_branch_uncond: {
571                midgard_branch_uncond br_uncond;
572                memcpy((char *) &br_uncond, (char *) &word, sizeof(br_uncond));
573                printf("br.uncond ");
574
575                if (br_uncond.unknown != 1)
576                        printf("unknown:%d, ", br_uncond.unknown);
577
578                if (br_uncond.offset >= 0)
579                        printf("+");
580
581                printf("%d", br_uncond.offset);
582
583                printf(" -> %X\n", br_uncond.dest_tag);
584                break;
585        }
586
587        case midgard_jmp_writeout_op_branch_cond:
588        case midgard_jmp_writeout_op_writeout:
589        case midgard_jmp_writeout_op_discard:
590        default: {
591                midgard_branch_cond br_cond;
592                memcpy((char *) &br_cond, (char *) &word, sizeof(br_cond));
593
594                printf("br.");
595
596                print_branch_op(br_cond.op);
597                print_branch_cond(br_cond.cond);
598
599                printf(" ");
600
601                if (br_cond.offset >= 0)
602                        printf("+");
603
604                printf("%d", br_cond.offset);
605
606                printf(" -> %X\n", br_cond.dest_tag);
607                break;
608        }
609        }
610}
611
612static void
613print_extended_branch_writeout_field(uint8_t *words)
614{
615        midgard_branch_extended br;
616        memcpy((char *) &br, (char *) words, sizeof(br));
617
618        printf("brx.");
619
620        print_branch_op(br.op);
621
622        /* Condition repeated 8 times in all known cases. Check this. */
623
624        unsigned cond = br.cond & 0x3;
625
626        for (unsigned i = 0; i < 16; i += 2) {
627                assert(((br.cond >> i) & 0x3) == cond);
628        }
629
630        print_branch_cond(cond);
631
632        if (br.unknown)
633                printf(".unknown%d", br.unknown);
634
635        printf(" ");
636
637        if (br.offset >= 0)
638                printf("+");
639
640        printf("%d", br.offset);
641
642        printf(" -> %X\n", br.dest_tag);
643}
644
645static unsigned
646num_alu_fields_enabled(uint32_t control_word)
647{
648        unsigned ret = 0;
649
650        if ((control_word >> 17) & 1)
651                ret++;
652
653        if ((control_word >> 19) & 1)
654                ret++;
655
656        if ((control_word >> 21) & 1)
657                ret++;
658
659        if ((control_word >> 23) & 1)
660                ret++;
661
662        if ((control_word >> 25) & 1)
663                ret++;
664
665        return ret;
666}
667
668static float
669float_bitcast(uint32_t integer)
670{
671        union {
672                uint32_t i;
673                float f;
674        } v;
675
676        v.i = integer;
677        return v.f;
678}
679
680static void
681print_alu_word(uint32_t *words, unsigned num_quad_words,
682               unsigned tabs)
683{
684        uint32_t control_word = words[0];
685        uint16_t *beginning_ptr = (uint16_t *)(words + 1);
686        unsigned num_fields = num_alu_fields_enabled(control_word);
687        uint16_t *word_ptr = beginning_ptr + num_fields;
688        unsigned num_words = 2 + num_fields;
689
690        if ((control_word >> 16) & 1)
691                printf("unknown bit 16 enabled\n");
692
693        if ((control_word >> 17) & 1) {
694                print_vector_field("vmul", word_ptr, *beginning_ptr, tabs);
695                beginning_ptr += 1;
696                word_ptr += 3;
697                num_words += 3;
698        }
699
700        if ((control_word >> 18) & 1)
701                printf("unknown bit 18 enabled\n");
702
703        if ((control_word >> 19) & 1) {
704                print_scalar_field("sadd", word_ptr, *beginning_ptr, tabs);
705                beginning_ptr += 1;
706                word_ptr += 2;
707                num_words += 2;
708        }
709
710        if ((control_word >> 20) & 1)
711                printf("unknown bit 20 enabled\n");
712
713        if ((control_word >> 21) & 1) {
714                print_vector_field("vadd", word_ptr, *beginning_ptr, tabs);
715                beginning_ptr += 1;
716                word_ptr += 3;
717                num_words += 3;
718        }
719
720        if ((control_word >> 22) & 1)
721                printf("unknown bit 22 enabled\n");
722
723        if ((control_word >> 23) & 1) {
724                print_scalar_field("smul", word_ptr, *beginning_ptr, tabs);
725                beginning_ptr += 1;
726                word_ptr += 2;
727                num_words += 2;
728        }
729
730        if ((control_word >> 24) & 1)
731                printf("unknown bit 24 enabled\n");
732
733        if ((control_word >> 25) & 1) {
734                print_vector_field("lut", word_ptr, *beginning_ptr, tabs);
735                beginning_ptr += 1;
736                word_ptr += 3;
737                num_words += 3;
738        }
739
740        if ((control_word >> 26) & 1) {
741                print_compact_branch_writeout_field(*word_ptr);
742                word_ptr += 1;
743                num_words += 1;
744        }
745
746        if ((control_word >> 27) & 1) {
747                print_extended_branch_writeout_field((uint8_t *) word_ptr);
748                word_ptr += 3;
749                num_words += 3;
750        }
751
752        if (num_quad_words > (num_words + 7) / 8) {
753                assert(num_quad_words == (num_words + 15) / 8);
754                //Assume that the extra quadword is constants
755                void *consts = words + (4 * num_quad_words - 4);
756
757                if (is_embedded_constant_int) {
758                        if (is_embedded_constant_half) {
759                                int16_t *sconsts = (int16_t *) consts;
760                                printf("sconstants %d, %d, %d, %d\n",
761                                       sconsts[0],
762                                       sconsts[1],
763                                       sconsts[2],
764                                       sconsts[3]);
765                        } else {
766                                int32_t *iconsts = (int32_t *) consts;
767                                printf("iconstants %d, %d, %d, %d\n",
768                                       iconsts[0],
769                                       iconsts[1],
770                                       iconsts[2],
771                                       iconsts[3]);
772                        }
773                } else {
774                        if (is_embedded_constant_half) {
775                                uint16_t *hconsts = (uint16_t *) consts;
776                                printf("hconstants %g, %g, %g, %g\n",
777                                       _mesa_half_to_float(hconsts[0]),
778                                       _mesa_half_to_float(hconsts[1]),
779                                       _mesa_half_to_float(hconsts[2]),
780                                       _mesa_half_to_float(hconsts[3]));
781                        } else {
782                                uint32_t *fconsts = (uint32_t *) consts;
783                                printf("fconstants %g, %g, %g, %g\n",
784                                       float_bitcast(fconsts[0]),
785                                       float_bitcast(fconsts[1]),
786                                       float_bitcast(fconsts[2]),
787                                       float_bitcast(fconsts[3]));
788                        }
789
790                }
791        }
792}
793
794/* Swizzle/mask formats are common between load/store ops and texture ops, it
795 * looks like... */
796
797static void
798print_swizzle(uint32_t swizzle)
799{
800        unsigned i;
801
802        if (swizzle != 0xE4) {
803                printf(".");
804
805                for (i = 0; i < 4; i++)
806                        printf("%c", "xyzw"[(swizzle >> (2 * i)) & 3]);
807        }
808}
809
810static void
811print_mask(uint32_t mask)
812{
813        unsigned i;
814
815        if (mask != 0xF) {
816                printf(".");
817
818                for (i = 0; i < 4; i++)
819                        if (mask & (1 << i))
820                                printf("%c", "xyzw"[i]);
821
822                /* Handle degenerate case */
823                if (mask == 0)
824                        printf("0");
825        }
826}
827
828static void
829print_varying_parameters(midgard_load_store_word *word)
830{
831        midgard_varying_parameter param;
832        unsigned v = word->varying_parameters;
833        memcpy(&param, &v, sizeof(param));
834
835        if (param.is_varying) {
836                /* If a varying, there are qualifiers */
837                if (param.flat)
838                        printf(".flat");
839
840                if (param.interpolation != midgard_interp_default) {
841                        if (param.interpolation == midgard_interp_centroid)
842                                printf(".centroid");
843                        else
844                                printf(".interp%d", param.interpolation);
845                }
846        } else if (param.flat || param.interpolation) {
847                printf(" /* is_varying not set but varying metadata attached */");
848        }
849
850        if (param.zero1 || param.zero2)
851                printf(" /* zero tripped, %d %d */ ", param.zero1, param.zero2);
852}
853
854static bool
855is_op_varying(unsigned op)
856{
857        switch (op) {
858        case midgard_op_store_vary_16:
859        case midgard_op_store_vary_32:
860        case midgard_op_load_vary_16:
861        case midgard_op_load_vary_32:
862                return true;
863        }
864
865        return false;
866}
867
868static void
869print_load_store_instr(uint64_t data,
870                       unsigned tabs)
871{
872        midgard_load_store_word *word = (midgard_load_store_word *) &data;
873
874        print_ld_st_opcode(word->op);
875
876        if (is_op_varying(word->op))
877                print_varying_parameters(word);
878
879        printf(" r%d", word->reg);
880        print_mask(word->mask);
881
882        int address = word->address;
883
884        if (word->op == midgard_op_load_uniform_32) {
885                /* Uniforms use their own addressing scheme */
886
887                int lo = word->varying_parameters >> 7;
888                int hi = word->address;
889
890                /* TODO: Combine fields logically */
891                address = (hi << 3) | lo;
892        }
893
894        printf(", %d", address);
895
896        print_swizzle(word->swizzle);
897
898        printf(", 0x%X /* %X */\n", word->unknown, word->varying_parameters);
899}
900
901static void
902print_load_store_word(uint32_t *word, unsigned tabs)
903{
904        midgard_load_store *load_store = (midgard_load_store *) word;
905
906        if (load_store->word1 != 3) {
907                print_load_store_instr(load_store->word1, tabs);
908        }
909
910        if (load_store->word2 != 3) {
911                print_load_store_instr(load_store->word2, tabs);
912        }
913}
914
915static void
916print_texture_reg(bool full, bool select, bool upper)
917{
918        if (full)
919                printf("r%d", REG_TEX_BASE + select);
920        else
921                printf("hr%d", (REG_TEX_BASE + select) * 2 + upper);
922
923        if (full && upper)
924                printf("// error: out full / upper mutually exclusive\n");
925
926}
927
928static void
929print_texture_format(int format)
930{
931        /* Act like a modifier */
932        printf(".");
933
934        switch (format) {
935                DEFINE_CASE(TEXTURE_2D, "2d");
936                DEFINE_CASE(TEXTURE_3D, "3d");
937                DEFINE_CASE(TEXTURE_CUBE, "cube");
938
939        default:
940                printf("fmt_%d", format);
941                break;
942        }
943}
944
945static void
946print_texture_op(int format)
947{
948        /* Act like a modifier */
949        printf(".");
950
951        switch (format) {
952                DEFINE_CASE(TEXTURE_OP_NORMAL, "normal");
953                DEFINE_CASE(TEXTURE_OP_TEXEL_FETCH, "texelfetch");
954
955        default:
956                printf("op_%d", format);
957                break;
958        }
959}
960
961#undef DEFINE_CASE
962
963static void
964print_texture_word(uint32_t *word, unsigned tabs)
965{
966        midgard_texture_word *texture = (midgard_texture_word *) word;
967
968        /* Instruction family, like ALU words have theirs */
969        printf("texture");
970
971        /* Broad category of texture operation in question */
972        print_texture_op(texture->op);
973
974        /* Specific format in question */
975        print_texture_format(texture->format);
976
977        /* Instruction "modifiers" parallel the ALU instructions. First group
978         * are modifiers that act alone */
979
980        if (!texture->filter)
981                printf(".raw");
982
983        if (texture->shadow)
984                printf(".shadow");
985
986        if (texture->cont)
987                printf(".cont");
988
989        if (texture->last)
990                printf(".last");
991
992        /* Second set are modifiers which take an extra argument each */
993
994        if (texture->has_offset)
995                printf(".offset");
996
997        if (texture->bias)
998                printf(".bias");
999
1000        printf(" ");
1001
1002        print_texture_reg(texture->out_full, texture->out_reg_select, texture->out_upper);
1003        print_mask(texture->mask);
1004        printf(", ");
1005
1006        printf("texture%d, ", texture->texture_handle);
1007
1008        printf("sampler%d", texture->sampler_handle);
1009        print_swizzle(texture->swizzle);
1010        printf(", ");
1011
1012        print_texture_reg(/*texture->in_reg_full*/true, texture->in_reg_select, texture->in_reg_upper);
1013        printf(".%c%c, ", "xyzw"[texture->in_reg_swizzle_left],
1014               "xyzw"[texture->in_reg_swizzle_right]);
1015
1016        /* TODO: can offsets be full words? */
1017        if (texture->has_offset) {
1018                print_texture_reg(false, texture->offset_reg_select, texture->offset_reg_upper);
1019                printf(", ");
1020        }
1021
1022        if (texture->bias)
1023                printf("%f, ", texture->bias / 256.0f);
1024
1025        printf("\n");
1026
1027        /* While not zero in general, for these simple instructions the
1028         * following unknowns are zero, so we don't include them */
1029
1030        if (texture->unknown1 ||
1031                        texture->unknown2 ||
1032                        texture->unknown3 ||
1033                        texture->unknown4 ||
1034                        texture->unknownA ||
1035                        texture->unknownB ||
1036                        texture->unknown8 ||
1037                        texture->unknown9) {
1038                printf("// unknown1 = 0x%x\n", texture->unknown1);
1039                printf("// unknown2 = 0x%x\n", texture->unknown2);
1040                printf("// unknown3 = 0x%x\n", texture->unknown3);
1041                printf("// unknown4 = 0x%x\n", texture->unknown4);
1042                printf("// unknownA = 0x%x\n", texture->unknownA);
1043                printf("// unknownB = 0x%x\n", texture->unknownB);
1044                printf("// unknown8 = 0x%x\n", texture->unknown8);
1045                printf("// unknown9 = 0x%x\n", texture->unknown9);
1046        }
1047
1048        /* Similarly, if no offset is applied, these are zero. If an offset
1049         * -is- applied, or gradients are used, etc, these are nonzero but
1050         *  largely unknown still. */
1051
1052        if (texture->offset_unknown1 ||
1053                        texture->offset_reg_select ||
1054                        texture->offset_reg_upper ||
1055                        texture->offset_unknown4 ||
1056                        texture->offset_unknown5 ||
1057                        texture->offset_unknown6 ||
1058                        texture->offset_unknown7 ||
1059                        texture->offset_unknown8 ||
1060                        texture->offset_unknown9) {
1061                printf("// offset_unknown1 = 0x%x\n", texture->offset_unknown1);
1062                printf("// offset_reg_select = 0x%x\n", texture->offset_reg_select);
1063                printf("// offset_reg_upper = 0x%x\n", texture->offset_reg_upper);
1064                printf("// offset_unknown4 = 0x%x\n", texture->offset_unknown4);
1065                printf("// offset_unknown5 = 0x%x\n", texture->offset_unknown5);
1066                printf("// offset_unknown6 = 0x%x\n", texture->offset_unknown6);
1067                printf("// offset_unknown7 = 0x%x\n", texture->offset_unknown7);
1068                printf("// offset_unknown8 = 0x%x\n", texture->offset_unknown8);
1069                printf("// offset_unknown9 = 0x%x\n", texture->offset_unknown9);
1070        }
1071
1072        /* Don't blow up */
1073        if (texture->unknown7 != 0x1)
1074                printf("// (!) unknown7 = %d\n", texture->unknown7);
1075}
1076
1077void
1078disassemble_midgard(uint8_t *code, size_t size)
1079{
1080        uint32_t *words = (uint32_t *) code;
1081        unsigned num_words = size / 4;
1082        int tabs = 0;
1083
1084        bool prefetch_flag = false;
1085
1086        unsigned i = 0;
1087
1088        while (i < num_words) {
1089                unsigned num_quad_words = midgard_word_size[words[i] & 0xF];
1090
1091                switch (midgard_word_types[words[i] & 0xF]) {
1092                case midgard_word_type_texture:
1093                        print_texture_word(&words[i], tabs);
1094                        break;
1095
1096                case midgard_word_type_load_store:
1097                        print_load_store_word(&words[i], tabs);
1098                        break;
1099
1100                case midgard_word_type_alu:
1101                        print_alu_word(&words[i], num_quad_words, tabs);
1102
1103                        if (prefetch_flag)
1104                                return;
1105
1106                        /* Reset word static analysis state */
1107                        is_embedded_constant_half = false;
1108                        is_embedded_constant_int = false;
1109
1110                        break;
1111
1112                default:
1113                        printf("Unknown word type %u:\n", words[i] & 0xF);
1114                        num_quad_words = 1;
1115                        print_quad_word(&words[i], tabs);
1116                        printf("\n");
1117                        break;
1118                }
1119
1120                printf("\n");
1121
1122                unsigned next = (words[i] & 0xF0) >> 4;
1123
1124                i += 4 * num_quad_words;
1125
1126                /* Break based on instruction prefetch flag */
1127
1128                if (i < num_words && next == 1) {
1129                        prefetch_flag = true;
1130
1131                        if (midgard_word_types[words[i] & 0xF] != midgard_word_type_alu)
1132                                return;
1133                }
1134        }
1135
1136        return;
1137}
1138