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