|  | /* Single instruction disassembler for the Visium. | 
|  |  | 
|  | Copyright (C) 2002-2020 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; | 
|  | } |