* i960-dis.c (struct tabent, struct sparse_tabent): Declare the
[deliverable/binutils-gdb.git] / opcodes / i960-dis.c
1 /* Disassemble i80960 instructions.
2 Copyright (C) 1990, 1991 Free Software Foundation, Inc.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; see the file COPYING. If not, write to
16 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
17
18 #include "dis-asm.h"
19
20 static const char *const reg_names[] = {
21 /* 0 */ "pfp", "sp", "rip", "r3", "r4", "r5", "r6", "r7",
22 /* 8 */ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
23 /* 16 */ "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
24 /* 24 */ "g8", "g9", "g10", "g11", "g12", "g13", "g14", "fp",
25 /* 32 */ "pc", "ac", "ip", "tc", "fp0", "fp1", "fp2", "fp3"
26 };
27
28
29 static FILE *stream; /* Output goes here */
30 static struct disassemble_info *info;
31 static void print_addr();
32 static void ctrl();
33 static void cobr();
34 static void reg();
35 static int mem();
36 static void ea();
37 static void dstop();
38 static void regop();
39 static void invalid();
40 static int pinsn();
41 static void put_abs();
42
43
44 /* Print the i960 instruction at address 'memaddr' in debugged memory,
45 on INFO->STREAM. Returns length of the instruction, in bytes. */
46
47 int
48 print_insn_i960 (memaddr, info_arg)
49 bfd_vma memaddr;
50 struct disassemble_info *info_arg;
51 {
52 unsigned int word1, word2 = 0xdeadbeef;
53 bfd_byte buffer[8];
54 int status;
55
56 info = info_arg;
57 stream = info->stream;
58
59 /* Read word1. Only read word2 if the instruction
60 needs it, to prevent reading past the end of a section. */
61
62 status = (*info->read_memory_func) (memaddr, (bfd_byte *) buffer, 4, info);
63 if (status != 0)
64 {
65 (*info->memory_error_func) (status, memaddr, info);
66 return -1;
67 }
68
69 word1 = bfd_getl32 (buffer);
70
71 /* Divide instruction set into classes based on high 4 bits of opcode. */
72 switch ( (word1 >> 28) & 0xf )
73 {
74 default:
75 break;
76 case 0x8:
77 case 0x9:
78 case 0xa:
79 case 0xb:
80 case 0xc:
81 /* Read word2. */
82 status = (*info->read_memory_func)
83 (memaddr + 4, (bfd_byte *) (buffer + 4), 4, info);
84 if (status != 0)
85 {
86 (*info->memory_error_func) (status, memaddr, info);
87 return -1;
88 }
89 word2 = bfd_getl32 (buffer + 4);
90 break;
91 }
92
93 return pinsn( memaddr, word1, word2 );
94 }
95 \f
96 #define IN_GDB
97
98 /*****************************************************************************
99 * All code below this point should be identical with that of
100 * the disassembler in gdmp960.
101
102 A noble sentiment, but at least in cosmetic ways (info->fprintf_func), it
103 just ain't so. -kingdon, 31 Mar 93
104 *****************************************************************************/
105
106 struct tabent {
107 char *name;
108 signed char numops;
109 };
110
111 struct sparse_tabent {
112 int opcode;
113 char *name;
114 signed char numops;
115 };
116
117 static int
118 pinsn( memaddr, word1, word2 )
119 unsigned long memaddr;
120 unsigned long word1, word2;
121 {
122 int instr_len;
123
124 instr_len = 4;
125 put_abs( word1, word2 );
126
127 /* Divide instruction set into classes based on high 4 bits of opcode*/
128 switch ( (word1 >> 28) & 0xf ){
129 case 0x0:
130 case 0x1:
131 ctrl( memaddr, word1, word2 );
132 break;
133 case 0x2:
134 case 0x3:
135 cobr( memaddr, word1, word2 );
136 break;
137 case 0x5:
138 case 0x6:
139 case 0x7:
140 reg( word1 );
141 break;
142 case 0x8:
143 case 0x9:
144 case 0xa:
145 case 0xb:
146 case 0xc:
147 instr_len = mem( memaddr, word1, word2, 0 );
148 break;
149 default:
150 /* invalid instruction, print as data word */
151 invalid( word1 );
152 break;
153 }
154 return instr_len;
155 }
156
157 /****************************************/
158 /* CTRL format */
159 /****************************************/
160 static void
161 ctrl( memaddr, word1, word2 )
162 unsigned long memaddr;
163 unsigned long word1, word2;
164 {
165 int i;
166 static const struct tabent ctrl_tab[] = {
167 NULL, 0, /* 0x00 */
168 NULL, 0, /* 0x01 */
169 NULL, 0, /* 0x02 */
170 NULL, 0, /* 0x03 */
171 NULL, 0, /* 0x04 */
172 NULL, 0, /* 0x05 */
173 NULL, 0, /* 0x06 */
174 NULL, 0, /* 0x07 */
175 "b", 1, /* 0x08 */
176 "call", 1, /* 0x09 */
177 "ret", 0, /* 0x0a */
178 "bal", 1, /* 0x0b */
179 NULL, 0, /* 0x0c */
180 NULL, 0, /* 0x0d */
181 NULL, 0, /* 0x0e */
182 NULL, 0, /* 0x0f */
183 "bno", 1, /* 0x10 */
184 "bg", 1, /* 0x11 */
185 "be", 1, /* 0x12 */
186 "bge", 1, /* 0x13 */
187 "bl", 1, /* 0x14 */
188 "bne", 1, /* 0x15 */
189 "ble", 1, /* 0x16 */
190 "bo", 1, /* 0x17 */
191 "faultno", 0, /* 0x18 */
192 "faultg", 0, /* 0x19 */
193 "faulte", 0, /* 0x1a */
194 "faultge", 0, /* 0x1b */
195 "faultl", 0, /* 0x1c */
196 "faultne", 0, /* 0x1d */
197 "faultle", 0, /* 0x1e */
198 "faulto", 0, /* 0x1f */
199 };
200
201 i = (word1 >> 24) & 0xff;
202 if ( (ctrl_tab[i].name == NULL) || ((word1 & 1) != 0) ){
203 invalid( word1 );
204 return;
205 }
206
207 (*info->fprintf_func) ( stream, ctrl_tab[i].name );
208 if ( word1 & 2 ){ /* Predicts branch not taken */
209 (*info->fprintf_func) ( stream, ".f" );
210 }
211
212 if ( ctrl_tab[i].numops == 1 ){
213 /* EXTRACT DISPLACEMENT AND CONVERT TO ADDRESS */
214 word1 &= 0x00ffffff;
215 if ( word1 & 0x00800000 ){ /* Sign bit is set */
216 word1 |= (-1 & ~0xffffff); /* Sign extend */
217 }
218 (*info->fprintf_func)( stream, "\t" );
219 print_addr( word1 + memaddr );
220 }
221 }
222
223 /****************************************/
224 /* COBR format */
225 /****************************************/
226 static void
227 cobr( memaddr, word1, word2 )
228 unsigned long memaddr;
229 unsigned long word1, word2;
230 {
231 int src1;
232 int src2;
233 int i;
234
235 static const struct tabent cobr_tab[] = {
236 "testno", 1, /* 0x20 */
237 "testg", 1, /* 0x21 */
238 "teste", 1, /* 0x22 */
239 "testge", 1, /* 0x23 */
240 "testl", 1, /* 0x24 */
241 "testne", 1, /* 0x25 */
242 "testle", 1, /* 0x26 */
243 "testo", 1, /* 0x27 */
244 NULL, 0, /* 0x28 */
245 NULL, 0, /* 0x29 */
246 NULL, 0, /* 0x2a */
247 NULL, 0, /* 0x2b */
248 NULL, 0, /* 0x2c */
249 NULL, 0, /* 0x2d */
250 NULL, 0, /* 0x2e */
251 NULL, 0, /* 0x2f */
252 "bbc", 3, /* 0x30 */
253 "cmpobg", 3, /* 0x31 */
254 "cmpobe", 3, /* 0x32 */
255 "cmpobge", 3, /* 0x33 */
256 "cmpobl", 3, /* 0x34 */
257 "cmpobne", 3, /* 0x35 */
258 "cmpoble", 3, /* 0x36 */
259 "bbs", 3, /* 0x37 */
260 "cmpibno", 3, /* 0x38 */
261 "cmpibg", 3, /* 0x39 */
262 "cmpibe", 3, /* 0x3a */
263 "cmpibge", 3, /* 0x3b */
264 "cmpibl", 3, /* 0x3c */
265 "cmpibne", 3, /* 0x3d */
266 "cmpible", 3, /* 0x3e */
267 "cmpibo", 3, /* 0x3f */
268 };
269
270 i = ((word1 >> 24) & 0xff) - 0x20;
271 if ( cobr_tab[i].name == NULL ){
272 invalid( word1 );
273 return;
274 }
275
276 (*info->fprintf_func) ( stream, cobr_tab[i].name );
277 if ( word1 & 2 ){ /* Predicts branch not taken */
278 (*info->fprintf_func) ( stream, ".f" );
279 }
280 (*info->fprintf_func)( stream, "\t" );
281
282 src1 = (word1 >> 19) & 0x1f;
283 src2 = (word1 >> 14) & 0x1f;
284
285 if ( word1 & 0x02000 ){ /* M1 is 1 */
286 (*info->fprintf_func)( stream, "%d", src1 );
287 } else { /* M1 is 0 */
288 (*info->fprintf_func)( stream, reg_names[src1] );
289 }
290
291 if ( cobr_tab[i].numops > 1 ){
292 if ( word1 & 1 ){ /* S2 is 1 */
293 (*info->fprintf_func)( stream, ",sf%d,", src2 );
294 } else { /* S1 is 0 */
295 (*info->fprintf_func)( stream, ",%s,", reg_names[src2] );
296 }
297
298 /* Extract displacement and convert to address
299 */
300 word1 &= 0x00001ffc;
301 if ( word1 & 0x00001000 ){ /* Negative displacement */
302 word1 |= (-1 & ~0x1fff); /* Sign extend */
303 }
304 print_addr( memaddr + word1 );
305 }
306 }
307
308 /****************************************/
309 /* MEM format */
310 /****************************************/
311 static int /* returns instruction length: 4 or 8 */
312 mem( memaddr, word1, word2, noprint )
313 unsigned long memaddr;
314 unsigned long word1, word2;
315 int noprint; /* If TRUE, return instruction length, but
316 * don't output any text.
317 */
318 {
319 int i, j;
320 int len;
321 int mode;
322 int offset;
323 const char *reg1, *reg2, *reg3;
324
325 /* This lookup table is too sparse to make it worth typing in, but not
326 so large as to make a sparse array necessary. We create the table
327 at runtime. */
328
329 /*
330 * NOTE: In this table, the meaning of 'numops' is:
331 * 1: single operand
332 * 2: 2 operands, load instruction
333 * -2: 2 operands, store instruction
334 */
335 static struct tabent *mem_tab;
336 /* Opcodes of 0x8X, 9X, aX, bX, and cX must be in the table. */
337 #define MEM_MIN 0x80
338 #define MEM_MAX 0xcf
339 #define MEM_SIZ ( * sizeof(struct tabent))
340
341 static const struct sparse_tabent mem_init[] = {
342 0x80, "ldob", 2,
343 0x82, "stob", -2,
344 0x84, "bx", 1,
345 0x85, "balx", 2,
346 0x86, "callx", 1,
347 0x88, "ldos", 2,
348 0x8a, "stos", -2,
349 0x8c, "lda", 2,
350 0x90, "ld", 2,
351 0x92, "st", -2,
352 0x98, "ldl", 2,
353 0x9a, "stl", -2,
354 0xa0, "ldt", 2,
355 0xa2, "stt", -2,
356 0xb0, "ldq", 2,
357 0xb2, "stq", -2,
358 0xc0, "ldib", 2,
359 0xc2, "stib", -2,
360 0xc8, "ldis", 2,
361 0xca, "stis", -2,
362 0, NULL, 0
363 };
364 static struct tabent mem_tab_buf[MEM_MAX - MEM_MIN + 1];
365
366 if ( mem_tab == NULL ){
367 mem_tab = mem_tab_buf;
368 for ( i = 0; mem_init[i].opcode != 0; i++ ){
369 j = mem_init[i].opcode - MEM_MIN;
370 mem_tab[j].name = mem_init[i].name;
371 mem_tab[j].numops = mem_init[i].numops;
372 }
373 }
374
375 i = ((word1 >> 24) & 0xff) - MEM_MIN;
376 mode = (word1 >> 10) & 0xf;
377
378 if ( (mem_tab[i].name != NULL) /* Valid instruction */
379 && ((mode == 5) || (mode >=12)) ){ /* With 32-bit displacement */
380 len = 8;
381 } else {
382 len = 4;
383 }
384
385 if ( noprint ){
386 return len;
387 }
388
389 if ( (mem_tab[i].name == NULL) || (mode == 6) ){
390 invalid( word1 );
391 return len;
392 }
393
394 (*info->fprintf_func)( stream, "%s\t", mem_tab[i].name );
395
396 reg1 = reg_names[ (word1 >> 19) & 0x1f ]; /* MEMB only */
397 reg2 = reg_names[ (word1 >> 14) & 0x1f ];
398 reg3 = reg_names[ word1 & 0x1f ]; /* MEMB only */
399 offset = word1 & 0xfff; /* MEMA only */
400
401 switch ( mem_tab[i].numops ){
402
403 case 2: /* LOAD INSTRUCTION */
404 if ( mode & 4 ){ /* MEMB FORMAT */
405 ea( memaddr, mode, reg2, reg3, word1, word2 );
406 (*info->fprintf_func)( stream, ",%s", reg1 );
407 } else { /* MEMA FORMAT */
408 (*info->fprintf_func)( stream, "0x%x", (unsigned) offset );
409 if (mode & 8) {
410 (*info->fprintf_func)( stream, "(%s)", reg2 );
411 }
412 (*info->fprintf_func)( stream, ",%s", reg1 );
413 }
414 break;
415
416 case -2: /* STORE INSTRUCTION */
417 if ( mode & 4 ){ /* MEMB FORMAT */
418 (*info->fprintf_func)( stream, "%s,", reg1 );
419 ea( memaddr, mode, reg2, reg3, word1, word2 );
420 } else { /* MEMA FORMAT */
421 (*info->fprintf_func)( stream, "%s,0x%x", reg1, (unsigned) offset );
422 if (mode & 8) {
423 (*info->fprintf_func)( stream, "(%s)", reg2 );
424 }
425 }
426 break;
427
428 case 1: /* BX/CALLX INSTRUCTION */
429 if ( mode & 4 ){ /* MEMB FORMAT */
430 ea( memaddr, mode, reg2, reg3, word1, word2 );
431 } else { /* MEMA FORMAT */
432 (*info->fprintf_func)( stream, "0x%x", (unsigned) offset );
433 if (mode & 8) {
434 (*info->fprintf_func)( stream, "(%s)", reg2 );
435 }
436 }
437 break;
438 }
439
440 return len;
441 }
442
443 /****************************************/
444 /* REG format */
445 /****************************************/
446 static void
447 reg( word1 )
448 unsigned long word1;
449 {
450 int i, j;
451 int opcode;
452 int fp;
453 int m1, m2, m3;
454 int s1, s2;
455 int src, src2, dst;
456 char *mnemp;
457
458 /* This lookup table is too sparse to make it worth typing in, but not
459 so large as to make a sparse array necessary. We create the table
460 at runtime. */
461
462 /*
463 * NOTE: In this table, the meaning of 'numops' is:
464 * 1: single operand, which is NOT a destination.
465 * -1: single operand, which IS a destination.
466 * 2: 2 operands, the 2nd of which is NOT a destination.
467 * -2: 2 operands, the 2nd of which IS a destination.
468 * 3: 3 operands
469 *
470 * If an opcode mnemonic begins with "F", it is a floating-point
471 * opcode (the "F" is not printed).
472 */
473
474 static struct tabent *reg_tab;
475 static const struct sparse_tabent reg_init[] = {
476 #define REG_MIN 0x580
477 0x580, "notbit", 3,
478 0x581, "and", 3,
479 0x582, "andnot", 3,
480 0x583, "setbit", 3,
481 0x584, "notand", 3,
482 0x586, "xor", 3,
483 0x587, "or", 3,
484 0x588, "nor", 3,
485 0x589, "xnor", 3,
486 0x58a, "not", -2,
487 0x58b, "ornot", 3,
488 0x58c, "clrbit", 3,
489 0x58d, "notor", 3,
490 0x58e, "nand", 3,
491 0x58f, "alterbit", 3,
492 0x590, "addo", 3,
493 0x591, "addi", 3,
494 0x592, "subo", 3,
495 0x593, "subi", 3,
496 0x594, "cmpob", 2, /* xl */
497 0x595, "cmpib", 2, /* xl */
498 0x596, "cmpos", 2, /* xl */
499 0x597, "cmpis", 2, /* xl */
500 0x598, "shro", 3,
501 0x59a, "shrdi", 3,
502 0x59b, "shri", 3,
503 0x59c, "shlo", 3,
504 0x59d, "rotate", 3,
505 0x59e, "shli", 3,
506 0x5a0, "cmpo", 2,
507 0x5a1, "cmpi", 2,
508 0x5a2, "concmpo", 2,
509 0x5a3, "concmpi", 2,
510 0x5a4, "cmpinco", 3,
511 0x5a5, "cmpinci", 3,
512 0x5a6, "cmpdeco", 3,
513 0x5a7, "cmpdeci", 3,
514 0x5ac, "scanbyte", 2,
515 0x5ad, "bswap", -2, /* xl */
516 0x5ae, "chkbit", 2,
517 0x5b0, "addc", 3,
518 0x5b2, "subc", 3,
519 0x5b4, "intdis", 0, /* xl */
520 0x5b5, "inten", 0, /* xl */
521 0x5cc, "mov", -2,
522 0x5d8, "eshro", 3,
523 0x5dc, "movl", -2,
524 0x5ec, "movt", -2,
525 0x5fc, "movq", -2,
526 0x600, "synmov", 2,
527 0x601, "synmovl", 2,
528 0x602, "synmovq", 2,
529 0x603, "cmpstr", 3,
530 0x604, "movqstr", 3,
531 0x605, "movstr", 3,
532 0x610, "atmod", 3,
533 0x612, "atadd", 3,
534 0x613, "inspacc", -2,
535 0x614, "ldphy", -2,
536 0x615, "synld", -2,
537 0x617, "fill", 3,
538 0x630, "sdma", 3,
539 0x631, "udma", 0,
540 0x640, "spanbit", -2,
541 0x641, "scanbit", -2,
542 0x642, "daddc", 3,
543 0x643, "dsubc", 3,
544 0x644, "dmovt", -2,
545 0x645, "modac", 3,
546 0x646, "condrec", -2,
547 0x650, "modify", 3,
548 0x651, "extract", 3,
549 0x654, "modtc", 3,
550 0x655, "modpc", 3,
551 0x656, "receive", -2,
552 0x658, "intctl", -2, /* xl */
553 0x659, "sysctl", 3,
554 0x65b, "icctl", 3, /* xl */
555 0x65c, "dcctl", 3, /* xl */
556 0x65d, "halt", 0, /* xl */
557 0x660, "calls", 1,
558 0x662, "send", 3,
559 0x663, "sendserv", 1,
560 0x664, "resumprcs", 1,
561 0x665, "schedprcs", 1,
562 0x666, "saveprcs", 0,
563 0x668, "condwait", 1,
564 0x669, "wait", 1,
565 0x66a, "signal", 1,
566 0x66b, "mark", 0,
567 0x66c, "fmark", 0,
568 0x66d, "flushreg", 0,
569 0x66f, "syncf", 0,
570 0x670, "emul", 3,
571 0x671, "ediv", 3,
572 0x673, "ldtime", -1,
573 0x674, "Fcvtir", -2,
574 0x675, "Fcvtilr", -2,
575 0x676, "Fscalerl", 3,
576 0x677, "Fscaler", 3,
577 0x680, "Fatanr", 3,
578 0x681, "Flogepr", 3,
579 0x682, "Flogr", 3,
580 0x683, "Fremr", 3,
581 0x684, "Fcmpor", 2,
582 0x685, "Fcmpr", 2,
583 0x688, "Fsqrtr", -2,
584 0x689, "Fexpr", -2,
585 0x68a, "Flogbnr", -2,
586 0x68b, "Froundr", -2,
587 0x68c, "Fsinr", -2,
588 0x68d, "Fcosr", -2,
589 0x68e, "Ftanr", -2,
590 0x68f, "Fclassr", 1,
591 0x690, "Fatanrl", 3,
592 0x691, "Flogeprl", 3,
593 0x692, "Flogrl", 3,
594 0x693, "Fremrl", 3,
595 0x694, "Fcmporl", 2,
596 0x695, "Fcmprl", 2,
597 0x698, "Fsqrtrl", -2,
598 0x699, "Fexprl", -2,
599 0x69a, "Flogbnrl", -2,
600 0x69b, "Froundrl", -2,
601 0x69c, "Fsinrl", -2,
602 0x69d, "Fcosrl", -2,
603 0x69e, "Ftanrl", -2,
604 0x69f, "Fclassrl", 1,
605 0x6c0, "Fcvtri", -2,
606 0x6c1, "Fcvtril", -2,
607 0x6c2, "Fcvtzri", -2,
608 0x6c3, "Fcvtzril", -2,
609 0x6c9, "Fmovr", -2,
610 0x6d9, "Fmovrl", -2,
611 0x6e1, "Fmovre", -2,
612 0x6e2, "Fcpysre", 3,
613 0x6e3, "Fcpyrsre", 3,
614 0x701, "mulo", 3,
615 0x708, "remo", 3,
616 0x70b, "divo", 3,
617 0x741, "muli", 3,
618 0x748, "remi", 3,
619 0x749, "modi", 3,
620 0x74b, "divi", 3,
621 0x780, "addono", 3, /* xl */
622 0x781, "addino", 3, /* xl */
623 0x782, "subono", 3, /* xl */
624 0x783, "subino", 3, /* xl */
625 0x784, "selno", 3, /* xl */
626 0x78b, "Fdivr", 3,
627 0x78c, "Fmulr", 3,
628 0x78d, "Fsubr", 3,
629 0x78f, "Faddr", 3,
630 0x790, "addog", 3, /* xl */
631 0x791, "addig", 3, /* xl */
632 0x792, "subog", 3, /* xl */
633 0x793, "subig", 3, /* xl */
634 0x794, "selg", 3, /* xl */
635 0x79b, "Fdivrl", 3,
636 0x79c, "Fmulrl", 3,
637 0x79d, "Fsubrl", 3,
638 0x79f, "Faddrl", 3,
639 #define REG_MAX 0x79f
640 0x7a0, "addoe", 3, /* xl */
641 0x7a1, "addie", 3, /* xl */
642 0x7a2, "suboe", 3, /* xl */
643 0x7a3, "subie", 3, /* xl */
644 0x7a4, "sele", 3, /* xl */
645 0x7b0, "addoge", 3, /* xl */
646 0x7b1, "addige", 3, /* xl */
647 0x7b2, "suboge", 3, /* xl */
648 0x7b3, "subige", 3, /* xl */
649 0x7b4, "selge", 3, /* xl */
650 0x7c0, "addol", 3, /* xl */
651 0x7c1, "addil", 3, /* xl */
652 0x7c2, "subol", 3, /* xl */
653 0x7c3, "subil", 3, /* xl */
654 0x7c4, "sell", 3, /* xl */
655 0x7d0, "addone", 3, /* xl */
656 0x7d1, "addine", 3, /* xl */
657 0x7d2, "subone", 3, /* xl */
658 0x7d3, "subine", 3, /* xl */
659 0x7d4, "selne", 3, /* xl */
660 0x7e0, "addole", 3, /* xl */
661 0x7e1, "addile", 3, /* xl */
662 0x7e2, "subole", 3, /* xl */
663 0x7e3, "subile", 3, /* xl */
664 0x7e4, "selle", 3, /* xl */
665 0x7f0, "addoo", 3, /* xl */
666 0x7f1, "addio", 3, /* xl */
667 0x7f2, "suboo", 3, /* xl */
668 0x7f3, "subio", 3, /* xl */
669 0x7f4, "selo", 3, /* xl */
670 #undef REG_MAX /* xl */
671 #define REG_MAX 0x7f4 /* xl */
672 0, NULL, 0
673 };
674 static struct tabent reg_tab_buf[REG_MAX - REG_MIN + 1];
675
676 if ( reg_tab == NULL ){
677 reg_tab = reg_tab_buf;
678 for ( i = 0; reg_init[i].opcode != 0; i++ ){
679 j = reg_init[i].opcode - REG_MIN;
680 reg_tab[j].name = reg_init[i].name;
681 reg_tab[j].numops = reg_init[i].numops;
682 }
683 }
684
685 opcode = ((word1 >> 20) & 0xff0) | ((word1 >> 7) & 0xf);
686 i = opcode - REG_MIN;
687
688 if ( (opcode<REG_MIN) || (opcode>REG_MAX) || (reg_tab[i].name==NULL) ){
689 invalid( word1 );
690 return;
691 }
692
693 mnemp = reg_tab[i].name;
694 if ( *mnemp == 'F' ){
695 fp = 1;
696 mnemp++;
697 } else {
698 fp = 0;
699 }
700
701 (*info->fprintf_func)( stream, mnemp );
702
703 s1 = (word1 >> 5) & 1;
704 s2 = (word1 >> 6) & 1;
705 m1 = (word1 >> 11) & 1;
706 m2 = (word1 >> 12) & 1;
707 m3 = (word1 >> 13) & 1;
708 src = word1 & 0x1f;
709 src2 = (word1 >> 14) & 0x1f;
710 dst = (word1 >> 19) & 0x1f;
711
712 if ( reg_tab[i].numops != 0 ){
713 (*info->fprintf_func)( stream, "\t" );
714
715 switch ( reg_tab[i].numops ){
716 case 1:
717 regop( m1, s1, src, fp );
718 break;
719 case -1:
720 dstop( m3, dst, fp );
721 break;
722 case 2:
723 regop( m1, s1, src, fp );
724 (*info->fprintf_func)( stream, "," );
725 regop( m2, s2, src2, fp );
726 break;
727 case -2:
728 regop( m1, s1, src, fp );
729 (*info->fprintf_func)( stream, "," );
730 dstop( m3, dst, fp );
731 break;
732 case 3:
733 regop( m1, s1, src, fp );
734 (*info->fprintf_func)( stream, "," );
735 regop( m2, s2, src2, fp );
736 (*info->fprintf_func)( stream, "," );
737 dstop( m3, dst, fp );
738 break;
739 }
740 }
741 }
742
743
744 /*
745 * Print out effective address for memb instructions.
746 */
747 static void
748 ea( memaddr, mode, reg2, reg3, word1, word2 )
749 unsigned long memaddr;
750 int mode;
751 char *reg2, *reg3;
752 int word1;
753 unsigned int word2;
754 {
755 int scale;
756 static const int scale_tab[] = { 1, 2, 4, 8, 16 };
757
758 scale = (word1 >> 7) & 0x07;
759 if ( (scale > 4) || ((word1 >> 5) & 0x03 != 0) ){
760 invalid( word1 );
761 return;
762 }
763 scale = scale_tab[scale];
764
765 switch (mode) {
766 case 4: /* (reg) */
767 (*info->fprintf_func)( stream, "(%s)", reg2 );
768 break;
769 case 5: /* displ+8(ip) */
770 print_addr( word2+8+memaddr );
771 break;
772 case 7: /* (reg)[index*scale] */
773 if (scale == 1) {
774 (*info->fprintf_func)( stream, "(%s)[%s]", reg2, reg3 );
775 } else {
776 (*info->fprintf_func)( stream, "(%s)[%s*%d]",reg2,reg3,scale);
777 }
778 break;
779 case 12: /* displacement */
780 print_addr( word2 );
781 break;
782 case 13: /* displ(reg) */
783 print_addr( word2 );
784 (*info->fprintf_func)( stream, "(%s)", reg2 );
785 break;
786 case 14: /* displ[index*scale] */
787 print_addr( word2 );
788 if (scale == 1) {
789 (*info->fprintf_func)( stream, "[%s]", reg3 );
790 } else {
791 (*info->fprintf_func)( stream, "[%s*%d]", reg3, scale );
792 }
793 break;
794 case 15: /* displ(reg)[index*scale] */
795 print_addr( word2 );
796 if (scale == 1) {
797 (*info->fprintf_func)( stream, "(%s)[%s]", reg2, reg3 );
798 } else {
799 (*info->fprintf_func)( stream, "(%s)[%s*%d]",reg2,reg3,scale );
800 }
801 break;
802 default:
803 invalid( word1 );
804 return;
805 }
806 }
807
808
809 /************************************************/
810 /* Register Instruction Operand */
811 /************************************************/
812 static void
813 regop( mode, spec, reg, fp )
814 int mode, spec, reg, fp;
815 {
816 if ( fp ){ /* FLOATING POINT INSTRUCTION */
817 if ( mode == 1 ){ /* FP operand */
818 switch ( reg ){
819 case 0: (*info->fprintf_func)( stream, "fp0" );
820 break;
821 case 1: (*info->fprintf_func)( stream, "fp1" );
822 break;
823 case 2: (*info->fprintf_func)( stream, "fp2" );
824 break;
825 case 3: (*info->fprintf_func)( stream, "fp3" );
826 break;
827 case 16: (*info->fprintf_func)( stream, "0f0.0" );
828 break;
829 case 22: (*info->fprintf_func)( stream, "0f1.0" );
830 break;
831 default: (*info->fprintf_func)( stream, "?" );
832 break;
833 }
834 } else { /* Non-FP register */
835 (*info->fprintf_func)( stream, reg_names[reg] );
836 }
837 } else { /* NOT FLOATING POINT */
838 if ( mode == 1 ){ /* Literal */
839 (*info->fprintf_func)( stream, "%d", reg );
840 } else { /* Register */
841 if ( spec == 0 ){
842 (*info->fprintf_func)( stream, reg_names[reg] );
843 } else {
844 (*info->fprintf_func)( stream, "sf%d", reg );
845 }
846 }
847 }
848 }
849
850 /************************************************/
851 /* Register Instruction Destination Operand */
852 /************************************************/
853 static void
854 dstop( mode, reg, fp )
855 int mode, reg, fp;
856 {
857 /* 'dst' operand can't be a literal. On non-FP instructions, register
858 * mode is assumed and "m3" acts as if were "s3"; on FP-instructions,
859 * sf registers are not allowed so m3 acts normally.
860 */
861 if ( fp ){
862 regop( mode, 0, reg, fp );
863 } else {
864 regop( 0, mode, reg, fp );
865 }
866 }
867
868
869 static void
870 invalid( word1 )
871 int word1;
872 {
873 (*info->fprintf_func)( stream, ".word\t0x%08x", (unsigned) word1 );
874 }
875
876 static void
877 print_addr(a)
878 int a;
879 {
880 (*info->print_address_func) ((bfd_vma) a, info);
881 }
882
883 static void
884 put_abs( word1, word2 )
885 unsigned long word1, word2;
886 {
887 #ifdef IN_GDB
888 return;
889 #else
890 int len;
891
892 switch ( (word1 >> 28) & 0xf ){
893 case 0x8:
894 case 0x9:
895 case 0xa:
896 case 0xb:
897 case 0xc:
898 /* MEM format instruction */
899 len = mem( 0, word1, word2, 1 );
900 break;
901 default:
902 len = 4;
903 break;
904 }
905
906 if ( len == 8 ){
907 (*info->fprintf_func)( stream, "%08x %08x\t", word1, word2 );
908 } else {
909 (*info->fprintf_func)( stream, "%08x \t", word1 );
910 }
911 ;
912
913 #endif
914 }
This page took 0.052879 seconds and 5 git commands to generate.