ce48f99555d4e88095f0590882f27c12ce3339da
[cacao.git] / alpha / disass.c
1 /* disass.c ********************************************************************
2
3         Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst
4
5         See file COPYRIGHT for information on usage and disclaimer of warranties
6
7         A very primitive disassembler for Alpha machine code for easy debugging.
8
9         Authors: Andreas  Krall      EMAIL: cacao@complang.tuwien.ac.at
10                  Reinhard Grafl      EMAIL: cacao@complang.tuwien.ac.at
11
12         Last Change: 1998/11/06
13
14 *******************************************************************************/
15
16 /*  The disassembler uses two tables for decoding the instructions. The first
17         table (ops) is used to classify the instructions based on the op code and
18         contains the instruction names for instructions which don't used the
19         function codes. This table is indexed by the op code (6 bit, 64 entries).
20         The second table (op3s) contains instructions which contain both an op
21         code and a function code. This table is an unsorted list of instructions
22         which is terminated by op code and function code zero. This list is
23         searched linearly for a matching pair of opcode and function code.
24 */
25
26 #define ITYPE_UNDEF 0           /* undefined instructions (illegal opcode)    */
27 #define ITYPE_JMP   1           /* jump instructions                          */
28 #define ITYPE_MEM   2           /* memory instructions                        */
29 #define ITYPE_BRA   3           /* branch instructions                        */
30 #define ITYPE_OP    4           /* integer instructions                       */
31 #define ITYPE_FOP   5           /* floating point instructions                */
32
33
34 /* instruction decode table for 6 bit op codes                                */
35
36 static struct {char *name; int itype;} ops[] = {
37
38         /* 0x00 */  {"",        ITYPE_UNDEF},
39         /* 0x01 */  {"",        ITYPE_UNDEF},
40         /* 0x02 */  {"",        ITYPE_UNDEF},
41         /* 0x03 */  {"",        ITYPE_UNDEF},
42         /* 0x04 */  {"",        ITYPE_UNDEF},
43         /* 0x05 */  {"",        ITYPE_UNDEF},
44         /* 0x06 */  {"",        ITYPE_UNDEF},
45         /* 0x07 */  {"",        ITYPE_UNDEF},
46         /* 0x08 */  {"LDA    ",   ITYPE_MEM},
47         /* 0x09 */  {"LDAH   ",   ITYPE_MEM},
48         /* 0x0a */  {"LDB    ",   ITYPE_MEM},
49         /* 0x0b */  {"LDQ_U  ",   ITYPE_MEM},
50         /* 0x0c */  {"LDW    ",   ITYPE_MEM},
51         /* 0x0d */  {"STW    ",   ITYPE_MEM},
52         /* 0x0e */  {"STB    ",   ITYPE_MEM},
53         /* 0x0f */  {"STQ_U  ",   ITYPE_MEM},
54         /* 0x10 */  {"OP     ",    ITYPE_OP},
55         /* 0x11 */  {"OP     ",    ITYPE_OP},
56         /* 0x12 */  {"OP     ",    ITYPE_OP},
57         /* 0x13 */  {"OP     ",    ITYPE_OP},
58         /* 0x14 */  {"",        ITYPE_UNDEF},
59         /* 0x15 */  {"",        ITYPE_UNDEF},
60         /* 0x16 */  {"FOP    ",   ITYPE_FOP},
61         /* 0x17 */  {"FOP    ",   ITYPE_FOP},
62         /* 0x18 */  {"MEMFMT ",   ITYPE_MEM},
63         /* 0x19 */  {"",        ITYPE_UNDEF},
64         /* 0x1a */  {"JMP    ",   ITYPE_JMP},
65         /* 0x1b */  {"",        ITYPE_UNDEF},
66         /* 0x1c */  {"OP     ",    ITYPE_OP},
67         /* 0x1d */  {"",        ITYPE_UNDEF},
68         /* 0x1e */  {"",        ITYPE_UNDEF},
69         /* 0x1f */  {"",        ITYPE_UNDEF},
70         /* 0x20 */  {"LDF    ",   ITYPE_MEM},
71         /* 0x21 */  {"LDG    ",   ITYPE_MEM},
72         /* 0x22 */  {"LDS    ",   ITYPE_MEM},
73         /* 0x23 */  {"LDT    ",   ITYPE_MEM},
74         /* 0x24 */  {"STF    ",   ITYPE_MEM},
75         /* 0x25 */  {"STG    ",   ITYPE_MEM},
76         /* 0x26 */  {"STS    ",   ITYPE_MEM},
77         /* 0x27 */  {"STT    ",   ITYPE_MEM},
78         /* 0x28 */  {"LDL    ",   ITYPE_MEM},
79         /* 0x29 */  {"LDQ    ",   ITYPE_MEM},
80         /* 0x2a */  {"LDL_L  ",   ITYPE_MEM},
81         /* 0x2b */  {"LDQ_L  ",   ITYPE_MEM},
82         /* 0x2c */  {"STL    ",   ITYPE_MEM},
83         /* 0x2d */  {"STQ    ",   ITYPE_MEM},
84         /* 0x2e */  {"STL_C  ",   ITYPE_MEM},
85         /* 0x2f */  {"STQ_C  ",   ITYPE_MEM},
86         /* 0x30 */  {"BR     ",   ITYPE_BRA},
87         /* 0x31 */  {"FBEQ   ",   ITYPE_BRA},
88         /* 0x32 */  {"FBLT   ",   ITYPE_BRA},
89         /* 0x33 */  {"FBLE   ",   ITYPE_BRA},
90         /* 0x34 */  {"BSR    ",   ITYPE_BRA},
91         /* 0x35 */  {"FBNE   ",   ITYPE_BRA},
92         /* 0x36 */  {"FBGE   ",   ITYPE_BRA},
93         /* 0x37 */  {"FBGT   ",   ITYPE_BRA},
94         /* 0x38 */  {"BLBC   ",   ITYPE_BRA},
95         /* 0x39 */  {"BEQ    ",   ITYPE_BRA},
96         /* 0x3a */  {"BLT    ",   ITYPE_BRA},
97         /* 0x3b */  {"BLE    ",   ITYPE_BRA},
98         /* 0x3c */  {"BLBS   ",   ITYPE_BRA},
99         /* 0x3d */  {"BNE    ",   ITYPE_BRA},
100         /* 0x3e */  {"BGE    ",   ITYPE_BRA},
101         /* 0x3f */  {"BGT    ",   ITYPE_BRA}
102 };
103
104
105 /* instruction decode list for 6 bit op codes and 9 bit function codes        */
106  
107 static struct { u2 op, fun; char *name; }  op3s[] = {
108
109         { 0x10, 0x00,  "ADDL   " },
110         { 0x10, 0x40,  "ADDL/V " },
111         { 0x10, 0x20,  "ADDQ   " },
112         { 0x10, 0x60,  "ADDQ/V " },
113         { 0x10, 0x09,  "SUBL   " },
114         { 0x10, 0x49,  "SUBL/V " },
115         { 0x10, 0x29,  "SUBQ   " },
116         { 0x10, 0x69,  "SUBQ/V " },
117         { 0x10, 0x2D,  "CMPEQ  " },
118         { 0x10, 0x4D,  "CMPLT  " },
119         { 0x10, 0x6D,  "CMPLE  " },
120         { 0x10, 0x1D,  "CMPULT " },
121         { 0x10, 0x3D,  "CMPULE " },
122         { 0x10, 0x0F,  "CMPBGE " },
123         { 0x10, 0x02,  "S4ADDL " },
124         { 0x10, 0x0b,  "S4SUBL " },
125         { 0x10, 0x22,  "S4ADDQ " },
126         { 0x10, 0x2b,  "S4SUBQ " },
127         { 0x10, 0x12,  "S8ADDL " },
128         { 0x10, 0x1b,  "S8SUBL " },
129         { 0x10, 0x32,  "S8ADDQ " },
130         { 0x10, 0x3b,  "S8SUBQ " },
131         { 0x11, 0x00,  "AND    " },
132         { 0x11, 0x20,  "OR     " },
133         { 0x11, 0x40,  "XOR    " },
134         { 0x11, 0x08,  "ANDNOT " },
135         { 0x11, 0x28,  "ORNOT  " },
136         { 0x11, 0x48,  "XORNOT " },
137         { 0x11, 0x24,  "CMOVEQ " },
138         { 0x11, 0x44,  "CMOVLT " },
139         { 0x11, 0x64,  "CMOVLE " },
140         { 0x11, 0x26,  "CMOVNE " },
141         { 0x11, 0x46,  "CMOVGE " },
142         { 0x11, 0x66,  "CMOVGT " },
143         { 0x11, 0x14,  "CMOVLBS" },
144         { 0x11, 0x16,  "CMOVLBC" },
145         { 0x12, 0x39,  "SLL    " },
146         { 0x12, 0x3C,  "SRA    " },
147         { 0x12, 0x34,  "SRL    " },
148         { 0x12, 0x30,  "ZAP    " },
149         { 0x12, 0x31,  "ZAPNOT " },
150         { 0x12, 0x06,  "EXTBL  " },
151         { 0x12, 0x16,  "EXTWL  " },
152         { 0x12, 0x26,  "EXTLL  " },
153         { 0x12, 0x36,  "EXTQL  " },
154         { 0x12, 0x5a,  "EXTWH  " },
155         { 0x12, 0x6a,  "EXTLH  " },
156         { 0x12, 0x7a,  "EXTQH  " },
157         { 0x12, 0x0b,  "INSBL  " },
158         { 0x12, 0x1b,  "INSWL  " },
159         { 0x12, 0x2b,  "INSLL  " },
160         { 0x12, 0x3b,  "INSQL  " },
161         { 0x12, 0x57,  "INSWH  " },
162         { 0x12, 0x67,  "INSLH  " },
163         { 0x12, 0x77,  "INSQH  " },
164         { 0x12, 0x02,  "MSKBL  " },
165         { 0x12, 0x12,  "MSKWL  " },
166         { 0x12, 0x22,  "MSKLL  " },
167         { 0x12, 0x32,  "MSKQL  " },
168         { 0x12, 0x52,  "MSKWH  " },
169         { 0x12, 0x62,  "MSKLH  " },
170         { 0x12, 0x72,  "MSKQH  " },
171         { 0x13, 0x00,  "MULL   " },
172         { 0x13, 0x20,  "MULQ   " },
173         { 0x13, 0x40,  "MULL/V " },
174         { 0x13, 0x60,  "MULQ/V " },
175         { 0x13, 0x30,  "UMULH  " },
176         { 0x16, 0x080, "FADD   " },
177         { 0x16, 0x0a0, "DADD   " },
178         { 0x16, 0x081, "FSUB   " },
179         { 0x16, 0x0a1, "DSUB   " },
180         { 0x16, 0x082, "FMUL   " },
181         { 0x16, 0x0a2, "DMUL   " },
182         { 0x16, 0x083, "FDIV   " },
183         { 0x16, 0x0a3, "DDIV   " },
184         { 0x16, 0x580, "FADDS  " },
185         { 0x16, 0x5a0, "DADDS  " },
186         { 0x16, 0x581, "FSUBS  " },
187         { 0x16, 0x5a1, "DSUBS  " },
188         { 0x16, 0x582, "FMULS  " },
189         { 0x16, 0x5a2, "DMULS  " },
190         { 0x16, 0x583, "FDIVS  " },
191         { 0x16, 0x5a3, "DDIVS  " },
192         { 0x16, 0x0ac, "CVTDF  " },
193         { 0x16, 0x0bc, "CVTLF  " },
194         { 0x16, 0x0be, "CVTLD  " },
195         { 0x16, 0x0af, "CVTDL  " },
196         { 0x16, 0x02f, "CVTDLC " },
197         { 0x16, 0x5ac, "CVTDFS " },
198         { 0x16, 0x5af, "CVTDLS " },
199         { 0x16, 0x52f, "CVTDLCS" },
200         { 0x16, 0x0a4, "FCMPUN " },
201         { 0x16, 0x0a5, "FCMPEQ " },
202         { 0x16, 0x0a6, "FCMPLT " },
203         { 0x16, 0x0a7, "FCMPLE " },
204         { 0x16, 0x5a4, "FCMPUNS" },
205         { 0x16, 0x5a5, "FCMPEQS" },
206         { 0x16, 0x5a6, "FCMPLTS" },
207         { 0x16, 0x5a7, "FCMPLES" },
208         { 0x17, 0x020, "FMOV   " },
209         { 0x17, 0x021, "FMOVN  " },
210         { 0x1c, 0x0,   "BSEXT  " },
211         { 0x1c, 0x1,   "WSEXT  " },
212         
213         { 0x00, 0x00,  NULL }
214 };
215
216
217 /* function disassemble ********************************************************
218
219         outputs a disassembler listing of one machine code instruction on 'stdout'
220         c:   instructions machine code
221         pos: instructions address relative to method start
222
223 *******************************************************************************/
224
225 static void disasscmd (int c, int pos)
226 {
227         int op;                     /* 6 bit op code                              */
228         int opfun;                  /* 7 bit function code                        */
229         int ra, rb, rc;             /* 6 bit register specifiers                  */
230         int lit;                    /* 8 bit unsigned literal                     */
231         int i;                      /* loop counter                               */
232
233         op    = (c >> 26) & 0x3f;   /* 6 bit op code                              */
234         opfun = (c >> 5)  & 0x7f;   /* 7 bit function code                        */
235         ra    = (c >> 21) & 0x1f;   /* 6 bit source register specifier            */
236         rb    = (c >> 16) & 0x1f;   /* 6 bit source register specifier            */
237         rc    = (c >> 0)  & 0x1f;   /* 6 bit destination register specifiers      */
238         lit   = (c >> 13) & 0xff;   /* 8 bit unsigned literal                     */
239
240         printf ("%6x: %8x  ", pos, c);
241         
242         switch (ops[op].itype) {
243                 case ITYPE_JMP:
244                         switch ((c >> 14) & 3) {  /* branch hint */
245                                 case 0:
246                                         printf ("JMP     "); 
247                                         break;
248                                 case 1:
249                                         printf ("JSR     "); 
250                                         break;
251                                 case 2:
252                                         printf ("RET     "); 
253                                         break;
254                                 case 3:
255                                         printf ("JSR_CO  "); 
256                                         break;
257                                 }
258                         printf ("$%d,$%d\n", ra, rb); 
259                         break;
260
261                 case ITYPE_MEM: {
262                         int disp = (c << 16) >> 16; /* 16 bit signed displacement         */
263
264                         if (op == 0x18 && ra == 0 && ra == 0 && disp == 0)
265                                 printf ("TRAPB\n"); 
266                         else
267                                 printf ("%s $%d,$%d,%d\n", ops[op].name, ra, rb, disp); 
268                         break;
269                         }
270
271                 case ITYPE_BRA:             /* 21 bit signed branch offset */
272                         printf("%s $%d,%x\n", ops[op].name, ra, pos + 4 + ((c << 11) >> 9));
273                         break;
274                         
275                 case ITYPE_FOP: {
276                         int fopfun = (c >> 5) & 0x7ff;  /* 11 bit fp function code        */
277
278                         if (op == 0x17 && fopfun == 0x020 && ra == rb) {
279                                 if (ra == 31 && rc == 31)
280                                         printf("FNOP\n");
281                                 else
282                                         printf("FMOV    $f%d,$f%d\n", ra, rc);
283                                 return;
284                                 }
285                         for (i = 0; op3s[i].name; i++)
286                                 if (op3s[i].op == op && op3s[i].fun == fopfun) {
287                                         printf("%s $f%d,$f%d,$f%d\n", op3s[i].name, ra, rb,  rc);
288                                         return;
289                                         }
290                         printf("%s%x $f%d,$f%d,$f%d\n", ops[op].name, fopfun, ra, rb, rc);
291                         break;
292                         }
293
294                 case ITYPE_OP:
295                         if (op == 0x11 && opfun == 0x20 && ra == rb && ~(c&0x1000)) {
296                                 if (ra == 31 && rc == 31)
297                                         printf("NOP\n");
298                                 else if (ra == 31)
299                                         printf("CLR     $%d\n", rc);
300                                 else
301                                         printf("MOV     $%d,$%d\n", ra, rc);
302                                 return;
303                                 }
304                         for (i = 0; op3s[i].name; i++) {
305                                 if (op3s[i].op == op && op3s[i].fun == opfun) {
306                                         if (c & 0x1000)                  /* immediate instruction */
307                                                 printf("%s $%d,#%d,$%d\n", op3s[i].name, ra, lit, rc);
308                                         else
309                                                 printf("%s $%d,$%d,$%d\n", op3s[i].name, ra, rb,  rc);
310                                         return;
311                                         }
312                                 }
313                         /* fall through */
314                 default:
315                         if (c & 0x1000)                          /* immediate instruction */
316                                 printf("UNDEF  %x(%x) $%d,#%d,$%d\n", op, opfun, ra, lit, rc);
317                         else
318                                 printf("UNDEF  %x(%x) $%d,$%d,$%d\n", op, opfun, ra, rb,  rc);          
319                 }
320 }
321
322
323 /* function disassemble ********************************************************
324
325         outputs a disassembler listing of some machine code on 'stdout'
326         code: pointer to first instruction
327         len:  code size (number of instructions * 4)
328
329 *******************************************************************************/
330
331 static void disassemble (int *code, int len)
332 {
333         int p;
334
335         printf ("  --- disassembler listing ---\n");    
336         for (p = 0; p < len; p += 4, code++)
337                 disasscmd (*code, p); 
338 }
339
340
341 /*
342  * These are local overrides for various environment variables in Emacs.
343  * Please do not remove this and leave it at the end of the file, where
344  * Emacs will automagically detect them.
345  * ---------------------------------------------------------------------
346  * Local variables:
347  * mode: c
348  * indent-tabs-mode: t
349  * c-basic-offset: 4
350  * tab-width: 4
351  * End:
352  */