xref: /netbsd-src/external/gpl3/binutils.old/dist/opcodes/m10200-dis.c (revision e992f068c547fd6e84b3f104dc2340adcc955732)
175fd0b74Schristos /* Disassemble MN10200 instructions.
2*e992f068Schristos    Copyright (C) 1996-2022 Free Software Foundation, Inc.
375fd0b74Schristos 
475fd0b74Schristos    This file is part of the GNU opcodes library.
575fd0b74Schristos 
675fd0b74Schristos    This library is free software; you can redistribute it and/or modify
775fd0b74Schristos    it under the terms of the GNU General Public License as published by
875fd0b74Schristos    the Free Software Foundation; either version 3, or (at your option)
975fd0b74Schristos    any later version.
1075fd0b74Schristos 
1175fd0b74Schristos    It is distributed in the hope that it will be useful, but WITHOUT
1275fd0b74Schristos    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
1375fd0b74Schristos    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
1475fd0b74Schristos    License for more details.
1575fd0b74Schristos 
1675fd0b74Schristos    You should have received a copy of the GNU General Public License
1775fd0b74Schristos    along with this program; if not, write to the Free Software
1875fd0b74Schristos    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
1975fd0b74Schristos    MA 02110-1301, USA.  */
2075fd0b74Schristos 
2175fd0b74Schristos #include "sysdep.h"
2275fd0b74Schristos #include <stdio.h>
2375fd0b74Schristos #include "opcode/mn10200.h"
24ede78133Schristos #include "disassemble.h"
2575fd0b74Schristos #include "opintl.h"
2675fd0b74Schristos 
2775fd0b74Schristos static void
disassemble(bfd_vma memaddr,struct disassemble_info * info,unsigned long insn,unsigned long extension,unsigned int size)2875fd0b74Schristos disassemble (bfd_vma memaddr,
2975fd0b74Schristos 	     struct disassemble_info *info,
3075fd0b74Schristos 	     unsigned long insn,
3175fd0b74Schristos 	     unsigned long extension,
3275fd0b74Schristos 	     unsigned int size)
3375fd0b74Schristos {
3475fd0b74Schristos   struct mn10200_opcode *op = (struct mn10200_opcode *)mn10200_opcodes;
3575fd0b74Schristos   const struct mn10200_operand *operand;
3675fd0b74Schristos   int match = 0;
3775fd0b74Schristos 
3875fd0b74Schristos   /* Find the opcode.  */
3975fd0b74Schristos   while (op->name)
4075fd0b74Schristos     {
4175fd0b74Schristos       int mysize, extra_shift;
4275fd0b74Schristos 
4375fd0b74Schristos       if (op->format == FMT_1)
4475fd0b74Schristos 	mysize = 1;
4575fd0b74Schristos       else if (op->format == FMT_2
4675fd0b74Schristos 	       || op->format == FMT_4)
4775fd0b74Schristos 	mysize = 2;
4875fd0b74Schristos       else if (op->format == FMT_3
4975fd0b74Schristos 	       || op->format == FMT_5)
5075fd0b74Schristos 	mysize = 3;
5175fd0b74Schristos       else if (op->format == FMT_6)
5275fd0b74Schristos 	mysize = 4;
5375fd0b74Schristos       else if (op->format == FMT_7)
5475fd0b74Schristos 	mysize = 5;
5575fd0b74Schristos       else
5675fd0b74Schristos 	abort ();
5775fd0b74Schristos 
5875fd0b74Schristos       if (op->format == FMT_2 || op->format == FMT_5)
5975fd0b74Schristos 	extra_shift = 8;
6075fd0b74Schristos       else if (op->format == FMT_3
6175fd0b74Schristos 	       || op->format == FMT_6
6275fd0b74Schristos 	       || op->format == FMT_7)
6375fd0b74Schristos 	extra_shift = 16;
6475fd0b74Schristos       else
6575fd0b74Schristos 	extra_shift = 0;
6675fd0b74Schristos 
6775fd0b74Schristos       if ((op->mask & insn) == op->opcode
6875fd0b74Schristos 	  && size == (unsigned int) mysize)
6975fd0b74Schristos 	{
7075fd0b74Schristos 	  const unsigned char *opindex_ptr;
7175fd0b74Schristos 	  unsigned int nocomma;
7275fd0b74Schristos 	  int paren = 0;
7375fd0b74Schristos 
7475fd0b74Schristos 	  match = 1;
7575fd0b74Schristos 	  (*info->fprintf_func) (info->stream, "%s\t", op->name);
7675fd0b74Schristos 
7775fd0b74Schristos 	  /* Now print the operands.  */
7875fd0b74Schristos 	  for (opindex_ptr = op->operands, nocomma = 1;
7975fd0b74Schristos 	       *opindex_ptr != 0;
8075fd0b74Schristos 	       opindex_ptr++)
8175fd0b74Schristos 	    {
8275fd0b74Schristos 	      unsigned long value;
8375fd0b74Schristos 
8475fd0b74Schristos 	      operand = &mn10200_operands[*opindex_ptr];
8575fd0b74Schristos 
86012573ebSchristos 	      if ((operand->flags & MN10200_OPERAND_DREG) != 0
87012573ebSchristos 		  || (operand->flags & MN10200_OPERAND_AREG) != 0)
88012573ebSchristos 		value = ((insn >> (operand->shift + extra_shift))
89012573ebSchristos 			 & ((1 << operand->bits) - 1));
90012573ebSchristos 	      else if ((operand->flags & MN10200_OPERAND_EXTENDED) != 0)
9175fd0b74Schristos 		{
9275fd0b74Schristos 		  value = (insn & 0xffff) << 8;
9375fd0b74Schristos 		  value |= extension;
9475fd0b74Schristos 		}
9575fd0b74Schristos 	      else
9675fd0b74Schristos 		value = ((insn >> (operand->shift))
9775fd0b74Schristos 			 & ((1L << operand->bits) - 1L));
9875fd0b74Schristos 
9975fd0b74Schristos 	      if ((operand->flags & MN10200_OPERAND_SIGNED) != 0)
10075fd0b74Schristos 		value = ((long)(value << (32 - operand->bits))
10175fd0b74Schristos 			  >> (32 - operand->bits));
10275fd0b74Schristos 
10375fd0b74Schristos 	      if (!nocomma
10475fd0b74Schristos 		  && (!paren
10575fd0b74Schristos 		      || ((operand->flags & MN10200_OPERAND_PAREN) == 0)))
10675fd0b74Schristos 		(*info->fprintf_func) (info->stream, ",");
10775fd0b74Schristos 
10875fd0b74Schristos 	      nocomma = 0;
10975fd0b74Schristos 
11075fd0b74Schristos 	      if ((operand->flags & MN10200_OPERAND_DREG) != 0)
11175fd0b74Schristos 		(*info->fprintf_func) (info->stream, "d%ld", value);
11275fd0b74Schristos 
11375fd0b74Schristos 	      else if ((operand->flags & MN10200_OPERAND_AREG) != 0)
11475fd0b74Schristos 		(*info->fprintf_func) (info->stream, "a%ld", value);
11575fd0b74Schristos 
11675fd0b74Schristos 	      else if ((operand->flags & MN10200_OPERAND_PSW) != 0)
11775fd0b74Schristos 		(*info->fprintf_func) (info->stream, "psw");
11875fd0b74Schristos 
11975fd0b74Schristos 	      else if ((operand->flags & MN10200_OPERAND_MDR) != 0)
12075fd0b74Schristos 		(*info->fprintf_func) (info->stream, "mdr");
12175fd0b74Schristos 
12275fd0b74Schristos 	      else if ((operand->flags & MN10200_OPERAND_PAREN) != 0)
12375fd0b74Schristos 		{
12475fd0b74Schristos 		  if (paren)
12575fd0b74Schristos 		    (*info->fprintf_func) (info->stream, ")");
12675fd0b74Schristos 		  else
12775fd0b74Schristos 		    {
12875fd0b74Schristos 		      (*info->fprintf_func) (info->stream, "(");
12975fd0b74Schristos 		      nocomma = 1;
13075fd0b74Schristos 		    }
13175fd0b74Schristos 		  paren = !paren;
13275fd0b74Schristos 		}
13375fd0b74Schristos 
13475fd0b74Schristos 	      else if ((operand->flags & MN10200_OPERAND_PCREL) != 0)
13575fd0b74Schristos 		(*info->print_address_func)
13675fd0b74Schristos 		  ((value + memaddr + mysize) & 0xffffff, info);
13775fd0b74Schristos 
13875fd0b74Schristos 	      else if ((operand->flags & MN10200_OPERAND_MEMADDR) != 0)
13975fd0b74Schristos 		(*info->print_address_func) (value, info);
14075fd0b74Schristos 
14175fd0b74Schristos 	      else
14275fd0b74Schristos 		(*info->fprintf_func) (info->stream, "%ld", value);
14375fd0b74Schristos 	    }
14475fd0b74Schristos 	  /* All done. */
14575fd0b74Schristos 	  break;
14675fd0b74Schristos 	}
14775fd0b74Schristos       op++;
14875fd0b74Schristos     }
14975fd0b74Schristos 
15075fd0b74Schristos   if (!match)
15175fd0b74Schristos     (*info->fprintf_func) (info->stream, _("unknown\t0x%04lx"), insn);
15275fd0b74Schristos }
15375fd0b74Schristos 
15475fd0b74Schristos int
print_insn_mn10200(bfd_vma memaddr,struct disassemble_info * info)15575fd0b74Schristos print_insn_mn10200 (bfd_vma memaddr, struct disassemble_info *info)
15675fd0b74Schristos {
15775fd0b74Schristos   int status;
15875fd0b74Schristos   bfd_byte buffer[4];
15975fd0b74Schristos   unsigned long insn;
16075fd0b74Schristos   unsigned long extension = 0;
16175fd0b74Schristos   unsigned int consume;
16275fd0b74Schristos 
16375fd0b74Schristos   /* First figure out how big the opcode is.  */
16475fd0b74Schristos   status = (*info->read_memory_func) (memaddr, buffer, 1, info);
16575fd0b74Schristos   if (status != 0)
16675fd0b74Schristos     {
16775fd0b74Schristos       (*info->memory_error_func) (status, memaddr, info);
16875fd0b74Schristos       return -1;
16975fd0b74Schristos     }
17075fd0b74Schristos 
17175fd0b74Schristos   insn = *(unsigned char *) buffer;
17275fd0b74Schristos 
17375fd0b74Schristos   /* These are one byte insns.  */
17475fd0b74Schristos   if ((insn & 0xf0) == 0x00
17575fd0b74Schristos       || (insn & 0xf0) == 0x10
17675fd0b74Schristos       || (insn & 0xf0) == 0x20
17775fd0b74Schristos       || (insn & 0xf0) == 0x30
17875fd0b74Schristos       || ((insn & 0xf0) == 0x80
17975fd0b74Schristos 	  && (insn & 0x0c) >> 2 != (insn & 0x03))
18075fd0b74Schristos       || (insn & 0xf0) == 0x90
18175fd0b74Schristos       || (insn & 0xf0) == 0xa0
18275fd0b74Schristos       || (insn & 0xf0) == 0xb0
18375fd0b74Schristos       || (insn & 0xff) == 0xeb
18475fd0b74Schristos       || (insn & 0xff) == 0xf6
18575fd0b74Schristos       || (insn & 0xff) == 0xfe
18675fd0b74Schristos       || (insn & 0xff) == 0xff)
18775fd0b74Schristos     {
18875fd0b74Schristos       extension = 0;
18975fd0b74Schristos       consume = 1;
19075fd0b74Schristos     }
19175fd0b74Schristos 
19275fd0b74Schristos   /* These are two byte insns.  */
19375fd0b74Schristos   else if ((insn & 0xf0) == 0x40
19475fd0b74Schristos 	   || (insn & 0xf0) == 0x50
19575fd0b74Schristos 	   || (insn & 0xf0) == 0x60
19675fd0b74Schristos 	   || (insn & 0xf0) == 0x70
19775fd0b74Schristos 	   || (insn & 0xf0) == 0x80
19875fd0b74Schristos 	   || (insn & 0xfc) == 0xd0
19975fd0b74Schristos 	   || (insn & 0xfc) == 0xd4
20075fd0b74Schristos 	   || (insn & 0xfc) == 0xd8
20175fd0b74Schristos 	   || (insn & 0xfc) == 0xe0
20275fd0b74Schristos 	   || (insn & 0xfc) == 0xe4
20375fd0b74Schristos 	   || (insn & 0xff) == 0xe8
20475fd0b74Schristos 	   || (insn & 0xff) == 0xe9
20575fd0b74Schristos 	   || (insn & 0xff) == 0xea
20675fd0b74Schristos 	   || (insn & 0xff) == 0xf0
20775fd0b74Schristos 	   || (insn & 0xff) == 0xf1
20875fd0b74Schristos 	   || (insn & 0xff) == 0xf2
20975fd0b74Schristos 	   || (insn & 0xff) == 0xf3)
21075fd0b74Schristos     {
21175fd0b74Schristos       status = (*info->read_memory_func) (memaddr, buffer, 2, info);
21275fd0b74Schristos       if (status != 0)
21375fd0b74Schristos 	{
21475fd0b74Schristos 	  (*info->memory_error_func) (status, memaddr, info);
21575fd0b74Schristos 	   return -1;
21675fd0b74Schristos 	}
21775fd0b74Schristos       insn = bfd_getb16 (buffer);
21875fd0b74Schristos       consume = 2;
21975fd0b74Schristos     }
22075fd0b74Schristos 
22175fd0b74Schristos   /* These are three byte insns with a 16bit operand in little
22275fd0b74Schristos      endian form.  */
22375fd0b74Schristos   else if ((insn & 0xf0) == 0xc0
22475fd0b74Schristos 	   || (insn & 0xfc) == 0xdc
22575fd0b74Schristos 	   || (insn & 0xfc) == 0xec
22675fd0b74Schristos 	   || (insn & 0xff) == 0xf8
22775fd0b74Schristos 	   || (insn & 0xff) == 0xf9
22875fd0b74Schristos 	   || (insn & 0xff) == 0xfa
22975fd0b74Schristos 	   || (insn & 0xff) == 0xfb
23075fd0b74Schristos 	   || (insn & 0xff) == 0xfc
23175fd0b74Schristos 	   || (insn & 0xff) == 0xfd)
23275fd0b74Schristos     {
23375fd0b74Schristos       status = (*info->read_memory_func) (memaddr + 1, buffer, 2, info);
23475fd0b74Schristos       if (status != 0)
23575fd0b74Schristos 	{
23675fd0b74Schristos 	  (*info->memory_error_func) (status, memaddr, info);
23775fd0b74Schristos 	  return -1;
23875fd0b74Schristos 	}
23975fd0b74Schristos       insn <<= 16;
24075fd0b74Schristos       insn |= bfd_getl16 (buffer);
24175fd0b74Schristos       extension = 0;
24275fd0b74Schristos       consume = 3;
24375fd0b74Schristos     }
24475fd0b74Schristos   /* These are three byte insns too, but we don't have to mess with
24575fd0b74Schristos      endianness stuff.  */
24675fd0b74Schristos   else if ((insn & 0xff) == 0xf5)
24775fd0b74Schristos     {
24875fd0b74Schristos       status = (*info->read_memory_func) (memaddr + 1, buffer, 2, info);
24975fd0b74Schristos       if (status != 0)
25075fd0b74Schristos 	{
25175fd0b74Schristos 	  (*info->memory_error_func) (status, memaddr, info);
25275fd0b74Schristos 	  return -1;
25375fd0b74Schristos 	}
25475fd0b74Schristos       insn <<= 16;
25575fd0b74Schristos       insn |= bfd_getb16 (buffer);
25675fd0b74Schristos       extension = 0;
25775fd0b74Schristos       consume = 3;
25875fd0b74Schristos     }
25975fd0b74Schristos 
26075fd0b74Schristos   /* These are four byte insns.  */
26175fd0b74Schristos   else if ((insn & 0xff) == 0xf7)
26275fd0b74Schristos     {
26375fd0b74Schristos       status = (*info->read_memory_func) (memaddr, buffer, 2, info);
26475fd0b74Schristos       if (status != 0)
26575fd0b74Schristos 	{
26675fd0b74Schristos 	  (*info->memory_error_func) (status, memaddr, info);
26775fd0b74Schristos 	  return -1;
26875fd0b74Schristos 	}
26975fd0b74Schristos       insn = bfd_getb16 (buffer);
27075fd0b74Schristos       insn <<= 16;
27175fd0b74Schristos       status = (*info->read_memory_func) (memaddr + 2, buffer, 2, info);
27275fd0b74Schristos       if (status != 0)
27375fd0b74Schristos 	{
27475fd0b74Schristos 	  (*info->memory_error_func) (status, memaddr, info);
27575fd0b74Schristos 	  return -1;
27675fd0b74Schristos 	}
27775fd0b74Schristos       insn |= bfd_getl16 (buffer);
27875fd0b74Schristos       extension = 0;
27975fd0b74Schristos       consume = 4;
28075fd0b74Schristos     }
28175fd0b74Schristos 
28275fd0b74Schristos   /* These are five byte insns.  */
28375fd0b74Schristos   else if ((insn & 0xff) == 0xf4)
28475fd0b74Schristos     {
28575fd0b74Schristos       status = (*info->read_memory_func) (memaddr, buffer, 2, info);
28675fd0b74Schristos       if (status != 0)
28775fd0b74Schristos 	{
28875fd0b74Schristos 	  (*info->memory_error_func) (status, memaddr, info);
28975fd0b74Schristos 	  return -1;
29075fd0b74Schristos 	}
29175fd0b74Schristos       insn = bfd_getb16 (buffer);
29275fd0b74Schristos       insn <<= 16;
29375fd0b74Schristos 
29475fd0b74Schristos       status = (*info->read_memory_func) (memaddr + 4, buffer, 1, info);
29575fd0b74Schristos       if (status != 0)
29675fd0b74Schristos 	{
29775fd0b74Schristos 	  (*info->memory_error_func) (status, memaddr, info);
29875fd0b74Schristos 	  return -1;
29975fd0b74Schristos 	}
30075fd0b74Schristos       insn |= (*(unsigned char *)buffer << 8) & 0xff00;
30175fd0b74Schristos 
30275fd0b74Schristos       status = (*info->read_memory_func) (memaddr + 3, buffer, 1, info);
30375fd0b74Schristos       if (status != 0)
30475fd0b74Schristos 	{
30575fd0b74Schristos 	  (*info->memory_error_func) (status, memaddr, info);
30675fd0b74Schristos 	  return -1;
30775fd0b74Schristos 	}
30875fd0b74Schristos       insn |= (*(unsigned char *)buffer) & 0xff;
30975fd0b74Schristos 
31075fd0b74Schristos       status = (*info->read_memory_func) (memaddr + 2, buffer, 1, info);
31175fd0b74Schristos       if (status != 0)
31275fd0b74Schristos 	{
31375fd0b74Schristos 	  (*info->memory_error_func) (status, memaddr, info);
31475fd0b74Schristos 	  return -1;
31575fd0b74Schristos 	}
31675fd0b74Schristos       extension = (*(unsigned char *)buffer) & 0xff;
31775fd0b74Schristos       consume = 5;
31875fd0b74Schristos     }
31975fd0b74Schristos   else
32075fd0b74Schristos     {
32175fd0b74Schristos       (*info->fprintf_func) (info->stream, _("unknown\t0x%02lx"), insn);
32275fd0b74Schristos       return 1;
32375fd0b74Schristos     }
32475fd0b74Schristos 
32575fd0b74Schristos   disassemble (memaddr, info, insn, extension, consume);
32675fd0b74Schristos 
32775fd0b74Schristos   return consume;
32875fd0b74Schristos }
329