m68hc11-dis.c revision 1.1
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
32static const char *const reg_name[] =
33{
34  "X", "Y", "SP", "PC"
35};
36
37static const char *const reg_src_table[] =
38{
39  "A", "B", "CCR", "TMP3", "D", "X", "Y", "SP"
40};
41
42static 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.  */
50static int read_memory (bfd_vma, bfd_byte *, int, struct disassemble_info *);
51static int print_indexed_operand (bfd_vma, struct disassemble_info *,
52                                  int*, int, int, bfd_vma, int);
53static int print_insn (bfd_vma, struct disassemble_info *, int);
54
55static int
56read_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.  */
75static int
76print_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.  */
235static int
236print_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.  */
868int
869print_insn_m68hc11 (bfd_vma memaddr, struct disassemble_info* info)
870{
871  return print_insn (memaddr, info, cpu6811);
872}
873
874int
875print_insn_m68hc12 (bfd_vma memaddr, struct disassemble_info* info)
876{
877  return print_insn (memaddr, info, cpu6812);
878}
879
880int
881print_insn_m9s12x (bfd_vma memaddr, struct disassemble_info* info)
882{
883  return print_insn (memaddr, info, cpu6812|cpu9s12x);
884}
885
886int
887print_insn_m9s12xg (bfd_vma memaddr, struct disassemble_info* info)
888{
889  return print_insn (memaddr, info, cpuxgate);
890}
891