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