/src/binutils-gdb/opcodes/m10200-dis.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Disassemble MN10200 instructions. |
2 | | Copyright (C) 1996-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 "opcode/mn10200.h" |
24 | | #include "disassemble.h" |
25 | | #include "opintl.h" |
26 | | |
27 | | static void |
28 | | disassemble (bfd_vma memaddr, |
29 | | struct disassemble_info *info, |
30 | | unsigned long insn, |
31 | | unsigned long extension, |
32 | | unsigned int size) |
33 | 64.4k | { |
34 | 64.4k | struct mn10200_opcode *op = (struct mn10200_opcode *)mn10200_opcodes; |
35 | 64.4k | const struct mn10200_operand *operand; |
36 | 64.4k | int match = 0; |
37 | | |
38 | | /* Find the opcode. */ |
39 | 3.88M | while (op->name) |
40 | 3.87M | { |
41 | 3.87M | int mysize, extra_shift; |
42 | | |
43 | 3.87M | if (op->format == FMT_1) |
44 | 387k | mysize = 1; |
45 | 3.49M | else if (op->format == FMT_2 |
46 | 3.49M | || op->format == FMT_4) |
47 | 1.59M | mysize = 2; |
48 | 1.89M | else if (op->format == FMT_3 |
49 | 1.89M | || op->format == FMT_5) |
50 | 615k | mysize = 3; |
51 | 1.27M | else if (op->format == FMT_6) |
52 | 551k | mysize = 4; |
53 | 728k | else if (op->format == FMT_7) |
54 | 728k | mysize = 5; |
55 | 0 | else |
56 | 0 | abort (); |
57 | | |
58 | 3.87M | if (op->format == FMT_2 || op->format == FMT_5) |
59 | 889k | extra_shift = 8; |
60 | 2.98M | else if (op->format == FMT_3 |
61 | 2.98M | || op->format == FMT_6 |
62 | 2.98M | || op->format == FMT_7) |
63 | 1.51M | extra_shift = 16; |
64 | 1.47M | else |
65 | 1.47M | extra_shift = 0; |
66 | | |
67 | 3.87M | if ((op->mask & insn) == op->opcode |
68 | 3.87M | && size == (unsigned int) mysize) |
69 | 63.5k | { |
70 | 63.5k | const unsigned char *opindex_ptr; |
71 | 63.5k | unsigned int nocomma; |
72 | 63.5k | int paren = 0; |
73 | | |
74 | 63.5k | match = 1; |
75 | 63.5k | (*info->fprintf_func) (info->stream, "%s\t", op->name); |
76 | | |
77 | | /* Now print the operands. */ |
78 | 63.5k | for (opindex_ptr = op->operands, nocomma = 1; |
79 | 250k | *opindex_ptr != 0; |
80 | 187k | opindex_ptr++) |
81 | 187k | { |
82 | 187k | unsigned long value; |
83 | | |
84 | 187k | operand = &mn10200_operands[*opindex_ptr]; |
85 | | |
86 | 187k | if ((operand->flags & MN10200_OPERAND_DREG) != 0 |
87 | 187k | || (operand->flags & MN10200_OPERAND_AREG) != 0) |
88 | 93.6k | value = ((insn >> (operand->shift + extra_shift)) |
89 | 93.6k | & ((1 << operand->bits) - 1)); |
90 | 93.6k | else if ((operand->flags & MN10200_OPERAND_EXTENDED) != 0) |
91 | 541 | { |
92 | 541 | value = (insn & 0xffff) << 8; |
93 | 541 | value |= extension; |
94 | 541 | } |
95 | 93.0k | else |
96 | 93.0k | value = ((insn >> (operand->shift)) |
97 | 93.0k | & ((1L << operand->bits) - 1L)); |
98 | | |
99 | 187k | if ((operand->flags & MN10200_OPERAND_SIGNED) != 0) |
100 | 16.4k | value = ((long)(value << (32 - operand->bits)) |
101 | 16.4k | >> (32 - operand->bits)); |
102 | | |
103 | 187k | if (!nocomma |
104 | 187k | && (!paren |
105 | 95.6k | || ((operand->flags & MN10200_OPERAND_PAREN) == 0))) |
106 | 59.2k | (*info->fprintf_func) (info->stream, ","); |
107 | | |
108 | 187k | nocomma = 0; |
109 | | |
110 | 187k | if ((operand->flags & MN10200_OPERAND_DREG) != 0) |
111 | 53.2k | (*info->fprintf_func) (info->stream, "d%ld", value); |
112 | | |
113 | 133k | else if ((operand->flags & MN10200_OPERAND_AREG) != 0) |
114 | 40.3k | (*info->fprintf_func) (info->stream, "a%ld", value); |
115 | | |
116 | 93.6k | else if ((operand->flags & MN10200_OPERAND_PSW) != 0) |
117 | 375 | (*info->fprintf_func) (info->stream, "psw"); |
118 | | |
119 | 93.2k | else if ((operand->flags & MN10200_OPERAND_MDR) != 0) |
120 | 227 | (*info->fprintf_func) (info->stream, "mdr"); |
121 | | |
122 | 93.0k | else if ((operand->flags & MN10200_OPERAND_PAREN) != 0) |
123 | 72.9k | { |
124 | 72.9k | if (paren) |
125 | 36.4k | (*info->fprintf_func) (info->stream, ")"); |
126 | 36.4k | else |
127 | 36.4k | { |
128 | 36.4k | (*info->fprintf_func) (info->stream, "("); |
129 | 36.4k | nocomma = 1; |
130 | 36.4k | } |
131 | 72.9k | paren = !paren; |
132 | 72.9k | } |
133 | | |
134 | 20.0k | else if ((operand->flags & MN10200_OPERAND_PCREL) != 0) |
135 | 3.84k | (*info->print_address_func) |
136 | 3.84k | ((value + memaddr + mysize) & 0xffffff, info); |
137 | | |
138 | 16.1k | else if ((operand->flags & MN10200_OPERAND_MEMADDR) != 0) |
139 | 2.00k | (*info->print_address_func) (value, info); |
140 | | |
141 | 14.1k | else |
142 | 14.1k | (*info->fprintf_func) (info->stream, "%ld", value); |
143 | 187k | } |
144 | | /* All done. */ |
145 | 63.5k | break; |
146 | 63.5k | } |
147 | 3.81M | op++; |
148 | 3.81M | } |
149 | | |
150 | 64.4k | if (!match) |
151 | 872 | (*info->fprintf_func) (info->stream, _("unknown\t0x%04lx"), insn); |
152 | 64.4k | } |
153 | | |
154 | | int |
155 | | print_insn_mn10200 (bfd_vma memaddr, struct disassemble_info *info) |
156 | 64.5k | { |
157 | 64.5k | int status; |
158 | 64.5k | bfd_byte buffer[4]; |
159 | 64.5k | unsigned long insn; |
160 | 64.5k | unsigned long extension = 0; |
161 | 64.5k | unsigned int consume; |
162 | | |
163 | | /* First figure out how big the opcode is. */ |
164 | 64.5k | status = (*info->read_memory_func) (memaddr, buffer, 1, info); |
165 | 64.5k | if (status != 0) |
166 | 1 | { |
167 | 1 | (*info->memory_error_func) (status, memaddr, info); |
168 | 1 | return -1; |
169 | 1 | } |
170 | | |
171 | 64.5k | insn = *(unsigned char *) buffer; |
172 | | |
173 | | /* These are one byte insns. */ |
174 | 64.5k | if ((insn & 0xf0) == 0x00 |
175 | 64.5k | || (insn & 0xf0) == 0x10 |
176 | 64.5k | || (insn & 0xf0) == 0x20 |
177 | 64.5k | || (insn & 0xf0) == 0x30 |
178 | 64.5k | || ((insn & 0xf0) == 0x80 |
179 | 39.9k | && (insn & 0x0c) >> 2 != (insn & 0x03)) |
180 | 64.5k | || (insn & 0xf0) == 0x90 |
181 | 64.5k | || (insn & 0xf0) == 0xa0 |
182 | 64.5k | || (insn & 0xf0) == 0xb0 |
183 | 64.5k | || (insn & 0xff) == 0xeb |
184 | 64.5k | || (insn & 0xff) == 0xf6 |
185 | 64.5k | || (insn & 0xff) == 0xfe |
186 | 64.5k | || (insn & 0xff) == 0xff) |
187 | 41.8k | { |
188 | 41.8k | extension = 0; |
189 | 41.8k | consume = 1; |
190 | 41.8k | } |
191 | | |
192 | | /* These are two byte insns. */ |
193 | 22.6k | else if ((insn & 0xf0) == 0x40 |
194 | 22.6k | || (insn & 0xf0) == 0x50 |
195 | 22.6k | || (insn & 0xf0) == 0x60 |
196 | 22.6k | || (insn & 0xf0) == 0x70 |
197 | 22.6k | || (insn & 0xf0) == 0x80 |
198 | 22.6k | || (insn & 0xfc) == 0xd0 |
199 | 22.6k | || (insn & 0xfc) == 0xd4 |
200 | 22.6k | || (insn & 0xfc) == 0xd8 |
201 | 22.6k | || (insn & 0xfc) == 0xe0 |
202 | 22.6k | || (insn & 0xfc) == 0xe4 |
203 | 22.6k | || (insn & 0xff) == 0xe8 |
204 | 22.6k | || (insn & 0xff) == 0xe9 |
205 | 22.6k | || (insn & 0xff) == 0xea |
206 | 22.6k | || (insn & 0xff) == 0xf0 |
207 | 22.6k | || (insn & 0xff) == 0xf1 |
208 | 22.6k | || (insn & 0xff) == 0xf2 |
209 | 22.6k | || (insn & 0xff) == 0xf3) |
210 | 16.0k | { |
211 | 16.0k | status = (*info->read_memory_func) (memaddr, buffer, 2, info); |
212 | 16.0k | if (status != 0) |
213 | 29 | { |
214 | 29 | (*info->memory_error_func) (status, memaddr, info); |
215 | 29 | return -1; |
216 | 29 | } |
217 | 16.0k | insn = bfd_getb16 (buffer); |
218 | 16.0k | consume = 2; |
219 | 16.0k | } |
220 | | |
221 | | /* These are three byte insns with a 16bit operand in little |
222 | | endian form. */ |
223 | 6.60k | else if ((insn & 0xf0) == 0xc0 |
224 | 6.60k | || (insn & 0xfc) == 0xdc |
225 | 6.60k | || (insn & 0xfc) == 0xec |
226 | 6.60k | || (insn & 0xff) == 0xf8 |
227 | 6.60k | || (insn & 0xff) == 0xf9 |
228 | 6.60k | || (insn & 0xff) == 0xfa |
229 | 6.60k | || (insn & 0xff) == 0xfb |
230 | 6.60k | || (insn & 0xff) == 0xfc |
231 | 6.60k | || (insn & 0xff) == 0xfd) |
232 | 5.37k | { |
233 | 5.37k | status = (*info->read_memory_func) (memaddr + 1, buffer, 2, info); |
234 | 5.37k | if (status != 0) |
235 | 19 | { |
236 | 19 | (*info->memory_error_func) (status, memaddr, info); |
237 | 19 | return -1; |
238 | 19 | } |
239 | 5.35k | insn <<= 16; |
240 | 5.35k | insn |= bfd_getl16 (buffer); |
241 | 5.35k | extension = 0; |
242 | 5.35k | consume = 3; |
243 | 5.35k | } |
244 | | /* These are three byte insns too, but we don't have to mess with |
245 | | endianness stuff. */ |
246 | 1.22k | else if ((insn & 0xff) == 0xf5) |
247 | 368 | { |
248 | 368 | status = (*info->read_memory_func) (memaddr + 1, buffer, 2, info); |
249 | 368 | if (status != 0) |
250 | 3 | { |
251 | 3 | (*info->memory_error_func) (status, memaddr, info); |
252 | 3 | return -1; |
253 | 3 | } |
254 | 365 | insn <<= 16; |
255 | 365 | insn |= bfd_getb16 (buffer); |
256 | 365 | extension = 0; |
257 | 365 | consume = 3; |
258 | 365 | } |
259 | | |
260 | | /* These are four byte insns. */ |
261 | 860 | else if ((insn & 0xff) == 0xf7) |
262 | 316 | { |
263 | 316 | status = (*info->read_memory_func) (memaddr, buffer, 2, info); |
264 | 316 | if (status != 0) |
265 | 1 | { |
266 | 1 | (*info->memory_error_func) (status, memaddr, info); |
267 | 1 | return -1; |
268 | 1 | } |
269 | 315 | insn = bfd_getb16 (buffer); |
270 | 315 | insn <<= 16; |
271 | 315 | status = (*info->read_memory_func) (memaddr + 2, buffer, 2, info); |
272 | 315 | if (status != 0) |
273 | 3 | { |
274 | 3 | (*info->memory_error_func) (status, memaddr, info); |
275 | 3 | return -1; |
276 | 3 | } |
277 | 312 | insn |= bfd_getl16 (buffer); |
278 | 312 | extension = 0; |
279 | 312 | consume = 4; |
280 | 312 | } |
281 | | |
282 | | /* These are five byte insns. */ |
283 | 544 | else if ((insn & 0xff) == 0xf4) |
284 | 544 | { |
285 | 544 | status = (*info->read_memory_func) (memaddr, buffer, 2, info); |
286 | 544 | if (status != 0) |
287 | 1 | { |
288 | 1 | (*info->memory_error_func) (status, memaddr, info); |
289 | 1 | return -1; |
290 | 1 | } |
291 | 543 | insn = bfd_getb16 (buffer); |
292 | 543 | insn <<= 16; |
293 | | |
294 | 543 | status = (*info->read_memory_func) (memaddr + 4, buffer, 1, info); |
295 | 543 | if (status != 0) |
296 | 2 | { |
297 | 2 | (*info->memory_error_func) (status, memaddr, info); |
298 | 2 | return -1; |
299 | 2 | } |
300 | 541 | insn |= (*(unsigned char *)buffer << 8) & 0xff00; |
301 | | |
302 | 541 | status = (*info->read_memory_func) (memaddr + 3, buffer, 1, info); |
303 | 541 | if (status != 0) |
304 | 0 | { |
305 | 0 | (*info->memory_error_func) (status, memaddr, info); |
306 | 0 | return -1; |
307 | 0 | } |
308 | 541 | insn |= (*(unsigned char *)buffer) & 0xff; |
309 | | |
310 | 541 | status = (*info->read_memory_func) (memaddr + 2, buffer, 1, info); |
311 | 541 | if (status != 0) |
312 | 0 | { |
313 | 0 | (*info->memory_error_func) (status, memaddr, info); |
314 | 0 | return -1; |
315 | 0 | } |
316 | 541 | extension = (*(unsigned char *)buffer) & 0xff; |
317 | 541 | consume = 5; |
318 | 541 | } |
319 | 0 | else |
320 | 0 | { |
321 | 0 | (*info->fprintf_func) (info->stream, _("unknown\t0x%02lx"), insn); |
322 | 0 | return 1; |
323 | 0 | } |
324 | | |
325 | 64.4k | disassemble (memaddr, info, insn, extension, consume); |
326 | | |
327 | 64.4k | return consume; |
328 | 64.5k | } |