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