xref: /netbsd-src/external/gpl3/binutils/dist/opcodes/m10200-dis.c (revision cb63e24e8d6aae7ddac1859a9015f48b1d8bd90e)
1 /* Disassemble MN10200 instructions.
2    Copyright (C) 1996-2024 Free Software Foundation, Inc.
3 
4    This file is part of the GNU opcodes library.
5 
6    This library is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3, or (at your option)
9    any later version.
10 
11    It is distributed in the hope that it will be useful, but WITHOUT
12    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
14    License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19    MA 02110-1301, USA.  */
20 
21 #include "sysdep.h"
22 #include <stdio.h>
23 #include "opcode/mn10200.h"
24 #include "disassemble.h"
25 #include "opintl.h"
26 
27 static void
disassemble(bfd_vma memaddr,struct disassemble_info * info,unsigned long insn,unsigned long extension,unsigned int size)28 disassemble (bfd_vma memaddr,
29 	     struct disassemble_info *info,
30 	     unsigned long insn,
31 	     unsigned long extension,
32 	     unsigned int size)
33 {
34   struct mn10200_opcode *op = (struct mn10200_opcode *)mn10200_opcodes;
35   const struct mn10200_operand *operand;
36   int match = 0;
37 
38   /* Find the opcode.  */
39   while (op->name)
40     {
41       int mysize, extra_shift;
42 
43       if (op->format == FMT_1)
44 	mysize = 1;
45       else if (op->format == FMT_2
46 	       || op->format == FMT_4)
47 	mysize = 2;
48       else if (op->format == FMT_3
49 	       || op->format == FMT_5)
50 	mysize = 3;
51       else if (op->format == FMT_6)
52 	mysize = 4;
53       else if (op->format == FMT_7)
54 	mysize = 5;
55       else
56 	abort ();
57 
58       if (op->format == FMT_2 || op->format == FMT_5)
59 	extra_shift = 8;
60       else if (op->format == FMT_3
61 	       || op->format == FMT_6
62 	       || op->format == FMT_7)
63 	extra_shift = 16;
64       else
65 	extra_shift = 0;
66 
67       if ((op->mask & insn) == op->opcode
68 	  && size == (unsigned int) mysize)
69 	{
70 	  const unsigned char *opindex_ptr;
71 	  unsigned int nocomma;
72 	  int paren = 0;
73 
74 	  match = 1;
75 	  (*info->fprintf_func) (info->stream, "%s\t", op->name);
76 
77 	  /* Now print the operands.  */
78 	  for (opindex_ptr = op->operands, nocomma = 1;
79 	       *opindex_ptr != 0;
80 	       opindex_ptr++)
81 	    {
82 	      unsigned long value;
83 
84 	      operand = &mn10200_operands[*opindex_ptr];
85 
86 	      if ((operand->flags & MN10200_OPERAND_DREG) != 0
87 		  || (operand->flags & MN10200_OPERAND_AREG) != 0)
88 		value = ((insn >> (operand->shift + extra_shift))
89 			 & ((1 << operand->bits) - 1));
90 	      else if ((operand->flags & MN10200_OPERAND_EXTENDED) != 0)
91 		{
92 		  value = (insn & 0xffff) << 8;
93 		  value |= extension;
94 		}
95 	      else
96 		value = ((insn >> (operand->shift))
97 			 & ((1L << operand->bits) - 1L));
98 
99 	      if ((operand->flags & MN10200_OPERAND_SIGNED) != 0)
100 		value = ((long)(value << (32 - operand->bits))
101 			  >> (32 - operand->bits));
102 
103 	      if (!nocomma
104 		  && (!paren
105 		      || ((operand->flags & MN10200_OPERAND_PAREN) == 0)))
106 		(*info->fprintf_func) (info->stream, ",");
107 
108 	      nocomma = 0;
109 
110 	      if ((operand->flags & MN10200_OPERAND_DREG) != 0)
111 		(*info->fprintf_func) (info->stream, "d%ld", value);
112 
113 	      else if ((operand->flags & MN10200_OPERAND_AREG) != 0)
114 		(*info->fprintf_func) (info->stream, "a%ld", value);
115 
116 	      else if ((operand->flags & MN10200_OPERAND_PSW) != 0)
117 		(*info->fprintf_func) (info->stream, "psw");
118 
119 	      else if ((operand->flags & MN10200_OPERAND_MDR) != 0)
120 		(*info->fprintf_func) (info->stream, "mdr");
121 
122 	      else if ((operand->flags & MN10200_OPERAND_PAREN) != 0)
123 		{
124 		  if (paren)
125 		    (*info->fprintf_func) (info->stream, ")");
126 		  else
127 		    {
128 		      (*info->fprintf_func) (info->stream, "(");
129 		      nocomma = 1;
130 		    }
131 		  paren = !paren;
132 		}
133 
134 	      else if ((operand->flags & MN10200_OPERAND_PCREL) != 0)
135 		(*info->print_address_func)
136 		  ((value + memaddr + mysize) & 0xffffff, info);
137 
138 	      else if ((operand->flags & MN10200_OPERAND_MEMADDR) != 0)
139 		(*info->print_address_func) (value, info);
140 
141 	      else
142 		(*info->fprintf_func) (info->stream, "%ld", value);
143 	    }
144 	  /* All done. */
145 	  break;
146 	}
147       op++;
148     }
149 
150   if (!match)
151     (*info->fprintf_func) (info->stream, _("unknown\t0x%04lx"), insn);
152 }
153 
154 int
print_insn_mn10200(bfd_vma memaddr,struct disassemble_info * info)155 print_insn_mn10200 (bfd_vma memaddr, struct disassemble_info *info)
156 {
157   int status;
158   bfd_byte buffer[4];
159   unsigned long insn;
160   unsigned long extension = 0;
161   unsigned int consume;
162 
163   /* First figure out how big the opcode is.  */
164   status = (*info->read_memory_func) (memaddr, buffer, 1, info);
165   if (status != 0)
166     {
167       (*info->memory_error_func) (status, memaddr, info);
168       return -1;
169     }
170 
171   insn = *(unsigned char *) buffer;
172 
173   /* These are one byte insns.  */
174   if ((insn & 0xf0) == 0x00
175       || (insn & 0xf0) == 0x10
176       || (insn & 0xf0) == 0x20
177       || (insn & 0xf0) == 0x30
178       || ((insn & 0xf0) == 0x80
179 	  && (insn & 0x0c) >> 2 != (insn & 0x03))
180       || (insn & 0xf0) == 0x90
181       || (insn & 0xf0) == 0xa0
182       || (insn & 0xf0) == 0xb0
183       || (insn & 0xff) == 0xeb
184       || (insn & 0xff) == 0xf6
185       || (insn & 0xff) == 0xfe
186       || (insn & 0xff) == 0xff)
187     {
188       extension = 0;
189       consume = 1;
190     }
191 
192   /* These are two byte insns.  */
193   else if ((insn & 0xf0) == 0x40
194 	   || (insn & 0xf0) == 0x50
195 	   || (insn & 0xf0) == 0x60
196 	   || (insn & 0xf0) == 0x70
197 	   || (insn & 0xf0) == 0x80
198 	   || (insn & 0xfc) == 0xd0
199 	   || (insn & 0xfc) == 0xd4
200 	   || (insn & 0xfc) == 0xd8
201 	   || (insn & 0xfc) == 0xe0
202 	   || (insn & 0xfc) == 0xe4
203 	   || (insn & 0xff) == 0xe8
204 	   || (insn & 0xff) == 0xe9
205 	   || (insn & 0xff) == 0xea
206 	   || (insn & 0xff) == 0xf0
207 	   || (insn & 0xff) == 0xf1
208 	   || (insn & 0xff) == 0xf2
209 	   || (insn & 0xff) == 0xf3)
210     {
211       status = (*info->read_memory_func) (memaddr, buffer, 2, info);
212       if (status != 0)
213 	{
214 	  (*info->memory_error_func) (status, memaddr, info);
215 	   return -1;
216 	}
217       insn = bfd_getb16 (buffer);
218       consume = 2;
219     }
220 
221   /* These are three byte insns with a 16bit operand in little
222      endian form.  */
223   else if ((insn & 0xf0) == 0xc0
224 	   || (insn & 0xfc) == 0xdc
225 	   || (insn & 0xfc) == 0xec
226 	   || (insn & 0xff) == 0xf8
227 	   || (insn & 0xff) == 0xf9
228 	   || (insn & 0xff) == 0xfa
229 	   || (insn & 0xff) == 0xfb
230 	   || (insn & 0xff) == 0xfc
231 	   || (insn & 0xff) == 0xfd)
232     {
233       status = (*info->read_memory_func) (memaddr + 1, buffer, 2, info);
234       if (status != 0)
235 	{
236 	  (*info->memory_error_func) (status, memaddr, info);
237 	  return -1;
238 	}
239       insn <<= 16;
240       insn |= bfd_getl16 (buffer);
241       extension = 0;
242       consume = 3;
243     }
244   /* These are three byte insns too, but we don't have to mess with
245      endianness stuff.  */
246   else if ((insn & 0xff) == 0xf5)
247     {
248       status = (*info->read_memory_func) (memaddr + 1, buffer, 2, info);
249       if (status != 0)
250 	{
251 	  (*info->memory_error_func) (status, memaddr, info);
252 	  return -1;
253 	}
254       insn <<= 16;
255       insn |= bfd_getb16 (buffer);
256       extension = 0;
257       consume = 3;
258     }
259 
260   /* These are four byte insns.  */
261   else if ((insn & 0xff) == 0xf7)
262     {
263       status = (*info->read_memory_func) (memaddr, buffer, 2, info);
264       if (status != 0)
265 	{
266 	  (*info->memory_error_func) (status, memaddr, info);
267 	  return -1;
268 	}
269       insn = bfd_getb16 (buffer);
270       insn <<= 16;
271       status = (*info->read_memory_func) (memaddr + 2, buffer, 2, info);
272       if (status != 0)
273 	{
274 	  (*info->memory_error_func) (status, memaddr, info);
275 	  return -1;
276 	}
277       insn |= bfd_getl16 (buffer);
278       extension = 0;
279       consume = 4;
280     }
281 
282   /* These are five byte insns.  */
283   else if ((insn & 0xff) == 0xf4)
284     {
285       status = (*info->read_memory_func) (memaddr, buffer, 2, info);
286       if (status != 0)
287 	{
288 	  (*info->memory_error_func) (status, memaddr, info);
289 	  return -1;
290 	}
291       insn = bfd_getb16 (buffer);
292       insn <<= 16;
293 
294       status = (*info->read_memory_func) (memaddr + 4, buffer, 1, info);
295       if (status != 0)
296 	{
297 	  (*info->memory_error_func) (status, memaddr, info);
298 	  return -1;
299 	}
300       insn |= (*(unsigned char *)buffer << 8) & 0xff00;
301 
302       status = (*info->read_memory_func) (memaddr + 3, buffer, 1, info);
303       if (status != 0)
304 	{
305 	  (*info->memory_error_func) (status, memaddr, info);
306 	  return -1;
307 	}
308       insn |= (*(unsigned char *)buffer) & 0xff;
309 
310       status = (*info->read_memory_func) (memaddr + 2, buffer, 1, info);
311       if (status != 0)
312 	{
313 	  (*info->memory_error_func) (status, memaddr, info);
314 	  return -1;
315 	}
316       extension = (*(unsigned char *)buffer) & 0xff;
317       consume = 5;
318     }
319   else
320     {
321       (*info->fprintf_func) (info->stream, _("unknown\t0x%02lx"), insn);
322       return 1;
323     }
324 
325   disassemble (memaddr, info, insn, extension, consume);
326 
327   return consume;
328 }
329