/src/binutils-gdb/opcodes/mcore-dis.c
Line | Count | Source |
1 | | /* Disassemble Motorola M*Core instructions. |
2 | | Copyright (C) 1993-2026 Free Software Foundation, Inc. |
3 | | |
4 | | This file is part of the GNU opcodes library. |
5 | | |
6 | | This library is free software; you can redistribute it and/or modify |
7 | | it under the terms of the GNU General Public License as published by |
8 | | the Free Software Foundation; either version 3, or (at your option) |
9 | | any later version. |
10 | | |
11 | | It is distributed in the hope that it will be useful, but WITHOUT |
12 | | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
13 | | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public |
14 | | License for more details. |
15 | | |
16 | | You should have received a copy of the GNU General Public License |
17 | | along with this program; if not, write to the Free Software |
18 | | Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
19 | | MA 02110-1301, USA. */ |
20 | | |
21 | | #include "sysdep.h" |
22 | | #include <stdio.h> |
23 | | #include "libiberty.h" |
24 | | #define STATIC_TABLE |
25 | | #define DEFINE_TABLE |
26 | | |
27 | | #include "mcore-opc.h" |
28 | | #include "disassemble.h" |
29 | | |
30 | | /* Mask for each mcore_opclass: */ |
31 | | static const unsigned short imsk[] = { |
32 | | /* O0 */ 0xFFFF, |
33 | | /* OT */ 0xFFFC, |
34 | | /* O1 */ 0xFFF0, |
35 | | /* OC */ 0xFE00, |
36 | | /* O2 */ 0xFF00, |
37 | | /* X1 */ 0xFFF0, |
38 | | /* OI */ 0xFE00, |
39 | | /* OB */ 0xFE00, |
40 | | |
41 | | /* OMa */ 0xFFF0, |
42 | | /* SI */ 0xFE00, |
43 | | /* I7 */ 0xF800, |
44 | | /* LS */ 0xF000, |
45 | | /* BR */ 0xF800, |
46 | | /* BL */ 0xFF00, |
47 | | /* LR */ 0xF000, |
48 | | /* LJ */ 0xFF00, |
49 | | |
50 | | /* RM */ 0xFFF0, |
51 | | /* RQ */ 0xFFF0, |
52 | | /* JSR */ 0xFFF0, |
53 | | /* JMP */ 0xFFF0, |
54 | | /* OBRa*/ 0xFFF0, |
55 | | /* OBRb*/ 0xFF80, |
56 | | /* OBRc*/ 0xFF00, |
57 | | /* OBR2*/ 0xFE00, |
58 | | |
59 | | /* O1R1*/ 0xFFF0, |
60 | | /* OMb */ 0xFF80, |
61 | | /* OMc */ 0xFF00, |
62 | | /* SIa */ 0xFE00, |
63 | | |
64 | | /* MULSH */ 0xFF00, |
65 | | /* OPSR */ 0xFFF8, /* psrset/psrclr */ |
66 | | |
67 | | /* JC */ 0, /* JC,JU,JL don't appear in object */ |
68 | | /* JU */ 0, |
69 | | /* JL */ 0, |
70 | | /* RSI */ 0, |
71 | | /* DO21*/ 0, |
72 | | /* OB2 */ 0 /* OB2 won't appear in object. */ |
73 | | }; |
74 | | |
75 | | static const char *grname[] = { |
76 | | "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", |
77 | | "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" |
78 | | }; |
79 | | |
80 | | static const char X[] = "??"; |
81 | | |
82 | | static const char *crname[] = { |
83 | | "psr", "vbr", "epsr", "fpsr", "epc", "fpc", "ss0", "ss1", |
84 | | "ss2", "ss3", "ss4", "gcr", "gsr", X, X, X, |
85 | | X, X, X, X, X, X, X, X, |
86 | | X, X, X, X, X, X, X, X |
87 | | }; |
88 | | |
89 | | static const unsigned isiz[] = { 2, 0, 1, 0 }; |
90 | | |
91 | | int |
92 | | print_insn_mcore (bfd_vma memaddr, |
93 | | struct disassemble_info *info) |
94 | 135k | { |
95 | 135k | unsigned char ibytes[4]; |
96 | 135k | fprintf_ftype print_func = info->fprintf_func; |
97 | 135k | void *stream = info->stream; |
98 | 135k | unsigned int inst; |
99 | 135k | unsigned int i; |
100 | 135k | int status; |
101 | | |
102 | 135k | info->bytes_per_chunk = 2; |
103 | | |
104 | 135k | status = info->read_memory_func (memaddr, ibytes, 2, info); |
105 | | |
106 | 135k | if (status != 0) |
107 | 73 | { |
108 | 73 | info->memory_error_func (status, memaddr, info); |
109 | 73 | return -1; |
110 | 73 | } |
111 | | |
112 | 135k | if (info->endian == BFD_ENDIAN_BIG) |
113 | 0 | inst = (ibytes[0] << 8) | ibytes[1]; |
114 | 135k | else if (info->endian == BFD_ENDIAN_LITTLE) |
115 | 135k | inst = (ibytes[1] << 8) | ibytes[0]; |
116 | 0 | else |
117 | 0 | abort (); |
118 | | |
119 | | /* Just a linear search of the table. */ |
120 | 10.8M | for (i = 0; i < ARRAY_SIZE (mcore_table); i++) |
121 | 10.8M | if (mcore_table[i].inst == (inst & imsk[mcore_table[i].opclass])) |
122 | 119k | break; |
123 | | |
124 | 135k | if (i == ARRAY_SIZE (mcore_table)) |
125 | 15.1k | (*print_func) (stream, ".short 0x%04x", inst); |
126 | 119k | else |
127 | 119k | { |
128 | 119k | const char *name = grname[inst & 0x0F]; |
129 | | |
130 | 119k | (*print_func) (stream, "%s", mcore_table[i].name); |
131 | | |
132 | 119k | switch (mcore_table[i].opclass) |
133 | 119k | { |
134 | 22.3k | case O0: |
135 | 22.3k | break; |
136 | | |
137 | 385 | case OT: |
138 | 385 | (*print_func) (stream, "\t%d", inst & 0x3); |
139 | 385 | break; |
140 | | |
141 | 4.79k | case O1: |
142 | 5.46k | case JMP: |
143 | 5.83k | case JSR: |
144 | 5.83k | (*print_func) (stream, "\t%s", name); |
145 | 5.83k | break; |
146 | | |
147 | 2.49k | case OC: |
148 | 2.49k | (*print_func) (stream, "\t%s, %s", name, crname[(inst >> 4) & 0x1F]); |
149 | 2.49k | break; |
150 | | |
151 | 431 | case O1R1: |
152 | 431 | (*print_func) (stream, "\t%s, r1", name); |
153 | 431 | break; |
154 | | |
155 | 369 | case MULSH: |
156 | 9.84k | case O2: |
157 | 9.84k | (*print_func) (stream, "\t%s, %s", name, grname[(inst >> 4) & 0xF]); |
158 | 9.84k | break; |
159 | | |
160 | 1.03k | case X1: |
161 | 1.03k | (*print_func) (stream, "\tr1, %s", name); |
162 | 1.03k | break; |
163 | | |
164 | 2.79k | case OI: |
165 | 2.79k | (*print_func) (stream, "\t%s, %d", name, ((inst >> 4) & 0x1F) + 1); |
166 | 2.79k | break; |
167 | | |
168 | 1.28k | case RM: |
169 | 1.28k | (*print_func) (stream, "\t%s-r15, (r0)", name); |
170 | 1.28k | break; |
171 | | |
172 | 994 | case RQ: |
173 | 994 | (*print_func) (stream, "\tr4-r7, (%s)", name); |
174 | 994 | break; |
175 | | |
176 | 6.67k | case OB: |
177 | 6.80k | case OBRa: |
178 | 7.02k | case OBRb: |
179 | 8.00k | case OBRc: |
180 | 8.00k | case SI: |
181 | 10.0k | case SIa: |
182 | 10.2k | case OMb: |
183 | 10.7k | case OMc: |
184 | 10.7k | (*print_func) (stream, "\t%s, %d", name, (inst >> 4) & 0x1F); |
185 | 10.7k | break; |
186 | | |
187 | 107 | case OMa: |
188 | 107 | (*print_func) (stream, "\t%s, %d", name, 32); |
189 | 107 | break; |
190 | | |
191 | 4.03k | case I7: |
192 | 4.03k | (*print_func) (stream, "\t%s, %d", name, (inst >> 4) & 0x7F); |
193 | 4.03k | break; |
194 | | |
195 | 25.7k | case LS: |
196 | 25.7k | (*print_func) (stream, "\t%s, (%s, %d)", grname[(inst >> 8) & 0xF], |
197 | 25.7k | name, ((inst >> 4) & 0xF) << isiz[(inst >> 13) & 3]); |
198 | 25.7k | break; |
199 | | |
200 | 19.2k | case BR: |
201 | 19.2k | { |
202 | 19.2k | uint32_t val = ((inst & 0x7FF) ^ 0x400) - 0x400; |
203 | | |
204 | 19.2k | val = memaddr + 2 + (val << 1); |
205 | 19.2k | (*print_func) (stream, "\t0x%x", val); |
206 | | |
207 | 19.2k | if (strcmp (mcore_table[i].name, "bsr") == 0) |
208 | 12.6k | { |
209 | | /* For bsr, we'll try to get a symbol for the target. */ |
210 | 12.6k | if (info->print_address_func && val != 0) |
211 | 12.6k | { |
212 | 12.6k | (*print_func) (stream, "\t// "); |
213 | 12.6k | info->print_address_func (val, info); |
214 | 12.6k | } |
215 | 12.6k | } |
216 | 19.2k | } |
217 | 19.2k | break; |
218 | | |
219 | 1.36k | case BL: |
220 | 1.36k | { |
221 | 1.36k | uint32_t val = memaddr + 2 + ((inst | ~0xF) << 1); |
222 | | |
223 | 1.36k | (*print_func) (stream, "\t%s, 0x%x", |
224 | 1.36k | grname[(inst >> 4) & 0xF], val); |
225 | 1.36k | } |
226 | 1.36k | break; |
227 | | |
228 | 7.78k | case LR: |
229 | 7.78k | { |
230 | 7.78k | uint32_t val; |
231 | | |
232 | 7.78k | val = (memaddr + 2 + ((inst & 0xFF) << 2)) & ~3; |
233 | | |
234 | | /* We are not reading an instruction, so allow |
235 | | reads to extend beyond the next symbol. */ |
236 | 7.78k | info->stop_vma = 0; |
237 | 7.78k | status = info->read_memory_func (val, ibytes, 4, info); |
238 | 7.78k | if (status != 0) |
239 | 1.59k | { |
240 | 1.59k | info->memory_error_func (status, memaddr, info); |
241 | 1.59k | break; |
242 | 1.59k | } |
243 | | |
244 | 6.18k | if (info->endian == BFD_ENDIAN_LITTLE) |
245 | 6.18k | val = (((unsigned) ibytes[3] << 24) | (ibytes[2] << 16) |
246 | 6.18k | | (ibytes[1] << 8) | (ibytes[0])); |
247 | 0 | else |
248 | 0 | val = (((unsigned) ibytes[0] << 24) | (ibytes[1] << 16) |
249 | 0 | | (ibytes[2] << 8) | (ibytes[3])); |
250 | | |
251 | | /* Removed [] around literal value to match ABI syntax 12/95. */ |
252 | 6.18k | (*print_func) (stream, "\t%s, 0x%X", grname[(inst >> 8) & 0xF], val); |
253 | | |
254 | 6.18k | if (val == 0) |
255 | 789 | (*print_func) (stream, "\t// from address pool at 0x%x", |
256 | 789 | (uint32_t) (memaddr + 2 |
257 | 789 | + ((inst & 0xFF) << 2)) & ~3); |
258 | 6.18k | } |
259 | 0 | break; |
260 | | |
261 | 2.24k | case LJ: |
262 | 2.24k | { |
263 | 2.24k | uint32_t val; |
264 | | |
265 | 2.24k | val = (memaddr + 2 + ((inst & 0xFF) << 2)) & ~3; |
266 | | |
267 | | /* We are not reading an instruction, so allow |
268 | | reads to extend beyond the next symbol. */ |
269 | 2.24k | info->stop_vma = 0; |
270 | 2.24k | status = info->read_memory_func (val, ibytes, 4, info); |
271 | 2.24k | if (status != 0) |
272 | 417 | { |
273 | 417 | info->memory_error_func (status, memaddr, info); |
274 | 417 | break; |
275 | 417 | } |
276 | | |
277 | 1.82k | if (info->endian == BFD_ENDIAN_LITTLE) |
278 | 1.82k | val = (((unsigned) ibytes[3] << 24) | (ibytes[2] << 16) |
279 | 1.82k | | (ibytes[1] << 8) | (ibytes[0])); |
280 | 0 | else |
281 | 0 | val = (((unsigned) ibytes[0] << 24) | (ibytes[1] << 16) |
282 | 0 | | (ibytes[2] << 8) | (ibytes[3])); |
283 | | |
284 | | /* Removed [] around literal value to match ABI syntax 12/95. */ |
285 | 1.82k | (*print_func) (stream, "\t0x%X", val); |
286 | | /* For jmpi/jsri, we'll try to get a symbol for the target. */ |
287 | 1.82k | if (info->print_address_func && val != 0) |
288 | 1.65k | { |
289 | 1.65k | (*print_func) (stream, "\t// "); |
290 | 1.65k | info->print_address_func (val, info); |
291 | 1.65k | } |
292 | 175 | else |
293 | 175 | { |
294 | 175 | (*print_func) (stream, "\t// from address pool at 0x%x", |
295 | 175 | (uint32_t) (memaddr + 2 |
296 | 175 | + ((inst & 0xFF) << 2)) & ~3); |
297 | 175 | } |
298 | 1.82k | } |
299 | 0 | break; |
300 | | |
301 | 0 | case OPSR: |
302 | 0 | { |
303 | 0 | static char *fields[] = { |
304 | 0 | "af", "ie", "fe", "fe,ie", |
305 | 0 | "ee", "ee,ie", "ee,fe", "ee,fe,ie" |
306 | 0 | }; |
307 | |
|
308 | 0 | (*print_func) (stream, "\t%s", fields[inst & 0x7]); |
309 | 0 | } |
310 | 0 | break; |
311 | | |
312 | 1.31k | default: |
313 | | /* If the disassembler lags the instruction set. */ |
314 | 1.31k | (*print_func) (stream, "\tundecoded operands, inst is 0x%04x", inst); |
315 | 1.31k | break; |
316 | 119k | } |
317 | 119k | } |
318 | | |
319 | | /* Say how many bytes we consumed. */ |
320 | 135k | return 2; |
321 | 135k | } |