| /* Single instruction disassembler for the Visium. | 
 |  | 
 |    Copyright (C) 2002-2022 Free Software Foundation, Inc. | 
 |  | 
 |    This file is part of the GNU opcodes library. | 
 |  | 
 |    This library is free software; you can redistribute it and/or modify | 
 |    it under the terms of the GNU General Public License as published by | 
 |    the Free Software Foundation; either version 3, or (at your option) | 
 |    any later version. | 
 |  | 
 |    It is distributed in the hope that it will be useful, but WITHOUT | 
 |    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | 
 |    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public | 
 |    License for more details. | 
 |  | 
 |    You should have received a copy of the GNU General Public License | 
 |    along with this program; if not, write to the Free Software | 
 |    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, | 
 |    MA 02110-1301, USA.  */ | 
 |  | 
 | #include "sysdep.h" | 
 | #include "disassemble.h" | 
 | #include "opcode/visium.h" | 
 |  | 
 | #include <string.h> | 
 | #include <stdlib.h> | 
 | #include <stdio.h> | 
 | #include <ctype.h> | 
 | #include <setjmp.h> | 
 |  | 
 | /* Maximum length of an instruction.  */ | 
 | #define MAXLEN 4 | 
 |  | 
 | struct private | 
 | { | 
 |   /* Points to first byte not fetched.  */ | 
 |   bfd_byte *max_fetched; | 
 |   bfd_byte the_buffer[MAXLEN]; | 
 |   bfd_vma insn_start; | 
 |   jmp_buf bailout; | 
 | }; | 
 |  | 
 | /* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive) | 
 |    to ADDR (exclusive) are valid.  Returns 1 for success, longjmps | 
 |    on error.  */ | 
 | #define FETCH_DATA(info, addr) \ | 
 |   ((addr) <= ((struct private *)(info->private_data))->max_fetched \ | 
 |    ? 1 : fetch_data ((info), (addr))) | 
 |  | 
 | static int fetch_data (struct disassemble_info *info, bfd_byte * addr); | 
 |  | 
 | static int | 
 | fetch_data (struct disassemble_info *info, bfd_byte *addr) | 
 | { | 
 |   int status; | 
 |   struct private *priv = (struct private *) info->private_data; | 
 |   bfd_vma start = priv->insn_start + (priv->max_fetched - priv->the_buffer); | 
 |  | 
 |   status = (*info->read_memory_func) (start, | 
 | 				      priv->max_fetched, | 
 | 				      addr - priv->max_fetched, info); | 
 |   if (status != 0) | 
 |     { | 
 |       (*info->memory_error_func) (status, start, info); | 
 |       longjmp (priv->bailout, 1); | 
 |     } | 
 |   else | 
 |     priv->max_fetched = addr; | 
 |   return 1; | 
 | } | 
 |  | 
 | static char *size_names[] = { "?", "b", "w", "?", "l", "?", "?", "?" }; | 
 |  | 
 | static char *cc_names[] = | 
 | { | 
 |   "fa", "eq", "cs", "os", "ns", "ne", "cc", "oc", | 
 |   "nc", "ge", "gt", "hi", "le", "ls", "lt", "tr" | 
 | }; | 
 |  | 
 | /* Disassemble non-storage relative instructions.  */ | 
 |  | 
 | static int | 
 | disassem_class0 (disassemble_info *info, unsigned int ins) | 
 | { | 
 |   int opcode = (ins >> 21) & 0x000f; | 
 |  | 
 |   if (ins & CLASS0_UNUSED_MASK) | 
 |     goto illegal_opcode; | 
 |  | 
 |   switch (opcode) | 
 |     { | 
 |     case 0: | 
 |       /* BRR instruction.  */ | 
 |       { | 
 | 	unsigned cbf = (ins >> 27) & 0x000f; | 
 | 	int displacement = ((ins & 0xffff) ^ 0x8000) - 0x8000; | 
 |  | 
 | 	if (ins == 0) | 
 | 	  (*info->fprintf_func) (info->stream, "nop"); | 
 | 	else | 
 | 	  (*info->fprintf_func) (info->stream, "brr     %s,%+d", | 
 | 				 cc_names[cbf], displacement); | 
 |       } | 
 |       break; | 
 |     case 1: | 
 |       /* Illegal opcode.  */ | 
 |       goto illegal_opcode; | 
 |       break; | 
 |     case 2: | 
 |       /* Illegal opcode.  */ | 
 |       goto illegal_opcode; | 
 |       break; | 
 |     case 3: | 
 |       /* Illegal opcode.  */ | 
 |       goto illegal_opcode; | 
 |       break; | 
 |     case 4: | 
 |       /* Illegal opcode.  */ | 
 |       goto illegal_opcode; | 
 |       break; | 
 |     case 5: | 
 |       /* Illegal opcode.  */ | 
 |       goto illegal_opcode; | 
 |       break; | 
 |     case 6: | 
 |       /* Illegal opcode.  */ | 
 |       goto illegal_opcode; | 
 |       break; | 
 |     case 7: | 
 |       /* Illegal opcode.  */ | 
 |       goto illegal_opcode; | 
 |       break; | 
 |     case 8: | 
 |       /* Illegal opcode.  */ | 
 |       goto illegal_opcode; | 
 |       break; | 
 |     case 9: | 
 |       /* Illegal opcode.  */ | 
 |       goto illegal_opcode; | 
 |       break; | 
 |     case 10: | 
 |       /* Illegal opcode.  */ | 
 |       goto illegal_opcode; | 
 |       break; | 
 |     case 11: | 
 |       /* Illegal opcode.  */ | 
 |       goto illegal_opcode; | 
 |       break; | 
 |     case 12: | 
 |       /* Illegal opcode.  */ | 
 |       goto illegal_opcode; | 
 |       break; | 
 |     case 13: | 
 |       /* Illegal opcode.  */ | 
 |       goto illegal_opcode; | 
 |       break; | 
 |     case 14: | 
 |       /* Illegal opcode.  */ | 
 |       goto illegal_opcode; | 
 |       break; | 
 |     case 15: | 
 |       /* Illegal opcode.  */ | 
 |       goto illegal_opcode; | 
 |       break; | 
 |     } | 
 |   return 0; | 
 |  | 
 |  illegal_opcode: | 
 |   return -1; | 
 | } | 
 |  | 
 | /* Disassemble non-storage register class instructions.   */ | 
 |  | 
 | static int | 
 | disassem_class1 (disassemble_info *info, unsigned int ins) | 
 | { | 
 |   int opcode = (ins >> 21) & 0xf; | 
 |   int source_a = (ins >> 16) & 0x1f; | 
 |   int source_b = (ins >> 4) & 0x1f; | 
 |   int indx = (ins >> 10) & 0x1f; | 
 |  | 
 |   int size = ins & 0x7; | 
 |  | 
 |   if (ins & CLASS1_UNUSED_MASK) | 
 |     goto illegal_opcode; | 
 |  | 
 |   switch (opcode) | 
 |     { | 
 |     case 0: | 
 |       /* Stop.  */ | 
 |       (*info->fprintf_func) (info->stream, "stop    %d,r%d", indx, source_a); | 
 |       break; | 
 |     case 1: | 
 |       /* BMI - Block Move Indirect.  */ | 
 |       if (ins != BMI) | 
 | 	goto illegal_opcode; | 
 |  | 
 |       (*info->fprintf_func) (info->stream, "bmi     r1,r2,r3"); | 
 |       break; | 
 |     case 2: | 
 |       /* Illegal opcode.  */ | 
 |       goto illegal_opcode; | 
 |       break; | 
 |     case 3: | 
 |       /* BMD - Block Move Direct.  */ | 
 |       if (ins != BMD) | 
 | 	goto illegal_opcode; | 
 |  | 
 |       (*info->fprintf_func) (info->stream, "bmd     r1,r2,r3"); | 
 |       break; | 
 |     case 4: | 
 |       /* DSI - Disable Interrupts.  */ | 
 |       if (ins != DSI) | 
 | 	goto illegal_opcode; | 
 |  | 
 |       (*info->fprintf_func) (info->stream, "dsi"); | 
 |       break; | 
 |  | 
 |     case 5: | 
 |       /* ENI - Enable Interrupts.  */ | 
 |       if (ins != ENI) | 
 | 	goto illegal_opcode; | 
 |  | 
 |       (*info->fprintf_func) (info->stream, "eni"); | 
 |       break; | 
 |  | 
 |     case 6: | 
 |       /* Illegal opcode (was EUT).  */ | 
 |       goto illegal_opcode; | 
 |       break; | 
 |     case 7: | 
 |       /* RFI - Return from Interrupt.  */ | 
 |       if (ins != RFI) | 
 | 	goto illegal_opcode; | 
 |  | 
 |       (*info->fprintf_func) (info->stream, "rfi"); | 
 |       break; | 
 |     case 8: | 
 |       /* Illegal opcode.  */ | 
 |       goto illegal_opcode; | 
 |       break; | 
 |     case 9: | 
 |       /* Illegal opcode.  */ | 
 |       goto illegal_opcode; | 
 |       break; | 
 |     case 10: | 
 |       /* Illegal opcode.  */ | 
 |       goto illegal_opcode; | 
 |       break; | 
 |     case 11: | 
 |       /* Illegal opcode.  */ | 
 |       goto illegal_opcode; | 
 |       break; | 
 |     case 12: | 
 |       /* Illegal opcode.  */ | 
 |       goto illegal_opcode; | 
 |       break; | 
 |     case 13: | 
 |       goto illegal_opcode; | 
 |       break; | 
 |     case 14: | 
 |       goto illegal_opcode; | 
 |       break; | 
 |     case 15: | 
 |       if (ins & EAM_SELECT_MASK) | 
 | 	{ | 
 | 	  /* Extension arithmetic module write */ | 
 | 	  int fp_ins = (ins >> 27) & 0xf; | 
 |  | 
 | 	  if (size != 4) | 
 | 	    goto illegal_opcode; | 
 |  | 
 | 	  if (ins & FP_SELECT_MASK) | 
 | 	    { | 
 | 	      /* Which floating point instructions don't need a fsrcB | 
 | 	         register.  */ | 
 | 	      const int no_fsrcb[16] = { 1, 0, 0, 0, 0, 1, 1, 1, | 
 | 		1, 1, 0, 0, 1, 0, 0, 0 | 
 | 	      }; | 
 | 	      if (no_fsrcb[fp_ins] && source_b) | 
 | 		goto illegal_opcode; | 
 |  | 
 | 	      /* Check that none of the floating register register numbers | 
 | 	         is higher than 15. (If this is fload, then srcA is a | 
 | 	         general register.  */ | 
 | 	      if (ins & ((1 << 14) | (1 << 8)) || (fp_ins && ins & (1 << 20))) | 
 | 		goto illegal_opcode; | 
 |  | 
 | 	      switch (fp_ins) | 
 | 		{ | 
 | 		case 0: | 
 | 		  (*info->fprintf_func) (info->stream, "fload   f%d,r%d", | 
 | 					 indx, source_a); | 
 | 		  break; | 
 | 		case 1: | 
 | 		  (*info->fprintf_func) (info->stream, "fadd    f%d,f%d,f%d", | 
 | 					 indx, source_a, source_b); | 
 | 		  break; | 
 | 		case 2: | 
 | 		  (*info->fprintf_func) (info->stream, "fsub    f%d,f%d,f%d", | 
 | 					 indx, source_a, source_b); | 
 | 		  break; | 
 | 		case 3: | 
 | 		  (*info->fprintf_func) (info->stream, "fmult   f%d,f%d,f%d", | 
 | 					 indx, source_a, source_b); | 
 | 		  break; | 
 | 		case 4: | 
 | 		  (*info->fprintf_func) (info->stream, "fdiv    f%d,f%d,f%d", | 
 | 					 indx, source_a, source_b); | 
 | 		  break; | 
 | 		case 5: | 
 | 		  (*info->fprintf_func) (info->stream, "fsqrt   f%d,f%d", | 
 | 					 indx, source_a); | 
 | 		  break; | 
 | 		case 6: | 
 | 		  (*info->fprintf_func) (info->stream, "fneg    f%d,f%d", | 
 | 					 indx, source_a); | 
 | 		  break; | 
 | 		case 7: | 
 | 		  (*info->fprintf_func) (info->stream, "fabs    f%d,f%d", | 
 | 					 indx, source_a); | 
 | 		  break; | 
 | 		case 8: | 
 | 		  (*info->fprintf_func) (info->stream, "ftoi    f%d,f%d", | 
 | 					 indx, source_a); | 
 | 		  break; | 
 | 		case 9: | 
 | 		  (*info->fprintf_func) (info->stream, "itof    f%d,f%d", | 
 | 					 indx, source_a); | 
 | 		  break; | 
 | 		case 12: | 
 | 		  (*info->fprintf_func) (info->stream, "fmove   f%d,f%d", | 
 | 					 indx, source_a); | 
 | 		  break; | 
 | 		default: | 
 | 		  (*info->fprintf_func) (info->stream, | 
 | 					 "fpinst  %d,f%d,f%d,f%d", fp_ins, | 
 | 					 indx, source_a, source_b); | 
 | 		  break; | 
 | 		} | 
 | 	    } | 
 | 	  else | 
 | 	    { | 
 | 	      /* Which EAM operations do not need a srcB register.  */ | 
 | 	      const int no_srcb[32] = | 
 | 	      { 0, 0, 1, 1, 0, 1, 1, 1, | 
 | 		0, 1, 1, 1, 0, 0, 0, 0, | 
 | 		0, 0, 0, 0, 0, 0, 0, 0, | 
 | 		0, 0, 0, 0, 0, 0, 0, 0 | 
 | 	      }; | 
 |  | 
 | 	      if (no_srcb[indx] && source_b) | 
 | 		goto illegal_opcode; | 
 |  | 
 | 	      if (fp_ins) | 
 | 		goto illegal_opcode; | 
 |  | 
 | 	      switch (indx) | 
 | 		{ | 
 | 		case 0: | 
 | 		  (*info->fprintf_func) (info->stream, "mults   r%d,r%d", | 
 | 					 source_a, source_b); | 
 | 		  break; | 
 | 		case 1: | 
 | 		  (*info->fprintf_func) (info->stream, "multu   r%d,r%d", | 
 | 					 source_a, source_b); | 
 | 		  break; | 
 | 		case 2: | 
 | 		  (*info->fprintf_func) (info->stream, "divs    r%d", | 
 | 					 source_a); | 
 | 		  break; | 
 | 		case 3: | 
 | 		  (*info->fprintf_func) (info->stream, "divu    r%d", | 
 | 					 source_a); | 
 | 		  break; | 
 | 		case 4: | 
 | 		  (*info->fprintf_func) (info->stream, "writemd r%d,r%d", | 
 | 					 source_a, source_b); | 
 | 		  break; | 
 | 		case 5: | 
 | 		  (*info->fprintf_func) (info->stream, "writemdc r%d", | 
 | 					 source_a); | 
 | 		  break; | 
 | 		case 6: | 
 | 		  (*info->fprintf_func) (info->stream, "divds   r%d", | 
 | 					 source_a); | 
 | 		  break; | 
 | 		case 7: | 
 | 		  (*info->fprintf_func) (info->stream, "divdu   r%d", | 
 | 					 source_a); | 
 | 		  break; | 
 | 		case 9: | 
 | 		  (*info->fprintf_func) (info->stream, "asrd    r%d", | 
 | 					 source_a); | 
 | 		  break; | 
 | 		case 10: | 
 | 		  (*info->fprintf_func) (info->stream, "lsrd    r%d", | 
 | 					 source_a); | 
 | 		  break; | 
 | 		case 11: | 
 | 		  (*info->fprintf_func) (info->stream, "asld    r%d", | 
 | 					 source_a); | 
 | 		  break; | 
 | 		default: | 
 | 		  (*info->fprintf_func) (info->stream, | 
 | 					 "eamwrite %d,r%d,r%d", indx, | 
 | 					 source_a, source_b); | 
 | 		  break; | 
 | 		} | 
 | 	    } | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  /* WRITE - write to memory.  */ | 
 | 	  (*info->fprintf_func) (info->stream, "write.%s %d(r%d),r%d", | 
 | 				 size_names[size], indx, source_a, source_b); | 
 | 	} | 
 |       break; | 
 |     } | 
 |  | 
 |   return 0; | 
 |  | 
 |  illegal_opcode: | 
 |   return -1; | 
 | } | 
 |  | 
 | /* Disassemble storage immediate class instructions.   */ | 
 |  | 
 | static int | 
 | disassem_class2 (disassemble_info *info, unsigned int ins) | 
 | { | 
 |   int opcode = (ins >> 21) & 0xf; | 
 |   int source_a = (ins >> 16) & 0x1f; | 
 |   unsigned immediate = ins & 0x0000ffff; | 
 |  | 
 |   if (ins & CC_MASK) | 
 |     goto illegal_opcode; | 
 |  | 
 |   switch (opcode) | 
 |     { | 
 |     case 0: | 
 |       /* ADDI instruction.  */ | 
 |       (*info->fprintf_func) (info->stream, "addi    r%d,%d", source_a, | 
 | 			     immediate); | 
 |       break; | 
 |     case 1: | 
 |       /* Illegal opcode.  */ | 
 |       goto illegal_opcode; | 
 |       break; | 
 |     case 2: | 
 |       /* SUBI instruction.  */ | 
 |       (*info->fprintf_func) (info->stream, "subi    r%d,%d", source_a, | 
 | 			     immediate); | 
 |       break; | 
 |     case 3: | 
 |       /* Illegal opcode.  */ | 
 |       goto illegal_opcode; | 
 |       break; | 
 |     case 4: | 
 |       /* MOVIL instruction.  */ | 
 |       (*info->fprintf_func) (info->stream, "movil   r%d,0x%04X", source_a, | 
 | 			     immediate); | 
 |       break; | 
 |     case 5: | 
 |       /* MOVIU instruction.  */ | 
 |       (*info->fprintf_func) (info->stream, "moviu   r%d,0x%04X", source_a, | 
 | 			     immediate); | 
 |       break; | 
 |     case 6: | 
 |       /* MOVIQ instruction.  */ | 
 |       (*info->fprintf_func) (info->stream, "moviq   r%d,%u", source_a, | 
 | 			     immediate); | 
 |       break; | 
 |     case 7: | 
 |       /* Illegal opcode.  */ | 
 |       goto illegal_opcode; | 
 |       break; | 
 |     case 8: | 
 |       /* WRTL instruction.  */ | 
 |       if (source_a != 0) | 
 | 	goto illegal_opcode; | 
 |  | 
 |       (*info->fprintf_func) (info->stream, "wrtl    0x%04X", immediate); | 
 |       break; | 
 |     case 9: | 
 |       /* WRTU instruction.  */ | 
 |       if (source_a != 0) | 
 | 	goto illegal_opcode; | 
 |  | 
 |       (*info->fprintf_func) (info->stream, "wrtu    0x%04X", immediate); | 
 |       break; | 
 |     case 10: | 
 |       /* Illegal opcode.  */ | 
 |       goto illegal_opcode; | 
 |       break; | 
 |     case 11: | 
 |       /* Illegal opcode.  */ | 
 |       goto illegal_opcode; | 
 |       break; | 
 |     case 12: | 
 |       /* Illegal opcode.  */ | 
 |       goto illegal_opcode; | 
 |       break; | 
 |     case 13: | 
 |       /* Illegal opcode.  */ | 
 |       goto illegal_opcode; | 
 |       break; | 
 |     case 14: | 
 |       /* Illegal opcode.  */ | 
 |       goto illegal_opcode; | 
 |       break; | 
 |     case 15: | 
 |       /* Illegal opcode.  */ | 
 |       goto illegal_opcode; | 
 |       break; | 
 |     } | 
 |  | 
 |   return 0; | 
 |  | 
 |  illegal_opcode: | 
 |   return -1; | 
 | } | 
 |  | 
 | /* Disassemble storage register class instructions.  */ | 
 |  | 
 | static int | 
 | disassem_class3 (disassemble_info *info, unsigned int ins) | 
 | { | 
 |   int opcode = (ins >> 21) & 0xf; | 
 |   int source_b = (ins >> 4) & 0x1f; | 
 |   int source_a = (ins >> 16) & 0x1f; | 
 |   int size = ins & 0x7; | 
 |   int dest = (ins >> 10) & 0x1f; | 
 |  | 
 |   /* Those instructions that don't have a srcB register.  */ | 
 |   const int no_srcb[16] = | 
 |   { 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0 }; | 
 |  | 
 |   /* These are instructions which can take an immediate srcB value.  */ | 
 |   const int srcb_immed[16] = | 
 |   { 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1 }; | 
 |  | 
 |   /* User opcodes should not provide a non-zero srcB register | 
 |      when none is required. Only a BRA or floating point | 
 |      instruction should have a non-zero condition code field. | 
 |      Only a WRITE or EAMWRITE (opcode 15) should select an EAM | 
 |      or floating point operation.  Note that FP_SELECT_MASK is | 
 |      the same bit (bit 3) as the interrupt bit which | 
 |      distinguishes SYS1 from BRA and SYS2 from RFLAG.  */ | 
 |   if ((no_srcb[opcode] && source_b) | 
 |       || (!srcb_immed[opcode] && ins & CLASS3_SOURCEB_IMMED) | 
 |       || (opcode != 12 && opcode != 15 && ins & CC_MASK) | 
 |       || (opcode != 15 && ins & (EAM_SELECT_MASK | FP_SELECT_MASK))) | 
 |     goto illegal_opcode; | 
 |  | 
 |  | 
 |   switch (opcode) | 
 |     { | 
 |     case 0: | 
 |       /* ADD instruction.  */ | 
 |       (*info->fprintf_func) (info->stream, "add.%s   r%d,r%d,r%d", | 
 | 			     size_names[size], dest, source_a, source_b); | 
 |       break; | 
 |     case 1: | 
 |       /* ADC instruction.  */ | 
 |       (*info->fprintf_func) (info->stream, "adc.%s   r%d,r%d,r%d", | 
 | 			     size_names[size], dest, source_a, source_b); | 
 |       break; | 
 |     case 2: | 
 |       /* SUB instruction.  */ | 
 |       if (dest == 0) | 
 | 	(*info->fprintf_func) (info->stream, "cmp.%s   r%d,r%d", | 
 | 			       size_names[size], source_a, source_b); | 
 |       else | 
 | 	(*info->fprintf_func) (info->stream, "sub.%s   r%d,r%d,r%d", | 
 | 			       size_names[size], dest, source_a, source_b); | 
 |       break; | 
 |     case 3: | 
 |       /* SUBC instruction.  */ | 
 |       if (dest == 0) | 
 | 	(*info->fprintf_func) (info->stream, "cmpc.%s  r%d,r%d", | 
 | 			       size_names[size], source_a, source_b); | 
 |       else | 
 | 	(*info->fprintf_func) (info->stream, "subc.%s  r%d,r%d,r%d", | 
 | 			       size_names[size], dest, source_a, source_b); | 
 |       break; | 
 |     case 4: | 
 |       /* EXTW instruction.  */ | 
 |       if (size == 1) | 
 | 	goto illegal_opcode; | 
 |  | 
 |       (*info->fprintf_func) (info->stream, "extw.%s  r%d,r%d", | 
 | 			     size_names[size], dest, source_a); | 
 |       break; | 
 |     case 5: | 
 |       /* ASR instruction.  */ | 
 |       if (ins & CLASS3_SOURCEB_IMMED) | 
 | 	(*info->fprintf_func) (info->stream, "asr.%s   r%d,r%d,%d", | 
 | 			       size_names[size], dest, source_a, source_b); | 
 |       else | 
 | 	(*info->fprintf_func) (info->stream, "asr.%s   r%d,r%d,r%d", | 
 | 			       size_names[size], dest, source_a, source_b); | 
 |       break; | 
 |     case 6: | 
 |       /* LSR instruction.  */ | 
 |       if (ins & CLASS3_SOURCEB_IMMED) | 
 | 	(*info->fprintf_func) (info->stream, "lsr.%s   r%d,r%d,%d", | 
 | 			       size_names[size], dest, source_a, source_b); | 
 |       else | 
 | 	(*info->fprintf_func) (info->stream, "lsr.%s   r%d,r%d,r%d", | 
 | 			       size_names[size], dest, source_a, source_b); | 
 |       break; | 
 |     case 7: | 
 |       /* ASL instruction.  */ | 
 |       if (ins & CLASS3_SOURCEB_IMMED) | 
 | 	(*info->fprintf_func) (info->stream, "asl.%s   r%d,r%d,%d", | 
 | 			       size_names[size], dest, source_a, source_b); | 
 |       else | 
 | 	(*info->fprintf_func) (info->stream, "asl.%s   r%d,r%d,r%d", | 
 | 			       size_names[size], dest, source_a, source_b); | 
 |       break; | 
 |     case 8: | 
 |       /* XOR instruction.  */ | 
 |       (*info->fprintf_func) (info->stream, "xor.%s   r%d,r%d,r%d", | 
 | 			     size_names[size], dest, source_a, source_b); | 
 |       break; | 
 |     case 9: | 
 |       /* OR instruction.  */ | 
 |       if (source_b == 0) | 
 | 	(*info->fprintf_func) (info->stream, "move.%s  r%d,r%d", | 
 | 			       size_names[size], dest, source_a); | 
 |       else | 
 | 	(*info->fprintf_func) (info->stream, "or.%s    r%d,r%d,r%d", | 
 | 			       size_names[size], dest, source_a, source_b); | 
 |       break; | 
 |     case 10: | 
 |       /* AND instruction.  */ | 
 |       (*info->fprintf_func) (info->stream, "and.%s   r%d,r%d,r%d", | 
 | 			     size_names[size], dest, source_a, source_b); | 
 |       break; | 
 |     case 11: | 
 |       /* NOT instruction.  */ | 
 |       (*info->fprintf_func) (info->stream, "not.%s   r%d,r%d", | 
 | 			     size_names[size], dest, source_a); | 
 |       break; | 
 |     case 12: | 
 |       /* BRA instruction.  */ | 
 |       { | 
 | 	unsigned cbf = (ins >> 27) & 0x000f; | 
 |  | 
 | 	if (size != 4) | 
 | 	  goto illegal_opcode; | 
 |  | 
 | 	(*info->fprintf_func) (info->stream, "bra     %s,r%d,r%d", | 
 | 			       cc_names[cbf], source_a, dest); | 
 |       } | 
 |       break; | 
 |     case 13: | 
 |       /* RFLAG instruction.  */ | 
 |       if (source_a || size != 4) | 
 | 	goto illegal_opcode; | 
 |  | 
 |       (*info->fprintf_func) (info->stream, "rflag   r%d", dest); | 
 |       break; | 
 |     case 14: | 
 |       /* EXTB instruction.  */ | 
 |       (*info->fprintf_func) (info->stream, "extb.%s  r%d,r%d", | 
 | 			     size_names[size], dest, source_a); | 
 |       break; | 
 |     case 15: | 
 |       if (!(ins & CLASS3_SOURCEB_IMMED)) | 
 | 	goto illegal_opcode; | 
 |  | 
 |       if (ins & EAM_SELECT_MASK) | 
 | 	{ | 
 | 	  /* Extension arithmetic module read.  */ | 
 | 	  int fp_ins = (ins >> 27) & 0xf; | 
 |  | 
 | 	  if (size != 4) | 
 | 	    goto illegal_opcode; | 
 |  | 
 | 	  if (ins & FP_SELECT_MASK) | 
 | 	    { | 
 | 	      /* Check fsrcA <= 15 and fsrcB <= 15.  */ | 
 | 	      if (ins & ((1 << 20) | (1 << 8))) | 
 | 		goto illegal_opcode; | 
 |  | 
 | 	      switch (fp_ins) | 
 | 		{ | 
 | 		case 0: | 
 | 		  if (source_b) | 
 | 		    goto illegal_opcode; | 
 |  | 
 | 		  (*info->fprintf_func) (info->stream, "fstore  r%d,f%d", | 
 | 					 dest, source_a); | 
 | 		  break; | 
 | 		case 10: | 
 | 		  (*info->fprintf_func) (info->stream, "fcmp    r%d,f%d,f%d", | 
 | 					 dest, source_a, source_b); | 
 | 		  break; | 
 | 		case 11: | 
 | 		  (*info->fprintf_func) (info->stream, "fcmpe   r%d,f%d,f%d", | 
 | 					 dest, source_a, source_b); | 
 | 		  break; | 
 | 		default: | 
 | 		  (*info->fprintf_func) (info->stream, | 
 | 					 "fpuread %d,r%d,f%d,f%d", fp_ins, | 
 | 					 dest, source_a, source_b); | 
 | 		  break; | 
 | 		} | 
 | 	    } | 
 | 	  else | 
 | 	    { | 
 | 	      if (fp_ins || source_a) | 
 | 		goto illegal_opcode; | 
 |  | 
 | 	      switch (source_b) | 
 | 		{ | 
 | 		case 0: | 
 | 		  (*info->fprintf_func) (info->stream, "readmda r%d", dest); | 
 | 		  break; | 
 | 		case 1: | 
 | 		  (*info->fprintf_func) (info->stream, "readmdb r%d", dest); | 
 | 		  break; | 
 | 		case 2: | 
 | 		  (*info->fprintf_func) (info->stream, "readmdc r%d", dest); | 
 | 		  break; | 
 | 		default: | 
 | 		  (*info->fprintf_func) (info->stream, "eamread r%d,%d", | 
 | 					 dest, source_b); | 
 | 		  break; | 
 | 		} | 
 | 	    } | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  if (ins & FP_SELECT_MASK) | 
 | 	    goto illegal_opcode; | 
 |  | 
 | 	  /* READ instruction.  */ | 
 | 	  (*info->fprintf_func) (info->stream, "read.%s  r%d,%d(r%d)", | 
 | 				 size_names[size], dest, source_b, source_a); | 
 | 	} | 
 |       break; | 
 |     } | 
 |  | 
 |   return 0; | 
 |  | 
 |  illegal_opcode: | 
 |   return -1; | 
 |  | 
 | } | 
 |  | 
 | /* Print the visium instruction at address addr in debugged memory, | 
 |    on info->stream. Return length of the instruction, in bytes.  */ | 
 |  | 
 | int | 
 | print_insn_visium (bfd_vma addr, disassemble_info *info) | 
 | { | 
 |   unsigned ins; | 
 |   unsigned p1, p2; | 
 |   int ans; | 
 |   int i; | 
 |  | 
 |   /* Stuff copied from m68k-dis.c.  */ | 
 |   struct private priv; | 
 |   bfd_byte *buffer = priv.the_buffer; | 
 |   info->private_data = (PTR) & priv; | 
 |   priv.max_fetched = priv.the_buffer; | 
 |   priv.insn_start = addr; | 
 |   if (setjmp (priv.bailout) != 0) | 
 |     { | 
 |       /* Error return.  */ | 
 |       return -1; | 
 |     } | 
 |  | 
 |   /* We do return this info.  */ | 
 |   info->insn_info_valid = 1; | 
 |  | 
 |   /* Assume non branch insn.  */ | 
 |   info->insn_type = dis_nonbranch; | 
 |  | 
 |   /* Assume no delay.  */ | 
 |   info->branch_delay_insns = 0; | 
 |  | 
 |   /* Assume no target known.  */ | 
 |   info->target = 0; | 
 |  | 
 |   /* Get 32-bit instruction word.  */ | 
 |   FETCH_DATA (info, buffer + 4); | 
 |   ins = (unsigned) buffer[0] << 24; | 
 |   ins |= buffer[1] << 16; | 
 |   ins |= buffer[2] << 8; | 
 |   ins |= buffer[3]; | 
 |  | 
 |   ans = 0; | 
 |  | 
 |   p1 = buffer[0] ^ buffer[1] ^ buffer[2] ^ buffer[3]; | 
 |   p2 = 0; | 
 |   for (i = 0; i < 8; i++) | 
 |     { | 
 |       p2 += p1 & 1; | 
 |       p1 >>= 1; | 
 |     } | 
 |  | 
 |   /* Decode the instruction.  */ | 
 |   if (p2 & 1) | 
 |     ans = -1; | 
 |   else | 
 |     { | 
 |       switch ((ins >> 25) & 0x3) | 
 | 	{ | 
 | 	case 0: | 
 | 	  ans = disassem_class0 (info, ins); | 
 | 	  break; | 
 | 	case 1: | 
 | 	  ans = disassem_class1 (info, ins); | 
 | 	  break; | 
 | 	case 2: | 
 | 	  ans = disassem_class2 (info, ins); | 
 | 	  break; | 
 | 	case 3: | 
 | 	  ans = disassem_class3 (info, ins); | 
 | 	  break; | 
 | 	} | 
 |     } | 
 |  | 
 |   if (ans != 0) | 
 |     (*info->fprintf_func) (info->stream, "err"); | 
 |  | 
 |   /* Return number of bytes consumed (always 4 for the Visium).  */ | 
 |   return 4; | 
 | } |