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