1/*
2 * Copyright (c) 2016 Etnaviv Project
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, sub license,
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
12 * next paragraph) shall be included in all copies or substantial portions
13 * of the 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 NON-INFRINGEMENT. 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
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 *
23 * Authors:
24 *    Christian Gmeiner <christian.gmeiner@gmail.com>
25 */
26
27#include "etnaviv_disasm.h"
28#include "etnaviv_asm.h"
29
30#include <assert.h>
31#include <stdbool.h>
32#include <stdio.h>
33#include <stdlib.h>
34
35#include "hw/isa.xml.h"
36#include "util/u_math.h"
37#include "util/half_float.h"
38
39struct instr {
40   /* dword0: */
41   uint32_t opc         : 6;
42   uint32_t cond        : 5;
43   uint32_t sat         : 1;
44   uint32_t dst_use     : 1;
45   uint32_t dst_amode   : 3;
46   uint32_t dst_reg     : 7;
47   uint32_t dst_comps   : 4;
48   uint32_t tex_id      : 5;
49
50   /* dword1: */
51   uint32_t tex_amode   : 3;
52   uint32_t tex_swiz    : 8;
53   uint32_t src0_use    : 1;
54   uint32_t src0_reg    : 9;
55   uint32_t type_bit2   : 1;
56   uint32_t src0_swiz   : 8;
57   uint32_t src0_neg    : 1;
58   uint32_t src0_abs    : 1;
59
60   /* dword2: */
61   uint32_t src0_amode  : 3;
62   uint32_t src0_rgroup : 3;
63   uint32_t src1_use    : 1;
64   uint32_t src1_reg    : 9;
65   uint32_t opcode_bit6 : 1;
66   uint32_t src1_swiz   : 8;
67   uint32_t src1_neg    : 1;
68   uint32_t src1_abs    : 1;
69   uint32_t src1_amode  : 3;
70   uint32_t type_bit01  : 2;
71
72   /* dword3: */
73   union {
74      struct {
75         uint32_t src1_rgroup : 3;
76         uint32_t src2_use    : 1;
77         uint32_t src2_reg    : 9;
78         uint32_t sel_0       : 1;
79         uint32_t src2_swiz   : 8;
80         uint32_t src2_neg    : 1;
81         uint32_t src2_abs    : 1;
82         uint32_t sel_1       : 1;
83         uint32_t src2_amode  : 3;
84         uint32_t src2_rgroup : 3;
85         uint32_t dst_full    : 1;
86      };
87      uint32_t dword3;
88   };
89};
90struct opc_operands {
91   struct etna_inst_dst *dst;
92   struct etna_inst_tex *tex;
93   struct etna_inst_src *src0;
94   struct etna_inst_src *src1;
95   struct etna_inst_src *src2;
96
97   int imm;
98};
99
100static void
101printf_type(uint8_t type)
102{
103   switch(type) {
104   case INST_TYPE_F32:
105      /* as f32 is the default print nothing */
106      break;
107
108   case INST_TYPE_S32:
109      printf(".s32");
110      break;
111
112   case INST_TYPE_S8:
113      printf(".s8");
114      break;
115
116   case INST_TYPE_U16:
117      printf(".u16");
118      break;
119
120   case INST_TYPE_F16:
121      printf(".f16");
122      break;
123
124   case INST_TYPE_S16:
125      printf(".s16");
126      break;
127
128   case INST_TYPE_U32:
129      printf(".u32");
130      break;
131
132   case INST_TYPE_U8:
133      printf(".u8");
134      break;
135
136   default:
137      abort();
138      break;
139   }
140}
141
142static void
143print_condition(uint8_t condition)
144{
145   switch (condition) {
146   case INST_CONDITION_TRUE:
147      break;
148
149   case INST_CONDITION_GT:
150      printf(".GT");
151      break;
152
153   case INST_CONDITION_LT:
154      printf(".LT");
155      break;
156
157   case INST_CONDITION_GE:
158      printf(".GE");
159      break;
160
161   case INST_CONDITION_LE:
162      printf(".LE");
163      break;
164
165   case INST_CONDITION_EQ:
166      printf(".EQ");
167      break;
168
169   case INST_CONDITION_NE:
170      printf(".NE");
171      break;
172
173   case INST_CONDITION_AND:
174      printf(".AND");
175      break;
176
177   case INST_CONDITION_OR:
178      printf(".OR");
179      break;
180
181   case INST_CONDITION_XOR:
182      printf(".XOR");
183      break;
184
185   case INST_CONDITION_NOT:
186      printf(".NOT");
187      break;
188
189   case INST_CONDITION_NZ:
190      printf(".NZ");
191      break;
192
193   case INST_CONDITION_GEZ:
194      printf(".GEZ");
195      break;
196
197   case INST_CONDITION_GZ:
198      printf(".GZ");
199      break;
200
201   case INST_CONDITION_LEZ:
202      printf(".LEZ");
203      break;
204
205   case INST_CONDITION_LZ:
206      printf(".LZ");
207      break;
208
209   default:
210      abort();
211      break;
212   }
213}
214
215static void
216print_rgroup(uint8_t rgoup)
217{
218   switch (rgoup) {
219   case INST_RGROUP_TEMP:
220      printf("t");
221      break;
222
223   case INST_RGROUP_INTERNAL:
224      printf("i");
225      break;
226
227   case INST_RGROUP_UNIFORM_0:
228   case INST_RGROUP_UNIFORM_1:
229      printf("u");
230      break;
231   case 4:
232      printf("th");
233      break;
234   }
235}
236
237static void
238print_components(uint8_t components)
239{
240   if (components == 15)
241      return;
242
243   printf(".");
244   if (components & INST_COMPS_X)
245      printf("x");
246   else
247      printf("_");
248
249   if (components & INST_COMPS_Y)
250      printf("y");
251   else
252      printf("_");
253
254   if (components & INST_COMPS_Z)
255      printf("z");
256   else
257      printf("_");
258
259   if (components & INST_COMPS_W)
260      printf("w");
261   else
262      printf("_");
263}
264
265static inline void
266print_swiz_comp(uint8_t swiz_comp)
267{
268   switch (swiz_comp) {
269   case INST_SWIZ_COMP_X:
270      printf("x");
271      break;
272
273   case INST_SWIZ_COMP_Y:
274      printf("y");
275      break;
276
277   case INST_SWIZ_COMP_Z:
278      printf("z");
279      break;
280
281   case INST_SWIZ_COMP_W:
282      printf("w");
283      break;
284
285   default:
286      abort();
287      break;
288   }
289}
290
291static void
292print_swiz(uint8_t swiz)
293{
294   // if a null swizzle
295   if (swiz == 0xe4)
296      return;
297
298   const unsigned x = swiz & 0x3;
299   const unsigned y = (swiz & 0x0C) >> 2;
300   const unsigned z = (swiz & 0x30) >> 4;
301   const unsigned w = (swiz & 0xc0) >> 6;
302
303   printf(".");
304   print_swiz_comp(x);
305   print_swiz_comp(y);
306   print_swiz_comp(z);
307   print_swiz_comp(w);
308}
309
310static void
311print_amode(uint8_t amode)
312{
313   switch (amode) {
314   case INST_AMODE_DIRECT:
315      /* nothing to output */
316      break;
317
318   case INST_AMODE_ADD_A_X:
319      printf("[a.x]");
320      break;
321
322   case INST_AMODE_ADD_A_Y:
323      printf("[a.y]");
324      break;
325
326   case INST_AMODE_ADD_A_Z:
327      printf("[a.z]");
328      break;
329
330   case INST_AMODE_ADD_A_W:
331      printf("[a.w]");
332      break;
333
334   default:
335      abort();
336      break;
337   }
338}
339
340static void
341print_dst(struct etna_inst_dst *dst, bool sep)
342{
343   if (dst->use) {
344      printf("t%u", dst->reg);
345      print_amode(dst->amode);
346      print_components(dst->write_mask);
347   } else {
348      printf("void");
349   }
350
351   if (sep)
352      printf(", ");
353}
354
355static void
356print_tex(struct etna_inst_tex *tex, bool sep)
357{
358   printf("tex%u", tex->id);
359   print_amode(tex->amode);
360   print_swiz(tex->swiz);
361
362   if (sep)
363      printf(", ");
364}
365
366static void
367print_src(struct etna_inst_src *src, bool sep)
368{
369   if (src->use) {
370      if (src->rgroup == INST_RGROUP_IMMEDIATE) {
371         switch (src->imm_type) {
372         case 0: /* float */
373            printf("%f", uif(src->imm_val << 12));
374            break;
375         case 1: /* signed */
376            printf("%d", ((int) src->imm_val << 12) >> 12);
377            break;
378         case 2: /* unsigned */
379            printf("%d", src->imm_val);
380            break;
381         case 3: /* 16-bit */
382            printf("%f/%.5X", _mesa_half_to_float(src->imm_val), src->imm_val);
383            break;
384         }
385      } else {
386         if (src->neg)
387            printf("-");
388
389         if (src->abs)
390            printf("|");
391
392         if (src->rgroup == INST_RGROUP_UNIFORM_1)
393            src->reg += 128;
394
395         print_rgroup(src->rgroup);
396         printf("%u", src->reg);
397         print_amode(src->amode);
398         print_swiz(src->swiz);
399
400         if (src->abs)
401            printf("|");
402      }
403   } else {
404      printf("void");
405   }
406
407   if (sep)
408      printf(", ");
409}
410
411static void
412print_opc_default(struct opc_operands *operands)
413{
414   print_dst(operands->dst, true);
415   print_src(operands->src0, true);
416   print_src(operands->src1, true);
417   print_src(operands->src2, false);
418}
419
420static void
421print_opc_mov(struct opc_operands *operands)
422{
423   // dst (areg)
424   printf("a%u", operands->dst->reg);
425   print_components(operands->dst->write_mask);
426   printf(", ");
427
428   print_src(operands->src0, true);
429   print_src(operands->src1, true);
430   print_src(operands->src2, false);
431}
432
433static void
434print_opc_tex(struct opc_operands *operands)
435{
436   print_dst(operands->dst, true);
437   print_tex(operands->tex, true);
438   print_src(operands->src0, true);
439   print_src(operands->src1, true);
440   print_src(operands->src2, false);
441}
442
443static void
444print_opc_imm(struct opc_operands *operands)
445{
446   print_dst(operands->dst, true);
447   print_src(operands->src0, true);
448   print_src(operands->src1, true);
449   printf("label_%04d", operands->imm);
450}
451
452#define OPC_BITS 7
453
454static const struct opc_info {
455   const char *name;
456   void (*print)(struct opc_operands *operands);
457} opcs[1 << OPC_BITS] = {
458#define OPC(opc) [INST_OPCODE_##opc] = {#opc, print_opc_default}
459#define OPC_MOV(opc) [INST_OPCODE_##opc] = {#opc, print_opc_mov}
460#define OPC_TEX(opc) [INST_OPCODE_##opc] = {#opc, print_opc_tex}
461#define OPC_IMM(opc) [INST_OPCODE_##opc] = {#opc, print_opc_imm}
462   OPC(NOP),
463   OPC(ADD),
464   OPC(MAD),
465   OPC(MUL),
466   OPC(DST),
467   OPC(DP3),
468   OPC(DP4),
469   OPC(DSX),
470   OPC(DSY),
471   OPC(MOV),
472   OPC_MOV(MOVAR),
473   OPC_MOV(MOVAF),
474   OPC_MOV(MOVAI),
475   OPC(RCP),
476   OPC(RSQ),
477   OPC(LITP),
478   OPC(SELECT),
479   OPC(SET),
480   OPC(EXP),
481   OPC(LOG),
482   OPC(FRC),
483   OPC_IMM(CALL),
484   OPC(RET),
485   OPC_IMM(BRANCH),
486   OPC_TEX(TEXKILL),
487   OPC_TEX(TEXLD),
488   OPC_TEX(TEXLDB),
489   OPC_TEX(TEXLDD),
490   OPC_TEX(TEXLDL),
491   OPC_TEX(TEXLDPCF),
492   OPC_TEX(TEXLDLPCF),
493   OPC_TEX(TEXLDGPCF),
494   OPC(REP),
495   OPC(ENDREP),
496   OPC(LOOP),
497   OPC(ENDLOOP),
498   OPC(SQRT),
499   OPC(SIN),
500   OPC(COS),
501   OPC(FLOOR),
502   OPC(CEIL),
503   OPC(SIGN),
504   OPC(I2F),
505   OPC(F2I),
506   OPC(CMP),
507   OPC(LOAD),
508   OPC(STORE),
509   OPC(IMULLO0),
510   OPC(IMULHI0),
511   OPC(IMADLO0),
512   OPC(IMADHI0),
513   OPC(LEADZERO),
514   OPC(LSHIFT),
515   OPC(RSHIFT),
516   OPC(ROTATE),
517   OPC(OR),
518   OPC(AND),
519   OPC(XOR),
520   OPC(NOT),
521   OPC(DP2),
522   OPC(DIV),
523   OPC(IABS),
524};
525
526static void
527print_instr(uint32_t *dwords, int n, enum debug_t debug)
528{
529   struct instr *instr = (struct instr *)dwords;
530   const unsigned opc = instr->opc | (instr->opcode_bit6 << 6);
531   const char *name = opcs[opc].name;
532
533   printf("%04d: ", n);
534   if (debug & PRINT_RAW)
535      printf("%08x %08x %08x %08x  ", dwords[0], dwords[1], dwords[2],
536             dwords[3]);
537
538   if (name) {
539
540      struct etna_inst_dst dst = {
541         .use = instr->dst_use,
542         .amode = instr->dst_amode,
543         .reg = instr->dst_reg,
544         .write_mask = instr->dst_comps
545      };
546
547      struct etna_inst_tex tex = {
548         .id = instr->tex_id,
549         .amode = instr->tex_amode,
550         .swiz = instr->tex_swiz,
551      };
552
553      struct etna_inst_src src0 = {
554         .use = instr->src0_use,
555         .neg = instr->src0_neg,
556         .abs = instr->src0_abs,
557         .rgroup = instr->src0_rgroup,
558         .reg = instr->src0_reg,
559         .swiz = instr->src0_swiz,
560         .amode = instr->src0_amode,
561      };
562
563      struct etna_inst_src src1 = {
564         .use = instr->src1_use,
565         .neg = instr->src1_neg,
566         .abs = instr->src1_abs,
567         .rgroup = instr->src1_rgroup,
568         .reg = instr->src1_reg,
569         .swiz = instr->src1_swiz,
570         .amode = instr->src1_amode,
571      };
572
573      struct etna_inst_src src2 = {
574         .use = instr->src2_use,
575         .neg = instr->src2_neg,
576         .abs = instr->src2_abs,
577         .rgroup = instr->src2_rgroup,
578         .reg = instr->src2_reg,
579         .swiz = instr->src2_swiz,
580         .amode = instr->src2_amode,
581      };
582
583      int imm = (instr->dword3 & VIV_ISA_WORD_3_SRC2_IMM__MASK)
584                >> VIV_ISA_WORD_3_SRC2_IMM__SHIFT;
585
586      struct opc_operands operands = {
587         .dst = &dst,
588         .tex = &tex,
589         .src0 = &src0,
590         .src1 = &src1,
591         .src2 = &src2,
592         .imm = imm,
593      };
594
595      uint8_t type = instr->type_bit01 | (instr->type_bit2 << 2);
596
597      printf("%s", name);
598      printf_type(type);
599      if (instr->sat)
600         printf(".SAT");
601      print_condition(instr->cond);
602      printf(" ");
603      if (instr->sel_0)
604         printf("SEL_0 ");
605      if (instr->sel_1)
606         printf("SEL_1 ");
607      if (instr->dst_full)
608         printf("DST_FULL ");
609      opcs[opc].print(&operands);
610   } else {
611      printf("unknown (%d)", instr->opc);
612   }
613
614   printf("\n");
615}
616
617void
618etna_disasm(uint32_t *dwords, int sizedwords, enum debug_t debug)
619{
620   unsigned i;
621
622   assert((sizedwords % 2) == 0);
623
624   for (i = 0; i < sizedwords; i += 4)
625      print_instr(&dwords[i], i / 4, debug);
626}
627