|  | /* xgate-dis.c -- Freescale XGATE disassembly | 
|  | Copyright (C) 2009-2020 Free Software Foundation, Inc. | 
|  | Written by Sean Keys (skeys@ipdatasys.com) | 
|  |  | 
|  | 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 <assert.h> | 
|  | #include "disassemble.h" | 
|  | #include "opintl.h" | 
|  | #include "libiberty.h" | 
|  | #include "ansidecl.h" | 
|  | #include "opcode/xgate.h" | 
|  |  | 
|  | #define XGATE_TWO_BYTES      0x02 | 
|  | #define XGATE_NINE_BITS      0x1FF | 
|  | #define XGATE_TEN_BITS       0x3FF | 
|  | #define XGATE_NINE_SIGNBIT   0x100 | 
|  | #define XGATE_TEN_SIGNBIT    0x200 | 
|  |  | 
|  | /* Structures.  */ | 
|  | struct decodeInfo | 
|  | { | 
|  | unsigned int operMask; | 
|  | unsigned int operMasksRegisterBits; | 
|  | struct xgate_opcode *opcodePTR; | 
|  | }; | 
|  |  | 
|  | /* Prototypes for local functions.  */ | 
|  | static int print_insn (bfd_vma, struct disassemble_info *); | 
|  | static int read_memory (bfd_vma, bfd_byte*, int, struct disassemble_info *); | 
|  | static int ripBits (unsigned int *, int, | 
|  | struct xgate_opcode *, unsigned int); | 
|  | static int macro_search (char *, char *); | 
|  | static struct decodeInfo * find_match (unsigned int); | 
|  |  | 
|  | /* Statics.  */ | 
|  | static struct decodeInfo *decodeTable; | 
|  | static int initialized; | 
|  | static char previousOpName[10]; | 
|  | static unsigned int perviousBin; | 
|  |  | 
|  | /* Disassemble one instruction at address 'memaddr'.  Returns the number | 
|  | of bytes used by that instruction.  */ | 
|  |  | 
|  | static int | 
|  | print_insn (bfd_vma memaddr, struct disassemble_info* info) | 
|  | { | 
|  | int status; | 
|  | unsigned int raw_code; | 
|  | char *s = 0; | 
|  | long bytesRead = 0; | 
|  | int i = 0; | 
|  | struct xgate_opcode *opcodePTR = (struct xgate_opcode*) xgate_opcodes; | 
|  | struct decodeInfo *decodeTablePTR = 0; | 
|  | struct decodeInfo *decodePTR = 0; | 
|  | unsigned int operandRegisterBits = 0; | 
|  | signed int relAddr = 0; | 
|  | signed int operandOne = 0; | 
|  | signed int operandTwo = 0; | 
|  | bfd_byte buffer[4]; | 
|  | bfd_vma absAddress; | 
|  |  | 
|  | unsigned int operMaskReg = 0; | 
|  | /* Initialize our array of opcode masks and check them against our constant | 
|  | table.  */ | 
|  | if (!initialized) | 
|  | { | 
|  | decodeTable = xmalloc (sizeof (struct decodeInfo) * xgate_num_opcodes); | 
|  | for (i = 0, decodeTablePTR = decodeTable; i < xgate_num_opcodes; | 
|  | i++, decodeTablePTR++, opcodePTR++) | 
|  | { | 
|  | unsigned int bin = 0; | 
|  | unsigned int mask = 0; | 
|  | for (s = opcodePTR->format; *s; s++) | 
|  | { | 
|  | bin <<= 1; | 
|  | mask <<= 1; | 
|  | operandRegisterBits <<= 1; | 
|  | bin |= (*s == '1'); | 
|  | mask |= (*s == '0' || *s == '1'); | 
|  | operandRegisterBits |= (*s == 'r'); | 
|  | } | 
|  | /* Asserting will uncover inconsistencies in our table.  */ | 
|  | assert ((s - opcodePTR->format) == 16 || (s - opcodePTR->format) == 32); | 
|  | assert (opcodePTR->bin_opcode == bin); | 
|  |  | 
|  | decodeTablePTR->operMask = mask; | 
|  | decodeTablePTR->operMasksRegisterBits = operandRegisterBits; | 
|  | decodeTablePTR->opcodePTR = opcodePTR; | 
|  | } | 
|  | initialized = 1; | 
|  | } | 
|  |  | 
|  | /* Read 16 bits.  */ | 
|  | bytesRead += XGATE_TWO_BYTES; | 
|  | status = read_memory (memaddr, buffer, XGATE_TWO_BYTES, info); | 
|  | if (status == 0) | 
|  | { | 
|  | raw_code = buffer[0]; | 
|  | raw_code <<= 8; | 
|  | raw_code += buffer[1]; | 
|  |  | 
|  | decodePTR = find_match (raw_code); | 
|  | if (decodePTR) | 
|  | { | 
|  | operMaskReg = decodePTR->operMasksRegisterBits; | 
|  | (*info->fprintf_func)(info->stream, "%s", decodePTR->opcodePTR->name); | 
|  |  | 
|  | /* First we compare the shorthand format of the constraints. If we | 
|  | still are unable to pinpoint the operands | 
|  | we analyze the opcodes constraint string.  */ | 
|  | if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_MON_R_C)) | 
|  | { | 
|  | (*info->fprintf_func)(info->stream, " R%x, CCR", | 
|  | (raw_code >> 8) & 0x7); | 
|  | } | 
|  | else if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_MON_C_R)) | 
|  | { | 
|  | (*info->fprintf_func)(info->stream, " CCR, R%x", | 
|  | (raw_code >> 8) & 0x7); | 
|  | } | 
|  | else if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_MON_R_P)) | 
|  | { | 
|  | (*info->fprintf_func)(info->stream, " R%x, PC", | 
|  | (raw_code >> 8) & 0x7); | 
|  | } | 
|  | else if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_TRI)) | 
|  | { | 
|  | (*info->fprintf_func)(info->stream, " R%x, R%x, R%x", | 
|  | (raw_code >> 8) & 0x7, (raw_code >> 5) & 0x7, | 
|  | (raw_code >> 2) & 0x7); | 
|  | } | 
|  | else if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_IDR)) | 
|  | { | 
|  | if (raw_code & 0x01) | 
|  | { | 
|  | (*info->fprintf_func)(info->stream, " R%x, (R%x, R%x+)", | 
|  | (raw_code >> 8) & 0x7, (raw_code >> 5) & 0x7, | 
|  | (raw_code >> 2) & 0x7); | 
|  | } | 
|  | else if (raw_code & 0x02) | 
|  | { | 
|  | (*info->fprintf_func)(info->stream, " R%x, (R%x, -R%x)", | 
|  | (raw_code >> 8) & 0x7, (raw_code >> 5) & 0x7, | 
|  | (raw_code >> 2) & 0x7); | 
|  | } | 
|  | else | 
|  | { | 
|  | (*info->fprintf_func)(info->stream, " R%x, (R%x, R%x)", | 
|  | (raw_code >> 8) & 0x7, (raw_code >> 5) & 0x7, | 
|  | (raw_code >> 2) & 0x7); | 
|  | } | 
|  | } | 
|  | else if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_DYA)) | 
|  | { | 
|  | operandOne = ripBits (&operMaskReg, 3, decodePTR->opcodePTR, raw_code); | 
|  | operandTwo = ripBits (&operMaskReg, 3, decodePTR->opcodePTR, raw_code); | 
|  | ( *info->fprintf_func)(info->stream, " R%x, R%x", operandOne, | 
|  | operandTwo); | 
|  | } | 
|  | else if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_IDO5)) | 
|  | { | 
|  | (*info->fprintf_func)(info->stream, " R%x, (R%x, #0x%x)", | 
|  | (raw_code >> 8) & 0x7, (raw_code >> 5) & 0x7, raw_code & 0x1f); | 
|  | } | 
|  | else if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_MON)) | 
|  | { | 
|  | operandOne = ripBits (&operMaskReg, 3, decodePTR->opcodePTR, | 
|  | raw_code); | 
|  | (*info->fprintf_func)(info->stream, " R%x", operandOne); | 
|  | } | 
|  | else if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_REL9)) | 
|  | { | 
|  | /* If address is negative handle it accordingly.  */ | 
|  | if (raw_code & XGATE_NINE_SIGNBIT) | 
|  | { | 
|  | relAddr = XGATE_NINE_BITS >> 1; /* Clip sign bit.  */ | 
|  | relAddr = ~relAddr; /* Make signed.  */ | 
|  | relAddr |= (raw_code & 0xFF) + 1; /* Apply our value.  */ | 
|  | relAddr *= 2; /* Multiply by two as per processor docs.  */ | 
|  | } | 
|  | else | 
|  | { | 
|  | relAddr = raw_code & 0xff; | 
|  | relAddr = relAddr * 2 + 2; | 
|  | } | 
|  | (*info->fprintf_func)(info->stream, " *%d", relAddr); | 
|  | (*info->fprintf_func)(info->stream, "  Abs* 0x"); | 
|  | (*info->print_address_func)(memaddr + relAddr, info); | 
|  | } | 
|  | else if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_REL10)) | 
|  | { | 
|  | /* If address is negative handle it accordingly.  */ | 
|  | if (raw_code & XGATE_TEN_SIGNBIT) | 
|  | { | 
|  | relAddr = XGATE_TEN_BITS >> 1; /* Clip sign bit.  */ | 
|  | relAddr = ~relAddr; /* Make signed.  */ | 
|  | relAddr |= (raw_code & 0x1FF) + 1; /* Apply our value.  */ | 
|  | relAddr *= 2; /* Multiply by two as per processor docs.  */ | 
|  | } | 
|  | else | 
|  | { | 
|  | relAddr = raw_code & 0x1FF; | 
|  | relAddr = relAddr * 2 + 2; | 
|  | } | 
|  | (*info->fprintf_func)(info->stream, " *%d", relAddr); | 
|  | (*info->fprintf_func)(info->stream, "  Abs* 0x"); | 
|  | (*info->print_address_func)(memaddr + relAddr, info); | 
|  | } | 
|  | else if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_IMM4)) | 
|  | { | 
|  | (*info->fprintf_func)(info->stream, " R%x, #0x%02x", | 
|  | (raw_code >> 8) & 0x7, (raw_code >> 4) & 0xF); | 
|  | } | 
|  | else if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_IMM8)) | 
|  | { | 
|  | if (macro_search (decodePTR->opcodePTR->name, previousOpName) && | 
|  | previousOpName[0]) | 
|  | { | 
|  | absAddress = (0xFF & raw_code) << 8; | 
|  | absAddress |= perviousBin & 0xFF; | 
|  | (*info->fprintf_func)(info->stream, " R%x, #0x%02x Abs* 0x", | 
|  | (raw_code >> 8) & 0x7, raw_code & 0xff); | 
|  | (*info->print_address_func)(absAddress, info); | 
|  | previousOpName[0] = 0; | 
|  | } | 
|  | else | 
|  | { | 
|  | strcpy (previousOpName, decodePTR->opcodePTR->name); | 
|  | (*info->fprintf_func)(info->stream, " R%x, #0x%02x", | 
|  | (raw_code >> 8) & 0x7, raw_code & 0xff); | 
|  | } | 
|  | } | 
|  | else if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_IMM3)) | 
|  | { | 
|  | (*info->fprintf_func)(info->stream, " #0x%x", | 
|  | (raw_code >> 8) & 0x7); | 
|  | } | 
|  | else if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_INH)) | 
|  | { | 
|  | } | 
|  | else | 
|  | { | 
|  | (*info->fprintf_func)(info->stream, " unhandled mode %s", | 
|  | decodePTR->opcodePTR->constraints); | 
|  | } | 
|  | perviousBin = raw_code; | 
|  | } | 
|  | else | 
|  | { | 
|  | (*info->fprintf_func)(info->stream, | 
|  | " unable to find opcode match #0%x", raw_code); | 
|  | } | 
|  | } | 
|  | return bytesRead; | 
|  | } | 
|  |  | 
|  | int | 
|  | print_insn_xgate (bfd_vma memaddr, struct disassemble_info* info) | 
|  | { | 
|  | return print_insn (memaddr, info); | 
|  | } | 
|  |  | 
|  | static int | 
|  | read_memory (bfd_vma memaddr, bfd_byte* buffer, int size, | 
|  | struct disassemble_info* info) | 
|  | { | 
|  | int status; | 
|  | status = (*info->read_memory_func) (memaddr, buffer, size, info); | 
|  | if (status != 0) | 
|  | { | 
|  | (*info->memory_error_func) (status, memaddr, info); | 
|  | return -1; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int | 
|  | ripBits (unsigned int *operandBitsRemaining, | 
|  | int numBitsRequested, | 
|  | struct xgate_opcode *opcodePTR, | 
|  | unsigned int memory) | 
|  | { | 
|  | unsigned int currentBit; | 
|  | unsigned int operand = 0; | 
|  | int numBitsFound; | 
|  |  | 
|  | for (numBitsFound = 0, currentBit = 1u << ((opcodePTR->size * 8) - 1); | 
|  | numBitsFound < numBitsRequested && currentBit != 0; | 
|  | currentBit >>= 1) | 
|  | { | 
|  | if (currentBit & *operandBitsRemaining) | 
|  | { | 
|  | *operandBitsRemaining &= ~(currentBit); /* Consume the current bit.  */ | 
|  | operand <<= 1; /* Make room for our next bit.  */ | 
|  | numBitsFound++; | 
|  | operand |= (currentBit & memory) > 0; | 
|  | } | 
|  | } | 
|  | return operand; | 
|  | } | 
|  |  | 
|  | static int | 
|  | macro_search (char *currentName, char *lastName) | 
|  | { | 
|  | int i; | 
|  | int length = 0; | 
|  | char *where; | 
|  |  | 
|  | for (i = 0; i < xgate_num_opcodes; i++) | 
|  | { | 
|  | where = strstr (xgate_opcodes[i].constraints, lastName); | 
|  |  | 
|  | if (where) | 
|  | { | 
|  | length = strlen (where); | 
|  | } | 
|  | if (length) | 
|  | { | 
|  | where = strstr (xgate_opcodes[i].constraints, currentName); | 
|  | if (where) | 
|  | { | 
|  | length = strlen (where); | 
|  | return 1; | 
|  | } | 
|  | } | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static struct decodeInfo * | 
|  | find_match (unsigned int raw_code) | 
|  | { | 
|  | struct decodeInfo *decodeTablePTR = 0; | 
|  | int i; | 
|  |  | 
|  | for (i = 0, decodeTablePTR = decodeTable; i < xgate_num_opcodes; | 
|  | i++, decodeTablePTR++) | 
|  | { | 
|  | if ((raw_code & decodeTablePTR->operMask) | 
|  | == decodeTablePTR->opcodePTR->bin_opcode) | 
|  | { | 
|  | /* Make sure we didn't run into a macro or alias.  */ | 
|  | if (decodeTablePTR->opcodePTR->cycles_min != 0) | 
|  | { | 
|  | return decodeTablePTR; | 
|  | break; | 
|  | } | 
|  | else | 
|  | continue; | 
|  | } | 
|  | } | 
|  | return 0; | 
|  | } |