2004-02-20 Andrew Cagney <cagney@redhat.com>
[platform/upstream/binutils.git] / cpu / m32r.opc
1 /* M32R opcode support.  -*- C -*-
2
3    Copyright 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
4
5    Contributed by Red Hat Inc; developed under contract from
6    Mitsubishi Electric Corporation.
7
8    This file is part of the GNU Binutils.
9
10    Contributed by Red Hat Inc; developed under contract from Fujitsu.
11
12    This file is part of the GNU Binutils.
13
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.
18
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.
23
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.
27
28 */
29
30
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.
37
38    Each section is delimited with start and end markers.
39
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"
45 */
46 \f
47 /* -- opc.h */
48
49 #undef  CGEN_DIS_HASH_SIZE
50 #define CGEN_DIS_HASH_SIZE 256
51 #undef  CGEN_DIS_HASH
52 #define X(b) (((unsigned char *) (b))[0] & 0xf0)
53 #define CGEN_DIS_HASH(buffer, value) \
54 (X (buffer) | \
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)))
59
60 /* -- */
61 \f
62 /* -- asm.c */
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 *));
71
72 /* Handle '#' prefixes (i.e. skip over them).  */
73
74 static const char *
75 parse_hash (cd, strp, opindex, valuep)
76      CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
77      const char **strp;
78      int opindex ATTRIBUTE_UNUSED;
79      unsigned long *valuep ATTRIBUTE_UNUSED;
80 {
81   if (**strp == '#')
82     ++*strp;
83   return NULL;
84 }
85
86 /* Handle shigh(), high().  */
87
88 static const char *
89 parse_hi16 (cd, strp, opindex, valuep)
90      CGEN_CPU_DESC cd;
91      const char **strp;
92      int opindex;
93      unsigned long *valuep;
94 {
95   const char *errmsg;
96   enum cgen_parse_operand_result result_type;
97   bfd_vma value;
98
99   if (**strp == '#')
100     ++*strp;
101
102   if (strncasecmp (*strp, "high(", 5) == 0)
103     {
104       *strp += 5;
105       errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_HI16_ULO,
106                                    &result_type, &value);
107       if (**strp != ')')
108         return "missing `)'";
109       ++*strp;
110       if (errmsg == NULL
111           && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
112         value >>= 16;
113       *valuep = value;
114       return errmsg;
115     }
116   else if (strncasecmp (*strp, "shigh(", 6) == 0)
117     {
118       *strp += 6;
119       errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_HI16_SLO,
120                                    &result_type, &value);
121       if (**strp != ')')
122         return "missing `)'";
123       ++*strp;
124       if (errmsg == NULL
125           && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
126         value = (value >> 16) + (value & 0x8000 ? 1 : 0);
127       *valuep = value;
128       return errmsg;
129     }
130
131   return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
132 }
133
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.  */
137
138 static const char *
139 parse_slo16 (cd, strp, opindex, valuep)
140      CGEN_CPU_DESC cd;
141      const char **strp;
142      int opindex;
143      long *valuep;
144 {
145   const char *errmsg;
146   enum cgen_parse_operand_result result_type;
147   bfd_vma value;
148
149   if (**strp == '#')
150     ++*strp;
151
152   if (strncasecmp (*strp, "low(", 4) == 0)
153     {
154       *strp += 4;
155       errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_LO16,
156                                    &result_type, &value);
157       if (**strp != ')')
158         return "missing `)'";
159       ++*strp;
160       if (errmsg == NULL
161           && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
162         value &= 0xffff;
163       *valuep = value;
164       return errmsg;
165     }
166
167   if (strncasecmp (*strp, "sda(", 4) == 0)
168     {
169       *strp += 4;
170       errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_SDA16,
171                                    NULL, &value);
172       if (**strp != ')')
173         return "missing `)'";
174       ++*strp;
175       *valuep = value;
176       return errmsg;
177     }
178
179   return cgen_parse_signed_integer (cd, strp, opindex, valuep);
180 }
181
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.  */
185
186 static const char *
187 parse_ulo16 (cd, strp, opindex, valuep)
188      CGEN_CPU_DESC cd;
189      const char **strp;
190      int opindex;
191      unsigned long *valuep;
192 {
193   const char *errmsg;
194   enum cgen_parse_operand_result result_type;
195   bfd_vma value;
196
197   if (**strp == '#')
198     ++*strp;
199
200   if (strncasecmp (*strp, "low(", 4) == 0)
201     {
202       *strp += 4;
203       errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_LO16,
204                                    &result_type, &value);
205       if (**strp != ')')
206         return "missing `)'";
207       ++*strp;
208       if (errmsg == NULL
209           && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
210         value &= 0xffff;
211       *valuep = value;
212       return errmsg;
213     }
214
215   return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
216 }
217
218 /* -- */
219 \f
220 /* -- dis.c */
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 *));
223
224 /* Immediate values are prefixed with '#'.  */
225
226 #define CGEN_PRINT_NORMAL(cd, info, value, attrs, pc, length)   \
227   do                                                            \
228     {                                                           \
229       if (CGEN_BOOL_ATTR ((attrs), CGEN_OPERAND_HASH_PREFIX))   \
230         (*info->fprintf_func) (info->stream, "#");              \
231     }                                                           \
232   while (0)
233
234 /* Handle '#' prefixes as operands.  */
235
236 static void
237 print_hash (cd, dis_info, value, attrs, pc, length)
238      CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
239      PTR dis_info;
240      long value ATTRIBUTE_UNUSED;
241      unsigned int attrs ATTRIBUTE_UNUSED;
242      bfd_vma pc ATTRIBUTE_UNUSED;
243      int length ATTRIBUTE_UNUSED;
244 {
245   disassemble_info *info = (disassemble_info *) dis_info;
246   (*info->fprintf_func) (info->stream, "#");
247 }
248
249 #undef  CGEN_PRINT_INSN
250 #define CGEN_PRINT_INSN my_print_insn
251
252 static int
253 my_print_insn (cd, pc, info)
254      CGEN_CPU_DESC cd;
255      bfd_vma pc;
256      disassemble_info *info;
257 {
258   char buffer[CGEN_MAX_INSN_SIZE];
259   char *buf = buffer;
260   int status;
261   int buflen = (pc & 3) == 0 ? 4 : 2;
262
263   /* Read the base part of the insn.  */
264
265   status = (*info->read_memory_func) (pc, buf, buflen, info);
266   if (status != 0)
267     {
268       (*info->memory_error_func) (status, pc, info);
269       return -1;
270     }
271
272   /* 32 bit insn?  */
273   if ((pc & 3) == 0 && (buf[0] & 0x80) != 0)
274     return print_insn (cd, pc, info, buf, buflen);
275
276   /* Print the first insn.  */
277   if ((pc & 3) == 0)
278     {
279       if (print_insn (cd, pc, info, buf, 2) == 0)
280         (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
281       buf += 2;
282     }
283
284   if (buf[0] & 0x80)
285     {
286       /* Parallel.  */
287       (*info->fprintf_func) (info->stream, " || ");
288       buf[0] &= 0x7f;
289     }
290   else
291     (*info->fprintf_func) (info->stream, " -> ");
292
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);
298
299   return (pc & 3) ? 2 : 4;
300 }
301
302 /* -- */