1 /* M32R opcode support. -*- C -*-
3 Copyright 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
5 Contributed by Red Hat Inc; developed under contract from
6 Mitsubishi Electric Corporation.
8 This file is part of the GNU Binutils.
10 Contributed by Red Hat Inc; developed under contract from Fujitsu.
12 This file is part of the GNU Binutils.
14 This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation; either version 2 of the License, or
17 (at your option) any later version.
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
31 /* This file is an addendum to m32r.cpu. Heavy use of C code isn't
32 appropriate in .cpu files, so it resides here. This especially applies
33 to assembly/disassembly where parsing/printing can be quite involved.
34 Such things aren't really part of the specification of the cpu, per se,
35 so .cpu files provide the general framework and .opc files handle the
36 nitty-gritty details as necessary.
38 Each section is delimited with start and end markers.
40 <arch>-opc.h additions use: "-- opc.h"
41 <arch>-opc.c additions use: "-- opc.c"
42 <arch>-asm.c additions use: "-- asm.c"
43 <arch>-dis.c additions use: "-- dis.c"
44 <arch>-ibd.h additions use: "-- ibd.h"
49 #undef CGEN_DIS_HASH_SIZE
50 #define CGEN_DIS_HASH_SIZE 256
52 #define X(b) (((unsigned char *) (b))[0] & 0xf0)
53 #define CGEN_DIS_HASH(buffer, value) \
55 (X (buffer) == 0x40 || X (buffer) == 0xe0 || X (buffer) == 0x60 || X (buffer) == 0x50 ? 0 \
56 : X (buffer) == 0x70 || X (buffer) == 0xf0 ? (((unsigned char *) (buffer))[0] & 0xf) \
57 : X (buffer) == 0x30 ? ((((unsigned char *) (buffer))[1] & 0x70) >> 4) \
58 : ((((unsigned char *) (buffer))[1] & 0xf0) >> 4)))
63 static const char * parse_hash
64 PARAMS ((CGEN_CPU_DESC, const char **, int, unsigned long *));
65 static const char * parse_hi16
66 PARAMS ((CGEN_CPU_DESC, const char **, int, unsigned long *));
67 static const char * parse_slo16
68 PARAMS ((CGEN_CPU_DESC, const char **, int, long *));
69 static const char * parse_ulo16
70 PARAMS ((CGEN_CPU_DESC, const char **, int, unsigned long *));
72 /* Handle '#' prefixes (i.e. skip over them). */
75 parse_hash (cd, strp, opindex, valuep)
76 CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
78 int opindex ATTRIBUTE_UNUSED;
79 unsigned long *valuep ATTRIBUTE_UNUSED;
86 /* Handle shigh(), high(). */
89 parse_hi16 (cd, strp, opindex, valuep)
93 unsigned long *valuep;
96 enum cgen_parse_operand_result result_type;
102 if (strncasecmp (*strp, "high(", 5) == 0)
105 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_HI16_ULO,
106 &result_type, &value);
108 return "missing `)'";
111 && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
116 else if (strncasecmp (*strp, "shigh(", 6) == 0)
119 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_HI16_SLO,
120 &result_type, &value);
122 return "missing `)'";
125 && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
126 value = (value >> 16) + (value & 0x8000 ? 1 : 0);
131 return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
134 /* Handle low() in a signed context. Also handle sda().
135 The signedness of the value doesn't matter to low(), but this also
136 handles the case where low() isn't present. */
139 parse_slo16 (cd, strp, opindex, valuep)
146 enum cgen_parse_operand_result result_type;
152 if (strncasecmp (*strp, "low(", 4) == 0)
155 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_LO16,
156 &result_type, &value);
158 return "missing `)'";
161 && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
167 if (strncasecmp (*strp, "sda(", 4) == 0)
170 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_SDA16,
173 return "missing `)'";
179 return cgen_parse_signed_integer (cd, strp, opindex, valuep);
182 /* Handle low() in an unsigned context.
183 The signedness of the value doesn't matter to low(), but this also
184 handles the case where low() isn't present. */
187 parse_ulo16 (cd, strp, opindex, valuep)
191 unsigned long *valuep;
194 enum cgen_parse_operand_result result_type;
200 if (strncasecmp (*strp, "low(", 4) == 0)
203 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_LO16,
204 &result_type, &value);
206 return "missing `)'";
209 && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
215 return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
221 static void print_hash PARAMS ((CGEN_CPU_DESC, PTR, long, unsigned, bfd_vma, int));
222 static int my_print_insn PARAMS ((CGEN_CPU_DESC, bfd_vma, disassemble_info *));
224 /* Immediate values are prefixed with '#'. */
226 #define CGEN_PRINT_NORMAL(cd, info, value, attrs, pc, length) \
229 if (CGEN_BOOL_ATTR ((attrs), CGEN_OPERAND_HASH_PREFIX)) \
230 (*info->fprintf_func) (info->stream, "#"); \
234 /* Handle '#' prefixes as operands. */
237 print_hash (cd, dis_info, value, attrs, pc, length)
238 CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
240 long value ATTRIBUTE_UNUSED;
241 unsigned int attrs ATTRIBUTE_UNUSED;
242 bfd_vma pc ATTRIBUTE_UNUSED;
243 int length ATTRIBUTE_UNUSED;
245 disassemble_info *info = (disassemble_info *) dis_info;
246 (*info->fprintf_func) (info->stream, "#");
249 #undef CGEN_PRINT_INSN
250 #define CGEN_PRINT_INSN my_print_insn
253 my_print_insn (cd, pc, info)
256 disassemble_info *info;
258 char buffer[CGEN_MAX_INSN_SIZE];
261 int buflen = (pc & 3) == 0 ? 4 : 2;
263 /* Read the base part of the insn. */
265 status = (*info->read_memory_func) (pc, buf, buflen, info);
268 (*info->memory_error_func) (status, pc, info);
273 if ((pc & 3) == 0 && (buf[0] & 0x80) != 0)
274 return print_insn (cd, pc, info, buf, buflen);
276 /* Print the first insn. */
279 if (print_insn (cd, pc, info, buf, 2) == 0)
280 (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
287 (*info->fprintf_func) (info->stream, " || ");
291 (*info->fprintf_func) (info->stream, " -> ");
293 /* The "& 3" is to pass a consistent address.
294 Parallel insns arguably both begin on the word boundary.
295 Also, branch insns are calculated relative to the word boundary. */
296 if (print_insn (cd, pc & ~ (bfd_vma) 3, info, buf, 2) == 0)
297 (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
299 return (pc & 3) ? 2 : 4;