15f210c2aSfgsch /* m68hc11-dis.c -- Motorola 68HC11 & 68HC12 disassembly
2*cf2f2c56Smiod Copyright 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
3d2201f2fSdrahn Written by Stephane Carrez (stcarrez@nerim.fr)
45f210c2aSfgsch
55f210c2aSfgsch This program is free software; you can redistribute it and/or modify
65f210c2aSfgsch it under the terms of the GNU General Public License as published by
75f210c2aSfgsch the Free Software Foundation; either version 2 of the License, or
85f210c2aSfgsch (at your option) any later version.
95f210c2aSfgsch
105f210c2aSfgsch This program is distributed in the hope that it will be useful,
115f210c2aSfgsch but WITHOUT ANY WARRANTY; without even the implied warranty of
125f210c2aSfgsch MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
135f210c2aSfgsch GNU General Public License for more details.
145f210c2aSfgsch
155f210c2aSfgsch You should have received a copy of the GNU General Public License
165f210c2aSfgsch along with this program; if not, write to the Free Software
175f210c2aSfgsch Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
185f210c2aSfgsch
195f210c2aSfgsch #include <stdio.h>
205f210c2aSfgsch
215f210c2aSfgsch #include "ansidecl.h"
225f210c2aSfgsch #include "opcode/m68hc11.h"
235f210c2aSfgsch #include "dis-asm.h"
245f210c2aSfgsch
25d2201f2fSdrahn #define PC_REGNUM 3
26d2201f2fSdrahn
275f210c2aSfgsch static const char *const reg_name[] = {
285f210c2aSfgsch "X", "Y", "SP", "PC"
295f210c2aSfgsch };
305f210c2aSfgsch
315f210c2aSfgsch static const char *const reg_src_table[] = {
325f210c2aSfgsch "A", "B", "CCR", "TMP3", "D", "X", "Y", "SP"
335f210c2aSfgsch };
345f210c2aSfgsch
355f210c2aSfgsch static const char *const reg_dst_table[] = {
365f210c2aSfgsch "A", "B", "CCR", "TMP2", "D", "X", "Y", "SP"
375f210c2aSfgsch };
385f210c2aSfgsch
395f210c2aSfgsch #define OP_PAGE_MASK (M6811_OP_PAGE2|M6811_OP_PAGE3|M6811_OP_PAGE4)
405f210c2aSfgsch
41d2201f2fSdrahn /* Prototypes for local functions. */
42*cf2f2c56Smiod static int read_memory (bfd_vma, bfd_byte *, int, struct disassemble_info *);
43*cf2f2c56Smiod static int print_indexed_operand (bfd_vma, struct disassemble_info *,
44*cf2f2c56Smiod int*, int, int, bfd_vma);
45*cf2f2c56Smiod static int print_insn (bfd_vma, struct disassemble_info *, int);
46d2201f2fSdrahn
475f210c2aSfgsch static int
read_memory(bfd_vma memaddr,bfd_byte * buffer,int size,struct disassemble_info * info)48*cf2f2c56Smiod read_memory (bfd_vma memaddr, bfd_byte* buffer, int size,
49*cf2f2c56Smiod struct disassemble_info* info)
505f210c2aSfgsch {
515f210c2aSfgsch int status;
525f210c2aSfgsch
535f210c2aSfgsch /* Get first byte. Only one at a time because we don't know the
545f210c2aSfgsch size of the insn. */
555f210c2aSfgsch status = (*info->read_memory_func) (memaddr, buffer, size, info);
565f210c2aSfgsch if (status != 0)
575f210c2aSfgsch {
585f210c2aSfgsch (*info->memory_error_func) (status, memaddr, info);
595f210c2aSfgsch return -1;
605f210c2aSfgsch }
615f210c2aSfgsch return 0;
625f210c2aSfgsch }
635f210c2aSfgsch
645f210c2aSfgsch
655f210c2aSfgsch /* Read the 68HC12 indexed operand byte and print the corresponding mode.
665f210c2aSfgsch Returns the number of bytes read or -1 if failure. */
675f210c2aSfgsch static int
print_indexed_operand(bfd_vma memaddr,struct disassemble_info * info,int * indirect,int mov_insn,int pc_offset,bfd_vma endaddr)68*cf2f2c56Smiod print_indexed_operand (bfd_vma memaddr, struct disassemble_info* info,
69*cf2f2c56Smiod int* indirect, int mov_insn, int pc_offset,
70*cf2f2c56Smiod bfd_vma endaddr)
715f210c2aSfgsch {
725f210c2aSfgsch bfd_byte buffer[4];
735f210c2aSfgsch int reg;
745f210c2aSfgsch int status;
755f210c2aSfgsch short sval;
765f210c2aSfgsch int pos = 1;
775f210c2aSfgsch
78d2201f2fSdrahn if (indirect)
79d2201f2fSdrahn *indirect = 0;
80d2201f2fSdrahn
815f210c2aSfgsch status = read_memory (memaddr, &buffer[0], 1, info);
825f210c2aSfgsch if (status != 0)
835f210c2aSfgsch {
845f210c2aSfgsch return status;
855f210c2aSfgsch }
865f210c2aSfgsch
875f210c2aSfgsch /* n,r with 5-bits signed constant. */
885f210c2aSfgsch if ((buffer[0] & 0x20) == 0)
895f210c2aSfgsch {
905f210c2aSfgsch reg = (buffer[0] >> 6) & 3;
915f210c2aSfgsch sval = (buffer[0] & 0x1f);
925f210c2aSfgsch if (sval & 0x10)
935f210c2aSfgsch sval |= 0xfff0;
94d2201f2fSdrahn /* 68HC12 requires an adjustment for movb/movw pc relative modes. */
95d2201f2fSdrahn if (reg == PC_REGNUM && info->mach == bfd_mach_m6812 && mov_insn)
96d2201f2fSdrahn sval += pc_offset;
975f210c2aSfgsch (*info->fprintf_func) (info->stream, "%d,%s",
985f210c2aSfgsch (int) sval, reg_name[reg]);
99d2201f2fSdrahn
100d2201f2fSdrahn if (reg == PC_REGNUM)
101d2201f2fSdrahn {
102d2201f2fSdrahn (* info->fprintf_func) (info->stream, " {");
103d2201f2fSdrahn (* info->print_address_func) (endaddr + sval, info);
104d2201f2fSdrahn (* info->fprintf_func) (info->stream, "}");
105d2201f2fSdrahn }
1065f210c2aSfgsch }
1075f210c2aSfgsch
1085f210c2aSfgsch /* Auto pre/post increment/decrement. */
1095f210c2aSfgsch else if ((buffer[0] & 0xc0) != 0xc0)
1105f210c2aSfgsch {
1115f210c2aSfgsch const char *mode;
1125f210c2aSfgsch
1135f210c2aSfgsch reg = (buffer[0] >> 6) & 3;
1145f210c2aSfgsch sval = (buffer[0] & 0x0f);
1155f210c2aSfgsch if (sval & 0x8)
1165f210c2aSfgsch {
1175f210c2aSfgsch sval |= 0xfff0;
1185f210c2aSfgsch sval = -sval;
1195f210c2aSfgsch mode = "-";
1205f210c2aSfgsch }
1215f210c2aSfgsch else
1225f210c2aSfgsch {
1235f210c2aSfgsch sval = sval + 1;
1245f210c2aSfgsch mode = "+";
1255f210c2aSfgsch }
1265f210c2aSfgsch (*info->fprintf_func) (info->stream, "%d,%s%s%s",
1275f210c2aSfgsch (int) sval,
1285f210c2aSfgsch (buffer[0] & 0x10 ? "" : mode),
1295f210c2aSfgsch reg_name[reg], (buffer[0] & 0x10 ? mode : ""));
1305f210c2aSfgsch }
1315f210c2aSfgsch
1325f210c2aSfgsch /* [n,r] 16-bits offset indexed indirect. */
1335f210c2aSfgsch else if ((buffer[0] & 0x07) == 3)
1345f210c2aSfgsch {
1355f210c2aSfgsch if (mov_insn)
1365f210c2aSfgsch {
1375f210c2aSfgsch (*info->fprintf_func) (info->stream, "<invalid op: 0x%x>",
1385f210c2aSfgsch buffer[0] & 0x0ff);
1395f210c2aSfgsch return 0;
1405f210c2aSfgsch }
1415f210c2aSfgsch reg = (buffer[0] >> 3) & 0x03;
1425f210c2aSfgsch status = read_memory (memaddr + pos, &buffer[0], 2, info);
1435f210c2aSfgsch if (status != 0)
1445f210c2aSfgsch {
1455f210c2aSfgsch return status;
1465f210c2aSfgsch }
1475f210c2aSfgsch
1485f210c2aSfgsch pos += 2;
1495f210c2aSfgsch sval = ((buffer[0] << 8) | (buffer[1] & 0x0FF));
1505f210c2aSfgsch (*info->fprintf_func) (info->stream, "[%u,%s]",
1515f210c2aSfgsch sval & 0x0ffff, reg_name[reg]);
152d2201f2fSdrahn if (indirect)
153d2201f2fSdrahn *indirect = 1;
1545f210c2aSfgsch }
155d2201f2fSdrahn
156d2201f2fSdrahn /* n,r with 9 and 16 bit signed constant. */
1575f210c2aSfgsch else if ((buffer[0] & 0x4) == 0)
1585f210c2aSfgsch {
1595f210c2aSfgsch if (mov_insn)
1605f210c2aSfgsch {
1615f210c2aSfgsch (*info->fprintf_func) (info->stream, "<invalid op: 0x%x>",
1625f210c2aSfgsch buffer[0] & 0x0ff);
1635f210c2aSfgsch return 0;
1645f210c2aSfgsch }
1655f210c2aSfgsch reg = (buffer[0] >> 3) & 0x03;
1665f210c2aSfgsch status = read_memory (memaddr + pos,
1675f210c2aSfgsch &buffer[1], (buffer[0] & 0x2 ? 2 : 1), info);
1685f210c2aSfgsch if (status != 0)
1695f210c2aSfgsch {
1705f210c2aSfgsch return status;
1715f210c2aSfgsch }
1725f210c2aSfgsch if (buffer[0] & 2)
1735f210c2aSfgsch {
1745f210c2aSfgsch sval = ((buffer[1] << 8) | (buffer[2] & 0x0FF));
1755f210c2aSfgsch sval &= 0x0FFFF;
1765f210c2aSfgsch pos += 2;
177d2201f2fSdrahn endaddr += 2;
1785f210c2aSfgsch }
1795f210c2aSfgsch else
1805f210c2aSfgsch {
1815f210c2aSfgsch sval = buffer[1] & 0x00ff;
1825f210c2aSfgsch if (buffer[0] & 0x01)
1835f210c2aSfgsch sval |= 0xff00;
1845f210c2aSfgsch pos++;
185d2201f2fSdrahn endaddr++;
1865f210c2aSfgsch }
1875f210c2aSfgsch (*info->fprintf_func) (info->stream, "%d,%s",
1885f210c2aSfgsch (int) sval, reg_name[reg]);
189d2201f2fSdrahn if (reg == PC_REGNUM)
190d2201f2fSdrahn {
191d2201f2fSdrahn (* info->fprintf_func) (info->stream, " {");
192d2201f2fSdrahn (* info->print_address_func) (endaddr + sval, info);
193d2201f2fSdrahn (* info->fprintf_func) (info->stream, "}");
194d2201f2fSdrahn }
1955f210c2aSfgsch }
1965f210c2aSfgsch else
1975f210c2aSfgsch {
1985f210c2aSfgsch reg = (buffer[0] >> 3) & 0x03;
1995f210c2aSfgsch switch (buffer[0] & 3)
2005f210c2aSfgsch {
2015f210c2aSfgsch case 0:
2025f210c2aSfgsch (*info->fprintf_func) (info->stream, "A,%s", reg_name[reg]);
2035f210c2aSfgsch break;
2045f210c2aSfgsch case 1:
2055f210c2aSfgsch (*info->fprintf_func) (info->stream, "B,%s", reg_name[reg]);
2065f210c2aSfgsch break;
2075f210c2aSfgsch case 2:
2085f210c2aSfgsch (*info->fprintf_func) (info->stream, "D,%s", reg_name[reg]);
2095f210c2aSfgsch break;
2105f210c2aSfgsch case 3:
2115f210c2aSfgsch default:
2125f210c2aSfgsch (*info->fprintf_func) (info->stream, "[D,%s]", reg_name[reg]);
213d2201f2fSdrahn if (indirect)
214d2201f2fSdrahn *indirect = 1;
2155f210c2aSfgsch break;
2165f210c2aSfgsch }
2175f210c2aSfgsch }
2185f210c2aSfgsch
2195f210c2aSfgsch return pos;
2205f210c2aSfgsch }
2215f210c2aSfgsch
2225f210c2aSfgsch /* Disassemble one instruction at address 'memaddr'. Returns the number
2235f210c2aSfgsch of bytes used by that instruction. */
2245f210c2aSfgsch static int
print_insn(bfd_vma memaddr,struct disassemble_info * info,int arch)225*cf2f2c56Smiod print_insn (bfd_vma memaddr, struct disassemble_info* info, int arch)
2265f210c2aSfgsch {
2275f210c2aSfgsch int status;
2285f210c2aSfgsch bfd_byte buffer[4];
2295f210c2aSfgsch unsigned char code;
2305f210c2aSfgsch long format, pos, i;
2315f210c2aSfgsch short sval;
2325f210c2aSfgsch const struct m68hc11_opcode *opcode;
2335f210c2aSfgsch
2345f210c2aSfgsch /* Get first byte. Only one at a time because we don't know the
2355f210c2aSfgsch size of the insn. */
2365f210c2aSfgsch status = read_memory (memaddr, buffer, 1, info);
2375f210c2aSfgsch if (status != 0)
2385f210c2aSfgsch {
2395f210c2aSfgsch return status;
2405f210c2aSfgsch }
2415f210c2aSfgsch
2425f210c2aSfgsch format = 0;
2435f210c2aSfgsch code = buffer[0];
2445f210c2aSfgsch pos = 0;
2455f210c2aSfgsch
2465f210c2aSfgsch /* Look for page2,3,4 opcodes. */
2475f210c2aSfgsch if (code == M6811_OPCODE_PAGE2)
2485f210c2aSfgsch {
2495f210c2aSfgsch pos++;
2505f210c2aSfgsch format = M6811_OP_PAGE2;
2515f210c2aSfgsch }
2525f210c2aSfgsch else if (code == M6811_OPCODE_PAGE3 && arch == cpu6811)
2535f210c2aSfgsch {
2545f210c2aSfgsch pos++;
2555f210c2aSfgsch format = M6811_OP_PAGE3;
2565f210c2aSfgsch }
2575f210c2aSfgsch else if (code == M6811_OPCODE_PAGE4 && arch == cpu6811)
2585f210c2aSfgsch {
2595f210c2aSfgsch pos++;
2605f210c2aSfgsch format = M6811_OP_PAGE4;
2615f210c2aSfgsch }
2625f210c2aSfgsch
2635f210c2aSfgsch /* We are in page2,3,4; get the real opcode. */
2645f210c2aSfgsch if (pos == 1)
2655f210c2aSfgsch {
2665f210c2aSfgsch status = read_memory (memaddr + pos, &buffer[1], 1, info);
2675f210c2aSfgsch if (status != 0)
2685f210c2aSfgsch {
2695f210c2aSfgsch return status;
2705f210c2aSfgsch }
2715f210c2aSfgsch code = buffer[1];
2725f210c2aSfgsch }
2735f210c2aSfgsch
2745f210c2aSfgsch
2755f210c2aSfgsch /* Look first for a 68HC12 alias. All of them are 2-bytes long and
2765f210c2aSfgsch in page 1. There is no operand to print. We read the second byte
2775f210c2aSfgsch only when we have a possible match. */
2785f210c2aSfgsch if ((arch & cpu6812) && format == 0)
2795f210c2aSfgsch {
2805f210c2aSfgsch int must_read = 1;
2815f210c2aSfgsch
2825f210c2aSfgsch /* Walk the alias table to find a code1+code2 match. */
2835f210c2aSfgsch for (i = 0; i < m68hc12_num_alias; i++)
2845f210c2aSfgsch {
2855f210c2aSfgsch if (m68hc12_alias[i].code1 == code)
2865f210c2aSfgsch {
2875f210c2aSfgsch if (must_read)
2885f210c2aSfgsch {
2895f210c2aSfgsch status = read_memory (memaddr + pos + 1,
2905f210c2aSfgsch &buffer[1], 1, info);
2915f210c2aSfgsch if (status != 0)
2925f210c2aSfgsch break;
2935f210c2aSfgsch
2945f210c2aSfgsch must_read = 1;
2955f210c2aSfgsch }
2965f210c2aSfgsch if (m68hc12_alias[i].code2 == (unsigned char) buffer[1])
2975f210c2aSfgsch {
2985f210c2aSfgsch (*info->fprintf_func) (info->stream, "%s",
2995f210c2aSfgsch m68hc12_alias[i].name);
3005f210c2aSfgsch return 2;
3015f210c2aSfgsch }
3025f210c2aSfgsch }
3035f210c2aSfgsch }
3045f210c2aSfgsch }
3055f210c2aSfgsch
3065f210c2aSfgsch pos++;
3075f210c2aSfgsch
3085f210c2aSfgsch /* Scan the opcode table until we find the opcode
3095f210c2aSfgsch with the corresponding page. */
3105f210c2aSfgsch opcode = m68hc11_opcodes;
3115f210c2aSfgsch for (i = 0; i < m68hc11_num_opcodes; i++, opcode++)
3125f210c2aSfgsch {
3135f210c2aSfgsch int offset;
314d2201f2fSdrahn int pc_src_offset;
315*cf2f2c56Smiod int pc_dst_offset = 0;
3165f210c2aSfgsch
3175f210c2aSfgsch if ((opcode->arch & arch) == 0)
3185f210c2aSfgsch continue;
3195f210c2aSfgsch if (opcode->opcode != code)
3205f210c2aSfgsch continue;
3215f210c2aSfgsch if ((opcode->format & OP_PAGE_MASK) != format)
3225f210c2aSfgsch continue;
3235f210c2aSfgsch
3245f210c2aSfgsch if (opcode->format & M6812_OP_REG)
3255f210c2aSfgsch {
3265f210c2aSfgsch int j;
3275f210c2aSfgsch int is_jump;
3285f210c2aSfgsch
3295f210c2aSfgsch if (opcode->format & M6811_OP_JUMP_REL)
3305f210c2aSfgsch is_jump = 1;
3315f210c2aSfgsch else
3325f210c2aSfgsch is_jump = 0;
3335f210c2aSfgsch
3345f210c2aSfgsch status = read_memory (memaddr + pos, &buffer[0], 1, info);
3355f210c2aSfgsch if (status != 0)
3365f210c2aSfgsch {
3375f210c2aSfgsch return status;
3385f210c2aSfgsch }
3395f210c2aSfgsch for (j = 0; i + j < m68hc11_num_opcodes; j++)
3405f210c2aSfgsch {
3415f210c2aSfgsch if ((opcode[j].arch & arch) == 0)
3425f210c2aSfgsch continue;
3435f210c2aSfgsch if (opcode[j].opcode != code)
3445f210c2aSfgsch continue;
3455f210c2aSfgsch if (is_jump)
3465f210c2aSfgsch {
3475f210c2aSfgsch if (!(opcode[j].format & M6811_OP_JUMP_REL))
3485f210c2aSfgsch continue;
3495f210c2aSfgsch
3505f210c2aSfgsch if ((opcode[j].format & M6812_OP_IBCC_MARKER)
3515f210c2aSfgsch && (buffer[0] & 0xc0) != 0x80)
3525f210c2aSfgsch continue;
3535f210c2aSfgsch if ((opcode[j].format & M6812_OP_TBCC_MARKER)
3545f210c2aSfgsch && (buffer[0] & 0xc0) != 0x40)
3555f210c2aSfgsch continue;
3565f210c2aSfgsch if ((opcode[j].format & M6812_OP_DBCC_MARKER)
3575f210c2aSfgsch && (buffer[0] & 0xc0) != 0)
3585f210c2aSfgsch continue;
3595f210c2aSfgsch if ((opcode[j].format & M6812_OP_EQ_MARKER)
3605f210c2aSfgsch && (buffer[0] & 0x20) == 0)
3615f210c2aSfgsch break;
3625f210c2aSfgsch if (!(opcode[j].format & M6812_OP_EQ_MARKER)
3635f210c2aSfgsch && (buffer[0] & 0x20) != 0)
3645f210c2aSfgsch break;
3655f210c2aSfgsch continue;
3665f210c2aSfgsch }
3675f210c2aSfgsch if (opcode[j].format & M6812_OP_EXG_MARKER && buffer[0] & 0x80)
3685f210c2aSfgsch break;
3695f210c2aSfgsch if ((opcode[j].format & M6812_OP_SEX_MARKER)
3705f210c2aSfgsch && (((buffer[0] & 0x07) >= 3 && (buffer[0] & 7) <= 7))
3715f210c2aSfgsch && ((buffer[0] & 0x0f0) <= 0x20))
3725f210c2aSfgsch break;
3735f210c2aSfgsch if (opcode[j].format & M6812_OP_TFR_MARKER
3745f210c2aSfgsch && !(buffer[0] & 0x80))
3755f210c2aSfgsch break;
3765f210c2aSfgsch }
3775f210c2aSfgsch if (i + j < m68hc11_num_opcodes)
3785f210c2aSfgsch opcode = &opcode[j];
3795f210c2aSfgsch }
3805f210c2aSfgsch
3815f210c2aSfgsch /* We have found the opcode. Extract the operand and print it. */
3825f210c2aSfgsch (*info->fprintf_func) (info->stream, "%s", opcode->name);
3835f210c2aSfgsch
3845f210c2aSfgsch format = opcode->format;
3855f210c2aSfgsch if (format & (M6811_OP_MASK | M6811_OP_BITMASK
3865f210c2aSfgsch | M6811_OP_JUMP_REL | M6812_OP_JUMP_REL16))
3875f210c2aSfgsch {
3885f210c2aSfgsch (*info->fprintf_func) (info->stream, "\t");
3895f210c2aSfgsch }
3905f210c2aSfgsch
391d2201f2fSdrahn /* The movb and movw must be handled in a special way...
392d2201f2fSdrahn The source constant 'ii' is not always at the same place.
393d2201f2fSdrahn This is the same for the destination for the post-indexed byte.
394d2201f2fSdrahn The 'offset' is used to do the appropriate correction.
395d2201f2fSdrahn
396d2201f2fSdrahn offset offset
397d2201f2fSdrahn for constant for destination
398d2201f2fSdrahn movb 18 OB ii hh ll 0 0
399d2201f2fSdrahn 18 08 xb ii 1 -1
400d2201f2fSdrahn 18 0C hh ll hh ll 0 0
401d2201f2fSdrahn 18 09 xb hh ll 1 -1
402d2201f2fSdrahn 18 0D xb hh ll 0 0
403d2201f2fSdrahn 18 0A xb xb 0 0
404d2201f2fSdrahn
405d2201f2fSdrahn movw 18 03 jj kk hh ll 0 0
406d2201f2fSdrahn 18 00 xb jj kk 1 -1
407d2201f2fSdrahn 18 04 hh ll hh ll 0 0
408d2201f2fSdrahn 18 01 xb hh ll 1 -1
409d2201f2fSdrahn 18 05 xb hh ll 0 0
410d2201f2fSdrahn 18 02 xb xb 0 0
411d2201f2fSdrahn
412d2201f2fSdrahn After the source operand is read, the position 'pos' is incremented
413d2201f2fSdrahn this explains the negative offset for destination.
414d2201f2fSdrahn
415d2201f2fSdrahn movb/movw above are the only instructions with this matching
416d2201f2fSdrahn format. */
417d2201f2fSdrahn offset = ((format & M6812_OP_IDX_P2)
418d2201f2fSdrahn && (format & (M6811_OP_IMM8 | M6811_OP_IMM16 |
419d2201f2fSdrahn M6811_OP_IND16)));
4205f210c2aSfgsch
4215f210c2aSfgsch /* Operand with one more byte: - immediate, offset,
4225f210c2aSfgsch direct-low address. */
4235f210c2aSfgsch if (format &
4245f210c2aSfgsch (M6811_OP_IMM8 | M6811_OP_IX | M6811_OP_IY | M6811_OP_DIRECT))
4255f210c2aSfgsch {
4265f210c2aSfgsch status = read_memory (memaddr + pos + offset, &buffer[0], 1, info);
4275f210c2aSfgsch if (status != 0)
4285f210c2aSfgsch {
4295f210c2aSfgsch return status;
4305f210c2aSfgsch }
4315f210c2aSfgsch
4325f210c2aSfgsch pos++;
433d2201f2fSdrahn
434d2201f2fSdrahn /* This movb/movw is special (see above). */
435d2201f2fSdrahn offset = -offset;
436d2201f2fSdrahn
437d2201f2fSdrahn pc_dst_offset = 2;
4385f210c2aSfgsch if (format & M6811_OP_IMM8)
4395f210c2aSfgsch {
4405f210c2aSfgsch (*info->fprintf_func) (info->stream, "#%d", (int) buffer[0]);
4415f210c2aSfgsch format &= ~M6811_OP_IMM8;
442d2201f2fSdrahn /* Set PC destination offset. */
443d2201f2fSdrahn pc_dst_offset = 1;
4445f210c2aSfgsch }
4455f210c2aSfgsch else if (format & M6811_OP_IX)
4465f210c2aSfgsch {
4475f210c2aSfgsch /* Offsets are in range 0..255, print them unsigned. */
4485f210c2aSfgsch (*info->fprintf_func) (info->stream, "%u,x", buffer[0] & 0x0FF);
4495f210c2aSfgsch format &= ~M6811_OP_IX;
4505f210c2aSfgsch }
4515f210c2aSfgsch else if (format & M6811_OP_IY)
4525f210c2aSfgsch {
4535f210c2aSfgsch (*info->fprintf_func) (info->stream, "%u,y", buffer[0] & 0x0FF);
4545f210c2aSfgsch format &= ~M6811_OP_IY;
4555f210c2aSfgsch }
4565f210c2aSfgsch else if (format & M6811_OP_DIRECT)
4575f210c2aSfgsch {
4585f210c2aSfgsch (*info->fprintf_func) (info->stream, "*");
4595f210c2aSfgsch (*info->print_address_func) (buffer[0] & 0x0FF, info);
4605f210c2aSfgsch format &= ~M6811_OP_DIRECT;
4615f210c2aSfgsch }
4625f210c2aSfgsch }
4635f210c2aSfgsch
464d2201f2fSdrahn #define M6812_DST_MOVE (M6812_OP_IND16_P2 | M6812_OP_IDX_P2)
4655f210c2aSfgsch #define M6812_INDEXED_FLAGS (M6812_OP_IDX|M6812_OP_IDX_1|M6812_OP_IDX_2)
4665f210c2aSfgsch /* Analyze the 68HC12 indexed byte. */
4675f210c2aSfgsch if (format & M6812_INDEXED_FLAGS)
4685f210c2aSfgsch {
469d2201f2fSdrahn int indirect;
470d2201f2fSdrahn bfd_vma endaddr;
471d2201f2fSdrahn
472d2201f2fSdrahn endaddr = memaddr + pos + 1;
473d2201f2fSdrahn if (format & M6811_OP_IND16)
474d2201f2fSdrahn endaddr += 2;
475d2201f2fSdrahn pc_src_offset = -1;
476d2201f2fSdrahn pc_dst_offset = 1;
477d2201f2fSdrahn status = print_indexed_operand (memaddr + pos, info, &indirect,
478d2201f2fSdrahn (format & M6812_DST_MOVE),
479d2201f2fSdrahn pc_src_offset, endaddr);
4805f210c2aSfgsch if (status < 0)
4815f210c2aSfgsch {
4825f210c2aSfgsch return status;
4835f210c2aSfgsch }
4845f210c2aSfgsch pos += status;
485d2201f2fSdrahn
486d2201f2fSdrahn /* The indirect addressing mode of the call instruction does
487d2201f2fSdrahn not need the page code. */
488d2201f2fSdrahn if ((format & M6812_OP_PAGE) && indirect)
489d2201f2fSdrahn format &= ~M6812_OP_PAGE;
4905f210c2aSfgsch }
4915f210c2aSfgsch
4925f210c2aSfgsch /* 68HC12 dbcc/ibcc/tbcc operands. */
4935f210c2aSfgsch if ((format & M6812_OP_REG) && (format & M6811_OP_JUMP_REL))
4945f210c2aSfgsch {
4955f210c2aSfgsch status = read_memory (memaddr + pos, &buffer[0], 2, info);
4965f210c2aSfgsch if (status != 0)
4975f210c2aSfgsch {
4985f210c2aSfgsch return status;
4995f210c2aSfgsch }
5005f210c2aSfgsch (*info->fprintf_func) (info->stream, "%s,",
5015f210c2aSfgsch reg_src_table[buffer[0] & 0x07]);
5025f210c2aSfgsch sval = buffer[1] & 0x0ff;
5035f210c2aSfgsch if (buffer[0] & 0x10)
5045f210c2aSfgsch sval |= 0xff00;
5055f210c2aSfgsch
5065f210c2aSfgsch pos += 2;
5075f210c2aSfgsch (*info->print_address_func) (memaddr + pos + sval, info);
5085f210c2aSfgsch format &= ~(M6812_OP_REG | M6811_OP_JUMP_REL);
5095f210c2aSfgsch }
5105f210c2aSfgsch else if (format & (M6812_OP_REG | M6812_OP_REG_2))
5115f210c2aSfgsch {
5125f210c2aSfgsch status = read_memory (memaddr + pos, &buffer[0], 1, info);
5135f210c2aSfgsch if (status != 0)
5145f210c2aSfgsch {
5155f210c2aSfgsch return status;
5165f210c2aSfgsch }
5175f210c2aSfgsch
5185f210c2aSfgsch pos++;
5195f210c2aSfgsch (*info->fprintf_func) (info->stream, "%s,%s",
5205f210c2aSfgsch reg_src_table[(buffer[0] >> 4) & 7],
5215f210c2aSfgsch reg_dst_table[(buffer[0] & 7)]);
5225f210c2aSfgsch }
5235f210c2aSfgsch
524d2201f2fSdrahn if (format & (M6811_OP_IMM16 | M6811_OP_IND16))
525d2201f2fSdrahn {
526d2201f2fSdrahn int val;
527d2201f2fSdrahn bfd_vma addr;
528d2201f2fSdrahn unsigned page = 0;
529d2201f2fSdrahn
530d2201f2fSdrahn status = read_memory (memaddr + pos + offset, &buffer[0], 2, info);
531d2201f2fSdrahn if (status != 0)
532d2201f2fSdrahn {
533d2201f2fSdrahn return status;
534d2201f2fSdrahn }
535d2201f2fSdrahn if (format & M6812_OP_IDX_P2)
536d2201f2fSdrahn offset = -2;
537d2201f2fSdrahn else
538d2201f2fSdrahn offset = 0;
539d2201f2fSdrahn pos += 2;
540d2201f2fSdrahn
541d2201f2fSdrahn val = ((buffer[0] << 8) | (buffer[1] & 0x0FF));
542d2201f2fSdrahn val &= 0x0FFFF;
543d2201f2fSdrahn addr = val;
544d2201f2fSdrahn pc_dst_offset = 2;
545d2201f2fSdrahn if (format & M6812_OP_PAGE)
546d2201f2fSdrahn {
547d2201f2fSdrahn status = read_memory (memaddr + pos + offset, buffer, 1, info);
548d2201f2fSdrahn if (status != 0)
549d2201f2fSdrahn return status;
550d2201f2fSdrahn
551d2201f2fSdrahn page = (unsigned) buffer[0];
552d2201f2fSdrahn if (addr >= M68HC12_BANK_BASE && addr < 0x0c000)
553d2201f2fSdrahn addr = ((val - M68HC12_BANK_BASE)
554d2201f2fSdrahn | (page << M68HC12_BANK_SHIFT))
555d2201f2fSdrahn + M68HC12_BANK_VIRT;
556d2201f2fSdrahn }
557d2201f2fSdrahn else if ((arch & cpu6812)
558d2201f2fSdrahn && addr >= M68HC12_BANK_BASE && addr < 0x0c000)
559d2201f2fSdrahn {
560d2201f2fSdrahn int cur_page;
561d2201f2fSdrahn bfd_vma vaddr;
562d2201f2fSdrahn
563d2201f2fSdrahn if (memaddr >= M68HC12_BANK_VIRT)
564d2201f2fSdrahn cur_page = ((memaddr - M68HC12_BANK_VIRT)
565d2201f2fSdrahn >> M68HC12_BANK_SHIFT);
566d2201f2fSdrahn else
567d2201f2fSdrahn cur_page = 0;
568d2201f2fSdrahn
569d2201f2fSdrahn vaddr = ((addr - M68HC12_BANK_BASE)
570d2201f2fSdrahn + (cur_page << M68HC12_BANK_SHIFT))
571d2201f2fSdrahn + M68HC12_BANK_VIRT;
572d2201f2fSdrahn if (!info->symbol_at_address_func (addr, info)
573d2201f2fSdrahn && info->symbol_at_address_func (vaddr, info))
574d2201f2fSdrahn addr = vaddr;
575d2201f2fSdrahn }
576d2201f2fSdrahn if (format & M6811_OP_IMM16)
577d2201f2fSdrahn {
578d2201f2fSdrahn format &= ~M6811_OP_IMM16;
579d2201f2fSdrahn (*info->fprintf_func) (info->stream, "#");
580d2201f2fSdrahn }
581d2201f2fSdrahn else
582d2201f2fSdrahn format &= ~M6811_OP_IND16;
583d2201f2fSdrahn
584d2201f2fSdrahn (*info->print_address_func) (addr, info);
585d2201f2fSdrahn if (format & M6812_OP_PAGE)
586d2201f2fSdrahn {
587d2201f2fSdrahn (* info->fprintf_func) (info->stream, " {");
588d2201f2fSdrahn (* info->print_address_func) (val, info);
589d2201f2fSdrahn (* info->fprintf_func) (info->stream, ", %d}", page);
590d2201f2fSdrahn format &= ~M6812_OP_PAGE;
591d2201f2fSdrahn pos += 1;
592d2201f2fSdrahn }
593d2201f2fSdrahn }
594d2201f2fSdrahn
595d2201f2fSdrahn if (format & M6812_OP_IDX_P2)
596d2201f2fSdrahn {
597d2201f2fSdrahn (*info->fprintf_func) (info->stream, ", ");
598d2201f2fSdrahn status = print_indexed_operand (memaddr + pos + offset, info,
599d2201f2fSdrahn 0, 1, pc_dst_offset,
600d2201f2fSdrahn memaddr + pos + offset + 1);
601d2201f2fSdrahn if (status < 0)
602d2201f2fSdrahn return status;
603d2201f2fSdrahn pos += status;
604d2201f2fSdrahn }
605d2201f2fSdrahn
606d2201f2fSdrahn if (format & M6812_OP_IND16_P2)
607d2201f2fSdrahn {
608d2201f2fSdrahn int val;
609d2201f2fSdrahn
610d2201f2fSdrahn (*info->fprintf_func) (info->stream, ", ");
611d2201f2fSdrahn
612d2201f2fSdrahn status = read_memory (memaddr + pos + offset, &buffer[0], 2, info);
613d2201f2fSdrahn if (status != 0)
614d2201f2fSdrahn {
615d2201f2fSdrahn return status;
616d2201f2fSdrahn }
617d2201f2fSdrahn pos += 2;
618d2201f2fSdrahn
619d2201f2fSdrahn val = ((buffer[0] << 8) | (buffer[1] & 0x0FF));
620d2201f2fSdrahn val &= 0x0FFFF;
621d2201f2fSdrahn (*info->print_address_func) (val, info);
622d2201f2fSdrahn }
623d2201f2fSdrahn
6245f210c2aSfgsch /* M6811_OP_BITMASK and M6811_OP_JUMP_REL must be treated separately
6255f210c2aSfgsch and in that order. The brset/brclr insn have a bitmask and then
6265f210c2aSfgsch a relative branch offset. */
6275f210c2aSfgsch if (format & M6811_OP_BITMASK)
6285f210c2aSfgsch {
6295f210c2aSfgsch status = read_memory (memaddr + pos, &buffer[0], 1, info);
6305f210c2aSfgsch if (status != 0)
6315f210c2aSfgsch {
6325f210c2aSfgsch return status;
6335f210c2aSfgsch }
6345f210c2aSfgsch pos++;
6355f210c2aSfgsch (*info->fprintf_func) (info->stream, " #$%02x%s",
6365f210c2aSfgsch buffer[0] & 0x0FF,
6375f210c2aSfgsch (format & M6811_OP_JUMP_REL ? " " : ""));
6385f210c2aSfgsch format &= ~M6811_OP_BITMASK;
6395f210c2aSfgsch }
6405f210c2aSfgsch if (format & M6811_OP_JUMP_REL)
6415f210c2aSfgsch {
6425f210c2aSfgsch int val;
6435f210c2aSfgsch
6445f210c2aSfgsch status = read_memory (memaddr + pos, &buffer[0], 1, info);
6455f210c2aSfgsch if (status != 0)
6465f210c2aSfgsch {
6475f210c2aSfgsch return status;
6485f210c2aSfgsch }
6495f210c2aSfgsch
6505f210c2aSfgsch pos++;
6515f210c2aSfgsch val = (buffer[0] & 0x80) ? buffer[0] | 0xFFFFFF00 : buffer[0];
6525f210c2aSfgsch (*info->print_address_func) (memaddr + pos + val, info);
6535f210c2aSfgsch format &= ~M6811_OP_JUMP_REL;
6545f210c2aSfgsch }
6555f210c2aSfgsch else if (format & M6812_OP_JUMP_REL16)
6565f210c2aSfgsch {
6575f210c2aSfgsch int val;
6585f210c2aSfgsch
6595f210c2aSfgsch status = read_memory (memaddr + pos, &buffer[0], 2, info);
6605f210c2aSfgsch if (status != 0)
6615f210c2aSfgsch {
6625f210c2aSfgsch return status;
6635f210c2aSfgsch }
6645f210c2aSfgsch
6655f210c2aSfgsch pos += 2;
6665f210c2aSfgsch val = ((buffer[0] << 8) | (buffer[1] & 0x0FF));
6675f210c2aSfgsch if (val & 0x8000)
6685f210c2aSfgsch val |= 0xffff0000;
6695f210c2aSfgsch
6705f210c2aSfgsch (*info->print_address_func) (memaddr + pos + val, info);
6715f210c2aSfgsch format &= ~M6812_OP_JUMP_REL16;
6725f210c2aSfgsch }
673d2201f2fSdrahn
674d2201f2fSdrahn if (format & M6812_OP_PAGE)
6755f210c2aSfgsch {
6765f210c2aSfgsch int val;
6775f210c2aSfgsch
678d2201f2fSdrahn status = read_memory (memaddr + pos + offset, &buffer[0], 1, info);
6795f210c2aSfgsch if (status != 0)
6805f210c2aSfgsch {
6815f210c2aSfgsch return status;
6825f210c2aSfgsch }
683d2201f2fSdrahn pos += 1;
6845f210c2aSfgsch
685d2201f2fSdrahn val = buffer[0] & 0x0ff;
686d2201f2fSdrahn (*info->fprintf_func) (info->stream, ", %d", val);
6875f210c2aSfgsch }
6885f210c2aSfgsch
6895f210c2aSfgsch #ifdef DEBUG
6905f210c2aSfgsch /* Consistency check. 'format' must be 0, so that we have handled
6915f210c2aSfgsch all formats; and the computed size of the insn must match the
6925f210c2aSfgsch opcode table content. */
6935f210c2aSfgsch if (format & ~(M6811_OP_PAGE4 | M6811_OP_PAGE3 | M6811_OP_PAGE2))
6945f210c2aSfgsch {
6955f210c2aSfgsch (*info->fprintf_func) (info->stream, "; Error, format: %x", format);
6965f210c2aSfgsch }
6975f210c2aSfgsch if (pos != opcode->size)
6985f210c2aSfgsch {
6995f210c2aSfgsch (*info->fprintf_func) (info->stream, "; Error, size: %d expect %d",
7005f210c2aSfgsch pos, opcode->size);
7015f210c2aSfgsch }
7025f210c2aSfgsch #endif
7035f210c2aSfgsch return pos;
7045f210c2aSfgsch }
7055f210c2aSfgsch
7065f210c2aSfgsch /* Opcode not recognized. */
7075f210c2aSfgsch if (format == M6811_OP_PAGE2 && arch & cpu6812
708*cf2f2c56Smiod && ((code >= 0x30 && code <= 0x39) || (code >= 0x40)))
7095f210c2aSfgsch (*info->fprintf_func) (info->stream, "trap\t#%d", code & 0x0ff);
7105f210c2aSfgsch
7115f210c2aSfgsch else if (format == M6811_OP_PAGE2)
7125f210c2aSfgsch (*info->fprintf_func) (info->stream, ".byte\t0x%02x, 0x%02x",
7135f210c2aSfgsch M6811_OPCODE_PAGE2, code);
7145f210c2aSfgsch else if (format == M6811_OP_PAGE3)
7155f210c2aSfgsch (*info->fprintf_func) (info->stream, ".byte\t0x%02x, 0x%02x",
7165f210c2aSfgsch M6811_OPCODE_PAGE3, code);
7175f210c2aSfgsch else if (format == M6811_OP_PAGE4)
7185f210c2aSfgsch (*info->fprintf_func) (info->stream, ".byte\t0x%02x, 0x%02x",
7195f210c2aSfgsch M6811_OPCODE_PAGE4, code);
7205f210c2aSfgsch else
7215f210c2aSfgsch (*info->fprintf_func) (info->stream, ".byte\t0x%02x", code);
7225f210c2aSfgsch
7235f210c2aSfgsch return pos;
7245f210c2aSfgsch }
7255f210c2aSfgsch
7265f210c2aSfgsch /* Disassemble one instruction at address 'memaddr'. Returns the number
7275f210c2aSfgsch of bytes used by that instruction. */
7285f210c2aSfgsch int
print_insn_m68hc11(bfd_vma memaddr,struct disassemble_info * info)729*cf2f2c56Smiod print_insn_m68hc11 (bfd_vma memaddr, struct disassemble_info* info)
7305f210c2aSfgsch {
7315f210c2aSfgsch return print_insn (memaddr, info, cpu6811);
7325f210c2aSfgsch }
7335f210c2aSfgsch
7345f210c2aSfgsch int
print_insn_m68hc12(bfd_vma memaddr,struct disassemble_info * info)735*cf2f2c56Smiod print_insn_m68hc12 (bfd_vma memaddr, struct disassemble_info* info)
7365f210c2aSfgsch {
7375f210c2aSfgsch return print_insn (memaddr, info, cpu6812);
7385f210c2aSfgsch }
739