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