Home | History | Annotate | Download | only in opcodes
      1 /* m68hc11-dis.c -- Motorola 68HC11 & 68HC12 disassembly
      2    Copyright (C) 1999-2016 Free Software Foundation, Inc.
      3    Written by Stephane Carrez (stcarrez (at) nerim.fr)
      4    XGATE and S12X added by James Murray (jsm (at) jsm-net.demon.co.uk)
      5 
      6    This file is part of the GNU opcodes library.
      7 
      8    This library is free software; you can redistribute it and/or modify
      9    it under the terms of the GNU General Public License as published by
     10    the Free Software Foundation; either version 3, or (at your option)
     11    any later version.
     12 
     13    It is distributed in the hope that it will be useful, but WITHOUT
     14    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     15    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
     16    License for more details.
     17 
     18    You should have received a copy of the GNU General Public License
     19    along with this program; if not, write to the Free Software
     20    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
     21    MA 02110-1301, USA.  */
     22 
     23 #include "sysdep.h"
     24 #include <stdio.h>
     25 
     26 #include "opcode/m68hc11.h"
     27 #include "dis-asm.h"
     28 
     29 #define PC_REGNUM 3
     30 
     31 static const char *const reg_name[] =
     32 {
     33   "X", "Y", "SP", "PC"
     34 };
     35 
     36 static const char *const reg_src_table[] =
     37 {
     38   "A", "B", "CCR", "TMP3", "D", "X", "Y", "SP"
     39 };
     40 
     41 static const char *const reg_dst_table[] =
     42 {
     43   "A", "B", "CCR", "TMP2", "D", "X", "Y", "SP"
     44 };
     45 
     46 #define OP_PAGE_MASK (M6811_OP_PAGE2|M6811_OP_PAGE3|M6811_OP_PAGE4)
     47 
     48 /* Prototypes for local functions.  */
     49 static int read_memory (bfd_vma, bfd_byte *, int, struct disassemble_info *);
     50 static int print_indexed_operand (bfd_vma, struct disassemble_info *,
     51                                   int*, int, int, bfd_vma, int);
     52 static int print_insn (bfd_vma, struct disassemble_info *, int);
     53 
     54 static int
     55 read_memory (bfd_vma memaddr, bfd_byte* buffer, int size,
     56              struct disassemble_info* info)
     57 {
     58   int status;
     59 
     60   /* Get first byte.  Only one at a time because we don't know the
     61      size of the insn.  */
     62   status = (*info->read_memory_func) (memaddr, buffer, size, info);
     63   if (status != 0)
     64     {
     65       (*info->memory_error_func) (status, memaddr, info);
     66       return -1;
     67     }
     68   return 0;
     69 }
     70 
     71 
     72 /* Read the 68HC12 indexed operand byte and print the corresponding mode.
     73    Returns the number of bytes read or -1 if failure.  */
     74 static int
     75 print_indexed_operand (bfd_vma memaddr, struct disassemble_info* info,
     76                        int* indirect, int mov_insn, int pc_offset,
     77                        bfd_vma endaddr, int arch)
     78 {
     79   bfd_byte buffer[4];
     80   int reg;
     81   int status;
     82   short sval;
     83   int pos = 1;
     84 
     85   if (indirect)
     86     *indirect = 0;
     87 
     88   status = read_memory (memaddr, &buffer[0], 1, info);
     89   if (status != 0)
     90     {
     91       return status;
     92     }
     93 
     94   /* n,r with 5-bits signed constant.  */
     95   if ((buffer[0] & 0x20) == 0)
     96     {
     97       reg = (buffer[0] >> 6) & 3;
     98       sval = (buffer[0] & 0x1f);
     99       if (sval & 0x10)
    100 	sval |= 0xfff0;
    101       /* 68HC12 requires an adjustment for movb/movw pc relative modes.  */
    102       if (reg == PC_REGNUM && info->mach == bfd_mach_m6812 && mov_insn)
    103         sval += pc_offset;
    104       (*info->fprintf_func) (info->stream, "0x%x,%s",
    105 			     (unsigned short) sval, reg_name[reg]);
    106 
    107       if (reg == PC_REGNUM)
    108         {
    109           (* info->fprintf_func) (info->stream, " {");
    110 	      if (info->symtab_size > 0) /* Avoid duplicate 0x from core binutils. */
    111 	        (*info->fprintf_func) (info->stream, "0x");
    112           (* info->print_address_func) (endaddr + sval, info);
    113           (* info->fprintf_func) (info->stream, "}");
    114         }
    115     }
    116 
    117   /* Auto pre/post increment/decrement.  */
    118   else if ((buffer[0] & 0xc0) != 0xc0)
    119     {
    120       const char *mode;
    121 
    122       reg = (buffer[0] >> 6) & 3;
    123       sval = (buffer[0] & 0x0f);
    124       if (sval & 0x8)
    125 	{
    126 	  sval |= 0xfff0;
    127 	  sval = -sval;
    128 	  mode = "-";
    129 	}
    130       else
    131 	{
    132 	  sval = sval + 1;
    133 	  mode = "+";
    134 	}
    135       (*info->fprintf_func) (info->stream, "%d,%s%s%s",
    136 			     (unsigned short) sval,
    137 			     (buffer[0] & 0x10 ? "" : mode),
    138 			     reg_name[reg], (buffer[0] & 0x10 ? mode : ""));
    139     }
    140 
    141   /* [n,r] 16-bits offset indexed indirect.  */
    142   else if ((buffer[0] & 0x07) == 3)
    143     {
    144       if ((mov_insn) && (!(arch & cpu9s12x)))
    145       	{
    146       	  (*info->fprintf_func) (info->stream, "<invalid op: 0x%x>",
    147     				 buffer[0] & 0x0ff);
    148       	  return 0;
    149       	}
    150       reg = (buffer[0] >> 3) & 0x03;
    151       status = read_memory (memaddr + pos, &buffer[0], 2, info);
    152       if (status != 0)
    153 	{
    154 	  return status;
    155 	}
    156 
    157       pos += 2;
    158       sval = ((buffer[0] << 8) | (buffer[1] & 0x0FF));
    159       (*info->fprintf_func) (info->stream, "[0x%x,%s]",
    160 			     sval & 0x0ffff, reg_name[reg]);
    161       if (indirect)
    162         *indirect = 1;
    163     }
    164 
    165   /* n,r with 9 and 16 bit signed constant.  */
    166   else if ((buffer[0] & 0x4) == 0)
    167     {
    168       if ((mov_insn) && (!(arch & cpu9s12x)))
    169       	{
    170       	  (*info->fprintf_func) (info->stream, "<invalid op: 0x%x>",
    171     				 buffer[0] & 0x0ff);
    172       	  return 0;
    173       	}
    174 
    175       reg = (buffer[0] >> 3) & 0x03;
    176       status = read_memory (memaddr + pos,
    177 			    &buffer[1], (buffer[0] & 0x2 ? 2 : 1), info);
    178       if (status != 0)
    179 	{
    180 	  return status;
    181 	}
    182       if (buffer[0] & 2)
    183 	{
    184 	  sval = ((buffer[1] << 8) | (buffer[2] & 0x0FF));
    185 	  sval &= 0x0FFFF;
    186 	  pos += 2;
    187           endaddr += 2;
    188 	}
    189       else
    190 	{
    191 	  sval = buffer[1] & 0x00ff;
    192 	  if (buffer[0] & 0x01)
    193 	    sval |= 0xff00;
    194 	  pos++;
    195           endaddr++;
    196 	}
    197       (*info->fprintf_func) (info->stream, "0x%x,%s",
    198 			     (unsigned short) sval, reg_name[reg]);
    199       if (reg == PC_REGNUM)
    200         {
    201           (* info->fprintf_func) (info->stream, " {0x");
    202           (* info->print_address_func) (endaddr + sval, info);
    203           (* info->fprintf_func) (info->stream, "}");
    204         }
    205     }
    206   else
    207     {
    208       reg = (buffer[0] >> 3) & 0x03;
    209       switch (buffer[0] & 3)
    210 	{
    211 	case 0:
    212 	  (*info->fprintf_func) (info->stream, "A,%s", reg_name[reg]);
    213 	  break;
    214 	case 1:
    215 	  (*info->fprintf_func) (info->stream, "B,%s", reg_name[reg]);
    216 	  break;
    217 	case 2:
    218 	  (*info->fprintf_func) (info->stream, "D,%s", reg_name[reg]);
    219 	  break;
    220 	case 3:
    221 	default:
    222 	  (*info->fprintf_func) (info->stream, "[D,%s]", reg_name[reg]);
    223           if (indirect)
    224             *indirect = 1;
    225 	  break;
    226 	}
    227     }
    228 
    229   return pos;
    230 }
    231 
    232 /* Disassemble one instruction at address 'memaddr'.  Returns the number
    233    of bytes used by that instruction.  */
    234 static int
    235 print_insn (bfd_vma memaddr, struct disassemble_info* info, int arch)
    236 {
    237   int status;
    238   bfd_byte buffer[4];
    239   unsigned int code;
    240   long format, pos, i;
    241   short sval;
    242   const struct m68hc11_opcode *opcode;
    243 
    244   if (arch & cpuxgate)
    245     {
    246       int val;
    247       /* Get two bytes as all XGATE instructions are 16bit.  */
    248       status = read_memory (memaddr, buffer, 2, info);
    249       if (status != 0)
    250 	return status;
    251 
    252       format = 0;
    253       code = (buffer[0] << 8) + buffer[1];
    254 
    255       /* Scan the opcode table until we find the opcode
    256 	 with the corresponding page.  */
    257       opcode = m68hc11_opcodes;
    258       for (i = 0; i < m68hc11_num_opcodes; i++, opcode++)
    259 	{
    260 	  if ((opcode->opcode != (code & opcode->xg_mask)) || (opcode->arch != cpuxgate))
    261   	    continue;
    262 	  /* We have found the opcode.  Extract the operand and print it.  */
    263 	  (*info->fprintf_func) (info->stream, "%s", opcode->name);
    264 	  format = opcode->format;
    265 	  if (format & (M68XG_OP_NONE))
    266 	    {
    267 	      /* Nothing to print.  */
    268 	    }
    269 	  else if (format & M68XG_OP_IMM3)
    270 	    (*info->fprintf_func) (info->stream, " #0x%x", (code >> 8) & 0x7);
    271 	  else if (format & M68XG_OP_R_R)
    272 	    (*info->fprintf_func) (info->stream, " R%x, R%x",
    273 				   (code >> 8) & 0x7, (code >> 5) & 0x7);
    274 	  else if (format & M68XG_OP_R_R_R)
    275 	    (*info->fprintf_func) (info->stream, " R%x, R%x, R%x",
    276 				   (code >> 8) & 0x7, (code >> 5) & 0x7, (code >> 2) & 0x7);
    277 	  else if (format & M68XG_OP_RD_RB_RI)
    278 	    (*info->fprintf_func) (info->stream, " R%x, (R%x, R%x)",
    279 				   (code >> 8) & 0x7, (code >> 5) & 0x7, (code >> 2) & 0x7);
    280 	  else if (format & M68XG_OP_RD_RB_RIp)
    281 	    (*info->fprintf_func) (info->stream, " R%x, (R%x, R%x+)",
    282 				   (code >> 8) & 0x7, (code >> 5) & 0x7, (code >> 2) & 0x7);
    283 	  else if (format & M68XG_OP_RD_RB_mRI)
    284 	    (*info->fprintf_func) (info->stream, " R%x, (R%x, -R%x)",
    285 				   (code >> 8) & 0x7, (code >> 5) & 0x7, (code >> 2) & 0x7);
    286 	  else if (format & M68XG_OP_R_R_OFFS5)
    287 	    (*info->fprintf_func) (info->stream, " R%x, (R%x, #0x%x)",
    288 				   (code >> 8) & 0x7, (code >> 5) & 0x7, code & 0x1f);
    289 	  else if (format & M68XG_OP_R_IMM8)
    290 	    (*info->fprintf_func) (info->stream, " R%x, #0x%02x",
    291 				   (code >> 8) & 0x7, code & 0xff);
    292 	  else if (format & M68XG_OP_R_IMM4)
    293 	    (*info->fprintf_func) (info->stream, " R%x, #0x%x",
    294 				   (code >> 8) & 0x7, (code & 0xf0) >> 4);
    295 	  else if (format & M68XG_OP_REL9)
    296 	    {
    297 	      (*info->fprintf_func) (info->stream, " 0x");
    298 	      val = (buffer[0] & 0x1) ? buffer[1] | 0xFFFFFF00 : buffer[1];
    299 	      (*info->print_address_func) (memaddr + (val << 1) + 2, info);
    300 	    }
    301 	  else if (format & M68XG_OP_REL10)
    302 	    {
    303 	      (*info->fprintf_func) (info->stream, " 0x");
    304 	      val = (buffer[0] << 8) | (unsigned int) buffer[1];
    305 	      if (val & 0x200)
    306 		val |= 0xfffffc00;
    307 	      else
    308 		val &= 0x000001ff;
    309 	      (*info->print_address_func) (memaddr + (val << 1) + 2, info);
    310 	    }
    311 	  else if ((code & 0x00ff) == 0x00f8)
    312   	    (*info->fprintf_func) (info->stream, " R%x, CCR", (code >> 8) & 0x7);
    313 	  else if ((code & 0x00ff) == 0x00f9)
    314   	    (*info->fprintf_func) (info->stream, " CCR, R%x", (code >> 8) & 0x7);
    315 	  else if ((code & 0x00ff) == 0x0)
    316   	    (*info->fprintf_func) (info->stream, " R%x, PC", (code >> 8) & 0x7);
    317 	  else if (format & M68XG_OP_R)
    318   	    {
    319 	      /* Special cases for TFR.  */
    320 	      if ((code & 0xf8ff) == 0x00f8)
    321 		(*info->fprintf_func) (info->stream, " R%x, CCR", (code >> 8) & 0x7);
    322 	      else if ((code & 0xf8ff) == 0x00f9)
    323 		(*info->fprintf_func) (info->stream, " CCR, R%x", (code >> 8) & 0x7);
    324 	      else if ((code & 0xf8ff) == 0x00fa)
    325 		(*info->fprintf_func) (info->stream, " R%x, PC",  (code >> 8) & 0x7);
    326 	      else
    327 		(*info->fprintf_func) (info->stream, " R%x", (code >> 8) & 0x7);
    328 	    }
    329 	  else
    330 	    /* Opcode not recognized.  */
    331 	    (*info->fprintf_func) (info->stream, "Not yet handled TEST .byte\t0x%04x", code);
    332 	  return 2;
    333 	}
    334 
    335       /* Opcode not recognized.  */
    336       (*info->fprintf_func) (info->stream, ".byte\t0x%04x", code);
    337       return 2; /* Everything is two bytes.  */
    338     }
    339 
    340   /* HC11 and HC12.  */
    341 
    342   /* Get first byte.  Only one at a time because we don't know the
    343      size of the insn.  */
    344   status = read_memory (memaddr, buffer, 1, info);
    345   if (status != 0)
    346     return status;
    347 
    348   format = 0;
    349   code = buffer[0];
    350   pos = 0;
    351 
    352   /* Look for page2,3,4 opcodes.  */
    353   if (code == M6811_OPCODE_PAGE2)
    354     {
    355       pos++;
    356       format = M6811_OP_PAGE2;
    357     }
    358   else if (code == M6811_OPCODE_PAGE3 && arch == cpu6811)
    359     {
    360       pos++;
    361       format = M6811_OP_PAGE3;
    362     }
    363   else if (code == M6811_OPCODE_PAGE4 && arch == cpu6811)
    364     {
    365       pos++;
    366       format = M6811_OP_PAGE4;
    367     }
    368 
    369   /* We are in page2,3,4; get the real opcode.  */
    370   if (pos == 1)
    371     {
    372       status = read_memory (memaddr + pos, &buffer[1], 1, info);
    373       if (status != 0)
    374 	return status;
    375 
    376       code = buffer[1];
    377     }
    378 
    379   /* Look first for a 68HC12 alias.  All of them are 2-bytes long and
    380      in page 1.  There is no operand to print.  We read the second byte
    381      only when we have a possible match.  */
    382   if ((arch & cpu6812) && format == 0)
    383     {
    384       int must_read = 1;
    385 
    386       /* Walk the alias table to find a code1+code2 match.  */
    387       for (i = 0; i < m68hc12_num_alias; i++)
    388 	{
    389 	  if (m68hc12_alias[i].code1 == code)
    390 	    {
    391 	      if (must_read)
    392 		{
    393 		  status = read_memory (memaddr + pos + 1,
    394 					&buffer[1], 1, info);
    395 		  if (status != 0)
    396 		    break;
    397 
    398 		  must_read = 1;
    399 		}
    400 	      if (m68hc12_alias[i].code2 == (unsigned char) buffer[1])
    401 		{
    402 		  (*info->fprintf_func) (info->stream, "%s",
    403 					 m68hc12_alias[i].name);
    404 		  return 2;
    405 		}
    406 	    }
    407 	}
    408     }
    409 
    410   pos++;
    411 
    412   /* Scan the opcode table until we find the opcode
    413      with the corresponding page.  */
    414   opcode = m68hc11_opcodes;
    415   for (i = 0; i < m68hc11_num_opcodes; i++, opcode++)
    416     {
    417       int offset;
    418       int pc_src_offset;
    419       int pc_dst_offset = 0;
    420 
    421       if ((opcode->arch & arch) == 0)
    422 	continue;
    423       if (opcode->opcode != code)
    424 	continue;
    425       if ((opcode->format & OP_PAGE_MASK) != format)
    426 	continue;
    427 
    428       if (opcode->format & M6812_OP_REG)
    429 	{
    430 	  int j;
    431 	  int is_jump;
    432 
    433 	  if (opcode->format & M6811_OP_JUMP_REL)
    434 	    is_jump = 1;
    435 	  else
    436 	    is_jump = 0;
    437 
    438 	  status = read_memory (memaddr + pos, &buffer[0], 1, info);
    439 	  if (status != 0)
    440 	    {
    441 	      return status;
    442 	    }
    443 	  for (j = 0; i + j < m68hc11_num_opcodes; j++)
    444 	    {
    445 	      if ((opcode[j].arch & arch) == 0)
    446 		continue;
    447 	      if (opcode[j].opcode != code)
    448 		continue;
    449 	      if (is_jump)
    450 		{
    451 		  if (!(opcode[j].format & M6811_OP_JUMP_REL))
    452 		    continue;
    453 
    454 		  if ((opcode[j].format & M6812_OP_IBCC_MARKER)
    455 		      && (buffer[0] & 0xc0) != 0x80)
    456 		    continue;
    457 		  if ((opcode[j].format & M6812_OP_TBCC_MARKER)
    458 		      && (buffer[0] & 0xc0) != 0x40)
    459 		    continue;
    460 		  if ((opcode[j].format & M6812_OP_DBCC_MARKER)
    461 		      && (buffer[0] & 0xc0) != 0)
    462 		    continue;
    463 		  if ((opcode[j].format & M6812_OP_EQ_MARKER)
    464 		      && (buffer[0] & 0x20) == 0)
    465 		    break;
    466 		  if (!(opcode[j].format & M6812_OP_EQ_MARKER)
    467 		      && (buffer[0] & 0x20) != 0)
    468 		    break;
    469 		  continue;
    470 		}
    471 	      if (opcode[j].format & M6812_OP_EXG_MARKER && buffer[0] & 0x80)
    472 		break;
    473 	      if ((opcode[j].format & M6812_OP_SEX_MARKER)
    474 		  && (((buffer[0] & 0x07) >= 3 && (buffer[0] & 7) <= 7))
    475 		  && ((buffer[0] & 0x0f0) <= 0x20))
    476 		break;
    477 	      if ((opcode[j].format & M6812_OP_SEX_MARKER)
    478 		  && (arch & cpu9s12x)
    479 		  && ((buffer[0] == 0x4d) || (buffer[0] == 0x4e)))
    480 		break;
    481 	      if (opcode[j].format & M6812_OP_TFR_MARKER
    482 		  && !(buffer[0] & 0x80))
    483 		break;
    484 	    }
    485 	  if (i + j < m68hc11_num_opcodes)
    486 	    opcode = &opcode[j];
    487 	}
    488 
    489       /* We have found the opcode.  Extract the operand and print it.  */
    490       (*info->fprintf_func) (info->stream, "%s", opcode->name);
    491 
    492       format = opcode->format;
    493       if (format & (M6811_OP_MASK | M6811_OP_BITMASK
    494 		    | M6811_OP_JUMP_REL | M6812_OP_JUMP_REL16))
    495 	{
    496 	  (*info->fprintf_func) (info->stream, "\t");
    497 	}
    498 
    499       /* The movb and movw must be handled in a special way...
    500 	 The source constant 'ii' is not always at the same place.
    501 	 This is the same for the destination for the post-indexed byte.
    502 	 The 'offset' is used to do the appropriate correction.
    503 
    504 	 offset          offset
    505 	 for constant     for destination
    506 	 movb   18 OB ii hh ll       0          0
    507 	 18 08 xb ii          1          -1
    508 	 18 08 xb ff ii       2          1  9 bit
    509 	 18 08 xb ee ff ii    3          1  16 bit
    510 	 18 0C hh ll hh ll    0          0
    511 	 18 09 xb hh ll       1          -1
    512 	 18 0D xb hh ll       0          0
    513 	 18 0A xb xb          0          0
    514 
    515 	 movw   18 03 jj kk hh ll    0          0
    516 	 18 00 xb jj kk       1          -1
    517 	 18 04 hh ll hh ll    0          0
    518 	 18 01 xb hh ll       1          -1
    519 	 18 05 xb hh ll       0          0
    520 	 18 02 xb xb          0          0
    521 
    522 	 After the source operand is read, the position 'pos' is incremented
    523 	 this explains the negative offset for destination.
    524 
    525 	 movb/movw above are the only instructions with this matching
    526 	 format.  */
    527       offset = ((format & M6812_OP_IDX_P2)
    528 		&& (format & (M6811_OP_IMM8 | M6811_OP_IMM16 |
    529 			      M6811_OP_IND16)));
    530 
    531       if (offset)
    532 	{
    533 	  /* Check xb to see position of data.  */
    534 	  status = read_memory (memaddr + pos, &buffer[0], 1, info);
    535 	  if (status != 0)
    536 	    {
    537 	      return status;
    538 	    }
    539 
    540 	  if (((buffer[0] & 0xe0) == 0xe0) && ((buffer[0] & 0x04) == 0))
    541 	    {
    542 	      /* 9 or 16 bit.  */
    543 	      if ((buffer[0] & 0x02) == 0)
    544 		{
    545 		  /* 9 bit.  */
    546 		  offset = 2;
    547 		}
    548 	      else
    549 		{
    550 		  /* 16 bit.  */
    551 		  offset = 3;
    552 		}
    553 	    }
    554 	}
    555 
    556       /* Operand with one more byte: - immediate, offset,
    557 	 direct-low address.  */
    558       if (format &
    559 	  (M6811_OP_IMM8 | M6811_OP_IX | M6811_OP_IY | M6811_OP_DIRECT))
    560 	{
    561 	  status = read_memory (memaddr + pos + offset, &buffer[0], 1, info);
    562 	  if (status != 0)
    563 	    return status;
    564 
    565 	  /* This movb/movw is special (see above).  */
    566 	  if (offset < 2)
    567 	    {
    568 	      offset = -offset;
    569 	      pc_dst_offset = 2;
    570 	    }
    571 	  else
    572 	    {
    573 	      offset = -1;
    574 	      pc_dst_offset = 5;
    575 	    }
    576 	  pos++;
    577 
    578 	  if (format & M6811_OP_IMM8)
    579 	    {
    580 	      (*info->fprintf_func) (info->stream, "#0x%x", (int) buffer[0]);
    581 	      format &= ~M6811_OP_IMM8;
    582 	      /* Set PC destination offset.  */
    583 	      pc_dst_offset = 1;
    584 	    }
    585 	  else if (format & M6811_OP_IX)
    586 	    {
    587 	      /* Offsets are in range 0..255, print them unsigned.  */
    588 	      (*info->fprintf_func) (info->stream, "0x%x,x", buffer[0] & 0x0FF);
    589 	      format &= ~M6811_OP_IX;
    590 	    }
    591 	  else if (format & M6811_OP_IY)
    592 	    {
    593 	      (*info->fprintf_func) (info->stream, "0x%x,y", buffer[0] & 0x0FF);
    594 	      format &= ~M6811_OP_IY;
    595 	    }
    596 	  else if (format & M6811_OP_DIRECT)
    597 	    {
    598 	      (*info->fprintf_func) (info->stream, "*");
    599 	      if (info->symtab_size > 0) /* Avoid duplicate 0x. */
    600 		(*info->fprintf_func) (info->stream, "0x");
    601 	      (*info->print_address_func) (buffer[0] & 0x0FF, info);
    602 	      format &= ~M6811_OP_DIRECT;
    603 	    }
    604 	}
    605 
    606 #define M6812_DST_MOVE  (M6812_OP_IND16_P2 | M6812_OP_IDX_P2)
    607 #define M6812_INDEXED_FLAGS (M6812_OP_IDX|M6812_OP_IDX_1|M6812_OP_IDX_2)
    608       /* Analyze the 68HC12 indexed byte.  */
    609       if (format & M6812_INDEXED_FLAGS)
    610 	{
    611 	  int indirect;
    612 	  bfd_vma endaddr;
    613 
    614 	  endaddr = memaddr + pos + 1;
    615 	  if (format & M6811_OP_IND16)
    616 	    endaddr += 2;
    617 	  pc_src_offset = -1;
    618 	  pc_dst_offset = 1;
    619 	  status = print_indexed_operand (memaddr + pos, info, &indirect,
    620 					  (format & M6812_DST_MOVE),
    621 					  pc_src_offset, endaddr, arch);
    622 	  if (status < 0)
    623 	    return status;
    624 
    625 	  pos += status;
    626 
    627 	  /* The indirect addressing mode of the call instruction does
    628 	     not need the page code.  */
    629 	  if ((format & M6812_OP_PAGE) && indirect)
    630 	    format &= ~M6812_OP_PAGE;
    631 	}
    632 
    633       /* 68HC12 dbcc/ibcc/tbcc operands.  */
    634       if ((format & M6812_OP_REG) && (format & M6811_OP_JUMP_REL))
    635 	{
    636 	  status = read_memory (memaddr + pos, &buffer[0], 2, info);
    637 	  if (status != 0)
    638 	    return status;
    639 
    640 	  (*info->fprintf_func) (info->stream, "%s,",
    641 				 reg_src_table[buffer[0] & 0x07]);
    642 	  sval = buffer[1] & 0x0ff;
    643 	  if (buffer[0] & 0x10)
    644 	    sval |= 0xff00;
    645 
    646 	  pos += 2;
    647 	  (*info->fprintf_func) (info->stream, "0x");
    648 	  (*info->print_address_func) (memaddr + pos + sval, info);
    649 	  format &= ~(M6812_OP_REG | M6811_OP_JUMP_REL);
    650 	}
    651       else if (format & (M6812_OP_REG | M6812_OP_REG_2))
    652 	{
    653 	  status = read_memory (memaddr + pos, &buffer[0], 1, info);
    654 	  if (status != 0)
    655 	    return status;
    656 
    657 	  pos++;
    658 	  (*info->fprintf_func) (info->stream, "%s,%s",
    659 				 reg_src_table[(buffer[0] >> 4) & 7],
    660 				 reg_dst_table[(buffer[0] & 7)]);
    661 	}
    662 
    663       if (format & (M6811_OP_IMM16 | M6811_OP_IND16))
    664 	{
    665 	  int val;
    666 	  bfd_vma addr;
    667 	  unsigned page = 0;
    668 
    669 	  status = read_memory (memaddr + pos + offset, &buffer[0], 2, info);
    670 	  if (status != 0)
    671 	    return status;
    672 
    673 	  if (format & M6812_OP_IDX_P2)
    674 	    offset = -2;
    675 	  else
    676 	    offset = 0;
    677 	  pos += 2;
    678 
    679 	  val = ((buffer[0] << 8) | (buffer[1] & 0x0FF));
    680 	  val &= 0x0FFFF;
    681 	  addr = val;
    682 	  pc_dst_offset = 2;
    683 	  if (format & M6812_OP_PAGE)
    684 	    {
    685 	      status = read_memory (memaddr + pos + offset, buffer, 1, info);
    686 	      if (status != 0)
    687 		return status;
    688 
    689 	      page = (unsigned) buffer[0];
    690 	      if (addr >= M68HC12_BANK_BASE && addr < 0x0c000)
    691 		addr = ((val - M68HC12_BANK_BASE)
    692 			| (page << M68HC12_BANK_SHIFT))
    693 		  + M68HC12_BANK_VIRT;
    694 	    }
    695 	  else if ((arch & cpu6812)
    696 		   && addr >= M68HC12_BANK_BASE && addr < 0x0c000)
    697 	    {
    698 	      int cur_page;
    699 	      bfd_vma vaddr;
    700 
    701 	      if (memaddr >= M68HC12_BANK_VIRT)
    702 		cur_page = ((memaddr - M68HC12_BANK_VIRT)
    703 			    >> M68HC12_BANK_SHIFT);
    704 	      else
    705 		cur_page = 0;
    706 
    707 	      vaddr = ((addr - M68HC12_BANK_BASE)
    708 		       + (cur_page << M68HC12_BANK_SHIFT))
    709 		+ M68HC12_BANK_VIRT;
    710 	      if (!info->symbol_at_address_func (addr, info)
    711 		  && info->symbol_at_address_func (vaddr, info))
    712 		addr = vaddr;
    713 	    }
    714 	  if (format & M6811_OP_IMM16)
    715 	    {
    716 	      format &= ~M6811_OP_IMM16;
    717 	      (*info->fprintf_func) (info->stream, "#");
    718 	    }
    719 	  else
    720 	    {
    721 	      format &= ~M6811_OP_IND16;
    722 	    }
    723 
    724 	  if (info->symtab_size > 0) /* Avoid duplicate 0x from core binutils. */
    725 	    (*info->fprintf_func) (info->stream, "0x");
    726 
    727 	  (*info->print_address_func) (addr, info);
    728 	  if (format & M6812_OP_PAGE)
    729 	    {
    730 	      (* info->fprintf_func) (info->stream, " {");
    731 	      if (info->symtab_size > 0) /* Avoid duplicate 0x from core binutils. */
    732 		(*info->fprintf_func) (info->stream, "0x");
    733 	      (* info->print_address_func) (val, info);
    734 	      (* info->fprintf_func) (info->stream, ", 0x%x}", page);
    735 	      format &= ~M6812_OP_PAGE;
    736 	      pos += 1;
    737 	    }
    738 	}
    739 
    740       if (format & M6812_OP_IDX_P2)
    741 	{
    742 	  (*info->fprintf_func) (info->stream, ", ");
    743 	  status = print_indexed_operand (memaddr + pos + offset, info,
    744 					  0, 1, pc_dst_offset,
    745 					  memaddr + pos + offset + 1, arch);
    746 	  if (status < 0)
    747 	    return status;
    748 	  pos += status;
    749 	}
    750 
    751       if (format & M6812_OP_IND16_P2)
    752 	{
    753 	  int val;
    754 
    755 	  (*info->fprintf_func) (info->stream, ", ");
    756 
    757 	  status = read_memory (memaddr + pos + offset, &buffer[0], 2, info);
    758 	  if (status != 0)
    759 	    return status;
    760 
    761 	  pos += 2;
    762 
    763 	  val = ((buffer[0] << 8) | (buffer[1] & 0x0FF));
    764 	  val &= 0x0FFFF;
    765 	  if (info->symtab_size > 0) /* Avoid duplicate 0x from core binutils. */
    766 	    (*info->fprintf_func) (info->stream, "0x");
    767 	  (*info->print_address_func) (val, info);
    768 	}
    769 
    770       /* M6811_OP_BITMASK and M6811_OP_JUMP_REL must be treated separately
    771 	 and in that order.  The brset/brclr insn have a bitmask and then
    772 	 a relative branch offset.  */
    773       if (format & M6811_OP_BITMASK)
    774 	{
    775 	  status = read_memory (memaddr + pos, &buffer[0], 1, info);
    776 	  if (status != 0)
    777 	    return status;
    778 
    779 	  pos++;
    780 	  (*info->fprintf_func) (info->stream, ", #0x%02x%s",
    781 				 buffer[0] & 0x0FF,
    782 				 (format & M6811_OP_JUMP_REL ? ", " : ""));
    783 	  format &= ~M6811_OP_BITMASK;
    784 	}
    785       if (format & M6811_OP_JUMP_REL)
    786 	{
    787 	  int val;
    788 
    789 	  status = read_memory (memaddr + pos, &buffer[0], 1, info);
    790 	  if (status != 0)
    791 	    return status;
    792 
    793 	  (*info->fprintf_func) (info->stream, "0x");
    794 	  pos++;
    795 	  val = (buffer[0] & 0x80) ? buffer[0] | 0xFFFFFF00 : buffer[0];
    796 	  (*info->print_address_func) (memaddr + pos + val, info);
    797 	  format &= ~M6811_OP_JUMP_REL;
    798 	}
    799       else if (format & M6812_OP_JUMP_REL16)
    800 	{
    801 	  int val;
    802 
    803 	  status = read_memory (memaddr + pos, &buffer[0], 2, info);
    804 	  if (status != 0)
    805 	    return status;
    806 
    807 	  pos += 2;
    808 	  val = ((buffer[0] << 8) | (buffer[1] & 0x0FF));
    809 	  if (val & 0x8000)
    810 	    val |= 0xffff0000;
    811 
    812 	  (*info->fprintf_func) (info->stream, "0x");
    813 	  (*info->print_address_func) (memaddr + pos + val, info);
    814 	  format &= ~M6812_OP_JUMP_REL16;
    815 	}
    816 
    817       if (format & M6812_OP_PAGE)
    818 	{
    819 	  int val;
    820 
    821 	  status = read_memory (memaddr + pos + offset, &buffer[0], 1, info);
    822 	  if (status != 0)
    823 	    return status;
    824 
    825 	  pos += 1;
    826 
    827 	  val = buffer[0] & 0x0ff;
    828 	  (*info->fprintf_func) (info->stream, ", 0x%x", val);
    829 	}
    830 
    831 #ifdef DEBUG
    832       /* Consistency check.  'format' must be 0, so that we have handled
    833 	 all formats; and the computed size of the insn must match the
    834 	 opcode table content.  */
    835       if (format & ~(M6811_OP_PAGE4 | M6811_OP_PAGE3 | M6811_OP_PAGE2))
    836 	(*info->fprintf_func) (info->stream, "; Error, format: %lx", format);
    837 
    838       if (pos != opcode->size)
    839 	(*info->fprintf_func) (info->stream, "; Error, size: %ld expect %d",
    840 			       pos, opcode->size);
    841 #endif
    842       return pos;
    843     }
    844 
    845   /* Opcode not recognized.  */
    846   if (format == M6811_OP_PAGE2 && arch & cpu6812
    847       && ((code >= 0x30 && code <= 0x39) || (code >= 0x40)))
    848     (*info->fprintf_func) (info->stream, "trap\t#0x%02x", code & 0x0ff);
    849 
    850   else if (format == M6811_OP_PAGE2)
    851     (*info->fprintf_func) (info->stream, ".byte\t0x%02x, 0x%02x",
    852 			   M6811_OPCODE_PAGE2, code);
    853   else if (format == M6811_OP_PAGE3)
    854     (*info->fprintf_func) (info->stream, ".byte\t0x%02x, 0x%02x",
    855 			   M6811_OPCODE_PAGE3, code);
    856   else if (format == M6811_OP_PAGE4)
    857     (*info->fprintf_func) (info->stream, ".byte\t0x%02x, 0x%02x",
    858 			   M6811_OPCODE_PAGE4, code);
    859   else
    860     (*info->fprintf_func) (info->stream, ".byte\t0x%02x", code);
    861 
    862   return pos;
    863 }
    864 
    865 /* Disassemble one instruction at address 'memaddr'.  Returns the number
    866    of bytes used by that instruction.  */
    867 int
    868 print_insn_m68hc11 (bfd_vma memaddr, struct disassemble_info* info)
    869 {
    870   return print_insn (memaddr, info, cpu6811);
    871 }
    872 
    873 int
    874 print_insn_m68hc12 (bfd_vma memaddr, struct disassemble_info* info)
    875 {
    876   return print_insn (memaddr, info, cpu6812);
    877 }
    878 
    879 int
    880 print_insn_m9s12x (bfd_vma memaddr, struct disassemble_info* info)
    881 {
    882   return print_insn (memaddr, info, cpu6812|cpu9s12x);
    883 }
    884 
    885 int
    886 print_insn_m9s12xg (bfd_vma memaddr, struct disassemble_info* info)
    887 {
    888   return print_insn (memaddr, info, cpuxgate);
    889 }
    890