1/* m68hc11-dis.c -- Motorola 68HC11 & 68HC12 disassembly
2   Copyright 1999, 2000, 2001, 2002, 2003, 2006, 2007
3   Free Software Foundation, Inc.
4   Written by Stephane Carrez (stcarrez@nerim.fr)
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 <stdio.h>
24
25#include "ansidecl.h"
26#include "opcode/m68hc11.h"
27#include "dis-asm.h"
28
29#define PC_REGNUM 3
30
31static const char *const reg_name[] = {
32  "X", "Y", "SP", "PC"
33};
34
35static const char *const reg_src_table[] = {
36  "A", "B", "CCR", "TMP3", "D", "X", "Y", "SP"
37};
38
39static const char *const reg_dst_table[] = {
40  "A", "B", "CCR", "TMP2", "D", "X", "Y", "SP"
41};
42
43#define OP_PAGE_MASK (M6811_OP_PAGE2|M6811_OP_PAGE3|M6811_OP_PAGE4)
44
45/* Prototypes for local functions.  */
46static int read_memory (bfd_vma, bfd_byte *, int, struct disassemble_info *);
47static int print_indexed_operand (bfd_vma, struct disassemble_info *,
48                                  int*, int, int, bfd_vma);
49static int print_insn (bfd_vma, struct disassemble_info *, int);
50
51static int
52read_memory (bfd_vma memaddr, bfd_byte* buffer, int size,
53             struct disassemble_info* info)
54{
55  int status;
56
57  /* Get first byte.  Only one at a time because we don't know the
58     size of the insn.  */
59  status = (*info->read_memory_func) (memaddr, buffer, size, info);
60  if (status != 0)
61    {
62      (*info->memory_error_func) (status, memaddr, info);
63      return -1;
64    }
65  return 0;
66}
67
68
69/* Read the 68HC12 indexed operand byte and print the corresponding mode.
70   Returns the number of bytes read or -1 if failure.  */
71static int
72print_indexed_operand (bfd_vma memaddr, struct disassemble_info* info,
73                       int* indirect, int mov_insn, int pc_offset,
74                       bfd_vma endaddr)
75{
76  bfd_byte buffer[4];
77  int reg;
78  int status;
79  short sval;
80  int pos = 1;
81
82  if (indirect)
83    *indirect = 0;
84
85  status = read_memory (memaddr, &buffer[0], 1, info);
86  if (status != 0)
87    {
88      return status;
89    }
90
91  /* n,r with 5-bits signed constant.  */
92  if ((buffer[0] & 0x20) == 0)
93    {
94      reg = (buffer[0] >> 6) & 3;
95      sval = (buffer[0] & 0x1f);
96      if (sval & 0x10)
97	sval |= 0xfff0;
98      /* 68HC12 requires an adjustment for movb/movw pc relative modes.  */
99      if (reg == PC_REGNUM && info->mach == bfd_mach_m6812 && mov_insn)
100        sval += pc_offset;
101      (*info->fprintf_func) (info->stream, "%d,%s",
102			     (int) sval, reg_name[reg]);
103
104      if (reg == PC_REGNUM)
105        {
106          (* info->fprintf_func) (info->stream, " {");
107          (* info->print_address_func) (endaddr + sval, info);
108          (* info->fprintf_func) (info->stream, "}");
109        }
110    }
111
112  /* Auto pre/post increment/decrement.  */
113  else if ((buffer[0] & 0xc0) != 0xc0)
114    {
115      const char *mode;
116
117      reg = (buffer[0] >> 6) & 3;
118      sval = (buffer[0] & 0x0f);
119      if (sval & 0x8)
120	{
121	  sval |= 0xfff0;
122	  sval = -sval;
123	  mode = "-";
124	}
125      else
126	{
127	  sval = sval + 1;
128	  mode = "+";
129	}
130      (*info->fprintf_func) (info->stream, "%d,%s%s%s",
131			     (int) sval,
132			     (buffer[0] & 0x10 ? "" : mode),
133			     reg_name[reg], (buffer[0] & 0x10 ? mode : ""));
134    }
135
136  /* [n,r] 16-bits offset indexed indirect.  */
137  else if ((buffer[0] & 0x07) == 3)
138    {
139      if (mov_insn)
140	{
141	  (*info->fprintf_func) (info->stream, "<invalid op: 0x%x>",
142				 buffer[0] & 0x0ff);
143	  return 0;
144	}
145      reg = (buffer[0] >> 3) & 0x03;
146      status = read_memory (memaddr + pos, &buffer[0], 2, info);
147      if (status != 0)
148	{
149	  return status;
150	}
151
152      pos += 2;
153      sval = ((buffer[0] << 8) | (buffer[1] & 0x0FF));
154      (*info->fprintf_func) (info->stream, "[%u,%s]",
155			     sval & 0x0ffff, reg_name[reg]);
156      if (indirect)
157        *indirect = 1;
158    }
159
160  /* n,r with 9 and 16 bit signed constant.  */
161  else if ((buffer[0] & 0x4) == 0)
162    {
163      if (mov_insn)
164	{
165	  (*info->fprintf_func) (info->stream, "<invalid op: 0x%x>",
166				 buffer[0] & 0x0ff);
167	  return 0;
168	}
169      reg = (buffer[0] >> 3) & 0x03;
170      status = read_memory (memaddr + pos,
171			    &buffer[1], (buffer[0] & 0x2 ? 2 : 1), info);
172      if (status != 0)
173	{
174	  return status;
175	}
176      if (buffer[0] & 2)
177	{
178	  sval = ((buffer[1] << 8) | (buffer[2] & 0x0FF));
179	  sval &= 0x0FFFF;
180	  pos += 2;
181          endaddr += 2;
182	}
183      else
184	{
185	  sval = buffer[1] & 0x00ff;
186	  if (buffer[0] & 0x01)
187	    sval |= 0xff00;
188	  pos++;
189          endaddr++;
190	}
191      (*info->fprintf_func) (info->stream, "%d,%s",
192			     (int) sval, reg_name[reg]);
193      if (reg == PC_REGNUM)
194        {
195          (* info->fprintf_func) (info->stream, " {");
196          (* info->print_address_func) (endaddr + sval, info);
197          (* info->fprintf_func) (info->stream, "}");
198        }
199    }
200  else
201    {
202      reg = (buffer[0] >> 3) & 0x03;
203      switch (buffer[0] & 3)
204	{
205	case 0:
206	  (*info->fprintf_func) (info->stream, "A,%s", reg_name[reg]);
207	  break;
208	case 1:
209	  (*info->fprintf_func) (info->stream, "B,%s", reg_name[reg]);
210	  break;
211	case 2:
212	  (*info->fprintf_func) (info->stream, "D,%s", reg_name[reg]);
213	  break;
214	case 3:
215	default:
216	  (*info->fprintf_func) (info->stream, "[D,%s]", reg_name[reg]);
217          if (indirect)
218            *indirect = 1;
219	  break;
220	}
221    }
222
223  return pos;
224}
225
226/* Disassemble one instruction at address 'memaddr'.  Returns the number
227   of bytes used by that instruction.  */
228static int
229print_insn (bfd_vma memaddr, struct disassemble_info* info, int arch)
230{
231  int status;
232  bfd_byte buffer[4];
233  unsigned char code;
234  long format, pos, i;
235  short sval;
236  const struct m68hc11_opcode *opcode;
237
238  /* Get first byte.  Only one at a time because we don't know the
239     size of the insn.  */
240  status = read_memory (memaddr, buffer, 1, info);
241  if (status != 0)
242    {
243      return status;
244    }
245
246  format = 0;
247  code = buffer[0];
248  pos = 0;
249
250  /* Look for page2,3,4 opcodes.  */
251  if (code == M6811_OPCODE_PAGE2)
252    {
253      pos++;
254      format = M6811_OP_PAGE2;
255    }
256  else if (code == M6811_OPCODE_PAGE3 && arch == cpu6811)
257    {
258      pos++;
259      format = M6811_OP_PAGE3;
260    }
261  else if (code == M6811_OPCODE_PAGE4 && arch == cpu6811)
262    {
263      pos++;
264      format = M6811_OP_PAGE4;
265    }
266
267  /* We are in page2,3,4; get the real opcode.  */
268  if (pos == 1)
269    {
270      status = read_memory (memaddr + pos, &buffer[1], 1, info);
271      if (status != 0)
272	{
273	  return status;
274	}
275      code = buffer[1];
276    }
277
278
279  /* Look first for a 68HC12 alias.  All of them are 2-bytes long and
280     in page 1.  There is no operand to print.  We read the second byte
281     only when we have a possible match.  */
282  if ((arch & cpu6812) && format == 0)
283    {
284      int must_read = 1;
285
286      /* Walk the alias table to find a code1+code2 match.  */
287      for (i = 0; i < m68hc12_num_alias; i++)
288	{
289	  if (m68hc12_alias[i].code1 == code)
290	    {
291	      if (must_read)
292		{
293		  status = read_memory (memaddr + pos + 1,
294					&buffer[1], 1, info);
295		  if (status != 0)
296		    break;
297
298		  must_read = 1;
299		}
300	      if (m68hc12_alias[i].code2 == (unsigned char) buffer[1])
301		{
302		  (*info->fprintf_func) (info->stream, "%s",
303					 m68hc12_alias[i].name);
304		  return 2;
305		}
306	    }
307	}
308    }
309
310  pos++;
311
312  /* Scan the opcode table until we find the opcode
313     with the corresponding page.  */
314  opcode = m68hc11_opcodes;
315  for (i = 0; i < m68hc11_num_opcodes; i++, opcode++)
316    {
317      int offset;
318      int pc_src_offset;
319      int pc_dst_offset = 0;
320
321      if ((opcode->arch & arch) == 0)
322	continue;
323      if (opcode->opcode != code)
324	continue;
325      if ((opcode->format & OP_PAGE_MASK) != format)
326	continue;
327
328      if (opcode->format & M6812_OP_REG)
329	{
330	  int j;
331	  int is_jump;
332
333	  if (opcode->format & M6811_OP_JUMP_REL)
334	    is_jump = 1;
335	  else
336	    is_jump = 0;
337
338	  status = read_memory (memaddr + pos, &buffer[0], 1, info);
339	  if (status != 0)
340	    {
341	      return status;
342	    }
343	  for (j = 0; i + j < m68hc11_num_opcodes; j++)
344	    {
345	      if ((opcode[j].arch & arch) == 0)
346		continue;
347	      if (opcode[j].opcode != code)
348		continue;
349	      if (is_jump)
350		{
351		  if (!(opcode[j].format & M6811_OP_JUMP_REL))
352		    continue;
353
354		  if ((opcode[j].format & M6812_OP_IBCC_MARKER)
355		      && (buffer[0] & 0xc0) != 0x80)
356		    continue;
357		  if ((opcode[j].format & M6812_OP_TBCC_MARKER)
358		      && (buffer[0] & 0xc0) != 0x40)
359		    continue;
360		  if ((opcode[j].format & M6812_OP_DBCC_MARKER)
361		      && (buffer[0] & 0xc0) != 0)
362		    continue;
363		  if ((opcode[j].format & M6812_OP_EQ_MARKER)
364		      && (buffer[0] & 0x20) == 0)
365		    break;
366		  if (!(opcode[j].format & M6812_OP_EQ_MARKER)
367		      && (buffer[0] & 0x20) != 0)
368		    break;
369		  continue;
370		}
371	      if (opcode[j].format & M6812_OP_EXG_MARKER && buffer[0] & 0x80)
372		break;
373	      if ((opcode[j].format & M6812_OP_SEX_MARKER)
374		  && (((buffer[0] & 0x07) >= 3 && (buffer[0] & 7) <= 7))
375		  && ((buffer[0] & 0x0f0) <= 0x20))
376		break;
377	      if (opcode[j].format & M6812_OP_TFR_MARKER
378		  && !(buffer[0] & 0x80))
379		break;
380	    }
381	  if (i + j < m68hc11_num_opcodes)
382	    opcode = &opcode[j];
383	}
384
385      /* We have found the opcode.  Extract the operand and print it.  */
386      (*info->fprintf_func) (info->stream, "%s", opcode->name);
387
388      format = opcode->format;
389      if (format & (M6811_OP_MASK | M6811_OP_BITMASK
390		    | M6811_OP_JUMP_REL | M6812_OP_JUMP_REL16))
391	{
392	  (*info->fprintf_func) (info->stream, "\t");
393	}
394
395      /* The movb and movw must be handled in a special way...
396         The source constant 'ii' is not always at the same place.
397         This is the same for the destination for the post-indexed byte.
398         The 'offset' is used to do the appropriate correction.
399
400                                   offset          offset
401                              for constant     for destination
402         movb   18 OB ii hh ll       0          0
403                18 08 xb ii          1          -1
404                18 0C hh ll hh ll    0          0
405                18 09 xb hh ll       1          -1
406                18 0D xb hh ll       0          0
407                18 0A xb xb          0          0
408
409         movw   18 03 jj kk hh ll    0          0
410                18 00 xb jj kk       1          -1
411                18 04 hh ll hh ll    0          0
412                18 01 xb hh ll       1          -1
413                18 05 xb hh ll       0          0
414                18 02 xb xb          0          0
415
416         After the source operand is read, the position 'pos' is incremented
417         this explains the negative offset for destination.
418
419         movb/movw above are the only instructions with this matching
420         format.  */
421      offset = ((format & M6812_OP_IDX_P2)
422                && (format & (M6811_OP_IMM8 | M6811_OP_IMM16 |
423                              M6811_OP_IND16)));
424
425      /* Operand with one more byte: - immediate, offset,
426         direct-low address.  */
427      if (format &
428	  (M6811_OP_IMM8 | M6811_OP_IX | M6811_OP_IY | M6811_OP_DIRECT))
429	{
430	  status = read_memory (memaddr + pos + offset, &buffer[0], 1, info);
431	  if (status != 0)
432	    {
433	      return status;
434	    }
435
436	  pos++;
437
438          /* This movb/movw is special (see above).  */
439          offset = -offset;
440
441          pc_dst_offset = 2;
442	  if (format & M6811_OP_IMM8)
443	    {
444	      (*info->fprintf_func) (info->stream, "#%d", (int) buffer[0]);
445	      format &= ~M6811_OP_IMM8;
446              /* Set PC destination offset.  */
447              pc_dst_offset = 1;
448	    }
449	  else if (format & M6811_OP_IX)
450	    {
451	      /* Offsets are in range 0..255, print them unsigned.  */
452	      (*info->fprintf_func) (info->stream, "%u,x", buffer[0] & 0x0FF);
453	      format &= ~M6811_OP_IX;
454	    }
455	  else if (format & M6811_OP_IY)
456	    {
457	      (*info->fprintf_func) (info->stream, "%u,y", buffer[0] & 0x0FF);
458	      format &= ~M6811_OP_IY;
459	    }
460	  else if (format & M6811_OP_DIRECT)
461	    {
462	      (*info->fprintf_func) (info->stream, "*");
463	      (*info->print_address_func) (buffer[0] & 0x0FF, info);
464	      format &= ~M6811_OP_DIRECT;
465	    }
466	}
467
468#define M6812_DST_MOVE  (M6812_OP_IND16_P2 | M6812_OP_IDX_P2)
469#define M6812_INDEXED_FLAGS (M6812_OP_IDX|M6812_OP_IDX_1|M6812_OP_IDX_2)
470      /* Analyze the 68HC12 indexed byte.  */
471      if (format & M6812_INDEXED_FLAGS)
472	{
473          int indirect;
474          bfd_vma endaddr;
475
476          endaddr = memaddr + pos + 1;
477          if (format & M6811_OP_IND16)
478            endaddr += 2;
479          pc_src_offset = -1;
480          pc_dst_offset = 1;
481	  status = print_indexed_operand (memaddr + pos, info, &indirect,
482                                          (format & M6812_DST_MOVE),
483                                          pc_src_offset, endaddr);
484	  if (status < 0)
485	    {
486	      return status;
487	    }
488	  pos += status;
489
490          /* The indirect addressing mode of the call instruction does
491             not need the page code.  */
492          if ((format & M6812_OP_PAGE) && indirect)
493            format &= ~M6812_OP_PAGE;
494	}
495
496      /* 68HC12 dbcc/ibcc/tbcc operands.  */
497      if ((format & M6812_OP_REG) && (format & M6811_OP_JUMP_REL))
498	{
499	  status = read_memory (memaddr + pos, &buffer[0], 2, info);
500	  if (status != 0)
501	    {
502	      return status;
503	    }
504	  (*info->fprintf_func) (info->stream, "%s,",
505				 reg_src_table[buffer[0] & 0x07]);
506	  sval = buffer[1] & 0x0ff;
507	  if (buffer[0] & 0x10)
508	    sval |= 0xff00;
509
510	  pos += 2;
511	  (*info->print_address_func) (memaddr + pos + sval, info);
512	  format &= ~(M6812_OP_REG | M6811_OP_JUMP_REL);
513	}
514      else if (format & (M6812_OP_REG | M6812_OP_REG_2))
515	{
516	  status = read_memory (memaddr + pos, &buffer[0], 1, info);
517	  if (status != 0)
518	    {
519	      return status;
520	    }
521
522	  pos++;
523	  (*info->fprintf_func) (info->stream, "%s,%s",
524				 reg_src_table[(buffer[0] >> 4) & 7],
525				 reg_dst_table[(buffer[0] & 7)]);
526	}
527
528      if (format & (M6811_OP_IMM16 | M6811_OP_IND16))
529	{
530	  int val;
531          bfd_vma addr;
532          unsigned page = 0;
533
534	  status = read_memory (memaddr + pos + offset, &buffer[0], 2, info);
535	  if (status != 0)
536	    {
537	      return status;
538	    }
539	  if (format & M6812_OP_IDX_P2)
540	    offset = -2;
541	  else
542	    offset = 0;
543	  pos += 2;
544
545	  val = ((buffer[0] << 8) | (buffer[1] & 0x0FF));
546	  val &= 0x0FFFF;
547          addr = val;
548          pc_dst_offset = 2;
549          if (format & M6812_OP_PAGE)
550            {
551              status = read_memory (memaddr + pos + offset, buffer, 1, info);
552              if (status != 0)
553                return status;
554
555              page = (unsigned) buffer[0];
556              if (addr >= M68HC12_BANK_BASE && addr < 0x0c000)
557                addr = ((val - M68HC12_BANK_BASE)
558                        | (page << M68HC12_BANK_SHIFT))
559                   + M68HC12_BANK_VIRT;
560            }
561          else if ((arch & cpu6812)
562                   && addr >= M68HC12_BANK_BASE && addr < 0x0c000)
563             {
564                int cur_page;
565                bfd_vma vaddr;
566
567                if (memaddr >= M68HC12_BANK_VIRT)
568                   cur_page = ((memaddr - M68HC12_BANK_VIRT)
569                               >> M68HC12_BANK_SHIFT);
570                else
571                   cur_page = 0;
572
573                vaddr = ((addr - M68HC12_BANK_BASE)
574                         + (cur_page << M68HC12_BANK_SHIFT))
575                   + M68HC12_BANK_VIRT;
576                if (!info->symbol_at_address_func (addr, info)
577                    && info->symbol_at_address_func (vaddr, info))
578                   addr = vaddr;
579             }
580	  if (format & M6811_OP_IMM16)
581	    {
582	      format &= ~M6811_OP_IMM16;
583	      (*info->fprintf_func) (info->stream, "#");
584	    }
585	  else
586	    format &= ~M6811_OP_IND16;
587
588	  (*info->print_address_func) (addr, info);
589          if (format & M6812_OP_PAGE)
590            {
591              (* info->fprintf_func) (info->stream, " {");
592              (* info->print_address_func) (val, info);
593              (* info->fprintf_func) (info->stream, ", %d}", page);
594              format &= ~M6812_OP_PAGE;
595              pos += 1;
596            }
597	}
598
599      if (format & M6812_OP_IDX_P2)
600	{
601	  (*info->fprintf_func) (info->stream, ", ");
602	  status = print_indexed_operand (memaddr + pos + offset, info,
603                                          0, 1, pc_dst_offset,
604                                          memaddr + pos + offset + 1);
605	  if (status < 0)
606	    return status;
607	  pos += status;
608	}
609
610      if (format & M6812_OP_IND16_P2)
611	{
612	  int val;
613
614	  (*info->fprintf_func) (info->stream, ", ");
615
616	  status = read_memory (memaddr + pos + offset, &buffer[0], 2, info);
617	  if (status != 0)
618	    {
619	      return status;
620	    }
621	  pos += 2;
622
623	  val = ((buffer[0] << 8) | (buffer[1] & 0x0FF));
624	  val &= 0x0FFFF;
625	  (*info->print_address_func) (val, info);
626	}
627
628      /* M6811_OP_BITMASK and M6811_OP_JUMP_REL must be treated separately
629         and in that order.  The brset/brclr insn have a bitmask and then
630         a relative branch offset.  */
631      if (format & M6811_OP_BITMASK)
632	{
633	  status = read_memory (memaddr + pos, &buffer[0], 1, info);
634	  if (status != 0)
635	    {
636	      return status;
637	    }
638	  pos++;
639	  (*info->fprintf_func) (info->stream, " #$%02x%s",
640				 buffer[0] & 0x0FF,
641				 (format & M6811_OP_JUMP_REL ? " " : ""));
642	  format &= ~M6811_OP_BITMASK;
643	}
644      if (format & M6811_OP_JUMP_REL)
645	{
646	  int val;
647
648	  status = read_memory (memaddr + pos, &buffer[0], 1, info);
649	  if (status != 0)
650	    {
651	      return status;
652	    }
653
654	  pos++;
655	  val = (buffer[0] & 0x80) ? buffer[0] | 0xFFFFFF00 : buffer[0];
656	  (*info->print_address_func) (memaddr + pos + val, info);
657	  format &= ~M6811_OP_JUMP_REL;
658	}
659      else if (format & M6812_OP_JUMP_REL16)
660	{
661	  int val;
662
663	  status = read_memory (memaddr + pos, &buffer[0], 2, info);
664	  if (status != 0)
665	    {
666	      return status;
667	    }
668
669	  pos += 2;
670	  val = ((buffer[0] << 8) | (buffer[1] & 0x0FF));
671	  if (val & 0x8000)
672	    val |= 0xffff0000;
673
674	  (*info->print_address_func) (memaddr + pos + val, info);
675	  format &= ~M6812_OP_JUMP_REL16;
676	}
677
678      if (format & M6812_OP_PAGE)
679	{
680	  int val;
681
682	  status = read_memory (memaddr + pos + offset, &buffer[0], 1, info);
683	  if (status != 0)
684	    {
685	      return status;
686	    }
687	  pos += 1;
688
689	  val = buffer[0] & 0x0ff;
690	  (*info->fprintf_func) (info->stream, ", %d", val);
691	}
692
693#ifdef DEBUG
694      /* Consistency check.  'format' must be 0, so that we have handled
695         all formats; and the computed size of the insn must match the
696         opcode table content.  */
697      if (format & ~(M6811_OP_PAGE4 | M6811_OP_PAGE3 | M6811_OP_PAGE2))
698	{
699	  (*info->fprintf_func) (info->stream, "; Error, format: %lx", format);
700	}
701      if (pos != opcode->size)
702	{
703	  (*info->fprintf_func) (info->stream, "; Error, size: %ld expect %d",
704				 pos, opcode->size);
705	}
706#endif
707      return pos;
708    }
709
710  /* Opcode not recognized.  */
711  if (format == M6811_OP_PAGE2 && arch & cpu6812
712      && ((code >= 0x30 && code <= 0x39) || (code >= 0x40)))
713    (*info->fprintf_func) (info->stream, "trap\t#%d", code & 0x0ff);
714
715  else if (format == M6811_OP_PAGE2)
716    (*info->fprintf_func) (info->stream, ".byte\t0x%02x, 0x%02x",
717			   M6811_OPCODE_PAGE2, code);
718  else if (format == M6811_OP_PAGE3)
719    (*info->fprintf_func) (info->stream, ".byte\t0x%02x, 0x%02x",
720			   M6811_OPCODE_PAGE3, code);
721  else if (format == M6811_OP_PAGE4)
722    (*info->fprintf_func) (info->stream, ".byte\t0x%02x, 0x%02x",
723			   M6811_OPCODE_PAGE4, code);
724  else
725    (*info->fprintf_func) (info->stream, ".byte\t0x%02x", code);
726
727  return pos;
728}
729
730/* Disassemble one instruction at address 'memaddr'.  Returns the number
731   of bytes used by that instruction.  */
732int
733print_insn_m68hc11 (bfd_vma memaddr, struct disassemble_info* info)
734{
735  return print_insn (memaddr, info, cpu6811);
736}
737
738int
739print_insn_m68hc12 (bfd_vma memaddr, struct disassemble_info* info)
740{
741  return print_insn (memaddr, info, cpu6812);
742}
743