gas/
[binutils.git] / cpu / m32r.opc
blob3100fee9f924e664c04342d986a57d32f05a9346
1 /* M32R opcode support.  -*- C -*-
3    Copyright 1998, 1999, 2000, 2001, 2004, 2005, 2007, 2009
4    Free Software Foundation, Inc.
6    Contributed by Red Hat Inc; developed under contract from
7    Mitsubishi Electric Corporation.
9    This file is part of the GNU Binutils.
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 3 of the License, or
14    (at your option) any later version.
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
21    You should have received a copy of the GNU General Public License
22    along with this program; if not, write to the Free Software
23    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
24    MA 02110-1301, USA.  */
27 /* This file is an addendum to m32r.cpu.  Heavy use of C code isn't
28    appropriate in .cpu files, so it resides here.  This especially applies
29    to assembly/disassembly where parsing/printing can be quite involved.
30    Such things aren't really part of the specification of the cpu, per se,
31    so .cpu files provide the general framework and .opc files handle the
32    nitty-gritty details as necessary.
34    Each section is delimited with start and end markers.
36    <arch>-opc.h additions use: "-- opc.h"
37    <arch>-opc.c additions use: "-- opc.c"
38    <arch>-asm.c additions use: "-- asm.c"
39    <arch>-dis.c additions use: "-- dis.c"
40    <arch>-ibd.h additions use: "-- ibd.h"  */
42 /* -- opc.h */
44 #undef  CGEN_DIS_HASH_SIZE
45 #define CGEN_DIS_HASH_SIZE 256
46 #undef  CGEN_DIS_HASH
47 #if 0
48 #define X(b) (((unsigned char *) (b))[0] & 0xf0)
49 #define CGEN_DIS_HASH(buffer, value) \
50 (X (buffer) | \
51  (X (buffer) == 0x40 || X (buffer) == 0xe0 || X (buffer) == 0x60 || X (buffer) == 0x50 ? 0 \
52   : X (buffer) == 0x70 || X (buffer) == 0xf0 ? (((unsigned char *) (buffer))[0] & 0xf) \
53   : X (buffer) == 0x30 ? ((((unsigned char *) (buffer))[1] & 0x70) >> 4) \
54   : ((((unsigned char *) (buffer))[1] & 0xf0) >> 4)))
55 #else
56 #define CGEN_DIS_HASH(buffer, value) m32r_cgen_dis_hash (buffer, value)
57 extern unsigned int m32r_cgen_dis_hash (const char *, CGEN_INSN_INT);
58 #endif
60 /* -- */
62 /* -- opc.c */
63 unsigned int
64 m32r_cgen_dis_hash (const char * buf ATTRIBUTE_UNUSED, CGEN_INSN_INT value)
66   unsigned int x;
68   if (value & 0xffff0000) /* 32bit instructions.  */
69     value = (value >> 16) & 0xffff;
71   x = (value >> 8) & 0xf0;
72   if (x == 0x40 || x == 0xe0 || x == 0x60 || x == 0x50)
73     return x;
75   if (x == 0x70 || x == 0xf0)
76     return x | ((value >> 8) & 0x0f);
78   if (x == 0x30)
79     return x | ((value & 0x70) >> 4);
80   else
81     return x | ((value & 0xf0) >> 4);
84 /* -- */
86 /* -- asm.c */
87 static const char * MISSING_CLOSING_PARENTHESIS = N_("missing `)'");
89 /* Handle '#' prefixes (i.e. skip over them).  */
91 static const char *
92 parse_hash (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
93             const char **strp,
94             int opindex ATTRIBUTE_UNUSED,
95             long *valuep ATTRIBUTE_UNUSED)
97   if (**strp == '#')
98     ++*strp;
99   return NULL;
102 /* Handle shigh(), high().  */
104 static const char *
105 parse_hi16 (CGEN_CPU_DESC cd,
106             const char **strp,
107             int opindex,
108             unsigned long *valuep)
110   const char *errmsg;
111   enum cgen_parse_operand_result result_type;
112   bfd_vma value;
114   if (**strp == '#')
115     ++*strp;
117   if (strncasecmp (*strp, "high(", 5) == 0)
118     {
119       *strp += 5;
120       errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_HI16_ULO,
121                                    & result_type, & value);
122       if (**strp != ')')
123         return MISSING_CLOSING_PARENTHESIS;
124       ++*strp;
125       if (errmsg == NULL
126           && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
127         {
128           value >>= 16;
129           value &= 0xffff;
130         }
131       *valuep = value;
132       return errmsg;
133     }
134   else if (strncasecmp (*strp, "shigh(", 6) == 0)
135     {
136       *strp += 6;
137       errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_HI16_SLO,
138                                    & result_type, & value);
139       if (**strp != ')')
140         return MISSING_CLOSING_PARENTHESIS;
141       ++*strp;
142       if (errmsg == NULL
143           && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
144         {
145           value += 0x8000;
146           value >>= 16;
147           value &= 0xffff;
148         }
149       *valuep = value;
150       return errmsg;
151     }
153   return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
156 /* Handle low() in a signed context.  Also handle sda().
157    The signedness of the value doesn't matter to low(), but this also
158    handles the case where low() isn't present.  */
160 static const char *
161 parse_slo16 (CGEN_CPU_DESC cd,
162              const char ** strp,
163              int opindex,
164              long * valuep)
166   const char *errmsg;
167   enum cgen_parse_operand_result result_type;
168   bfd_vma value;
170   if (**strp == '#')
171     ++*strp;
173   if (strncasecmp (*strp, "low(", 4) == 0)
174     {
175       *strp += 4;
176       errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_LO16,
177                                    & result_type, & value);
178       if (**strp != ')')
179         return MISSING_CLOSING_PARENTHESIS;
180       ++*strp;
181       if (errmsg == NULL
182           && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
183         value = ((value & 0xffff) ^ 0x8000) - 0x8000;
184       *valuep = value;
185       return errmsg;
186     }
188   if (strncasecmp (*strp, "sda(", 4) == 0)
189     {
190       *strp += 4;
191       errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_SDA16,
192                                    NULL, & value);
193       if (**strp != ')')
194         return MISSING_CLOSING_PARENTHESIS;
195       ++*strp;
196       *valuep = value;
197       return errmsg;
198     }
200   return cgen_parse_signed_integer (cd, strp, opindex, valuep);
203 /* Handle low() in an unsigned context.
204    The signedness of the value doesn't matter to low(), but this also
205    handles the case where low() isn't present.  */
207 static const char *
208 parse_ulo16 (CGEN_CPU_DESC cd,
209              const char **strp,
210              int opindex,
211              unsigned long *valuep)
213   const char *errmsg;
214   enum cgen_parse_operand_result result_type;
215   bfd_vma value;
217   if (**strp == '#')
218     ++*strp;
220   if (strncasecmp (*strp, "low(", 4) == 0)
221     {
222       *strp += 4;
223       errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_M32R_LO16,
224                                    & result_type, & value);
225       if (**strp != ')')
226         return MISSING_CLOSING_PARENTHESIS;
227       ++*strp;
228       if (errmsg == NULL
229           && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER)
230         value &= 0xffff;
231       *valuep = value;
232       return errmsg;
233     }
235   return cgen_parse_unsigned_integer (cd, strp, opindex, valuep);
238 /* -- */
240 /* -- dis.c */
241 /* Immediate values are prefixed with '#'.  */
243 #define CGEN_PRINT_NORMAL(cd, info, value, attrs, pc, length)   \
244   do                                                            \
245     {                                                           \
246       if (CGEN_BOOL_ATTR ((attrs), CGEN_OPERAND_HASH_PREFIX))   \
247         (*info->fprintf_func) (info->stream, "#");              \
248     }                                                           \
249   while (0)
251 /* Handle '#' prefixes as operands.  */
253 static void
254 print_hash (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
255             void * dis_info,
256             long value ATTRIBUTE_UNUSED,
257             unsigned int attrs ATTRIBUTE_UNUSED,
258             bfd_vma pc ATTRIBUTE_UNUSED,
259             int length ATTRIBUTE_UNUSED)
261   disassemble_info *info = (disassemble_info *) dis_info;
263   (*info->fprintf_func) (info->stream, "#");
266 #undef  CGEN_PRINT_INSN
267 #define CGEN_PRINT_INSN my_print_insn
269 static int
270 my_print_insn (CGEN_CPU_DESC cd,
271                bfd_vma pc,
272                disassemble_info *info)
274   bfd_byte buffer[CGEN_MAX_INSN_SIZE];
275   bfd_byte *buf = buffer;
276   int status;
277   int buflen = (pc & 3) == 0 ? 4 : 2;
278   int big_p = CGEN_CPU_INSN_ENDIAN (cd) == CGEN_ENDIAN_BIG;
279   bfd_byte *x;
281   /* Read the base part of the insn.  */
283   status = (*info->read_memory_func) (pc - ((!big_p && (pc & 3) != 0) ? 2 : 0),
284                                       buf, buflen, info);
285   if (status != 0)
286     {
287       (*info->memory_error_func) (status, pc, info);
288       return -1;
289     }
291   /* 32 bit insn?  */
292   x = (big_p ? &buf[0] : &buf[3]);
293   if ((pc & 3) == 0 && (*x & 0x80) != 0)
294     return print_insn (cd, pc, info, buf, buflen);
296   /* Print the first insn.  */
297   if ((pc & 3) == 0)
298     {
299       buf += (big_p ? 0 : 2);
300       if (print_insn (cd, pc, info, buf, 2) == 0)
301         (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
302       buf += (big_p ? 2 : -2);
303     }
305   x = (big_p ? &buf[0] : &buf[1]);
306   if (*x & 0x80)
307     {
308       /* Parallel.  */
309       (*info->fprintf_func) (info->stream, " || ");
310       *x &= 0x7f;
311     }
312   else
313     (*info->fprintf_func) (info->stream, " -> ");
315   /* The "& 3" is to pass a consistent address.
316      Parallel insns arguably both begin on the word boundary.
317      Also, branch insns are calculated relative to the word boundary.  */
318   if (print_insn (cd, pc & ~ (bfd_vma) 3, info, buf, 2) == 0)
319     (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
321   return (pc & 3) ? 2 : 4;
324 /* -- */