xref: /openbsd-src/gnu/usr.bin/binutils/opcodes/m68hc11-dis.c (revision cf2f2c5620d6d9a4fd01930983c4b9a1f76d7aa3)
15f210c2aSfgsch /* m68hc11-dis.c -- Motorola 68HC11 & 68HC12 disassembly
2*cf2f2c56Smiod    Copyright 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
3d2201f2fSdrahn    Written by Stephane Carrez (stcarrez@nerim.fr)
45f210c2aSfgsch 
55f210c2aSfgsch This program is free software; you can redistribute it and/or modify
65f210c2aSfgsch it under the terms of the GNU General Public License as published by
75f210c2aSfgsch the Free Software Foundation; either version 2 of the License, or
85f210c2aSfgsch (at your option) any later version.
95f210c2aSfgsch 
105f210c2aSfgsch This program is distributed in the hope that it will be useful,
115f210c2aSfgsch but WITHOUT ANY WARRANTY; without even the implied warranty of
125f210c2aSfgsch MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
135f210c2aSfgsch GNU General Public License for more details.
145f210c2aSfgsch 
155f210c2aSfgsch You should have received a copy of the GNU General Public License
165f210c2aSfgsch along with this program; if not, write to the Free Software
175f210c2aSfgsch Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
185f210c2aSfgsch 
195f210c2aSfgsch #include <stdio.h>
205f210c2aSfgsch 
215f210c2aSfgsch #include "ansidecl.h"
225f210c2aSfgsch #include "opcode/m68hc11.h"
235f210c2aSfgsch #include "dis-asm.h"
245f210c2aSfgsch 
25d2201f2fSdrahn #define PC_REGNUM 3
26d2201f2fSdrahn 
275f210c2aSfgsch static const char *const reg_name[] = {
285f210c2aSfgsch   "X", "Y", "SP", "PC"
295f210c2aSfgsch };
305f210c2aSfgsch 
315f210c2aSfgsch static const char *const reg_src_table[] = {
325f210c2aSfgsch   "A", "B", "CCR", "TMP3", "D", "X", "Y", "SP"
335f210c2aSfgsch };
345f210c2aSfgsch 
355f210c2aSfgsch static const char *const reg_dst_table[] = {
365f210c2aSfgsch   "A", "B", "CCR", "TMP2", "D", "X", "Y", "SP"
375f210c2aSfgsch };
385f210c2aSfgsch 
395f210c2aSfgsch #define OP_PAGE_MASK (M6811_OP_PAGE2|M6811_OP_PAGE3|M6811_OP_PAGE4)
405f210c2aSfgsch 
41d2201f2fSdrahn /* Prototypes for local functions.  */
42*cf2f2c56Smiod static int read_memory (bfd_vma, bfd_byte *, int, struct disassemble_info *);
43*cf2f2c56Smiod static int print_indexed_operand (bfd_vma, struct disassemble_info *,
44*cf2f2c56Smiod                                   int*, int, int, bfd_vma);
45*cf2f2c56Smiod static int print_insn (bfd_vma, struct disassemble_info *, int);
46d2201f2fSdrahn 
475f210c2aSfgsch static int
read_memory(bfd_vma memaddr,bfd_byte * buffer,int size,struct disassemble_info * info)48*cf2f2c56Smiod read_memory (bfd_vma memaddr, bfd_byte* buffer, int size,
49*cf2f2c56Smiod              struct disassemble_info* info)
505f210c2aSfgsch {
515f210c2aSfgsch   int status;
525f210c2aSfgsch 
535f210c2aSfgsch   /* Get first byte.  Only one at a time because we don't know the
545f210c2aSfgsch      size of the insn.  */
555f210c2aSfgsch   status = (*info->read_memory_func) (memaddr, buffer, size, info);
565f210c2aSfgsch   if (status != 0)
575f210c2aSfgsch     {
585f210c2aSfgsch       (*info->memory_error_func) (status, memaddr, info);
595f210c2aSfgsch       return -1;
605f210c2aSfgsch     }
615f210c2aSfgsch   return 0;
625f210c2aSfgsch }
635f210c2aSfgsch 
645f210c2aSfgsch 
655f210c2aSfgsch /* Read the 68HC12 indexed operand byte and print the corresponding mode.
665f210c2aSfgsch    Returns the number of bytes read or -1 if failure.  */
675f210c2aSfgsch static int
print_indexed_operand(bfd_vma memaddr,struct disassemble_info * info,int * indirect,int mov_insn,int pc_offset,bfd_vma endaddr)68*cf2f2c56Smiod print_indexed_operand (bfd_vma memaddr, struct disassemble_info* info,
69*cf2f2c56Smiod                        int* indirect, int mov_insn, int pc_offset,
70*cf2f2c56Smiod                        bfd_vma endaddr)
715f210c2aSfgsch {
725f210c2aSfgsch   bfd_byte buffer[4];
735f210c2aSfgsch   int reg;
745f210c2aSfgsch   int status;
755f210c2aSfgsch   short sval;
765f210c2aSfgsch   int pos = 1;
775f210c2aSfgsch 
78d2201f2fSdrahn   if (indirect)
79d2201f2fSdrahn     *indirect = 0;
80d2201f2fSdrahn 
815f210c2aSfgsch   status = read_memory (memaddr, &buffer[0], 1, info);
825f210c2aSfgsch   if (status != 0)
835f210c2aSfgsch     {
845f210c2aSfgsch       return status;
855f210c2aSfgsch     }
865f210c2aSfgsch 
875f210c2aSfgsch   /* n,r with 5-bits signed constant.  */
885f210c2aSfgsch   if ((buffer[0] & 0x20) == 0)
895f210c2aSfgsch     {
905f210c2aSfgsch       reg = (buffer[0] >> 6) & 3;
915f210c2aSfgsch       sval = (buffer[0] & 0x1f);
925f210c2aSfgsch       if (sval & 0x10)
935f210c2aSfgsch 	sval |= 0xfff0;
94d2201f2fSdrahn       /* 68HC12 requires an adjustment for movb/movw pc relative modes.  */
95d2201f2fSdrahn       if (reg == PC_REGNUM && info->mach == bfd_mach_m6812 && mov_insn)
96d2201f2fSdrahn         sval += pc_offset;
975f210c2aSfgsch       (*info->fprintf_func) (info->stream, "%d,%s",
985f210c2aSfgsch 			     (int) sval, reg_name[reg]);
99d2201f2fSdrahn 
100d2201f2fSdrahn       if (reg == PC_REGNUM)
101d2201f2fSdrahn         {
102d2201f2fSdrahn           (* info->fprintf_func) (info->stream, " {");
103d2201f2fSdrahn           (* info->print_address_func) (endaddr + sval, info);
104d2201f2fSdrahn           (* info->fprintf_func) (info->stream, "}");
105d2201f2fSdrahn         }
1065f210c2aSfgsch     }
1075f210c2aSfgsch 
1085f210c2aSfgsch   /* Auto pre/post increment/decrement.  */
1095f210c2aSfgsch   else if ((buffer[0] & 0xc0) != 0xc0)
1105f210c2aSfgsch     {
1115f210c2aSfgsch       const char *mode;
1125f210c2aSfgsch 
1135f210c2aSfgsch       reg = (buffer[0] >> 6) & 3;
1145f210c2aSfgsch       sval = (buffer[0] & 0x0f);
1155f210c2aSfgsch       if (sval & 0x8)
1165f210c2aSfgsch 	{
1175f210c2aSfgsch 	  sval |= 0xfff0;
1185f210c2aSfgsch 	  sval = -sval;
1195f210c2aSfgsch 	  mode = "-";
1205f210c2aSfgsch 	}
1215f210c2aSfgsch       else
1225f210c2aSfgsch 	{
1235f210c2aSfgsch 	  sval = sval + 1;
1245f210c2aSfgsch 	  mode = "+";
1255f210c2aSfgsch 	}
1265f210c2aSfgsch       (*info->fprintf_func) (info->stream, "%d,%s%s%s",
1275f210c2aSfgsch 			     (int) sval,
1285f210c2aSfgsch 			     (buffer[0] & 0x10 ? "" : mode),
1295f210c2aSfgsch 			     reg_name[reg], (buffer[0] & 0x10 ? mode : ""));
1305f210c2aSfgsch     }
1315f210c2aSfgsch 
1325f210c2aSfgsch   /* [n,r] 16-bits offset indexed indirect.  */
1335f210c2aSfgsch   else if ((buffer[0] & 0x07) == 3)
1345f210c2aSfgsch     {
1355f210c2aSfgsch       if (mov_insn)
1365f210c2aSfgsch 	{
1375f210c2aSfgsch 	  (*info->fprintf_func) (info->stream, "<invalid op: 0x%x>",
1385f210c2aSfgsch 				 buffer[0] & 0x0ff);
1395f210c2aSfgsch 	  return 0;
1405f210c2aSfgsch 	}
1415f210c2aSfgsch       reg = (buffer[0] >> 3) & 0x03;
1425f210c2aSfgsch       status = read_memory (memaddr + pos, &buffer[0], 2, info);
1435f210c2aSfgsch       if (status != 0)
1445f210c2aSfgsch 	{
1455f210c2aSfgsch 	  return status;
1465f210c2aSfgsch 	}
1475f210c2aSfgsch 
1485f210c2aSfgsch       pos += 2;
1495f210c2aSfgsch       sval = ((buffer[0] << 8) | (buffer[1] & 0x0FF));
1505f210c2aSfgsch       (*info->fprintf_func) (info->stream, "[%u,%s]",
1515f210c2aSfgsch 			     sval & 0x0ffff, reg_name[reg]);
152d2201f2fSdrahn       if (indirect)
153d2201f2fSdrahn         *indirect = 1;
1545f210c2aSfgsch     }
155d2201f2fSdrahn 
156d2201f2fSdrahn   /* n,r with 9 and 16 bit signed constant.  */
1575f210c2aSfgsch   else if ((buffer[0] & 0x4) == 0)
1585f210c2aSfgsch     {
1595f210c2aSfgsch       if (mov_insn)
1605f210c2aSfgsch 	{
1615f210c2aSfgsch 	  (*info->fprintf_func) (info->stream, "<invalid op: 0x%x>",
1625f210c2aSfgsch 				 buffer[0] & 0x0ff);
1635f210c2aSfgsch 	  return 0;
1645f210c2aSfgsch 	}
1655f210c2aSfgsch       reg = (buffer[0] >> 3) & 0x03;
1665f210c2aSfgsch       status = read_memory (memaddr + pos,
1675f210c2aSfgsch 			    &buffer[1], (buffer[0] & 0x2 ? 2 : 1), info);
1685f210c2aSfgsch       if (status != 0)
1695f210c2aSfgsch 	{
1705f210c2aSfgsch 	  return status;
1715f210c2aSfgsch 	}
1725f210c2aSfgsch       if (buffer[0] & 2)
1735f210c2aSfgsch 	{
1745f210c2aSfgsch 	  sval = ((buffer[1] << 8) | (buffer[2] & 0x0FF));
1755f210c2aSfgsch 	  sval &= 0x0FFFF;
1765f210c2aSfgsch 	  pos += 2;
177d2201f2fSdrahn           endaddr += 2;
1785f210c2aSfgsch 	}
1795f210c2aSfgsch       else
1805f210c2aSfgsch 	{
1815f210c2aSfgsch 	  sval = buffer[1] & 0x00ff;
1825f210c2aSfgsch 	  if (buffer[0] & 0x01)
1835f210c2aSfgsch 	    sval |= 0xff00;
1845f210c2aSfgsch 	  pos++;
185d2201f2fSdrahn           endaddr++;
1865f210c2aSfgsch 	}
1875f210c2aSfgsch       (*info->fprintf_func) (info->stream, "%d,%s",
1885f210c2aSfgsch 			     (int) sval, reg_name[reg]);
189d2201f2fSdrahn       if (reg == PC_REGNUM)
190d2201f2fSdrahn         {
191d2201f2fSdrahn           (* info->fprintf_func) (info->stream, " {");
192d2201f2fSdrahn           (* info->print_address_func) (endaddr + sval, info);
193d2201f2fSdrahn           (* info->fprintf_func) (info->stream, "}");
194d2201f2fSdrahn         }
1955f210c2aSfgsch     }
1965f210c2aSfgsch   else
1975f210c2aSfgsch     {
1985f210c2aSfgsch       reg = (buffer[0] >> 3) & 0x03;
1995f210c2aSfgsch       switch (buffer[0] & 3)
2005f210c2aSfgsch 	{
2015f210c2aSfgsch 	case 0:
2025f210c2aSfgsch 	  (*info->fprintf_func) (info->stream, "A,%s", reg_name[reg]);
2035f210c2aSfgsch 	  break;
2045f210c2aSfgsch 	case 1:
2055f210c2aSfgsch 	  (*info->fprintf_func) (info->stream, "B,%s", reg_name[reg]);
2065f210c2aSfgsch 	  break;
2075f210c2aSfgsch 	case 2:
2085f210c2aSfgsch 	  (*info->fprintf_func) (info->stream, "D,%s", reg_name[reg]);
2095f210c2aSfgsch 	  break;
2105f210c2aSfgsch 	case 3:
2115f210c2aSfgsch 	default:
2125f210c2aSfgsch 	  (*info->fprintf_func) (info->stream, "[D,%s]", reg_name[reg]);
213d2201f2fSdrahn           if (indirect)
214d2201f2fSdrahn             *indirect = 1;
2155f210c2aSfgsch 	  break;
2165f210c2aSfgsch 	}
2175f210c2aSfgsch     }
2185f210c2aSfgsch 
2195f210c2aSfgsch   return pos;
2205f210c2aSfgsch }
2215f210c2aSfgsch 
2225f210c2aSfgsch /* Disassemble one instruction at address 'memaddr'.  Returns the number
2235f210c2aSfgsch    of bytes used by that instruction.  */
2245f210c2aSfgsch static int
print_insn(bfd_vma memaddr,struct disassemble_info * info,int arch)225*cf2f2c56Smiod print_insn (bfd_vma memaddr, struct disassemble_info* info, int arch)
2265f210c2aSfgsch {
2275f210c2aSfgsch   int status;
2285f210c2aSfgsch   bfd_byte buffer[4];
2295f210c2aSfgsch   unsigned char code;
2305f210c2aSfgsch   long format, pos, i;
2315f210c2aSfgsch   short sval;
2325f210c2aSfgsch   const struct m68hc11_opcode *opcode;
2335f210c2aSfgsch 
2345f210c2aSfgsch   /* Get first byte.  Only one at a time because we don't know the
2355f210c2aSfgsch      size of the insn.  */
2365f210c2aSfgsch   status = read_memory (memaddr, buffer, 1, info);
2375f210c2aSfgsch   if (status != 0)
2385f210c2aSfgsch     {
2395f210c2aSfgsch       return status;
2405f210c2aSfgsch     }
2415f210c2aSfgsch 
2425f210c2aSfgsch   format = 0;
2435f210c2aSfgsch   code = buffer[0];
2445f210c2aSfgsch   pos = 0;
2455f210c2aSfgsch 
2465f210c2aSfgsch   /* Look for page2,3,4 opcodes.  */
2475f210c2aSfgsch   if (code == M6811_OPCODE_PAGE2)
2485f210c2aSfgsch     {
2495f210c2aSfgsch       pos++;
2505f210c2aSfgsch       format = M6811_OP_PAGE2;
2515f210c2aSfgsch     }
2525f210c2aSfgsch   else if (code == M6811_OPCODE_PAGE3 && arch == cpu6811)
2535f210c2aSfgsch     {
2545f210c2aSfgsch       pos++;
2555f210c2aSfgsch       format = M6811_OP_PAGE3;
2565f210c2aSfgsch     }
2575f210c2aSfgsch   else if (code == M6811_OPCODE_PAGE4 && arch == cpu6811)
2585f210c2aSfgsch     {
2595f210c2aSfgsch       pos++;
2605f210c2aSfgsch       format = M6811_OP_PAGE4;
2615f210c2aSfgsch     }
2625f210c2aSfgsch 
2635f210c2aSfgsch   /* We are in page2,3,4; get the real opcode.  */
2645f210c2aSfgsch   if (pos == 1)
2655f210c2aSfgsch     {
2665f210c2aSfgsch       status = read_memory (memaddr + pos, &buffer[1], 1, info);
2675f210c2aSfgsch       if (status != 0)
2685f210c2aSfgsch 	{
2695f210c2aSfgsch 	  return status;
2705f210c2aSfgsch 	}
2715f210c2aSfgsch       code = buffer[1];
2725f210c2aSfgsch     }
2735f210c2aSfgsch 
2745f210c2aSfgsch 
2755f210c2aSfgsch   /* Look first for a 68HC12 alias.  All of them are 2-bytes long and
2765f210c2aSfgsch      in page 1.  There is no operand to print.  We read the second byte
2775f210c2aSfgsch      only when we have a possible match.  */
2785f210c2aSfgsch   if ((arch & cpu6812) && format == 0)
2795f210c2aSfgsch     {
2805f210c2aSfgsch       int must_read = 1;
2815f210c2aSfgsch 
2825f210c2aSfgsch       /* Walk the alias table to find a code1+code2 match.  */
2835f210c2aSfgsch       for (i = 0; i < m68hc12_num_alias; i++)
2845f210c2aSfgsch 	{
2855f210c2aSfgsch 	  if (m68hc12_alias[i].code1 == code)
2865f210c2aSfgsch 	    {
2875f210c2aSfgsch 	      if (must_read)
2885f210c2aSfgsch 		{
2895f210c2aSfgsch 		  status = read_memory (memaddr + pos + 1,
2905f210c2aSfgsch 					&buffer[1], 1, info);
2915f210c2aSfgsch 		  if (status != 0)
2925f210c2aSfgsch 		    break;
2935f210c2aSfgsch 
2945f210c2aSfgsch 		  must_read = 1;
2955f210c2aSfgsch 		}
2965f210c2aSfgsch 	      if (m68hc12_alias[i].code2 == (unsigned char) buffer[1])
2975f210c2aSfgsch 		{
2985f210c2aSfgsch 		  (*info->fprintf_func) (info->stream, "%s",
2995f210c2aSfgsch 					 m68hc12_alias[i].name);
3005f210c2aSfgsch 		  return 2;
3015f210c2aSfgsch 		}
3025f210c2aSfgsch 	    }
3035f210c2aSfgsch 	}
3045f210c2aSfgsch     }
3055f210c2aSfgsch 
3065f210c2aSfgsch   pos++;
3075f210c2aSfgsch 
3085f210c2aSfgsch   /* Scan the opcode table until we find the opcode
3095f210c2aSfgsch      with the corresponding page.  */
3105f210c2aSfgsch   opcode = m68hc11_opcodes;
3115f210c2aSfgsch   for (i = 0; i < m68hc11_num_opcodes; i++, opcode++)
3125f210c2aSfgsch     {
3135f210c2aSfgsch       int offset;
314d2201f2fSdrahn       int pc_src_offset;
315*cf2f2c56Smiod       int pc_dst_offset = 0;
3165f210c2aSfgsch 
3175f210c2aSfgsch       if ((opcode->arch & arch) == 0)
3185f210c2aSfgsch 	continue;
3195f210c2aSfgsch       if (opcode->opcode != code)
3205f210c2aSfgsch 	continue;
3215f210c2aSfgsch       if ((opcode->format & OP_PAGE_MASK) != format)
3225f210c2aSfgsch 	continue;
3235f210c2aSfgsch 
3245f210c2aSfgsch       if (opcode->format & M6812_OP_REG)
3255f210c2aSfgsch 	{
3265f210c2aSfgsch 	  int j;
3275f210c2aSfgsch 	  int is_jump;
3285f210c2aSfgsch 
3295f210c2aSfgsch 	  if (opcode->format & M6811_OP_JUMP_REL)
3305f210c2aSfgsch 	    is_jump = 1;
3315f210c2aSfgsch 	  else
3325f210c2aSfgsch 	    is_jump = 0;
3335f210c2aSfgsch 
3345f210c2aSfgsch 	  status = read_memory (memaddr + pos, &buffer[0], 1, info);
3355f210c2aSfgsch 	  if (status != 0)
3365f210c2aSfgsch 	    {
3375f210c2aSfgsch 	      return status;
3385f210c2aSfgsch 	    }
3395f210c2aSfgsch 	  for (j = 0; i + j < m68hc11_num_opcodes; j++)
3405f210c2aSfgsch 	    {
3415f210c2aSfgsch 	      if ((opcode[j].arch & arch) == 0)
3425f210c2aSfgsch 		continue;
3435f210c2aSfgsch 	      if (opcode[j].opcode != code)
3445f210c2aSfgsch 		continue;
3455f210c2aSfgsch 	      if (is_jump)
3465f210c2aSfgsch 		{
3475f210c2aSfgsch 		  if (!(opcode[j].format & M6811_OP_JUMP_REL))
3485f210c2aSfgsch 		    continue;
3495f210c2aSfgsch 
3505f210c2aSfgsch 		  if ((opcode[j].format & M6812_OP_IBCC_MARKER)
3515f210c2aSfgsch 		      && (buffer[0] & 0xc0) != 0x80)
3525f210c2aSfgsch 		    continue;
3535f210c2aSfgsch 		  if ((opcode[j].format & M6812_OP_TBCC_MARKER)
3545f210c2aSfgsch 		      && (buffer[0] & 0xc0) != 0x40)
3555f210c2aSfgsch 		    continue;
3565f210c2aSfgsch 		  if ((opcode[j].format & M6812_OP_DBCC_MARKER)
3575f210c2aSfgsch 		      && (buffer[0] & 0xc0) != 0)
3585f210c2aSfgsch 		    continue;
3595f210c2aSfgsch 		  if ((opcode[j].format & M6812_OP_EQ_MARKER)
3605f210c2aSfgsch 		      && (buffer[0] & 0x20) == 0)
3615f210c2aSfgsch 		    break;
3625f210c2aSfgsch 		  if (!(opcode[j].format & M6812_OP_EQ_MARKER)
3635f210c2aSfgsch 		      && (buffer[0] & 0x20) != 0)
3645f210c2aSfgsch 		    break;
3655f210c2aSfgsch 		  continue;
3665f210c2aSfgsch 		}
3675f210c2aSfgsch 	      if (opcode[j].format & M6812_OP_EXG_MARKER && buffer[0] & 0x80)
3685f210c2aSfgsch 		break;
3695f210c2aSfgsch 	      if ((opcode[j].format & M6812_OP_SEX_MARKER)
3705f210c2aSfgsch 		  && (((buffer[0] & 0x07) >= 3 && (buffer[0] & 7) <= 7))
3715f210c2aSfgsch 		  && ((buffer[0] & 0x0f0) <= 0x20))
3725f210c2aSfgsch 		break;
3735f210c2aSfgsch 	      if (opcode[j].format & M6812_OP_TFR_MARKER
3745f210c2aSfgsch 		  && !(buffer[0] & 0x80))
3755f210c2aSfgsch 		break;
3765f210c2aSfgsch 	    }
3775f210c2aSfgsch 	  if (i + j < m68hc11_num_opcodes)
3785f210c2aSfgsch 	    opcode = &opcode[j];
3795f210c2aSfgsch 	}
3805f210c2aSfgsch 
3815f210c2aSfgsch       /* We have found the opcode.  Extract the operand and print it.  */
3825f210c2aSfgsch       (*info->fprintf_func) (info->stream, "%s", opcode->name);
3835f210c2aSfgsch 
3845f210c2aSfgsch       format = opcode->format;
3855f210c2aSfgsch       if (format & (M6811_OP_MASK | M6811_OP_BITMASK
3865f210c2aSfgsch 		    | M6811_OP_JUMP_REL | M6812_OP_JUMP_REL16))
3875f210c2aSfgsch 	{
3885f210c2aSfgsch 	  (*info->fprintf_func) (info->stream, "\t");
3895f210c2aSfgsch 	}
3905f210c2aSfgsch 
391d2201f2fSdrahn       /* The movb and movw must be handled in a special way...
392d2201f2fSdrahn          The source constant 'ii' is not always at the same place.
393d2201f2fSdrahn          This is the same for the destination for the post-indexed byte.
394d2201f2fSdrahn          The 'offset' is used to do the appropriate correction.
395d2201f2fSdrahn 
396d2201f2fSdrahn                                    offset          offset
397d2201f2fSdrahn                               for constant     for destination
398d2201f2fSdrahn          movb   18 OB ii hh ll       0          0
399d2201f2fSdrahn                 18 08 xb ii          1          -1
400d2201f2fSdrahn                 18 0C hh ll hh ll    0          0
401d2201f2fSdrahn                 18 09 xb hh ll       1          -1
402d2201f2fSdrahn                 18 0D xb hh ll       0          0
403d2201f2fSdrahn                 18 0A xb xb          0          0
404d2201f2fSdrahn 
405d2201f2fSdrahn          movw   18 03 jj kk hh ll    0          0
406d2201f2fSdrahn                 18 00 xb jj kk       1          -1
407d2201f2fSdrahn                 18 04 hh ll hh ll    0          0
408d2201f2fSdrahn                 18 01 xb hh ll       1          -1
409d2201f2fSdrahn                 18 05 xb hh ll       0          0
410d2201f2fSdrahn                 18 02 xb xb          0          0
411d2201f2fSdrahn 
412d2201f2fSdrahn          After the source operand is read, the position 'pos' is incremented
413d2201f2fSdrahn          this explains the negative offset for destination.
414d2201f2fSdrahn 
415d2201f2fSdrahn          movb/movw above are the only instructions with this matching
416d2201f2fSdrahn          format.  */
417d2201f2fSdrahn       offset = ((format & M6812_OP_IDX_P2)
418d2201f2fSdrahn                 && (format & (M6811_OP_IMM8 | M6811_OP_IMM16 |
419d2201f2fSdrahn                               M6811_OP_IND16)));
4205f210c2aSfgsch 
4215f210c2aSfgsch       /* Operand with one more byte: - immediate, offset,
4225f210c2aSfgsch          direct-low address.  */
4235f210c2aSfgsch       if (format &
4245f210c2aSfgsch 	  (M6811_OP_IMM8 | M6811_OP_IX | M6811_OP_IY | M6811_OP_DIRECT))
4255f210c2aSfgsch 	{
4265f210c2aSfgsch 	  status = read_memory (memaddr + pos + offset, &buffer[0], 1, info);
4275f210c2aSfgsch 	  if (status != 0)
4285f210c2aSfgsch 	    {
4295f210c2aSfgsch 	      return status;
4305f210c2aSfgsch 	    }
4315f210c2aSfgsch 
4325f210c2aSfgsch 	  pos++;
433d2201f2fSdrahn 
434d2201f2fSdrahn           /* This movb/movw is special (see above).  */
435d2201f2fSdrahn           offset = -offset;
436d2201f2fSdrahn 
437d2201f2fSdrahn           pc_dst_offset = 2;
4385f210c2aSfgsch 	  if (format & M6811_OP_IMM8)
4395f210c2aSfgsch 	    {
4405f210c2aSfgsch 	      (*info->fprintf_func) (info->stream, "#%d", (int) buffer[0]);
4415f210c2aSfgsch 	      format &= ~M6811_OP_IMM8;
442d2201f2fSdrahn               /* Set PC destination offset.  */
443d2201f2fSdrahn               pc_dst_offset = 1;
4445f210c2aSfgsch 	    }
4455f210c2aSfgsch 	  else if (format & M6811_OP_IX)
4465f210c2aSfgsch 	    {
4475f210c2aSfgsch 	      /* Offsets are in range 0..255, print them unsigned.  */
4485f210c2aSfgsch 	      (*info->fprintf_func) (info->stream, "%u,x", buffer[0] & 0x0FF);
4495f210c2aSfgsch 	      format &= ~M6811_OP_IX;
4505f210c2aSfgsch 	    }
4515f210c2aSfgsch 	  else if (format & M6811_OP_IY)
4525f210c2aSfgsch 	    {
4535f210c2aSfgsch 	      (*info->fprintf_func) (info->stream, "%u,y", buffer[0] & 0x0FF);
4545f210c2aSfgsch 	      format &= ~M6811_OP_IY;
4555f210c2aSfgsch 	    }
4565f210c2aSfgsch 	  else if (format & M6811_OP_DIRECT)
4575f210c2aSfgsch 	    {
4585f210c2aSfgsch 	      (*info->fprintf_func) (info->stream, "*");
4595f210c2aSfgsch 	      (*info->print_address_func) (buffer[0] & 0x0FF, info);
4605f210c2aSfgsch 	      format &= ~M6811_OP_DIRECT;
4615f210c2aSfgsch 	    }
4625f210c2aSfgsch 	}
4635f210c2aSfgsch 
464d2201f2fSdrahn #define M6812_DST_MOVE  (M6812_OP_IND16_P2 | M6812_OP_IDX_P2)
4655f210c2aSfgsch #define M6812_INDEXED_FLAGS (M6812_OP_IDX|M6812_OP_IDX_1|M6812_OP_IDX_2)
4665f210c2aSfgsch       /* Analyze the 68HC12 indexed byte.  */
4675f210c2aSfgsch       if (format & M6812_INDEXED_FLAGS)
4685f210c2aSfgsch 	{
469d2201f2fSdrahn           int indirect;
470d2201f2fSdrahn           bfd_vma endaddr;
471d2201f2fSdrahn 
472d2201f2fSdrahn           endaddr = memaddr + pos + 1;
473d2201f2fSdrahn           if (format & M6811_OP_IND16)
474d2201f2fSdrahn             endaddr += 2;
475d2201f2fSdrahn           pc_src_offset = -1;
476d2201f2fSdrahn           pc_dst_offset = 1;
477d2201f2fSdrahn 	  status = print_indexed_operand (memaddr + pos, info, &indirect,
478d2201f2fSdrahn                                           (format & M6812_DST_MOVE),
479d2201f2fSdrahn                                           pc_src_offset, endaddr);
4805f210c2aSfgsch 	  if (status < 0)
4815f210c2aSfgsch 	    {
4825f210c2aSfgsch 	      return status;
4835f210c2aSfgsch 	    }
4845f210c2aSfgsch 	  pos += status;
485d2201f2fSdrahn 
486d2201f2fSdrahn           /* The indirect addressing mode of the call instruction does
487d2201f2fSdrahn              not need the page code.  */
488d2201f2fSdrahn           if ((format & M6812_OP_PAGE) && indirect)
489d2201f2fSdrahn             format &= ~M6812_OP_PAGE;
4905f210c2aSfgsch 	}
4915f210c2aSfgsch 
4925f210c2aSfgsch       /* 68HC12 dbcc/ibcc/tbcc operands.  */
4935f210c2aSfgsch       if ((format & M6812_OP_REG) && (format & M6811_OP_JUMP_REL))
4945f210c2aSfgsch 	{
4955f210c2aSfgsch 	  status = read_memory (memaddr + pos, &buffer[0], 2, info);
4965f210c2aSfgsch 	  if (status != 0)
4975f210c2aSfgsch 	    {
4985f210c2aSfgsch 	      return status;
4995f210c2aSfgsch 	    }
5005f210c2aSfgsch 	  (*info->fprintf_func) (info->stream, "%s,",
5015f210c2aSfgsch 				 reg_src_table[buffer[0] & 0x07]);
5025f210c2aSfgsch 	  sval = buffer[1] & 0x0ff;
5035f210c2aSfgsch 	  if (buffer[0] & 0x10)
5045f210c2aSfgsch 	    sval |= 0xff00;
5055f210c2aSfgsch 
5065f210c2aSfgsch 	  pos += 2;
5075f210c2aSfgsch 	  (*info->print_address_func) (memaddr + pos + sval, info);
5085f210c2aSfgsch 	  format &= ~(M6812_OP_REG | M6811_OP_JUMP_REL);
5095f210c2aSfgsch 	}
5105f210c2aSfgsch       else if (format & (M6812_OP_REG | M6812_OP_REG_2))
5115f210c2aSfgsch 	{
5125f210c2aSfgsch 	  status = read_memory (memaddr + pos, &buffer[0], 1, info);
5135f210c2aSfgsch 	  if (status != 0)
5145f210c2aSfgsch 	    {
5155f210c2aSfgsch 	      return status;
5165f210c2aSfgsch 	    }
5175f210c2aSfgsch 
5185f210c2aSfgsch 	  pos++;
5195f210c2aSfgsch 	  (*info->fprintf_func) (info->stream, "%s,%s",
5205f210c2aSfgsch 				 reg_src_table[(buffer[0] >> 4) & 7],
5215f210c2aSfgsch 				 reg_dst_table[(buffer[0] & 7)]);
5225f210c2aSfgsch 	}
5235f210c2aSfgsch 
524d2201f2fSdrahn       if (format & (M6811_OP_IMM16 | M6811_OP_IND16))
525d2201f2fSdrahn 	{
526d2201f2fSdrahn 	  int val;
527d2201f2fSdrahn           bfd_vma addr;
528d2201f2fSdrahn           unsigned page = 0;
529d2201f2fSdrahn 
530d2201f2fSdrahn 	  status = read_memory (memaddr + pos + offset, &buffer[0], 2, info);
531d2201f2fSdrahn 	  if (status != 0)
532d2201f2fSdrahn 	    {
533d2201f2fSdrahn 	      return status;
534d2201f2fSdrahn 	    }
535d2201f2fSdrahn 	  if (format & M6812_OP_IDX_P2)
536d2201f2fSdrahn 	    offset = -2;
537d2201f2fSdrahn 	  else
538d2201f2fSdrahn 	    offset = 0;
539d2201f2fSdrahn 	  pos += 2;
540d2201f2fSdrahn 
541d2201f2fSdrahn 	  val = ((buffer[0] << 8) | (buffer[1] & 0x0FF));
542d2201f2fSdrahn 	  val &= 0x0FFFF;
543d2201f2fSdrahn           addr = val;
544d2201f2fSdrahn           pc_dst_offset = 2;
545d2201f2fSdrahn           if (format & M6812_OP_PAGE)
546d2201f2fSdrahn             {
547d2201f2fSdrahn               status = read_memory (memaddr + pos + offset, buffer, 1, info);
548d2201f2fSdrahn               if (status != 0)
549d2201f2fSdrahn                 return status;
550d2201f2fSdrahn 
551d2201f2fSdrahn               page = (unsigned) buffer[0];
552d2201f2fSdrahn               if (addr >= M68HC12_BANK_BASE && addr < 0x0c000)
553d2201f2fSdrahn                 addr = ((val - M68HC12_BANK_BASE)
554d2201f2fSdrahn                         | (page << M68HC12_BANK_SHIFT))
555d2201f2fSdrahn                    + M68HC12_BANK_VIRT;
556d2201f2fSdrahn             }
557d2201f2fSdrahn           else if ((arch & cpu6812)
558d2201f2fSdrahn                    && addr >= M68HC12_BANK_BASE && addr < 0x0c000)
559d2201f2fSdrahn              {
560d2201f2fSdrahn                 int cur_page;
561d2201f2fSdrahn                 bfd_vma vaddr;
562d2201f2fSdrahn 
563d2201f2fSdrahn                 if (memaddr >= M68HC12_BANK_VIRT)
564d2201f2fSdrahn                    cur_page = ((memaddr - M68HC12_BANK_VIRT)
565d2201f2fSdrahn                                >> M68HC12_BANK_SHIFT);
566d2201f2fSdrahn                 else
567d2201f2fSdrahn                    cur_page = 0;
568d2201f2fSdrahn 
569d2201f2fSdrahn                 vaddr = ((addr - M68HC12_BANK_BASE)
570d2201f2fSdrahn                          + (cur_page << M68HC12_BANK_SHIFT))
571d2201f2fSdrahn                    + M68HC12_BANK_VIRT;
572d2201f2fSdrahn                 if (!info->symbol_at_address_func (addr, info)
573d2201f2fSdrahn                     && info->symbol_at_address_func (vaddr, info))
574d2201f2fSdrahn                    addr = vaddr;
575d2201f2fSdrahn              }
576d2201f2fSdrahn 	  if (format & M6811_OP_IMM16)
577d2201f2fSdrahn 	    {
578d2201f2fSdrahn 	      format &= ~M6811_OP_IMM16;
579d2201f2fSdrahn 	      (*info->fprintf_func) (info->stream, "#");
580d2201f2fSdrahn 	    }
581d2201f2fSdrahn 	  else
582d2201f2fSdrahn 	    format &= ~M6811_OP_IND16;
583d2201f2fSdrahn 
584d2201f2fSdrahn 	  (*info->print_address_func) (addr, info);
585d2201f2fSdrahn           if (format & M6812_OP_PAGE)
586d2201f2fSdrahn             {
587d2201f2fSdrahn               (* info->fprintf_func) (info->stream, " {");
588d2201f2fSdrahn               (* info->print_address_func) (val, info);
589d2201f2fSdrahn               (* info->fprintf_func) (info->stream, ", %d}", page);
590d2201f2fSdrahn               format &= ~M6812_OP_PAGE;
591d2201f2fSdrahn               pos += 1;
592d2201f2fSdrahn             }
593d2201f2fSdrahn 	}
594d2201f2fSdrahn 
595d2201f2fSdrahn       if (format & M6812_OP_IDX_P2)
596d2201f2fSdrahn 	{
597d2201f2fSdrahn 	  (*info->fprintf_func) (info->stream, ", ");
598d2201f2fSdrahn 	  status = print_indexed_operand (memaddr + pos + offset, info,
599d2201f2fSdrahn                                           0, 1, pc_dst_offset,
600d2201f2fSdrahn                                           memaddr + pos + offset + 1);
601d2201f2fSdrahn 	  if (status < 0)
602d2201f2fSdrahn 	    return status;
603d2201f2fSdrahn 	  pos += status;
604d2201f2fSdrahn 	}
605d2201f2fSdrahn 
606d2201f2fSdrahn       if (format & M6812_OP_IND16_P2)
607d2201f2fSdrahn 	{
608d2201f2fSdrahn 	  int val;
609d2201f2fSdrahn 
610d2201f2fSdrahn 	  (*info->fprintf_func) (info->stream, ", ");
611d2201f2fSdrahn 
612d2201f2fSdrahn 	  status = read_memory (memaddr + pos + offset, &buffer[0], 2, info);
613d2201f2fSdrahn 	  if (status != 0)
614d2201f2fSdrahn 	    {
615d2201f2fSdrahn 	      return status;
616d2201f2fSdrahn 	    }
617d2201f2fSdrahn 	  pos += 2;
618d2201f2fSdrahn 
619d2201f2fSdrahn 	  val = ((buffer[0] << 8) | (buffer[1] & 0x0FF));
620d2201f2fSdrahn 	  val &= 0x0FFFF;
621d2201f2fSdrahn 	  (*info->print_address_func) (val, info);
622d2201f2fSdrahn 	}
623d2201f2fSdrahn 
6245f210c2aSfgsch       /* M6811_OP_BITMASK and M6811_OP_JUMP_REL must be treated separately
6255f210c2aSfgsch          and in that order.  The brset/brclr insn have a bitmask and then
6265f210c2aSfgsch          a relative branch offset.  */
6275f210c2aSfgsch       if (format & M6811_OP_BITMASK)
6285f210c2aSfgsch 	{
6295f210c2aSfgsch 	  status = read_memory (memaddr + pos, &buffer[0], 1, info);
6305f210c2aSfgsch 	  if (status != 0)
6315f210c2aSfgsch 	    {
6325f210c2aSfgsch 	      return status;
6335f210c2aSfgsch 	    }
6345f210c2aSfgsch 	  pos++;
6355f210c2aSfgsch 	  (*info->fprintf_func) (info->stream, " #$%02x%s",
6365f210c2aSfgsch 				 buffer[0] & 0x0FF,
6375f210c2aSfgsch 				 (format & M6811_OP_JUMP_REL ? " " : ""));
6385f210c2aSfgsch 	  format &= ~M6811_OP_BITMASK;
6395f210c2aSfgsch 	}
6405f210c2aSfgsch       if (format & M6811_OP_JUMP_REL)
6415f210c2aSfgsch 	{
6425f210c2aSfgsch 	  int val;
6435f210c2aSfgsch 
6445f210c2aSfgsch 	  status = read_memory (memaddr + pos, &buffer[0], 1, info);
6455f210c2aSfgsch 	  if (status != 0)
6465f210c2aSfgsch 	    {
6475f210c2aSfgsch 	      return status;
6485f210c2aSfgsch 	    }
6495f210c2aSfgsch 
6505f210c2aSfgsch 	  pos++;
6515f210c2aSfgsch 	  val = (buffer[0] & 0x80) ? buffer[0] | 0xFFFFFF00 : buffer[0];
6525f210c2aSfgsch 	  (*info->print_address_func) (memaddr + pos + val, info);
6535f210c2aSfgsch 	  format &= ~M6811_OP_JUMP_REL;
6545f210c2aSfgsch 	}
6555f210c2aSfgsch       else if (format & M6812_OP_JUMP_REL16)
6565f210c2aSfgsch 	{
6575f210c2aSfgsch 	  int val;
6585f210c2aSfgsch 
6595f210c2aSfgsch 	  status = read_memory (memaddr + pos, &buffer[0], 2, info);
6605f210c2aSfgsch 	  if (status != 0)
6615f210c2aSfgsch 	    {
6625f210c2aSfgsch 	      return status;
6635f210c2aSfgsch 	    }
6645f210c2aSfgsch 
6655f210c2aSfgsch 	  pos += 2;
6665f210c2aSfgsch 	  val = ((buffer[0] << 8) | (buffer[1] & 0x0FF));
6675f210c2aSfgsch 	  if (val & 0x8000)
6685f210c2aSfgsch 	    val |= 0xffff0000;
6695f210c2aSfgsch 
6705f210c2aSfgsch 	  (*info->print_address_func) (memaddr + pos + val, info);
6715f210c2aSfgsch 	  format &= ~M6812_OP_JUMP_REL16;
6725f210c2aSfgsch 	}
673d2201f2fSdrahn 
674d2201f2fSdrahn       if (format & M6812_OP_PAGE)
6755f210c2aSfgsch 	{
6765f210c2aSfgsch 	  int val;
6775f210c2aSfgsch 
678d2201f2fSdrahn 	  status = read_memory (memaddr + pos + offset, &buffer[0], 1, info);
6795f210c2aSfgsch 	  if (status != 0)
6805f210c2aSfgsch 	    {
6815f210c2aSfgsch 	      return status;
6825f210c2aSfgsch 	    }
683d2201f2fSdrahn 	  pos += 1;
6845f210c2aSfgsch 
685d2201f2fSdrahn 	  val = buffer[0] & 0x0ff;
686d2201f2fSdrahn 	  (*info->fprintf_func) (info->stream, ", %d", val);
6875f210c2aSfgsch 	}
6885f210c2aSfgsch 
6895f210c2aSfgsch #ifdef DEBUG
6905f210c2aSfgsch       /* Consistency check.  'format' must be 0, so that we have handled
6915f210c2aSfgsch          all formats; and the computed size of the insn must match the
6925f210c2aSfgsch          opcode table content.  */
6935f210c2aSfgsch       if (format & ~(M6811_OP_PAGE4 | M6811_OP_PAGE3 | M6811_OP_PAGE2))
6945f210c2aSfgsch 	{
6955f210c2aSfgsch 	  (*info->fprintf_func) (info->stream, "; Error, format: %x", format);
6965f210c2aSfgsch 	}
6975f210c2aSfgsch       if (pos != opcode->size)
6985f210c2aSfgsch 	{
6995f210c2aSfgsch 	  (*info->fprintf_func) (info->stream, "; Error, size: %d expect %d",
7005f210c2aSfgsch 				 pos, opcode->size);
7015f210c2aSfgsch 	}
7025f210c2aSfgsch #endif
7035f210c2aSfgsch       return pos;
7045f210c2aSfgsch     }
7055f210c2aSfgsch 
7065f210c2aSfgsch   /* Opcode not recognized.  */
7075f210c2aSfgsch   if (format == M6811_OP_PAGE2 && arch & cpu6812
708*cf2f2c56Smiod       && ((code >= 0x30 && code <= 0x39) || (code >= 0x40)))
7095f210c2aSfgsch     (*info->fprintf_func) (info->stream, "trap\t#%d", code & 0x0ff);
7105f210c2aSfgsch 
7115f210c2aSfgsch   else if (format == M6811_OP_PAGE2)
7125f210c2aSfgsch     (*info->fprintf_func) (info->stream, ".byte\t0x%02x, 0x%02x",
7135f210c2aSfgsch 			   M6811_OPCODE_PAGE2, code);
7145f210c2aSfgsch   else if (format == M6811_OP_PAGE3)
7155f210c2aSfgsch     (*info->fprintf_func) (info->stream, ".byte\t0x%02x, 0x%02x",
7165f210c2aSfgsch 			   M6811_OPCODE_PAGE3, code);
7175f210c2aSfgsch   else if (format == M6811_OP_PAGE4)
7185f210c2aSfgsch     (*info->fprintf_func) (info->stream, ".byte\t0x%02x, 0x%02x",
7195f210c2aSfgsch 			   M6811_OPCODE_PAGE4, code);
7205f210c2aSfgsch   else
7215f210c2aSfgsch     (*info->fprintf_func) (info->stream, ".byte\t0x%02x", code);
7225f210c2aSfgsch 
7235f210c2aSfgsch   return pos;
7245f210c2aSfgsch }
7255f210c2aSfgsch 
7265f210c2aSfgsch /* Disassemble one instruction at address 'memaddr'.  Returns the number
7275f210c2aSfgsch    of bytes used by that instruction.  */
7285f210c2aSfgsch int
print_insn_m68hc11(bfd_vma memaddr,struct disassemble_info * info)729*cf2f2c56Smiod print_insn_m68hc11 (bfd_vma memaddr, struct disassemble_info* info)
7305f210c2aSfgsch {
7315f210c2aSfgsch   return print_insn (memaddr, info, cpu6811);
7325f210c2aSfgsch }
7335f210c2aSfgsch 
7345f210c2aSfgsch int
print_insn_m68hc12(bfd_vma memaddr,struct disassemble_info * info)735*cf2f2c56Smiod print_insn_m68hc12 (bfd_vma memaddr, struct disassemble_info* info)
7365f210c2aSfgsch {
7375f210c2aSfgsch   return print_insn (memaddr, info, cpu6812);
7385f210c2aSfgsch }
739