]>
Commit | Line | Data |
---|---|---|
3442f309 | 1 | /* Disassemble Motorola M*Core instructions. |
82704155 | 2 | Copyright (C) 1993-2019 Free Software Foundation, Inc. |
3f230321 | 3 | |
9b201bb5 | 4 | This file is part of the GNU opcodes library. |
3f230321 | 5 | |
9b201bb5 NC |
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. | |
3f230321 | 10 | |
9b201bb5 NC |
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. */ | |
3f230321 | 20 | |
0d8dfecf | 21 | #include "sysdep.h" |
3f230321 | 22 | #include <stdio.h> |
5703197e | 23 | #include "libiberty.h" |
3f230321 NC |
24 | #define STATIC_TABLE |
25 | #define DEFINE_TABLE | |
26 | ||
27 | #include "mcore-opc.h" | |
88c1242d | 28 | #include "disassemble.h" |
3f230321 | 29 | |
9cac79d3 | 30 | /* Mask for each mcore_opclass: */ |
7f6621cd | 31 | static const unsigned short imsk[] = { |
9cac79d3 NC |
32 | /* O0 */ 0xFFFF, |
33 | /* OT */ 0xFFFC, | |
34 | /* O1 */ 0xFFF0, | |
710c2d97 | 35 | /* OC */ 0xFE00, |
9cac79d3 NC |
36 | /* O2 */ 0xFF00, |
37 | /* X1 */ 0xFFF0, | |
38 | /* OI */ 0xFE00, | |
39 | /* OB */ 0xFE00, | |
7f6621cd | 40 | |
9cac79d3 NC |
41 | /* OMa */ 0xFFF0, |
42 | /* SI */ 0xFE00, | |
43 | /* I7 */ 0xF800, | |
44 | /* LS */ 0xF000, | |
45 | /* BR */ 0xF800, | |
46 | /* BL */ 0xFF00, | |
47 | /* LR */ 0xF000, | |
48 | /* LJ */ 0xFF00, | |
7f6621cd | 49 | |
9cac79d3 NC |
50 | /* RM */ 0xFFF0, |
51 | /* RQ */ 0xFFF0, | |
52 | /* JSR */ 0xFFF0, | |
53 | /* JMP */ 0xFFF0, | |
54 | /* OBRa*/ 0xFFF0, | |
55 | /* OBRb*/ 0xFF80, | |
56 | /* OBRc*/ 0xFF00, | |
57 | /* OBR2*/ 0xFE00, | |
7f6621cd | 58 | |
9cac79d3 NC |
59 | /* O1R1*/ 0xFFF0, |
60 | /* OMb */ 0xFF80, | |
61 | /* OMc */ 0xFF00, | |
62 | /* SIa */ 0xFE00, | |
63 | ||
7f6621cd | 64 | /* MULSH */ 0xFF00, |
97ee9b94 | 65 | /* OPSR */ 0xFFF8, /* psrset/psrclr */ |
7f6621cd | 66 | |
3f230321 NC |
67 | /* JC */ 0, /* JC,JU,JL don't appear in object */ |
68 | /* JU */ 0, | |
69 | /* JL */ 0, | |
70 | /* RSI */ 0, | |
71 | /* DO21*/ 0, | |
7f6621cd | 72 | /* OB2 */ 0 /* OB2 won't appear in object. */ |
3f230321 NC |
73 | }; |
74 | ||
7f6621cd | 75 | static const char *grname[] = { |
3f230321 NC |
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 | ||
7f6621cd | 82 | static const char *crname[] = { |
3f230321 NC |
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 | ||
7f6621cd | 91 | int |
bdc4de1b NC |
92 | print_insn_mcore (bfd_vma memaddr, |
93 | struct disassemble_info *info) | |
3f230321 | 94 | { |
6a51a8a8 | 95 | unsigned char ibytes[4]; |
91d6fa6a | 96 | fprintf_ftype print_func = info->fprintf_func; |
6a51a8a8 AM |
97 | void *stream = info->stream; |
98 | unsigned short inst; | |
5703197e | 99 | unsigned int i; |
6a51a8a8 | 100 | int status; |
3f230321 NC |
101 | |
102 | info->bytes_per_chunk = 2; | |
103 | ||
104 | status = info->read_memory_func (memaddr, ibytes, 2, info); | |
105 | ||
7f6621cd | 106 | if (status != 0) |
3f230321 NC |
107 | { |
108 | info->memory_error_func (status, memaddr, info); | |
109 | return -1; | |
110 | } | |
111 | ||
97ee9b94 | 112 | if (info->endian == BFD_ENDIAN_BIG) |
3f230321 | 113 | inst = (ibytes[0] << 8) | ibytes[1]; |
97ee9b94 NC |
114 | else if (info->endian == BFD_ENDIAN_LITTLE) |
115 | inst = (ibytes[1] << 8) | ibytes[0]; | |
116 | else | |
117 | abort (); | |
3f230321 NC |
118 | |
119 | /* Just a linear search of the table. */ | |
5703197e TS |
120 | for (i = 0; i < ARRAY_SIZE (mcore_table); i++) |
121 | if (mcore_table[i].inst == (inst & imsk[mcore_table[i].opclass])) | |
3f230321 NC |
122 | break; |
123 | ||
5703197e | 124 | if (i == ARRAY_SIZE (mcore_table)) |
91d6fa6a | 125 | (*print_func) (stream, ".short 0x%04x", inst); |
3f230321 NC |
126 | else |
127 | { | |
7f6621cd KH |
128 | const char *name = grname[inst & 0x0F]; |
129 | ||
5703197e | 130 | (*print_func) (stream, "%s", mcore_table[i].name); |
7f6621cd | 131 | |
5703197e | 132 | switch (mcore_table[i].opclass) |
3f230321 | 133 | { |
6a51a8a8 AM |
134 | case O0: |
135 | break; | |
136 | ||
137 | case OT: | |
91d6fa6a | 138 | (*print_func) (stream, "\t%d", inst & 0x3); |
6a51a8a8 AM |
139 | break; |
140 | ||
3f230321 NC |
141 | case O1: |
142 | case JMP: | |
6a51a8a8 | 143 | case JSR: |
91d6fa6a | 144 | (*print_func) (stream, "\t%s", name); |
6a51a8a8 AM |
145 | break; |
146 | ||
147 | case OC: | |
91d6fa6a | 148 | (*print_func) (stream, "\t%s, %s", name, crname[(inst >> 4) & 0x1F]); |
6a51a8a8 AM |
149 | break; |
150 | ||
151 | case O1R1: | |
91d6fa6a | 152 | (*print_func) (stream, "\t%s, r1", name); |
6a51a8a8 AM |
153 | break; |
154 | ||
97ee9b94 | 155 | case MULSH: |
6a51a8a8 | 156 | case O2: |
91d6fa6a | 157 | (*print_func) (stream, "\t%s, %s", name, grname[(inst >> 4) & 0xF]); |
6a51a8a8 AM |
158 | break; |
159 | ||
160 | case X1: | |
91d6fa6a | 161 | (*print_func) (stream, "\tr1, %s", name); |
6a51a8a8 AM |
162 | break; |
163 | ||
164 | case OI: | |
91d6fa6a | 165 | (*print_func) (stream, "\t%s, %d", name, ((inst >> 4) & 0x1F) + 1); |
6a51a8a8 AM |
166 | break; |
167 | ||
168 | case RM: | |
91d6fa6a | 169 | (*print_func) (stream, "\t%s-r15, (r0)", name); |
6a51a8a8 AM |
170 | break; |
171 | ||
172 | case RQ: | |
91d6fa6a | 173 | (*print_func) (stream, "\tr4-r7, (%s)", name); |
6a51a8a8 AM |
174 | break; |
175 | ||
3f230321 NC |
176 | case OB: |
177 | case OBRa: | |
178 | case OBRb: | |
179 | case OBRc: | |
180 | case SI: | |
181 | case SIa: | |
182 | case OMa: | |
183 | case OMb: | |
6a51a8a8 | 184 | case OMc: |
91d6fa6a | 185 | (*print_func) (stream, "\t%s, %d", name, (inst >> 4) & 0x1F); |
6a51a8a8 AM |
186 | break; |
187 | ||
188 | case I7: | |
91d6fa6a | 189 | (*print_func) (stream, "\t%s, %d", name, (inst >> 4) & 0x7F); |
6a51a8a8 AM |
190 | break; |
191 | ||
192 | case LS: | |
91d6fa6a NC |
193 | (*print_func) (stream, "\t%s, (%s, %d)", grname[(inst >> 8) & 0xF], |
194 | name, ((inst >> 4) & 0xF) << isiz[(inst >> 13) & 3]); | |
3f230321 | 195 | break; |
7f6621cd | 196 | |
3f230321 NC |
197 | case BR: |
198 | { | |
2480b6fa | 199 | uint32_t val = ((inst & 0x3FF) ^ 0x400) - 0x400; |
7f6621cd | 200 | |
2480b6fa AM |
201 | val = memaddr + 2 + (val << 1); |
202 | (*print_func) (stream, "\t0x%x", val); | |
7f6621cd | 203 | |
5703197e | 204 | if (strcmp (mcore_table[i].name, "bsr") == 0) |
3f230321 | 205 | { |
c1485d85 | 206 | /* For bsr, we'll try to get a symbol for the target. */ |
3f230321 NC |
207 | if (info->print_address_func && val != 0) |
208 | { | |
91d6fa6a | 209 | (*print_func) (stream, "\t// "); |
3f230321 NC |
210 | info->print_address_func (val, info); |
211 | } | |
212 | } | |
213 | } | |
214 | break; | |
7f6621cd | 215 | |
3f230321 NC |
216 | case BL: |
217 | { | |
2480b6fa AM |
218 | uint32_t val = inst & 0x000F; |
219 | (*print_func) (stream, "\t%s, 0x%x", | |
91d6fa6a | 220 | grname[(inst >> 4) & 0xF], |
2480b6fa | 221 | (uint32_t) (memaddr - (val << 1))); |
3f230321 NC |
222 | } |
223 | break; | |
7f6621cd | 224 | |
3f230321 NC |
225 | case LR: |
226 | { | |
2480b6fa | 227 | uint32_t val; |
7f6621cd | 228 | |
2480b6fa | 229 | val = (memaddr + 2 + ((inst & 0xFF) << 2)) & ~3; |
7f6621cd | 230 | |
bdc4de1b NC |
231 | /* We are not reading an instruction, so allow |
232 | reads to extend beyond the next symbol. */ | |
233 | info->stop_vma = 0; | |
3f230321 | 234 | status = info->read_memory_func (val, ibytes, 4, info); |
7f6621cd | 235 | if (status != 0) |
3f230321 NC |
236 | { |
237 | info->memory_error_func (status, memaddr, info); | |
238 | break; | |
239 | } | |
7f6621cd | 240 | |
97ee9b94 | 241 | if (info->endian == BFD_ENDIAN_LITTLE) |
2480b6fa AM |
242 | val = (((unsigned) ibytes[3] << 24) | (ibytes[2] << 16) |
243 | | (ibytes[1] << 8) | (ibytes[0])); | |
97ee9b94 | 244 | else |
2480b6fa AM |
245 | val = (((unsigned) ibytes[0] << 24) | (ibytes[1] << 16) |
246 | | (ibytes[2] << 8) | (ibytes[3])); | |
7f6621cd | 247 | |
3f230321 | 248 | /* Removed [] around literal value to match ABI syntax 12/95. */ |
2480b6fa | 249 | (*print_func) (stream, "\t%s, 0x%X", grname[(inst >> 8) & 0xF], val); |
3f230321 NC |
250 | |
251 | if (val == 0) | |
2480b6fa AM |
252 | (*print_func) (stream, "\t// from address pool at 0x%x", |
253 | (uint32_t) (memaddr + 2 | |
254 | + ((inst & 0xFF) << 2)) & ~3); | |
3f230321 NC |
255 | } |
256 | break; | |
7f6621cd | 257 | |
3f230321 NC |
258 | case LJ: |
259 | { | |
2480b6fa | 260 | uint32_t val; |
7f6621cd | 261 | |
2480b6fa | 262 | val = (memaddr + 2 + ((inst & 0xFF) << 2)) & ~3; |
7f6621cd | 263 | |
bdc4de1b NC |
264 | /* We are not reading an instruction, so allow |
265 | reads to extend beyond the next symbol. */ | |
266 | info->stop_vma = 0; | |
3f230321 | 267 | status = info->read_memory_func (val, ibytes, 4, info); |
7f6621cd | 268 | if (status != 0) |
3f230321 NC |
269 | { |
270 | info->memory_error_func (status, memaddr, info); | |
271 | break; | |
272 | } | |
273 | ||
97ee9b94 | 274 | if (info->endian == BFD_ENDIAN_LITTLE) |
2480b6fa AM |
275 | val = (((unsigned) ibytes[3] << 24) | (ibytes[2] << 16) |
276 | | (ibytes[1] << 8) | (ibytes[0])); | |
97ee9b94 | 277 | else |
2480b6fa AM |
278 | val = (((unsigned) ibytes[0] << 24) | (ibytes[1] << 16) |
279 | | (ibytes[2] << 8) | (ibytes[3])); | |
7f6621cd | 280 | |
3f230321 | 281 | /* Removed [] around literal value to match ABI syntax 12/95. */ |
2480b6fa | 282 | (*print_func) (stream, "\t0x%X", val); |
3f230321 NC |
283 | /* For jmpi/jsri, we'll try to get a symbol for the target. */ |
284 | if (info->print_address_func && val != 0) | |
285 | { | |
91d6fa6a | 286 | (*print_func) (stream, "\t// "); |
3f230321 NC |
287 | info->print_address_func (val, info); |
288 | } | |
289 | else | |
290 | { | |
2480b6fa AM |
291 | (*print_func) (stream, "\t// from address pool at 0x%x", |
292 | (uint32_t) (memaddr + 2 | |
293 | + ((inst & 0xFF) << 2)) & ~3); | |
3f230321 NC |
294 | } |
295 | } | |
296 | break; | |
7f6621cd | 297 | |
97ee9b94 NC |
298 | case OPSR: |
299 | { | |
7f6621cd KH |
300 | static char *fields[] = { |
301 | "af", "ie", "fe", "fe,ie", | |
97ee9b94 NC |
302 | "ee", "ee,ie", "ee,fe", "ee,fe,ie" |
303 | }; | |
7f6621cd | 304 | |
91d6fa6a | 305 | (*print_func) (stream, "\t%s", fields[inst & 0x7]); |
97ee9b94 NC |
306 | } |
307 | break; | |
7f6621cd | 308 | |
3f230321 | 309 | default: |
c1485d85 | 310 | /* If the disassembler lags the instruction set. */ |
91d6fa6a | 311 | (*print_func) (stream, "\tundecoded operands, inst is 0x%04x", inst); |
3f230321 NC |
312 | break; |
313 | } | |
314 | } | |
7f6621cd | 315 | |
c1485d85 | 316 | /* Say how many bytes we consumed. */ |
3f230321 NC |
317 | return 2; |
318 | } |