* Removed all Id tags.
[cacao.git] / src / vm / jit / alpha / disass.c
1 /* src/vm/jit/alpha/disass.c - primitive disassembler for Alpha machine code
2
3    Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
4    C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5    E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6    J. Wenninger, Institut f. Computersprachen - TU Wien
7
8    This file is part of CACAO.
9
10    This program is free software; you can redistribute it and/or
11    modify it under the terms of the GNU General Public License as
12    published by the Free Software Foundation; either version 2, or (at
13    your option) any later version.
14
15    This program is distributed in the hope that it will be useful, but
16    WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23    02110-1301, USA.
24
25 */
26
27
28 #include "config.h"
29
30 #include <stdio.h>
31
32 #include "vm/types.h"
33
34 #include "vm/global.h"
35
36 #include "vm/jit/abi.h"
37 #include "vm/jit/disass.h"
38
39
40 /*  The disassembler uses two tables for decoding the instructions. The first
41         table (ops) is used to classify the instructions based on the op code and
42         contains the instruction names for instructions which don't used the
43         function codes. This table is indexed by the op code (6 bit, 64 entries).
44         The second table (op3s) contains instructions which contain both an op
45         code and a function code. This table is an unsorted list of instructions
46         which is terminated by op code and function code zero. This list is
47         searched linearly for a matching pair of opcode and function code.
48 */
49
50 #define ITYPE_UNDEF 0           /* undefined instructions (illegal opcode)    */
51 #define ITYPE_JMP   1           /* jump instructions                          */
52 #define ITYPE_MEM   2           /* memory instructions                        */
53 #define ITYPE_FMEM  3           /* floating point memory instructions         */
54 #define ITYPE_BRA   4           /* branch instructions                        */
55 #define ITYPE_OP    5           /* integer instructions                       */
56 #define ITYPE_FOP   6           /* floating point instructions                */
57
58
59 /* instruction decode table for 6 bit op codes                                */
60
61 static struct {char *name; int itype;} ops[] = {
62         /* 0x00 */  {"",        ITYPE_UNDEF},
63         /* 0x01 */  {"",        ITYPE_UNDEF},
64         /* 0x02 */  {"",        ITYPE_UNDEF},
65         /* 0x03 */  {"",        ITYPE_UNDEF},
66         /* 0x04 */  {"",        ITYPE_UNDEF},
67         /* 0x05 */  {"",        ITYPE_UNDEF},
68         /* 0x06 */  {"",        ITYPE_UNDEF},
69         /* 0x07 */  {"",        ITYPE_UNDEF},
70         /* 0x08 */  {"lda    ",   ITYPE_MEM},
71         /* 0x09 */  {"ldah   ",   ITYPE_MEM},
72         /* 0x0a */  {"ldb    ",   ITYPE_MEM},
73         /* 0x0b */  {"ldq_u  ",   ITYPE_MEM},
74         /* 0x0c */  {"ldw    ",   ITYPE_MEM},
75         /* 0x0d */  {"stw    ",   ITYPE_MEM},
76         /* 0x0e */  {"stb    ",   ITYPE_MEM},
77         /* 0x0f */  {"stq_u  ",   ITYPE_MEM},
78         /* 0x10 */  {"op     ",    ITYPE_OP},
79         /* 0x11 */  {"op     ",    ITYPE_OP},
80         /* 0x12 */  {"op     ",    ITYPE_OP},
81         /* 0x13 */  {"op     ",    ITYPE_OP},
82         /* 0x14 */  {"",        ITYPE_UNDEF},
83         /* 0x15 */  {"",        ITYPE_UNDEF},
84         /* 0x16 */  {"fop    ",   ITYPE_FOP},
85         /* 0x17 */  {"fop    ",   ITYPE_FOP},
86         /* 0x18 */  {"memfmt ",   ITYPE_MEM},
87         /* 0x19 */  {"",        ITYPE_UNDEF},
88         /* 0x1a */  {"jmp    ",   ITYPE_JMP},
89         /* 0x1b */  {"",        ITYPE_UNDEF},
90         /* 0x1c */  {"op     ",    ITYPE_OP},
91         /* 0x1d */  {"",        ITYPE_UNDEF},
92         /* 0x1e */  {"",        ITYPE_UNDEF},
93         /* 0x1f */  {"",        ITYPE_UNDEF},
94         /* 0x20 */  {"ldf    ",  ITYPE_FMEM},
95         /* 0x21 */  {"ldg    ",  ITYPE_FMEM},
96         /* 0x22 */  {"lds    ",  ITYPE_FMEM},
97         /* 0x23 */  {"ldt    ",  ITYPE_FMEM},
98         /* 0x24 */  {"stf    ",  ITYPE_FMEM},
99         /* 0x25 */  {"stg    ",  ITYPE_FMEM},
100         /* 0x26 */  {"sts    ",  ITYPE_FMEM},
101         /* 0x27 */  {"stt    ",  ITYPE_FMEM},
102         /* 0x28 */  {"ldl    ",   ITYPE_MEM},
103         /* 0x29 */  {"ldq    ",   ITYPE_MEM},
104         /* 0x2a */  {"ldl_l  ",   ITYPE_MEM},
105         /* 0x2b */  {"ldq_l  ",   ITYPE_MEM},
106         /* 0x2c */  {"stl    ",   ITYPE_MEM},
107         /* 0x2d */  {"stq    ",   ITYPE_MEM},
108         /* 0x2e */  {"stl_c  ",   ITYPE_MEM},
109         /* 0x2f */  {"stq_c  ",   ITYPE_MEM},
110         /* 0x30 */  {"br     ",   ITYPE_BRA},
111         /* 0x31 */  {"fbeq   ",   ITYPE_BRA},
112         /* 0x32 */  {"fblt   ",   ITYPE_BRA},
113         /* 0x33 */  {"fble   ",   ITYPE_BRA},
114         /* 0x34 */  {"bsr    ",   ITYPE_BRA},
115         /* 0x35 */  {"fbne   ",   ITYPE_BRA},
116         /* 0x36 */  {"fbge   ",   ITYPE_BRA},
117         /* 0x37 */  {"fbgt   ",   ITYPE_BRA},
118         /* 0x38 */  {"blbc   ",   ITYPE_BRA},
119         /* 0x39 */  {"beq    ",   ITYPE_BRA},
120         /* 0x3a */  {"blt    ",   ITYPE_BRA},
121         /* 0x3b */  {"ble    ",   ITYPE_BRA},
122         /* 0x3c */  {"blbs   ",   ITYPE_BRA},
123         /* 0x3d */  {"bne    ",   ITYPE_BRA},
124         /* 0x3e */  {"bge    ",   ITYPE_BRA},
125         /* 0x3f */  {"bgt    ",   ITYPE_BRA}
126 };
127
128
129 /* instruction decode list for 6 bit op codes and 9 bit function codes        */
130  
131 static struct { u2 op, fun; char *name; }  op3s[] = {
132         { 0x10, 0x00,  "addl   " },
133         { 0x10, 0x40,  "addl/v " },
134         { 0x10, 0x20,  "addq   " },
135         { 0x10, 0x60,  "addq/v " },
136         { 0x10, 0x09,  "subl   " },
137         { 0x10, 0x49,  "subl/v " },
138         { 0x10, 0x29,  "subq   " },
139         { 0x10, 0x69,  "subq/v " },
140         { 0x10, 0x2D,  "cmpeq  " },
141         { 0x10, 0x4D,  "cmplt  " },
142         { 0x10, 0x6D,  "cmple  " },
143         { 0x10, 0x1D,  "cmpult " },
144         { 0x10, 0x3D,  "cmpule " },
145         { 0x10, 0x0F,  "cmpbge " },
146         { 0x10, 0x02,  "s4addl " },
147         { 0x10, 0x0b,  "s4subl " },
148         { 0x10, 0x22,  "s4addq " },
149         { 0x10, 0x2b,  "s4subq " },
150         { 0x10, 0x12,  "s8addl " },
151         { 0x10, 0x1b,  "s8subl " },
152         { 0x10, 0x32,  "s8addq " },
153         { 0x10, 0x3b,  "s8subq " },
154         { 0x11, 0x00,  "and    " },
155         { 0x11, 0x20,  "or     " },
156         { 0x11, 0x40,  "xor    " },
157         { 0x11, 0x08,  "andnot " },
158         { 0x11, 0x28,  "ornot  " },
159         { 0x11, 0x48,  "xornot " },
160         { 0x11, 0x24,  "cmoveq " },
161         { 0x11, 0x44,  "cmovlt " },
162         { 0x11, 0x64,  "cmovle " },
163         { 0x11, 0x26,  "cmovne " },
164         { 0x11, 0x46,  "cmovge " },
165         { 0x11, 0x66,  "cmovgt " },
166         { 0x11, 0x14,  "cmovlbs" },
167         { 0x11, 0x16,  "cmovlbc" },
168         { 0x12, 0x39,  "sll    " },
169         { 0x12, 0x3C,  "sra    " },
170         { 0x12, 0x34,  "srl    " },
171         { 0x12, 0x30,  "zap    " },
172         { 0x12, 0x31,  "zapnot " },
173         { 0x12, 0x06,  "extbl  " },
174         { 0x12, 0x16,  "extwl  " },
175         { 0x12, 0x26,  "extll  " },
176         { 0x12, 0x36,  "extql  " },
177         { 0x12, 0x5a,  "extwh  " },
178         { 0x12, 0x6a,  "extlh  " },
179         { 0x12, 0x7a,  "extqh  " },
180         { 0x12, 0x0b,  "insbl  " },
181         { 0x12, 0x1b,  "inswl  " },
182         { 0x12, 0x2b,  "insll  " },
183         { 0x12, 0x3b,  "insql  " },
184         { 0x12, 0x57,  "inswh  " },
185         { 0x12, 0x67,  "inslh  " },
186         { 0x12, 0x77,  "insqh  " },
187         { 0x12, 0x02,  "mskbl  " },
188         { 0x12, 0x12,  "mskwl  " },
189         { 0x12, 0x22,  "mskll  " },
190         { 0x12, 0x32,  "mskql  " },
191         { 0x12, 0x52,  "mskwh  " },
192         { 0x12, 0x62,  "msklh  " },
193         { 0x12, 0x72,  "mskqh  " },
194         { 0x13, 0x00,  "mull   " },
195         { 0x13, 0x20,  "mulq   " },
196         { 0x13, 0x40,  "mull/v " },
197         { 0x13, 0x60,  "mulq/v " },
198         { 0x13, 0x30,  "umulh  " },
199         { 0x16, 0x080, "fadd   " },
200         { 0x16, 0x0a0, "dadd   " },
201         { 0x16, 0x081, "fsub   " },
202         { 0x16, 0x0a1, "dsub   " },
203         { 0x16, 0x082, "fmul   " },
204         { 0x16, 0x0a2, "dmul   " },
205         { 0x16, 0x083, "fdiv   " },
206         { 0x16, 0x0a3, "ddiv   " },
207         { 0x16, 0x580, "fadds  " },
208         { 0x16, 0x5a0, "dadds  " },
209         { 0x16, 0x581, "fsubs  " },
210         { 0x16, 0x5a1, "dsubs  " },
211         { 0x16, 0x582, "fmuls  " },
212         { 0x16, 0x5a2, "dmuls  " },
213         { 0x16, 0x583, "fdivs  " },
214         { 0x16, 0x5a3, "ddivs  " },
215         { 0x16, 0x0ac, "cvtdf  " },
216         { 0x16, 0x0bc, "cvtlf  " },
217         { 0x16, 0x0be, "cvtld  " },
218         { 0x16, 0x0af, "cvtdl  " },
219         { 0x16, 0x02f, "cvtdlc " },
220         { 0x17, 0x030, "cvtli  " },
221         { 0x16, 0x1af, "cvtdlv " },
222         { 0x16, 0x12f, "cvtdlcv" },
223         { 0x17, 0x130, "cvtliv " },
224         { 0x16, 0x5ac, "cvtdfs " },
225         { 0x16, 0x5af, "cvtdls " },
226         { 0x16, 0x52f, "cvtdlcs" },
227         { 0x16, 0x0a4, "fcmpun " },
228         { 0x16, 0x0a5, "fcmpeq " },
229         { 0x16, 0x0a6, "fcmplt " },
230         { 0x16, 0x0a7, "fcmple " },
231         { 0x16, 0x5a4, "fcmpuns" },
232         { 0x16, 0x5a5, "fcmpeqs" },
233         { 0x16, 0x5a6, "fcmplts" },
234         { 0x16, 0x5a7, "fcmples" },
235         { 0x17, 0x020, "fmov   " },
236         { 0x17, 0x021, "fmovn  " },
237         { 0x1c, 0x0,   "bsext  " },
238         { 0x1c, 0x1,   "wsext  " },
239         
240         { 0x00, 0x00,  NULL }
241 };
242
243
244 /* disassinstr *****************************************************************
245
246    Outputs a disassembler listing of one machine code instruction on
247    'stdout'.
248
249    code: pointer to instructions machine code
250
251 *******************************************************************************/
252
253 u1 *disassinstr(u1 *code)
254 {
255         s4 op;                      /* 6 bit op code                              */
256         s4 opfun;                   /* 7 bit function code                        */
257         s4 ra, rb, rc;              /* 6 bit register specifiers                  */
258         s4 lit;                     /* 8 bit unsigned literal                     */
259         s4 i;                       /* loop counter                               */
260         s4 c;
261
262         c = *((s4 *) code);
263
264         op    = (c >> 26) & 0x3f;   /* 6 bit op code                              */
265         opfun = (c >> 5)  & 0x7f;   /* 7 bit function code                        */
266         ra    = (c >> 21) & 0x1f;   /* 6 bit source register specifier            */
267         rb    = (c >> 16) & 0x1f;   /* 6 bit source register specifier            */
268         rc    = (c >> 0)  & 0x1f;   /* 6 bit destination register specifiers      */
269         lit   = (c >> 13) & 0xff;   /* 8 bit unsigned literal                     */
270
271         printf("0x%016lx:   %08x    ", (u8) code, c);
272         
273         switch (ops[op].itype) {
274         case ITYPE_JMP:
275                 switch ((c >> 14) & 3) {  /* branch hint */
276                 case 0:
277                         if (ra == 31) {
278                                 printf("jmp     (%s)\n", abi_registers_integer_name[rb]); 
279                                 goto _return;
280                         }
281                         printf("jmp     "); 
282                         break;
283                 case 1:
284                         if (ra == 26) {
285                                 printf("jsr     (%s)\n", abi_registers_integer_name[rb]); 
286                                 goto _return;
287                         }
288                         printf("jsr     "); 
289                         break;
290                 case 2:
291                         if (ra == 31 && rb == 26) {
292                                 printf("ret\n"); 
293                                 goto _return;
294                         }
295                         if (ra == 31) {
296                                 printf("ret     (%s)\n", abi_registers_integer_name[rb]); 
297                                 goto _return;
298                         }
299                         printf("ret     ");
300                         break;
301                 case 3:
302                         printf("jsr_co  "); 
303                         break;
304                 }
305                 printf("%s,(%s)\n", abi_registers_integer_name[ra],
306                            abi_registers_integer_name[rb]); 
307                 break;
308
309         case ITYPE_MEM: {
310                 s4 disp = (c << 16) >> 16;              /* 16 bit signed displacement */
311
312                 if (op == 0x18 && ra == 0 && ra == 0 && disp == 0)
313                         printf("trapb\n"); 
314                 else
315                         printf("%s %s,%d(%s)\n", ops[op].name,
316                                    abi_registers_integer_name[ra], disp,
317                                    abi_registers_integer_name[rb]); 
318                 break;
319         }
320
321         case ITYPE_FMEM:
322                 printf("%s $f%d,%d(%s)\n", ops[op].name, ra, (c << 16) >> 16,
323                            abi_registers_integer_name[rb]); 
324                 break;
325
326         case ITYPE_BRA:                            /* 21 bit signed branch offset */
327                 if (op == 0x30 && ra == 31)
328                         printf("br      0x%016lx\n", (u8) code + 4 + ((c << 11) >> 9));
329                 else if (op == 0x34 && ra == 26)
330                         printf("brs     0x%016lx\n", (u8) code + 4 + ((c << 11) >> 9));
331                 else
332                         printf("%s %s,0x%016lx\n", ops[op].name,
333                                    abi_registers_integer_name[ra],
334                                    (u8) code + 4 + ((c << 11) >> 9));
335                 break;
336                         
337         case ITYPE_FOP: {
338                 s4 fopfun = (c >> 5) & 0x7ff;              /* 11 bit fp function code */
339
340                 if (op == 0x17 && fopfun == 0x020 && ra == rb) {
341                         if (ra == 31 && rc == 31)
342                                 printf("fnop\n");
343                         else
344                                 printf("fmov    $f%d,$f%d\n", ra, rc);
345                         goto _return;
346                 }
347                 for (i = 0; op3s[i].name; i++)
348                         if (op3s[i].op == op && op3s[i].fun == fopfun) {
349                                 printf("%s $f%d,$f%d,$f%d\n", op3s[i].name, ra, rb,  rc);
350                                 goto _return;
351                         }
352                 printf("%s%x $f%d,$f%d,$f%d\n", ops[op].name, fopfun, ra, rb, rc);
353                 break;
354         }
355
356         case ITYPE_OP:
357                 if (op == 0x11 && opfun == 0x20 && ra == rb && ~(c&0x1000)) {
358                         if (ra == 31 && rc == 31)
359                                 printf("nop\n");
360                         else if (ra == 31)
361                                 printf("clr     %s\n", abi_registers_integer_name[rc]);
362                         else
363                                 printf("mov     %s,%s\n", abi_registers_integer_name[ra],
364                                            abi_registers_integer_name[rc]);
365                         goto _return;
366                 }
367                 for (i = 0; op3s[i].name; i++) {
368                         if (op3s[i].op == op && op3s[i].fun == opfun) {
369                                 if (c & 0x1000)                      /* immediate instruction */
370                                         printf("%s %s,%d,%s\n", op3s[i].name,
371                                                    abi_registers_integer_name[ra], lit,
372                                                    abi_registers_integer_name[rc]);
373                                 else
374                                         printf("%s %s,%s,%s\n", op3s[i].name,
375                                                    abi_registers_integer_name[ra],
376                                                    abi_registers_integer_name[rb],
377                                                    abi_registers_integer_name[rc]);
378                                 goto _return;
379                         }
380                 }
381                 /* fall through */
382         default:
383                 if (c & 0x1000)                              /* immediate instruction */
384                         printf("UNDEF  %x(%x) $%d,%d,$%d\n", op, opfun, ra, lit, rc);
385                 else
386                         printf("UNDEF  %x(%x) $%d,$%d,$%d\n", op, opfun, ra, rb,  rc);          
387         }
388
389         /* 1 instruction is 4-bytes long */
390
391  _return:
392         return code + 4;
393 }
394
395
396 /* disassemble *****************************************************************
397
398    Outputs a disassembler listing of some machine code on 'stdout'.
399
400    start: pointer to first instruction
401    end:   pointer to last instruction
402
403 *******************************************************************************/
404
405 void disassemble(u1 *start, u1 *end)
406 {
407         printf("  --- disassembler listing ---\n");
408         for (; start < end; )
409                 start = disassinstr(start);
410 }
411
412
413 /*
414  * These are local overrides for various environment variables in Emacs.
415  * Please do not remove this and leave it at the end of the file, where
416  * Emacs will automagically detect them.
417  * ---------------------------------------------------------------------
418  * Local variables:
419  * mode: c
420  * indent-tabs-mode: t
421  * c-basic-offset: 4
422  * tab-width: 4
423  * End:
424  */