/src/binutils-gdb/opcodes/mcore-dis.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Disassemble Motorola M*Core instructions. |
2 | | Copyright (C) 1993-2025 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 | 132k | { |
95 | 132k | unsigned char ibytes[4]; |
96 | 132k | fprintf_ftype print_func = info->fprintf_func; |
97 | 132k | void *stream = info->stream; |
98 | 132k | unsigned int inst; |
99 | 132k | unsigned int i; |
100 | 132k | int status; |
101 | | |
102 | 132k | info->bytes_per_chunk = 2; |
103 | | |
104 | 132k | status = info->read_memory_func (memaddr, ibytes, 2, info); |
105 | | |
106 | 132k | if (status != 0) |
107 | 130 | { |
108 | 130 | info->memory_error_func (status, memaddr, info); |
109 | 130 | return -1; |
110 | 130 | } |
111 | | |
112 | 131k | if (info->endian == BFD_ENDIAN_BIG) |
113 | 0 | inst = (ibytes[0] << 8) | ibytes[1]; |
114 | 131k | else if (info->endian == BFD_ENDIAN_LITTLE) |
115 | 131k | inst = (ibytes[1] << 8) | ibytes[0]; |
116 | 0 | else |
117 | 0 | abort (); |
118 | | |
119 | | /* Just a linear search of the table. */ |
120 | 10.2M | for (i = 0; i < ARRAY_SIZE (mcore_table); i++) |
121 | 10.1M | if (mcore_table[i].inst == (inst & imsk[mcore_table[i].opclass])) |
122 | 115k | break; |
123 | | |
124 | 131k | if (i == ARRAY_SIZE (mcore_table)) |
125 | 16.2k | (*print_func) (stream, ".short 0x%04x", inst); |
126 | 115k | else |
127 | 115k | { |
128 | 115k | const char *name = grname[inst & 0x0F]; |
129 | | |
130 | 115k | (*print_func) (stream, "%s", mcore_table[i].name); |
131 | | |
132 | 115k | switch (mcore_table[i].opclass) |
133 | 115k | { |
134 | 26.0k | case O0: |
135 | 26.0k | break; |
136 | | |
137 | 693 | case OT: |
138 | 693 | (*print_func) (stream, "\t%d", inst & 0x3); |
139 | 693 | break; |
140 | | |
141 | 5.25k | case O1: |
142 | 5.68k | case JMP: |
143 | 6.09k | case JSR: |
144 | 6.09k | (*print_func) (stream, "\t%s", name); |
145 | 6.09k | break; |
146 | | |
147 | 2.44k | case OC: |
148 | 2.44k | (*print_func) (stream, "\t%s, %s", name, crname[(inst >> 4) & 0x1F]); |
149 | 2.44k | break; |
150 | | |
151 | 97 | case O1R1: |
152 | 97 | (*print_func) (stream, "\t%s, r1", name); |
153 | 97 | break; |
154 | | |
155 | 852 | case MULSH: |
156 | 9.05k | case O2: |
157 | 9.05k | (*print_func) (stream, "\t%s, %s", name, grname[(inst >> 4) & 0xF]); |
158 | 9.05k | break; |
159 | | |
160 | 1.25k | case X1: |
161 | 1.25k | (*print_func) (stream, "\tr1, %s", name); |
162 | 1.25k | break; |
163 | | |
164 | 2.19k | case OI: |
165 | 2.19k | (*print_func) (stream, "\t%s, %d", name, ((inst >> 4) & 0x1F) + 1); |
166 | 2.19k | break; |
167 | | |
168 | 1.97k | case RM: |
169 | 1.97k | (*print_func) (stream, "\t%s-r15, (r0)", name); |
170 | 1.97k | break; |
171 | | |
172 | 800 | case RQ: |
173 | 800 | (*print_func) (stream, "\tr4-r7, (%s)", name); |
174 | 800 | break; |
175 | | |
176 | 4.98k | case OB: |
177 | 5.03k | case OBRa: |
178 | 5.20k | case OBRb: |
179 | 5.83k | case OBRc: |
180 | 5.83k | case SI: |
181 | 7.73k | case SIa: |
182 | 7.97k | case OMa: |
183 | 8.13k | case OMb: |
184 | 8.57k | case OMc: |
185 | 8.57k | (*print_func) (stream, "\t%s, %d", name, (inst >> 4) & 0x1F); |
186 | 8.57k | break; |
187 | | |
188 | 4.51k | case I7: |
189 | 4.51k | (*print_func) (stream, "\t%s, %d", name, (inst >> 4) & 0x7F); |
190 | 4.51k | break; |
191 | | |
192 | 22.5k | case LS: |
193 | 22.5k | (*print_func) (stream, "\t%s, (%s, %d)", grname[(inst >> 8) & 0xF], |
194 | 22.5k | name, ((inst >> 4) & 0xF) << isiz[(inst >> 13) & 3]); |
195 | 22.5k | break; |
196 | | |
197 | 18.6k | case BR: |
198 | 18.6k | { |
199 | 18.6k | uint32_t val = ((inst & 0x3FF) ^ 0x400) - 0x400; |
200 | | |
201 | 18.6k | val = memaddr + 2 + (val << 1); |
202 | 18.6k | (*print_func) (stream, "\t0x%x", val); |
203 | | |
204 | 18.6k | if (strcmp (mcore_table[i].name, "bsr") == 0) |
205 | 11.7k | { |
206 | | /* For bsr, we'll try to get a symbol for the target. */ |
207 | 11.7k | if (info->print_address_func && val != 0) |
208 | 11.7k | { |
209 | 11.7k | (*print_func) (stream, "\t// "); |
210 | 11.7k | info->print_address_func (val, info); |
211 | 11.7k | } |
212 | 11.7k | } |
213 | 18.6k | } |
214 | 18.6k | break; |
215 | | |
216 | 756 | case BL: |
217 | 756 | { |
218 | 756 | uint32_t val = memaddr + 2 + ((inst | ~0xF) << 1); |
219 | | |
220 | 756 | (*print_func) (stream, "\t%s, 0x%x", |
221 | 756 | grname[(inst >> 4) & 0xF], val); |
222 | 756 | } |
223 | 756 | break; |
224 | | |
225 | 7.06k | case LR: |
226 | 7.06k | { |
227 | 7.06k | uint32_t val; |
228 | | |
229 | 7.06k | val = (memaddr + 2 + ((inst & 0xFF) << 2)) & ~3; |
230 | | |
231 | | /* We are not reading an instruction, so allow |
232 | | reads to extend beyond the next symbol. */ |
233 | 7.06k | info->stop_vma = 0; |
234 | 7.06k | status = info->read_memory_func (val, ibytes, 4, info); |
235 | 7.06k | if (status != 0) |
236 | 1.96k | { |
237 | 1.96k | info->memory_error_func (status, memaddr, info); |
238 | 1.96k | break; |
239 | 1.96k | } |
240 | | |
241 | 5.10k | if (info->endian == BFD_ENDIAN_LITTLE) |
242 | 5.10k | val = (((unsigned) ibytes[3] << 24) | (ibytes[2] << 16) |
243 | 5.10k | | (ibytes[1] << 8) | (ibytes[0])); |
244 | 0 | else |
245 | 0 | val = (((unsigned) ibytes[0] << 24) | (ibytes[1] << 16) |
246 | 0 | | (ibytes[2] << 8) | (ibytes[3])); |
247 | | |
248 | | /* Removed [] around literal value to match ABI syntax 12/95. */ |
249 | 5.10k | (*print_func) (stream, "\t%s, 0x%X", grname[(inst >> 8) & 0xF], val); |
250 | | |
251 | 5.10k | if (val == 0) |
252 | 737 | (*print_func) (stream, "\t// from address pool at 0x%x", |
253 | 737 | (uint32_t) (memaddr + 2 |
254 | 737 | + ((inst & 0xFF) << 2)) & ~3); |
255 | 5.10k | } |
256 | 0 | break; |
257 | | |
258 | 2.35k | case LJ: |
259 | 2.35k | { |
260 | 2.35k | uint32_t val; |
261 | | |
262 | 2.35k | val = (memaddr + 2 + ((inst & 0xFF) << 2)) & ~3; |
263 | | |
264 | | /* We are not reading an instruction, so allow |
265 | | reads to extend beyond the next symbol. */ |
266 | 2.35k | info->stop_vma = 0; |
267 | 2.35k | status = info->read_memory_func (val, ibytes, 4, info); |
268 | 2.35k | if (status != 0) |
269 | 807 | { |
270 | 807 | info->memory_error_func (status, memaddr, info); |
271 | 807 | break; |
272 | 807 | } |
273 | | |
274 | 1.55k | if (info->endian == BFD_ENDIAN_LITTLE) |
275 | 1.55k | val = (((unsigned) ibytes[3] << 24) | (ibytes[2] << 16) |
276 | 1.55k | | (ibytes[1] << 8) | (ibytes[0])); |
277 | 0 | else |
278 | 0 | val = (((unsigned) ibytes[0] << 24) | (ibytes[1] << 16) |
279 | 0 | | (ibytes[2] << 8) | (ibytes[3])); |
280 | | |
281 | | /* Removed [] around literal value to match ABI syntax 12/95. */ |
282 | 1.55k | (*print_func) (stream, "\t0x%X", val); |
283 | | /* For jmpi/jsri, we'll try to get a symbol for the target. */ |
284 | 1.55k | if (info->print_address_func && val != 0) |
285 | 1.25k | { |
286 | 1.25k | (*print_func) (stream, "\t// "); |
287 | 1.25k | info->print_address_func (val, info); |
288 | 1.25k | } |
289 | 296 | else |
290 | 296 | { |
291 | 296 | (*print_func) (stream, "\t// from address pool at 0x%x", |
292 | 296 | (uint32_t) (memaddr + 2 |
293 | 296 | + ((inst & 0xFF) << 2)) & ~3); |
294 | 296 | } |
295 | 1.55k | } |
296 | 0 | break; |
297 | | |
298 | 0 | case OPSR: |
299 | 0 | { |
300 | 0 | static char *fields[] = { |
301 | 0 | "af", "ie", "fe", "fe,ie", |
302 | 0 | "ee", "ee,ie", "ee,fe", "ee,fe,ie" |
303 | 0 | }; |
304 | |
|
305 | 0 | (*print_func) (stream, "\t%s", fields[inst & 0x7]); |
306 | 0 | } |
307 | 0 | break; |
308 | | |
309 | 579 | default: |
310 | | /* If the disassembler lags the instruction set. */ |
311 | 579 | (*print_func) (stream, "\tundecoded operands, inst is 0x%04x", inst); |
312 | 579 | break; |
313 | 115k | } |
314 | 115k | } |
315 | | |
316 | | /* Say how many bytes we consumed. */ |
317 | 131k | return 2; |
318 | 131k | } |