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