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