Support R_SPARC_WDISP10 and R_SPARC_H34.
[external/binutils.git] / cpu / fr30.opc
1 /* FR30 opcode support.  -*- C -*-
2    Copyright 2011 Free Software Foundation, Inc.
3
4    Contributed by Red Hat Inc;
5
6    This file is part of the GNU Binutils.
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21    MA 02110-1301, USA.  */
22
23 /* This file is an addendum to fr30.cpu.  Heavy use of C code isn't
24    appropriate in .cpu files, so it resides here.  This especially applies
25    to assembly/disassembly where parsing/printing can be quite involved.
26    Such things aren't really part of the specification of the cpu, per se,
27    so .cpu files provide the general framework and .opc files handle the
28    nitty-gritty details as necessary.
29
30    Each section is delimited with start and end markers.
31
32    <arch>-opc.h additions use: "-- opc.h"
33    <arch>-opc.c additions use: "-- opc.c"
34    <arch>-asm.c additions use: "-- asm.c"
35    <arch>-dis.c additions use: "-- dis.c"
36    <arch>-ibd.h additions use: "-- ibd.h".  */
37 \f
38 /* -- opc.h */
39
40 /* ??? This can be improved upon.  */
41 #undef  CGEN_DIS_HASH_SIZE
42 #define CGEN_DIS_HASH_SIZE 16
43 #undef  CGEN_DIS_HASH
44 #define CGEN_DIS_HASH(buffer, value) (((unsigned char *) (buffer))[0] >> 4)
45
46 /* -- */
47 \f
48 /* -- asm.c */
49 /* Handle register lists for LDMx and STMx.  */
50
51 static int
52 parse_register_number (const char **strp)
53 {
54   int regno;
55
56   if (**strp < '0' || **strp > '9')
57     return -1; /* Error.  */
58   regno = **strp - '0';
59   ++*strp;
60
61   if (**strp >= '0' && **strp <= '9')
62     {
63       regno = regno * 10 + (**strp - '0');
64       ++*strp;
65     }
66
67   return regno;
68 }
69
70 static const char *
71 parse_register_list (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
72                      const char **strp,
73                      int opindex ATTRIBUTE_UNUSED,
74                      unsigned long *valuep,
75                      int high_low,   /* 0 == high, 1 == low.  */
76                      int load_store) /* 0 == load, 1 == store.  */
77 {
78   *valuep = 0;
79   while (**strp && **strp != ')')
80     {
81       int regno;
82
83       if (**strp != 'R' && **strp != 'r')
84         break;
85       ++*strp;
86
87       regno = parse_register_number (strp);
88       if (regno == -1)
89         return _("Register number is not valid");
90       if (regno > 7 && !high_low)
91         return _("Register must be between r0 and r7");
92       if (regno < 8 && high_low)
93         return _("Register must be between r8 and r15");
94
95       if (high_low)
96         regno -= 8;
97
98       if (load_store) /* Mask is reversed for store.  */
99         *valuep |= 0x80 >> regno;
100       else
101         *valuep |= 1 << regno;
102
103       if (**strp == ',')
104         {
105           if (*(*strp + 1) == ')')
106             break;
107           ++*strp;
108         }
109     }
110
111   if (!*strp || **strp != ')')
112     return _("Register list is not valid");
113
114   return NULL;
115 }
116
117 static const char *
118 parse_low_register_list_ld (CGEN_CPU_DESC cd,
119                             const char **strp,
120                             int opindex,
121                             unsigned long *valuep)
122 {
123   return parse_register_list (cd, strp, opindex, valuep,
124                               0 /* Low.  */, 0 /* Load.  */);
125 }
126
127 static const char *
128 parse_hi_register_list_ld (CGEN_CPU_DESC cd,
129                            const char **strp,
130                            int opindex,
131                            unsigned long *valuep)
132 {
133   return parse_register_list (cd, strp, opindex, valuep,
134                               1 /* High.  */, 0 /* Load.  */);
135 }
136
137 static const char *
138 parse_low_register_list_st (CGEN_CPU_DESC cd,
139                             const char **strp,
140                             int opindex,
141                             unsigned long *valuep)
142 {
143   return parse_register_list (cd, strp, opindex, valuep,
144                               0 /* Low.  */, 1 /* Store.  */);
145 }
146
147 static const char *
148 parse_hi_register_list_st (CGEN_CPU_DESC cd,
149                            const char **strp,
150                            int opindex,
151                            unsigned long *valuep)
152 {
153   return parse_register_list (cd, strp, opindex, valuep,
154                               1 /* High.  */, 1 /* Store.  */);
155 }
156
157 /* -- */
158
159 /* -- dis.c */
160 static void
161 print_register_list (void * dis_info,
162                      long value,
163                      long offset,
164                      int load_store) /* 0 == load, 1 == store.  */
165 {
166   disassemble_info *info = dis_info;
167   int mask;
168   int reg_index = 0;
169   char * comma = "";
170
171   if (load_store)
172     mask = 0x80;
173   else
174     mask = 1;
175
176   if (value & mask)
177     {
178       (*info->fprintf_func) (info->stream, "r%li", reg_index + offset);
179       comma = ",";
180     }
181     
182   for (reg_index = 1; reg_index <= 7; ++reg_index)
183     {
184       if (load_store)
185         mask >>= 1;
186       else
187         mask <<= 1;
188
189       if (value & mask)
190         {
191           (*info->fprintf_func) (info->stream, "%sr%li", comma, reg_index + offset);
192           comma = ",";
193         }
194     }
195 }
196
197 static void
198 print_hi_register_list_ld (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
199                            void * dis_info,
200                            long value,
201                            unsigned int attrs ATTRIBUTE_UNUSED,
202                            bfd_vma pc ATTRIBUTE_UNUSED,
203                            int length ATTRIBUTE_UNUSED)
204 {
205   print_register_list (dis_info, value, 8, 0 /* Load.  */);
206 }
207
208 static void
209 print_low_register_list_ld (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
210                             void * dis_info,
211                             long value,
212                             unsigned int attrs ATTRIBUTE_UNUSED,
213                             bfd_vma pc ATTRIBUTE_UNUSED,
214                             int length ATTRIBUTE_UNUSED)
215 {
216   print_register_list (dis_info, value, 0, 0 /* Load.  */);
217 }
218
219 static void
220 print_hi_register_list_st (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
221                            void * dis_info,
222                            long value,
223                            unsigned int attrs ATTRIBUTE_UNUSED,
224                            bfd_vma pc ATTRIBUTE_UNUSED,
225                            int length ATTRIBUTE_UNUSED)
226 {
227   print_register_list (dis_info, value, 8, 1 /* Store.  */);
228 }
229
230 static void
231 print_low_register_list_st (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
232                             void * dis_info,
233                             long value,
234                             unsigned int attrs ATTRIBUTE_UNUSED,
235                             bfd_vma pc ATTRIBUTE_UNUSED,
236                             int length ATTRIBUTE_UNUSED)
237 {
238   print_register_list (dis_info, value, 0, 1 /* Store.  */);
239 }
240
241 static void
242 print_m4 (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
243           void * dis_info,
244           long value,
245           unsigned int attrs ATTRIBUTE_UNUSED,
246           bfd_vma pc ATTRIBUTE_UNUSED,
247           int length ATTRIBUTE_UNUSED)
248 {
249   disassemble_info *info = (disassemble_info *) dis_info;
250
251   (*info->fprintf_func) (info->stream, "%ld", value);
252 }
253 /* -- */