/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-2023 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 | 209k | { |
95 | 209k | unsigned char ibytes[4]; |
96 | 209k | fprintf_ftype print_func = info->fprintf_func; |
97 | 209k | void *stream = info->stream; |
98 | 209k | unsigned int inst; |
99 | 209k | unsigned int i; |
100 | 209k | int status; |
101 | | |
102 | 209k | info->bytes_per_chunk = 2; |
103 | | |
104 | 209k | status = info->read_memory_func (memaddr, ibytes, 2, info); |
105 | | |
106 | 209k | if (status != 0) |
107 | 77 | { |
108 | 77 | info->memory_error_func (status, memaddr, info); |
109 | 77 | return -1; |
110 | 77 | } |
111 | | |
112 | 209k | if (info->endian == BFD_ENDIAN_BIG) |
113 | 523 | inst = (ibytes[0] << 8) | ibytes[1]; |
114 | 208k | else if (info->endian == BFD_ENDIAN_LITTLE) |
115 | 208k | inst = (ibytes[1] << 8) | ibytes[0]; |
116 | 0 | else |
117 | 0 | abort (); |
118 | | |
119 | | /* Just a linear search of the table. */ |
120 | 17.7M | for (i = 0; i < ARRAY_SIZE (mcore_table); i++) |
121 | 17.7M | if (mcore_table[i].inst == (inst & imsk[mcore_table[i].opclass])) |
122 | 184k | break; |
123 | | |
124 | 209k | if (i == ARRAY_SIZE (mcore_table)) |
125 | 25.2k | (*print_func) (stream, ".short 0x%04x", inst); |
126 | 184k | else |
127 | 184k | { |
128 | 184k | const char *name = grname[inst & 0x0F]; |
129 | | |
130 | 184k | (*print_func) (stream, "%s", mcore_table[i].name); |
131 | | |
132 | 184k | switch (mcore_table[i].opclass) |
133 | 184k | { |
134 | 28.3k | case O0: |
135 | 28.3k | break; |
136 | | |
137 | 494 | case OT: |
138 | 494 | (*print_func) (stream, "\t%d", inst & 0x3); |
139 | 494 | break; |
140 | | |
141 | 7.61k | case O1: |
142 | 8.19k | case JMP: |
143 | 8.49k | case JSR: |
144 | 8.49k | (*print_func) (stream, "\t%s", name); |
145 | 8.49k | break; |
146 | | |
147 | 4.92k | case OC: |
148 | 4.92k | (*print_func) (stream, "\t%s, %s", name, crname[(inst >> 4) & 0x1F]); |
149 | 4.92k | break; |
150 | | |
151 | 78 | case O1R1: |
152 | 78 | (*print_func) (stream, "\t%s, r1", name); |
153 | 78 | break; |
154 | | |
155 | 806 | case MULSH: |
156 | 16.6k | case O2: |
157 | 16.6k | (*print_func) (stream, "\t%s, %s", name, grname[(inst >> 4) & 0xF]); |
158 | 16.6k | break; |
159 | | |
160 | 1.56k | case X1: |
161 | 1.56k | (*print_func) (stream, "\tr1, %s", name); |
162 | 1.56k | break; |
163 | | |
164 | 4.25k | case OI: |
165 | 4.25k | (*print_func) (stream, "\t%s, %d", name, ((inst >> 4) & 0x1F) + 1); |
166 | 4.25k | break; |
167 | | |
168 | 1.43k | case RM: |
169 | 1.43k | (*print_func) (stream, "\t%s-r15, (r0)", name); |
170 | 1.43k | break; |
171 | | |
172 | 947 | case RQ: |
173 | 947 | (*print_func) (stream, "\tr4-r7, (%s)", name); |
174 | 947 | break; |
175 | | |
176 | 8.12k | case OB: |
177 | 8.24k | case OBRa: |
178 | 8.44k | case OBRb: |
179 | 9.61k | case OBRc: |
180 | 9.61k | case SI: |
181 | 14.6k | case SIa: |
182 | 14.8k | case OMa: |
183 | 15.0k | case OMb: |
184 | 15.8k | case OMc: |
185 | 15.8k | (*print_func) (stream, "\t%s, %d", name, (inst >> 4) & 0x1F); |
186 | 15.8k | break; |
187 | | |
188 | 6.65k | case I7: |
189 | 6.65k | (*print_func) (stream, "\t%s, %d", name, (inst >> 4) & 0x7F); |
190 | 6.65k | break; |
191 | | |
192 | 46.2k | case LS: |
193 | 46.2k | (*print_func) (stream, "\t%s, (%s, %d)", grname[(inst >> 8) & 0xF], |
194 | 46.2k | name, ((inst >> 4) & 0xF) << isiz[(inst >> 13) & 3]); |
195 | 46.2k | break; |
196 | | |
197 | 34.3k | case BR: |
198 | 34.3k | { |
199 | 34.3k | uint32_t val = ((inst & 0x3FF) ^ 0x400) - 0x400; |
200 | | |
201 | 34.3k | val = memaddr + 2 + (val << 1); |
202 | 34.3k | (*print_func) (stream, "\t0x%x", val); |
203 | | |
204 | 34.3k | if (strcmp (mcore_table[i].name, "bsr") == 0) |
205 | 21.6k | { |
206 | | /* For bsr, we'll try to get a symbol for the target. */ |
207 | 21.6k | if (info->print_address_func && val != 0) |
208 | 21.6k | { |
209 | 21.6k | (*print_func) (stream, "\t// "); |
210 | 21.6k | info->print_address_func (val, info); |
211 | 21.6k | } |
212 | 21.6k | } |
213 | 34.3k | } |
214 | 34.3k | break; |
215 | | |
216 | 1.14k | case BL: |
217 | 1.14k | { |
218 | 1.14k | uint32_t val = memaddr + 2 + ((inst | ~0xF) << 1); |
219 | | |
220 | 1.14k | (*print_func) (stream, "\t%s, 0x%x", |
221 | 1.14k | grname[(inst >> 4) & 0xF], val); |
222 | 1.14k | } |
223 | 1.14k | break; |
224 | | |
225 | 9.79k | case LR: |
226 | 9.79k | { |
227 | 9.79k | uint32_t val; |
228 | | |
229 | 9.79k | 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 | 9.79k | info->stop_vma = 0; |
234 | 9.79k | status = info->read_memory_func (val, ibytes, 4, info); |
235 | 9.79k | if (status != 0) |
236 | 1.31k | { |
237 | 1.31k | info->memory_error_func (status, memaddr, info); |
238 | 1.31k | break; |
239 | 1.31k | } |
240 | | |
241 | 8.48k | if (info->endian == BFD_ENDIAN_LITTLE) |
242 | 8.47k | val = (((unsigned) ibytes[3] << 24) | (ibytes[2] << 16) |
243 | 8.47k | | (ibytes[1] << 8) | (ibytes[0])); |
244 | 4 | else |
245 | 4 | val = (((unsigned) ibytes[0] << 24) | (ibytes[1] << 16) |
246 | 4 | | (ibytes[2] << 8) | (ibytes[3])); |
247 | | |
248 | | /* Removed [] around literal value to match ABI syntax 12/95. */ |
249 | 8.48k | (*print_func) (stream, "\t%s, 0x%X", grname[(inst >> 8) & 0xF], val); |
250 | | |
251 | 8.48k | if (val == 0) |
252 | 733 | (*print_func) (stream, "\t// from address pool at 0x%x", |
253 | 733 | (uint32_t) (memaddr + 2 |
254 | 733 | + ((inst & 0xFF) << 2)) & ~3); |
255 | 8.48k | } |
256 | 0 | break; |
257 | | |
258 | 2.31k | case LJ: |
259 | 2.31k | { |
260 | 2.31k | uint32_t val; |
261 | | |
262 | 2.31k | 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.31k | info->stop_vma = 0; |
267 | 2.31k | status = info->read_memory_func (val, ibytes, 4, info); |
268 | 2.31k | if (status != 0) |
269 | 353 | { |
270 | 353 | info->memory_error_func (status, memaddr, info); |
271 | 353 | break; |
272 | 353 | } |
273 | | |
274 | 1.96k | if (info->endian == BFD_ENDIAN_LITTLE) |
275 | 1.96k | val = (((unsigned) ibytes[3] << 24) | (ibytes[2] << 16) |
276 | 1.96k | | (ibytes[1] << 8) | (ibytes[0])); |
277 | 1 | else |
278 | 1 | val = (((unsigned) ibytes[0] << 24) | (ibytes[1] << 16) |
279 | 1 | | (ibytes[2] << 8) | (ibytes[3])); |
280 | | |
281 | | /* Removed [] around literal value to match ABI syntax 12/95. */ |
282 | 1.96k | (*print_func) (stream, "\t0x%X", val); |
283 | | /* For jmpi/jsri, we'll try to get a symbol for the target. */ |
284 | 1.96k | if (info->print_address_func && val != 0) |
285 | 1.74k | { |
286 | 1.74k | (*print_func) (stream, "\t// "); |
287 | 1.74k | info->print_address_func (val, info); |
288 | 1.74k | } |
289 | 219 | else |
290 | 219 | { |
291 | 219 | (*print_func) (stream, "\t// from address pool at 0x%x", |
292 | 219 | (uint32_t) (memaddr + 2 |
293 | 219 | + ((inst & 0xFF) << 2)) & ~3); |
294 | 219 | } |
295 | 1.96k | } |
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 | 636 | default: |
310 | | /* If the disassembler lags the instruction set. */ |
311 | 636 | (*print_func) (stream, "\tundecoded operands, inst is 0x%04x", inst); |
312 | 636 | break; |
313 | 184k | } |
314 | 184k | } |
315 | | |
316 | | /* Say how many bytes we consumed. */ |
317 | 209k | return 2; |
318 | 209k | } |