1016e56d1Schristos /* xgate-dis.c -- Freescale XGATE disassembly
2*1424dfb3Schristos    Copyright (C) 2009-2020 Free Software Foundation, Inc.
3016e56d1Schristos    Written by Sean Keys (skeys@ipdatasys.com)
4016e56d1Schristos 
5016e56d1Schristos    This file is part of the GNU opcodes library.
6016e56d1Schristos 
7016e56d1Schristos    This library is free software; you can redistribute it and/or modify
8016e56d1Schristos    it under the terms of the GNU General Public License as published by
9016e56d1Schristos    the Free Software Foundation; either version 3, or (at your option)
10016e56d1Schristos    any later version.
11016e56d1Schristos 
12016e56d1Schristos    It is distributed in the hope that it will be useful, but WITHOUT
13016e56d1Schristos    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14016e56d1Schristos    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
15016e56d1Schristos    License for more details.
16016e56d1Schristos 
17016e56d1Schristos    You should have received a copy of the GNU General Public License
18016e56d1Schristos    along with this program; if not, write to the Free Software
19016e56d1Schristos    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
20016e56d1Schristos    MA 02110-1301, USA.  */
21016e56d1Schristos 
22016e56d1Schristos #include "sysdep.h"
23016e56d1Schristos #include <assert.h>
2407163879Schristos #include "disassemble.h"
25016e56d1Schristos #include "opintl.h"
26016e56d1Schristos #include "libiberty.h"
27016e56d1Schristos #include "ansidecl.h"
28016e56d1Schristos #include "opcode/xgate.h"
29016e56d1Schristos 
30016e56d1Schristos #define XGATE_TWO_BYTES      0x02
31016e56d1Schristos #define XGATE_NINE_BITS      0x1FF
32016e56d1Schristos #define XGATE_TEN_BITS       0x3FF
33016e56d1Schristos #define XGATE_NINE_SIGNBIT   0x100
34016e56d1Schristos #define XGATE_TEN_SIGNBIT    0x200
35016e56d1Schristos 
36016e56d1Schristos /* Structures.  */
37016e56d1Schristos struct decodeInfo
38016e56d1Schristos {
39016e56d1Schristos   unsigned int operMask;
40016e56d1Schristos   unsigned int operMasksRegisterBits;
41016e56d1Schristos   struct xgate_opcode *opcodePTR;
42016e56d1Schristos };
43016e56d1Schristos 
44016e56d1Schristos /* Prototypes for local functions.  */
45016e56d1Schristos static int print_insn (bfd_vma, struct disassemble_info *);
46016e56d1Schristos static int read_memory (bfd_vma, bfd_byte*, int, struct disassemble_info *);
47016e56d1Schristos static int ripBits (unsigned int *, int,
48016e56d1Schristos 		    struct xgate_opcode *, unsigned int);
49016e56d1Schristos static int macro_search (char *, char *);
50016e56d1Schristos static struct decodeInfo * find_match (unsigned int);
51016e56d1Schristos 
52016e56d1Schristos /* Statics.  */
53016e56d1Schristos static struct decodeInfo *decodeTable;
54016e56d1Schristos static int initialized;
55016e56d1Schristos static char previousOpName[10];
56016e56d1Schristos static unsigned int perviousBin;
57016e56d1Schristos 
58016e56d1Schristos /* Disassemble one instruction at address 'memaddr'.  Returns the number
59016e56d1Schristos    of bytes used by that instruction.  */
60016e56d1Schristos 
61016e56d1Schristos static int
print_insn(bfd_vma memaddr,struct disassemble_info * info)62016e56d1Schristos print_insn (bfd_vma memaddr, struct disassemble_info* info)
63016e56d1Schristos {
64016e56d1Schristos   int status;
65016e56d1Schristos   unsigned int raw_code;
66016e56d1Schristos   char *s = 0;
67016e56d1Schristos   long bytesRead = 0;
68016e56d1Schristos   int i = 0;
69016e56d1Schristos   struct xgate_opcode *opcodePTR = (struct xgate_opcode*) xgate_opcodes;
70016e56d1Schristos   struct decodeInfo *decodeTablePTR = 0;
71016e56d1Schristos   struct decodeInfo *decodePTR = 0;
72016e56d1Schristos   unsigned int operandRegisterBits = 0;
73016e56d1Schristos   signed int relAddr = 0;
74016e56d1Schristos   signed int operandOne = 0;
75016e56d1Schristos   signed int operandTwo = 0;
76016e56d1Schristos   bfd_byte buffer[4];
77016e56d1Schristos   bfd_vma absAddress;
78016e56d1Schristos 
79016e56d1Schristos   unsigned int operMaskReg = 0;
80016e56d1Schristos   /* Initialize our array of opcode masks and check them against our constant
81016e56d1Schristos      table.  */
82016e56d1Schristos   if (!initialized)
83016e56d1Schristos     {
84016e56d1Schristos       decodeTable = xmalloc (sizeof (struct decodeInfo) * xgate_num_opcodes);
85016e56d1Schristos       for (i = 0, decodeTablePTR = decodeTable; i < xgate_num_opcodes;
86016e56d1Schristos           i++, decodeTablePTR++, opcodePTR++)
87016e56d1Schristos         {
88016e56d1Schristos           unsigned int bin = 0;
89016e56d1Schristos           unsigned int mask = 0;
90016e56d1Schristos           for (s = opcodePTR->format; *s; s++)
91016e56d1Schristos             {
92016e56d1Schristos               bin <<= 1;
93016e56d1Schristos               mask <<= 1;
94016e56d1Schristos               operandRegisterBits <<= 1;
95016e56d1Schristos               bin |= (*s == '1');
96016e56d1Schristos               mask |= (*s == '0' || *s == '1');
97016e56d1Schristos               operandRegisterBits |= (*s == 'r');
98016e56d1Schristos             }
99016e56d1Schristos           /* Asserting will uncover inconsistencies in our table.  */
100016e56d1Schristos           assert ((s - opcodePTR->format) == 16 || (s - opcodePTR->format) == 32);
101016e56d1Schristos           assert (opcodePTR->bin_opcode == bin);
102016e56d1Schristos 
103016e56d1Schristos           decodeTablePTR->operMask = mask;
104016e56d1Schristos           decodeTablePTR->operMasksRegisterBits = operandRegisterBits;
105016e56d1Schristos           decodeTablePTR->opcodePTR = opcodePTR;
106016e56d1Schristos         }
107016e56d1Schristos       initialized = 1;
108016e56d1Schristos     }
109016e56d1Schristos 
110016e56d1Schristos   /* Read 16 bits.  */
111016e56d1Schristos   bytesRead += XGATE_TWO_BYTES;
112016e56d1Schristos   status = read_memory (memaddr, buffer, XGATE_TWO_BYTES, info);
113016e56d1Schristos   if (status == 0)
114016e56d1Schristos     {
115016e56d1Schristos       raw_code = buffer[0];
116016e56d1Schristos       raw_code <<= 8;
117016e56d1Schristos       raw_code += buffer[1];
118016e56d1Schristos 
119016e56d1Schristos       decodePTR = find_match (raw_code);
120016e56d1Schristos       if (decodePTR)
121016e56d1Schristos         {
122016e56d1Schristos           operMaskReg = decodePTR->operMasksRegisterBits;
123016e56d1Schristos           (*info->fprintf_func)(info->stream, "%s", decodePTR->opcodePTR->name);
124016e56d1Schristos 
125016e56d1Schristos           /* First we compare the shorthand format of the constraints. If we
126016e56d1Schristos 	      still are unable to pinpoint the operands
127016e56d1Schristos 	      we analyze the opcodes constraint string.  */
1287af5a897Schristos           if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_MON_R_C))
129016e56d1Schristos         	{
130016e56d1Schristos         	  (*info->fprintf_func)(info->stream, " R%x, CCR",
131016e56d1Schristos         		  (raw_code >> 8) & 0x7);
1327af5a897Schristos         	}
1337af5a897Schristos           else if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_MON_C_R))
1347af5a897Schristos             {
135016e56d1Schristos         	  (*info->fprintf_func)(info->stream, " CCR, R%x",
136016e56d1Schristos         	      (raw_code >> 8) & 0x7);
1377af5a897Schristos             }
1387af5a897Schristos           else if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_MON_R_P))
1397af5a897Schristos             {
140016e56d1Schristos         	  (*info->fprintf_func)(info->stream, " R%x, PC",
141016e56d1Schristos         	      (raw_code >> 8) & 0x7);
1427af5a897Schristos             }
1437af5a897Schristos           else if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_TRI))
144016e56d1Schristos             {
145016e56d1Schristos                   (*info->fprintf_func)(info->stream, " R%x, R%x, R%x",
146016e56d1Schristos                       (raw_code >> 8) & 0x7, (raw_code >> 5) & 0x7,
147016e56d1Schristos                       (raw_code >> 2) & 0x7);
148016e56d1Schristos             }
149016e56d1Schristos           else if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_IDR))
150016e56d1Schristos             {
151016e56d1Schristos                   if (raw_code & 0x01)
152016e56d1Schristos                     {
153016e56d1Schristos                       (*info->fprintf_func)(info->stream, " R%x, (R%x, R%x+)",
154016e56d1Schristos                           (raw_code >> 8) & 0x7, (raw_code >> 5) & 0x7,
155016e56d1Schristos                           (raw_code >> 2) & 0x7);
156016e56d1Schristos                     }
157016e56d1Schristos                    else if (raw_code & 0x02)
158016e56d1Schristos                           {
159016e56d1Schristos                             (*info->fprintf_func)(info->stream, " R%x, (R%x, -R%x)",
160016e56d1Schristos                                 (raw_code >> 8) & 0x7, (raw_code >> 5) & 0x7,
161016e56d1Schristos                                 (raw_code >> 2) & 0x7);
162016e56d1Schristos                           }
163016e56d1Schristos                    else
164016e56d1Schristos                      {
165016e56d1Schristos                        (*info->fprintf_func)(info->stream, " R%x, (R%x, R%x)",
166016e56d1Schristos                            (raw_code >> 8) & 0x7, (raw_code >> 5) & 0x7,
167016e56d1Schristos                            (raw_code >> 2) & 0x7);
168016e56d1Schristos                      }
169016e56d1Schristos             }
1707af5a897Schristos           else if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_DYA))
171016e56d1Schristos             {
172*1424dfb3Schristos         	  operandOne = ripBits (&operMaskReg, 3, decodePTR->opcodePTR, raw_code);
173*1424dfb3Schristos         	  operandTwo = ripBits (&operMaskReg, 3, decodePTR->opcodePTR, raw_code);
174016e56d1Schristos         	 ( *info->fprintf_func)(info->stream, " R%x, R%x", operandOne,
175016e56d1Schristos         	      operandTwo);
176016e56d1Schristos             }
1777af5a897Schristos           else if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_IDO5))
178016e56d1Schristos             {
179016e56d1Schristos         	  (*info->fprintf_func)(info->stream, " R%x, (R%x, #0x%x)",
180016e56d1Schristos         	      (raw_code >> 8) & 0x7, (raw_code >> 5) & 0x7, raw_code & 0x1f);
1817af5a897Schristos             }
1827af5a897Schristos           else if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_MON))
1837af5a897Schristos             {
184016e56d1Schristos         	  operandOne = ripBits (&operMaskReg, 3, decodePTR->opcodePTR,
185016e56d1Schristos         	     raw_code);
186016e56d1Schristos         	 (*info->fprintf_func)(info->stream, " R%x", operandOne);
1877af5a897Schristos             }
1887af5a897Schristos           else if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_REL9))
189016e56d1Schristos             {
190016e56d1Schristos               /* If address is negative handle it accordingly.  */
191016e56d1Schristos               if (raw_code & XGATE_NINE_SIGNBIT)
192016e56d1Schristos                 {
193016e56d1Schristos                   relAddr = XGATE_NINE_BITS >> 1; /* Clip sign bit.  */
194016e56d1Schristos                   relAddr = ~relAddr; /* Make signed.  */
195016e56d1Schristos                   relAddr |= (raw_code & 0xFF) + 1; /* Apply our value.  */
196*1424dfb3Schristos                   relAddr *= 2; /* Multiply by two as per processor docs.  */
197016e56d1Schristos                 }
198016e56d1Schristos               else
199016e56d1Schristos                 {
200016e56d1Schristos                   relAddr = raw_code & 0xff;
201*1424dfb3Schristos                   relAddr = relAddr * 2 + 2;
202016e56d1Schristos                 }
203016e56d1Schristos              (*info->fprintf_func)(info->stream, " *%d", relAddr);
204016e56d1Schristos              (*info->fprintf_func)(info->stream, "  Abs* 0x");
205016e56d1Schristos              (*info->print_address_func)(memaddr + relAddr, info);
206016e56d1Schristos            }
207016e56d1Schristos           else if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_REL10))
208016e56d1Schristos             {
209016e56d1Schristos               /* If address is negative handle it accordingly.  */
210016e56d1Schristos               if (raw_code & XGATE_TEN_SIGNBIT)
211016e56d1Schristos                 {
212016e56d1Schristos                   relAddr = XGATE_TEN_BITS >> 1; /* Clip sign bit.  */
213016e56d1Schristos                   relAddr = ~relAddr; /* Make signed.  */
214016e56d1Schristos                   relAddr |= (raw_code & 0x1FF) + 1; /* Apply our value.  */
215*1424dfb3Schristos                   relAddr *= 2; /* Multiply by two as per processor docs.  */
216016e56d1Schristos                 }
217016e56d1Schristos               else
218016e56d1Schristos                 {
219016e56d1Schristos                   relAddr = raw_code & 0x1FF;
220*1424dfb3Schristos                   relAddr = relAddr * 2 + 2;
221016e56d1Schristos                 }
222016e56d1Schristos               (*info->fprintf_func)(info->stream, " *%d", relAddr);
223016e56d1Schristos               (*info->fprintf_func)(info->stream, "  Abs* 0x");
224016e56d1Schristos               (*info->print_address_func)(memaddr + relAddr, info);
225016e56d1Schristos             }
2267af5a897Schristos           else if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_IMM4))
227016e56d1Schristos             {
228016e56d1Schristos               (*info->fprintf_func)(info->stream, " R%x, #0x%02x",
229016e56d1Schristos               (raw_code >> 8) & 0x7, (raw_code >> 4) & 0xF);
230016e56d1Schristos             }
231016e56d1Schristos           else if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_IMM8))
232016e56d1Schristos             {
233016e56d1Schristos               if (macro_search (decodePTR->opcodePTR->name, previousOpName) &&
234016e56d1Schristos                  previousOpName[0])
235016e56d1Schristos                {
236016e56d1Schristos                  absAddress = (0xFF & raw_code) << 8;
237016e56d1Schristos                  absAddress |= perviousBin & 0xFF;
238016e56d1Schristos                  (*info->fprintf_func)(info->stream, " R%x, #0x%02x Abs* 0x",
239016e56d1Schristos                      (raw_code >> 8) & 0x7, raw_code & 0xff);
240016e56d1Schristos                  (*info->print_address_func)(absAddress, info);
241016e56d1Schristos                  previousOpName[0] = 0;
242016e56d1Schristos                }
243016e56d1Schristos               else
244016e56d1Schristos                {
245016e56d1Schristos                  strcpy (previousOpName, decodePTR->opcodePTR->name);
246016e56d1Schristos                  (*info->fprintf_func)(info->stream, " R%x, #0x%02x",
247016e56d1Schristos                      (raw_code >> 8) & 0x7, raw_code & 0xff);
248016e56d1Schristos                }
249016e56d1Schristos             }
2507af5a897Schristos           else if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_IMM3))
251016e56d1Schristos             {
252016e56d1Schristos         	  (*info->fprintf_func)(info->stream, " #0x%x",
253016e56d1Schristos         	     (raw_code >> 8) & 0x7);
2547af5a897Schristos             }
2557af5a897Schristos           else if (!strcmp (decodePTR->opcodePTR->constraints, XGATE_OP_INH))
2567af5a897Schristos             {
2577af5a897Schristos             }
2587af5a897Schristos           else
2597af5a897Schristos             {
2607af5a897Schristos               (*info->fprintf_func)(info->stream, " unhandled mode %s",
261*1424dfb3Schristos 				    decodePTR->opcodePTR->constraints);
262016e56d1Schristos             }
263016e56d1Schristos           perviousBin = raw_code;
264016e56d1Schristos         }
265016e56d1Schristos       else
266016e56d1Schristos         {
267016e56d1Schristos           (*info->fprintf_func)(info->stream,
268016e56d1Schristos 				" unable to find opcode match #0%x", raw_code);
269016e56d1Schristos         }
270016e56d1Schristos     }
271016e56d1Schristos   return bytesRead;
272016e56d1Schristos }
273016e56d1Schristos 
274016e56d1Schristos int
print_insn_xgate(bfd_vma memaddr,struct disassemble_info * info)275016e56d1Schristos print_insn_xgate (bfd_vma memaddr, struct disassemble_info* info)
276016e56d1Schristos {
277016e56d1Schristos   return print_insn (memaddr, info);
278016e56d1Schristos }
279016e56d1Schristos 
280016e56d1Schristos static int
read_memory(bfd_vma memaddr,bfd_byte * buffer,int size,struct disassemble_info * info)281016e56d1Schristos read_memory (bfd_vma memaddr, bfd_byte* buffer, int size,
282016e56d1Schristos     struct disassemble_info* info)
283016e56d1Schristos {
284016e56d1Schristos   int status;
285016e56d1Schristos   status = (*info->read_memory_func) (memaddr, buffer, size, info);
286016e56d1Schristos   if (status != 0)
287016e56d1Schristos     {
288016e56d1Schristos       (*info->memory_error_func) (status, memaddr, info);
289016e56d1Schristos       return -1;
290016e56d1Schristos     }
291016e56d1Schristos   return 0;
292016e56d1Schristos }
293016e56d1Schristos 
294016e56d1Schristos static int
ripBits(unsigned int * operandBitsRemaining,int numBitsRequested,struct xgate_opcode * opcodePTR,unsigned int memory)295016e56d1Schristos ripBits (unsigned int *operandBitsRemaining,
296016e56d1Schristos 	 int numBitsRequested,
297016e56d1Schristos 	 struct xgate_opcode *opcodePTR,
298016e56d1Schristos 	 unsigned int memory)
299016e56d1Schristos {
300016e56d1Schristos   unsigned int currentBit;
301*1424dfb3Schristos   unsigned int operand = 0;
302016e56d1Schristos   int numBitsFound;
303016e56d1Schristos 
304*1424dfb3Schristos   for (numBitsFound = 0, currentBit = 1u << ((opcodePTR->size * 8) - 1);
305*1424dfb3Schristos        numBitsFound < numBitsRequested && currentBit != 0;
306*1424dfb3Schristos        currentBit >>= 1)
307016e56d1Schristos     {
308016e56d1Schristos       if (currentBit & *operandBitsRemaining)
309016e56d1Schristos 	{
310016e56d1Schristos 	  *operandBitsRemaining &= ~(currentBit); /* Consume the current bit.  */
311016e56d1Schristos 	  operand <<= 1; /* Make room for our next bit.  */
312016e56d1Schristos 	  numBitsFound++;
313016e56d1Schristos 	  operand |= (currentBit & memory) > 0;
314016e56d1Schristos 	}
315016e56d1Schristos     }
316016e56d1Schristos   return operand;
317016e56d1Schristos }
318016e56d1Schristos 
319016e56d1Schristos static int
macro_search(char * currentName,char * lastName)320016e56d1Schristos macro_search (char *currentName, char *lastName)
321016e56d1Schristos {
322016e56d1Schristos   int i;
323016e56d1Schristos   int length = 0;
324016e56d1Schristos   char *where;
325016e56d1Schristos 
326016e56d1Schristos   for (i = 0; i < xgate_num_opcodes; i++)
327016e56d1Schristos     {
328016e56d1Schristos       where = strstr (xgate_opcodes[i].constraints, lastName);
329016e56d1Schristos 
330016e56d1Schristos       if (where)
331016e56d1Schristos         {
332016e56d1Schristos           length = strlen (where);
333016e56d1Schristos         }
334016e56d1Schristos       if (length)
335016e56d1Schristos         {
336016e56d1Schristos           where = strstr (xgate_opcodes[i].constraints, currentName);
337016e56d1Schristos           if (where)
338016e56d1Schristos             {
339016e56d1Schristos               length = strlen (where);
340016e56d1Schristos               return 1;
341016e56d1Schristos             }
342016e56d1Schristos         }
343016e56d1Schristos     }
344016e56d1Schristos   return 0;
345016e56d1Schristos }
346016e56d1Schristos 
347016e56d1Schristos static struct decodeInfo *
find_match(unsigned int raw_code)348016e56d1Schristos find_match (unsigned int raw_code)
349016e56d1Schristos {
350016e56d1Schristos   struct decodeInfo *decodeTablePTR = 0;
351016e56d1Schristos   int i;
352016e56d1Schristos 
353016e56d1Schristos   for (i = 0, decodeTablePTR = decodeTable; i < xgate_num_opcodes;
354016e56d1Schristos       i++, decodeTablePTR++)
355016e56d1Schristos     {
356016e56d1Schristos       if ((raw_code & decodeTablePTR->operMask)
357016e56d1Schristos           == decodeTablePTR->opcodePTR->bin_opcode)
358016e56d1Schristos         {
359016e56d1Schristos           /* Make sure we didn't run into a macro or alias.  */
360016e56d1Schristos           if (decodeTablePTR->opcodePTR->cycles_min != 0)
361016e56d1Schristos             {
362016e56d1Schristos               return decodeTablePTR;
363016e56d1Schristos               break;
364016e56d1Schristos             }
365016e56d1Schristos           else
366016e56d1Schristos 	    continue;
367016e56d1Schristos         }
368016e56d1Schristos     }
369016e56d1Schristos   return 0;
370016e56d1Schristos }
371