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