1/*
2 * Copyright (c) 2018 Lima Project
3 *
4 * Copyright (c) 2013 Codethink (http://www.codethink.co.uk)
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sub license,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial portions
15 * of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
24 *
25 */
26
27#include "util/u_half.h"
28
29#include "ppir.h"
30#include "codegen.h"
31
32typedef struct {
33   char *name;
34   unsigned srcs;
35} asm_op;
36
37static void
38print_swizzle(uint8_t swizzle)
39{
40   if (swizzle == 0xE4)
41      return;
42
43   printf(".");
44   for (unsigned i = 0; i < 4; i++, swizzle >>= 2)
45      printf("%c", "xyzw"[swizzle & 3]);
46}
47
48static void
49print_mask(uint8_t mask)
50{
51   if (mask == 0xF)
52      return;
53
54   printf(".");
55   if (mask & 1) printf("x");
56   if (mask & 2) printf("y");
57   if (mask & 4) printf("z");
58   if (mask & 8) printf("w");
59}
60
61static void
62print_reg(ppir_codegen_vec4_reg reg, const char *special)
63{
64   if (special) {
65      printf("%s", special);
66   } else {
67      switch (reg)
68      {
69         case ppir_codegen_vec4_reg_constant0:
70            printf("^const0");
71            break;
72         case ppir_codegen_vec4_reg_constant1:
73            printf("^const1");
74            break;
75         case ppir_codegen_vec4_reg_texture:
76            printf("^texture");
77            break;
78         case ppir_codegen_vec4_reg_uniform:
79            printf("^uniform");
80            break;
81         default:
82            printf("$%u", reg);
83            break;
84      }
85   }
86}
87
88static void
89print_vector_source(ppir_codegen_vec4_reg reg, const char *special,
90                    uint8_t swizzle, bool abs, bool neg)
91{
92   if (neg)
93      printf("-");
94   if (abs)
95      printf("abs(");
96
97   print_reg(reg, special);
98   print_swizzle(swizzle);
99
100   if (abs)
101      printf(")");
102}
103
104static void
105print_source_scalar(unsigned reg, const char *special, bool abs, bool neg)
106{
107   if (neg)
108      printf("-");
109   if (abs)
110      printf("abs(");
111
112   print_reg(reg >> 2, special);
113   if (!special)
114      printf(".%c", "xyzw"[reg & 3]);
115
116   if (abs)
117      printf(")");
118}
119
120static void
121print_outmod(ppir_codegen_outmod modifier)
122{
123   switch (modifier)
124   {
125      case ppir_codegen_outmod_clamp_fraction:
126         printf(".sat");
127         break;
128      case ppir_codegen_outmod_clamp_positive:
129         printf(".pos");
130         break;
131      case ppir_codegen_outmod_round:
132         printf(".int");
133         break;
134      default:
135         break;
136   }
137}
138
139static void
140print_dest_scalar(unsigned reg)
141{
142   printf("$%u", reg >> 2);
143   printf(".%c ", "xyzw"[reg & 3]);
144}
145
146static void
147print_const(unsigned const_num, uint16_t *val)
148{
149   printf("const%u", const_num);
150   for (unsigned i = 0; i < 4; i++)
151      printf(" %f", util_half_to_float(val[i]));
152}
153
154static void
155print_const0(void *code, unsigned offset)
156{
157   (void) offset;
158
159   print_const(0, code);
160}
161
162static void
163print_const1(void *code, unsigned offset)
164{
165   (void) offset;
166
167   print_const(1, code);
168}
169
170static void
171print_varying(void *code, unsigned offset)
172{
173   (void) offset;
174   ppir_codegen_field_varying *varying = code;
175
176   printf("load");
177
178   bool perspective = varying->imm.source_type < 2 && varying->imm.perspective;
179   if (perspective)
180   {
181      printf(".perspective");
182      switch (varying->imm.perspective)
183      {
184      case 2:
185         printf(".z");
186         break;
187      case 3:
188         printf(".w");
189         break;
190      default:
191         printf(".unknown");
192         break;
193      }
194   }
195
196   printf(".v ");
197
198   switch (varying->imm.dest)
199   {
200   case ppir_codegen_vec4_reg_discard:
201      printf("^discard");
202      break;
203   default:
204      printf("$%u", varying->imm.dest);
205      break;
206   }
207   print_mask(varying->imm.mask);
208   printf(" ");
209
210   switch (varying->imm.source_type) {
211   case 1:
212      print_vector_source(varying->reg.source, NULL, varying->reg.swizzle,
213                          varying->reg.absolute, varying->reg.negate);
214      break;
215   case 2:
216      printf("gl_FragCoord");
217      break;
218   case 3:
219      if (varying->imm.perspective)
220         printf("gl_FrontFacing");
221      else
222         printf("gl_PointCoord");
223      break;
224   default:
225      switch (varying->imm.alignment) {
226      case 0:
227         printf("%u.%c", varying->imm.index >> 2,
228                "xyzw"[varying->imm.index & 3]);
229         break;
230      case 1: {
231         const char *c[2] = {"xy", "zw"};
232         printf("%u.%s", varying->imm.index >> 1, c[varying->imm.index & 1]);
233         break;
234      }
235      default:
236         printf("%u", varying->imm.index);
237         break;
238      }
239
240      if (varying->imm.offset_vector != 15) {
241         unsigned reg = (varying->imm.offset_vector << 2) +
242            varying->imm.offset_scalar;
243         printf("+");
244         print_source_scalar(reg, NULL, false, false);
245      }
246      break;
247   }
248}
249
250static void
251print_sampler(void *code, unsigned offset)
252{
253   (void) offset;
254   ppir_codegen_field_sampler *sampler = code;
255
256   printf("texld");
257   if (sampler->lod_bias_en)
258      printf(".b");
259
260   switch (sampler->type) {
261   case ppir_codegen_sampler_type_2d:
262      printf(".2d");
263      break;
264   case ppir_codegen_sampler_type_cube:
265      printf(".cube");
266      break;
267   default:
268      printf("_t%u", sampler->type);
269      break;
270   }
271
272   printf(" %u", sampler->index);
273
274   if (sampler->offset_en)
275   {
276      printf("+");
277      print_source_scalar(sampler->index_offset, NULL, false, false);
278   }
279
280   if (sampler->lod_bias_en)
281   {
282      printf(" ");
283      print_source_scalar(sampler->lod_bias, NULL, false, false);
284   }
285}
286
287static void
288print_uniform(void *code, unsigned offset)
289{
290   (void) offset;
291   ppir_codegen_field_uniform *uniform = code;
292
293   printf("load.");
294
295   switch (uniform->source) {
296   case ppir_codegen_uniform_src_uniform:
297      printf("u");
298      break;
299   case ppir_codegen_uniform_src_temporary:
300      printf("t");
301      break;
302   default:
303      printf(".u%u", uniform->source);
304      break;
305   }
306
307   if (uniform->alignment)
308      printf(" %u", uniform->index);
309   else
310      printf(" %u.%c", uniform->index >> 2, "xyzw"[uniform->index & 3]);
311
312   if (uniform->offset_en) {
313      printf(" ");
314      print_source_scalar(uniform->offset_reg, NULL, false, false);
315   }
316}
317
318#define CASE(_name, _srcs) \
319[ppir_codegen_vec4_mul_op_##_name] = { \
320   .name = #_name, \
321   .srcs = _srcs \
322}
323
324static const asm_op vec4_mul_ops[] = {
325   [0 ... 7] = {
326      .name = "mul",
327      .srcs = 2
328   },
329   CASE(not, 1),
330   CASE(and, 2),
331   CASE(or, 2),
332   CASE(xor, 2),
333   CASE(ne, 2),
334   CASE(gt, 2),
335   CASE(ge, 2),
336   CASE(eq, 2),
337   CASE(min, 2),
338   CASE(max, 2),
339   CASE(mov, 1),
340};
341
342#undef CASE
343
344static void
345print_vec4_mul(void *code, unsigned offset)
346{
347   (void) offset;
348   ppir_codegen_field_vec4_mul *vec4_mul = code;
349
350   asm_op op = vec4_mul_ops[vec4_mul->op];
351
352   if (op.name)
353      printf("%s", op.name);
354   else
355      printf("op%u", vec4_mul->op);
356   print_outmod(vec4_mul->dest_modifier);
357   printf(".v0 ");
358
359   if (vec4_mul->mask) {
360      printf("$%u", vec4_mul->dest);
361      print_mask(vec4_mul->mask);
362      printf(" ");
363   }
364
365   print_vector_source(vec4_mul->arg0_source, NULL,
366                       vec4_mul->arg0_swizzle,
367                       vec4_mul->arg0_absolute,
368                       vec4_mul->arg0_negate);
369
370   if (vec4_mul->op < 8 && vec4_mul->op != 0) {
371      printf("<<%u", vec4_mul->op);
372   }
373
374   printf(" ");
375
376   if (op.srcs > 1) {
377      print_vector_source(vec4_mul->arg1_source, NULL,
378                          vec4_mul->arg1_swizzle,
379                          vec4_mul->arg1_absolute,
380                          vec4_mul->arg1_negate);
381   }
382}
383
384#define CASE(_name, _srcs) \
385[ppir_codegen_vec4_acc_op_##_name] = { \
386   .name = #_name, \
387   .srcs = _srcs \
388}
389
390static const asm_op vec4_acc_ops[] = {
391   CASE(add, 2),
392   CASE(fract, 1),
393   CASE(ne, 2),
394   CASE(gt, 2),
395   CASE(ge, 2),
396   CASE(eq, 2),
397   CASE(floor, 1),
398   CASE(ceil, 1),
399   CASE(min, 2),
400   CASE(max, 2),
401   CASE(sum3, 1),
402   CASE(sum4, 1),
403   CASE(dFdx, 2),
404   CASE(dFdy, 2),
405   CASE(sel, 2),
406   CASE(mov, 1),
407};
408
409#undef CASE
410
411static void
412print_vec4_acc(void *code, unsigned offset)
413{
414   (void) offset;
415   ppir_codegen_field_vec4_acc *vec4_acc = code;
416
417   asm_op op = vec4_acc_ops[vec4_acc->op];
418
419   if (op.name)
420      printf("%s", op.name);
421   else
422      printf("op%u", vec4_acc->op);
423   print_outmod(vec4_acc->dest_modifier);
424   printf(".v1 ");
425
426   if (vec4_acc->mask) {
427      printf("$%u", vec4_acc->dest);
428      print_mask(vec4_acc->mask);
429      printf(" ");
430   }
431
432   print_vector_source(vec4_acc->arg0_source, vec4_acc->mul_in ? "^v0" : NULL,
433                       vec4_acc->arg0_swizzle,
434                       vec4_acc->arg0_absolute,
435                       vec4_acc->arg0_negate);
436
437   if (op.srcs > 1) {
438      printf(" ");
439      print_vector_source(vec4_acc->arg1_source, NULL,
440                          vec4_acc->arg1_swizzle,
441                          vec4_acc->arg1_absolute,
442                          vec4_acc->arg1_negate);
443   }
444}
445
446#define CASE(_name, _srcs) \
447[ppir_codegen_float_mul_op_##_name] = { \
448   .name = #_name, \
449   .srcs = _srcs \
450}
451
452static const asm_op float_mul_ops[] = {
453   [0 ... 7] = {
454      .name = "mul",
455      .srcs = 2
456   },
457   CASE(not, 1),
458   CASE(and, 2),
459   CASE(or, 2),
460   CASE(xor, 2),
461   CASE(ne, 2),
462   CASE(gt, 2),
463   CASE(ge, 2),
464   CASE(eq, 2),
465   CASE(min, 2),
466   CASE(max, 2),
467   CASE(mov, 1),
468};
469
470#undef CASE
471
472static void
473print_float_mul(void *code, unsigned offset)
474{
475   (void) offset;
476   ppir_codegen_field_float_mul *float_mul = code;
477
478   asm_op op = float_mul_ops[float_mul->op];
479
480   if (op.name)
481      printf("%s", op.name);
482   else
483      printf("op%u", float_mul->op);
484   print_outmod(float_mul->dest_modifier);
485   printf(".s0 ");
486
487   if (float_mul->output_en)
488      print_dest_scalar(float_mul->dest);
489
490   print_source_scalar(float_mul->arg0_source, NULL,
491                       float_mul->arg0_absolute,
492                       float_mul->arg0_negate);
493
494   if (float_mul->op < 8 && float_mul->op != 0) {
495      printf("<<%u", float_mul->op);
496   }
497
498   if (op.srcs > 1) {
499      printf(" ");
500
501      print_source_scalar(float_mul->arg1_source, NULL,
502                          float_mul->arg1_absolute,
503                          float_mul->arg1_negate);
504   }
505}
506
507#define CASE(_name, _srcs) \
508[ppir_codegen_float_acc_op_##_name] = { \
509   .name = #_name, \
510   .srcs = _srcs \
511}
512
513static const asm_op float_acc_ops[] = {
514   CASE(add, 2),
515   CASE(fract, 1),
516   CASE(ne, 2),
517   CASE(gt, 2),
518   CASE(ge, 2),
519   CASE(eq, 2),
520   CASE(floor, 1),
521   CASE(ceil, 1),
522   CASE(min, 2),
523   CASE(max, 2),
524   CASE(dFdx, 2),
525   CASE(dFdy, 2),
526   CASE(sel, 2),
527   CASE(mov, 1),
528};
529
530#undef CASE
531
532static void
533print_float_acc(void *code, unsigned offset)
534{
535   (void) offset;
536   ppir_codegen_field_float_acc *float_acc = code;
537
538   asm_op op = float_acc_ops[float_acc->op];
539
540   if (op.name)
541      printf("%s", op.name);
542   else
543      printf("op%u", float_acc->op);
544   print_outmod(float_acc->dest_modifier);
545   printf(".s1 ");
546
547   if (float_acc->output_en)
548      print_dest_scalar(float_acc->dest);
549
550   print_source_scalar(float_acc->arg0_source, float_acc->mul_in ? "^s0" : NULL,
551                       float_acc->arg0_absolute,
552                       float_acc->arg0_negate);
553
554   if (op.srcs > 1) {
555      printf(" ");
556      print_source_scalar(float_acc->arg1_source, NULL,
557                          float_acc->arg1_absolute,
558                          float_acc->arg1_negate);
559   }
560}
561
562#define CASE(_name, _srcs) \
563[ppir_codegen_combine_scalar_op_##_name] = { \
564   .name = #_name, \
565   .srcs = _srcs \
566}
567
568static const asm_op combine_ops[] = {
569   CASE(rcp, 1),
570   CASE(mov, 1),
571   CASE(sqrt, 1),
572   CASE(rsqrt, 1),
573   CASE(exp2, 1),
574   CASE(log2, 1),
575   CASE(sin, 1),
576   CASE(cos, 1),
577   CASE(atan, 1),
578   CASE(atan2, 1),
579};
580
581#undef CASE
582
583static void
584print_combine(void *code, unsigned offset)
585{
586   (void) offset;
587   ppir_codegen_field_combine *combine = code;
588
589   if (combine->scalar.dest_vec &&
590       combine->scalar.arg1_en) {
591      /* This particular combination can only be valid for scalar * vector
592       * multiplies, and the opcode field is reused for something else.
593       */
594      printf("mul");
595   } else {
596      asm_op op = combine_ops[combine->scalar.op];
597
598      if (op.name)
599         printf("%s", op.name);
600      else
601         printf("op%u", combine->scalar.op);
602   }
603
604   if (!combine->scalar.dest_vec)
605      print_outmod(combine->scalar.dest_modifier);
606   printf(".s2 ");
607
608   if (combine->scalar.dest_vec) {
609      printf("$%u", combine->vector.dest);
610      print_mask(combine->vector.mask);
611   } else {
612      print_dest_scalar(combine->scalar.dest);
613   }
614   printf(" ");
615
616   print_source_scalar(combine->scalar.arg0_src, NULL,
617                       combine->scalar.arg0_absolute,
618                       combine->scalar.arg0_negate);
619   printf(" ");
620
621   if (combine->scalar.arg1_en) {
622      if (combine->scalar.dest_vec) {
623         print_vector_source(combine->vector.arg1_source, NULL,
624                             combine->vector.arg1_swizzle,
625                             false, false);
626      } else {
627         print_source_scalar(combine->scalar.arg1_src, NULL,
628                             combine->scalar.arg1_absolute,
629                             combine->scalar.arg1_negate);
630      }
631   }
632}
633
634static void
635print_temp_write(void *code, unsigned offset)
636{
637   (void) offset;
638   ppir_codegen_field_temp_write *temp_write = code;
639
640   if (temp_write->fb_read.unknown_0 == 0x7) {
641      if (temp_write->fb_read.source)
642         printf("fb_color");
643      else
644         printf("fb_depth");
645      printf(" $%u", temp_write->fb_read.dest);
646
647      return;
648   }
649
650   printf("store.t");
651
652   if (temp_write->temp_write.alignment) {
653      printf(" %u", temp_write->temp_write.index);
654   } else {
655      printf(" %u.%c", temp_write->temp_write.index >> 2,
656             "xyzw"[temp_write->temp_write.index & 3]);
657   }
658
659   if (temp_write->temp_write.offset_en) {
660      printf("+");
661      print_source_scalar(temp_write->temp_write.offset_reg,
662                          NULL, false, false);
663   }
664
665   printf(" ");
666
667   if (temp_write->temp_write.alignment) {
668      print_reg(temp_write->temp_write.source >> 2, NULL);
669   } else {
670      print_source_scalar(temp_write->temp_write.source, NULL, false, false);
671   }
672}
673
674static void
675print_branch(void *code, unsigned offset)
676{
677   ppir_codegen_field_branch *branch = code;
678
679   if (branch->discard.word0 == PPIR_CODEGEN_DISCARD_WORD0 &&
680       branch->discard.word1 == PPIR_CODEGEN_DISCARD_WORD1 &&
681       branch->discard.word2 == PPIR_CODEGEN_DISCARD_WORD2) {
682      printf("discard");
683      return;
684   }
685
686
687   const char* cond[] = {
688      "nv", "lt", "eq", "le",
689      "gt", "ne", "ge", ""  ,
690   };
691
692   unsigned cond_mask = 0;
693   cond_mask |= (branch->branch.cond_lt ? 1 : 0);
694   cond_mask |= (branch->branch.cond_eq ? 2 : 0);
695   cond_mask |= (branch->branch.cond_gt ? 4 : 0);
696   printf("branch");
697   if (cond_mask != 0x7) {
698      printf(".%s ", cond[cond_mask]);
699      print_source_scalar(branch->branch.arg0_source, NULL, false, false);
700      printf(" ");
701      print_source_scalar(branch->branch.arg1_source, NULL, false, false);
702   }
703
704   printf(" %d", branch->branch.target + offset);
705}
706
707typedef void (*print_field_func)(void *, unsigned);
708
709static const print_field_func print_field[ppir_codegen_field_shift_count] = {
710   [ppir_codegen_field_shift_varying] = print_varying,
711   [ppir_codegen_field_shift_sampler] = print_sampler,
712   [ppir_codegen_field_shift_uniform] = print_uniform,
713   [ppir_codegen_field_shift_vec4_mul] = print_vec4_mul,
714   [ppir_codegen_field_shift_float_mul] = print_float_mul,
715   [ppir_codegen_field_shift_vec4_acc] = print_vec4_acc,
716   [ppir_codegen_field_shift_float_acc] = print_float_acc,
717   [ppir_codegen_field_shift_combine] = print_combine,
718   [ppir_codegen_field_shift_temp_write] = print_temp_write,
719   [ppir_codegen_field_shift_branch] = print_branch,
720   [ppir_codegen_field_shift_vec4_const_0] = print_const0,
721   [ppir_codegen_field_shift_vec4_const_1] = print_const1,
722};
723
724static const int ppir_codegen_field_size[] = {
725   34, 62, 41, 43, 30, 44, 31, 30, 41, 73, 64, 64
726};
727
728static void
729bitcopy(char *src, char *dst, unsigned bits, unsigned src_offset)
730{
731   src += src_offset / 8;
732   src_offset %= 8;
733
734   for (int b = bits; b > 0; b -= 8, src++, dst++) {
735      unsigned char out = ((unsigned char) *src) >> src_offset;
736      if (src_offset > 0 && src_offset + b > 8)
737         out |= ((unsigned char) *(src + 1)) << (8 - src_offset);
738      *dst = (char) out;
739   }
740}
741
742void
743ppir_disassemble_instr(uint32_t *instr, unsigned offset)
744{
745   ppir_codegen_ctrl *ctrl = (ppir_codegen_ctrl *) instr;
746
747   char *instr_code = (char *) (instr + 1);
748   unsigned bit_offset = 0;
749   bool first = true;
750   for (unsigned i = 0; i < ppir_codegen_field_shift_count; i++) {
751      char code[12];
752
753      if (!((ctrl->fields >> i) & 1))
754         continue;
755
756      unsigned bits = ppir_codegen_field_size[i];
757      bitcopy(instr_code, code, bits, bit_offset);
758
759      if (first)
760         first = false;
761      else
762         printf(", ");
763
764      print_field[i](code, offset);
765
766      bit_offset += bits;
767   }
768
769   if (ctrl->sync)
770      printf(", sync");
771   if (ctrl->stop)
772      printf(", stop");
773
774   printf("\n");
775}
776
777