| /* xgate-dis.c -- Freescale XGATE disassembly | 
 |    Copyright (C) 2009-2025 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; | 
 | } |