/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 | 89.1k | { |
34 | 89.1k | struct mn10200_opcode *op = (struct mn10200_opcode *)mn10200_opcodes; |
35 | 89.1k | const struct mn10200_operand *operand; |
36 | 89.1k | int match = 0; |
37 | | |
38 | | /* Find the opcode. */ |
39 | 5.17M | while (op->name) |
40 | 5.17M | { |
41 | 5.17M | int mysize, extra_shift; |
42 | | |
43 | 5.17M | if (op->format == FMT_1) |
44 | 525k | mysize = 1; |
45 | 4.65M | else if (op->format == FMT_2 |
46 | 4.65M | || op->format == FMT_4) |
47 | 2.13M | mysize = 2; |
48 | 2.51M | else if (op->format == FMT_3 |
49 | 2.51M | || op->format == FMT_5) |
50 | 808k | mysize = 3; |
51 | 1.70M | else if (op->format == FMT_6) |
52 | 731k | mysize = 4; |
53 | 977k | else if (op->format == FMT_7) |
54 | 977k | mysize = 5; |
55 | 0 | else |
56 | 0 | abort (); |
57 | | |
58 | 5.17M | if (op->format == FMT_2 || op->format == FMT_5) |
59 | 1.17M | extra_shift = 8; |
60 | 4.00M | else if (op->format == FMT_3 |
61 | 4.00M | || op->format == FMT_6 |
62 | 4.00M | || op->format == FMT_7) |
63 | 2.02M | extra_shift = 16; |
64 | 1.98M | else |
65 | 1.98M | extra_shift = 0; |
66 | | |
67 | 5.17M | if ((op->mask & insn) == op->opcode |
68 | 5.17M | && size == (unsigned int) mysize) |
69 | 88.4k | { |
70 | 88.4k | const unsigned char *opindex_ptr; |
71 | 88.4k | unsigned int nocomma; |
72 | 88.4k | int paren = 0; |
73 | | |
74 | 88.4k | match = 1; |
75 | 88.4k | (*info->fprintf_func) (info->stream, "%s\t", op->name); |
76 | | |
77 | | /* Now print the operands. */ |
78 | 88.4k | for (opindex_ptr = op->operands, nocomma = 1; |
79 | 356k | *opindex_ptr != 0; |
80 | 267k | opindex_ptr++) |
81 | 267k | { |
82 | 267k | unsigned long value; |
83 | | |
84 | 267k | operand = &mn10200_operands[*opindex_ptr]; |
85 | | |
86 | 267k | if ((operand->flags & MN10200_OPERAND_DREG) != 0 |
87 | 267k | || (operand->flags & MN10200_OPERAND_AREG) != 0) |
88 | 134k | value = ((insn >> (operand->shift + extra_shift)) |
89 | 134k | & ((1 << operand->bits) - 1)); |
90 | 132k | else if ((operand->flags & MN10200_OPERAND_EXTENDED) != 0) |
91 | 538 | { |
92 | 538 | value = (insn & 0xffff) << 8; |
93 | 538 | value |= extension; |
94 | 538 | } |
95 | 132k | else |
96 | 132k | value = ((insn >> (operand->shift)) |
97 | 132k | & ((1L << operand->bits) - 1L)); |
98 | | |
99 | 267k | if ((operand->flags & MN10200_OPERAND_SIGNED) != 0) |
100 | 20.6k | value = ((long)(value << (32 - operand->bits)) |
101 | 20.6k | >> (32 - operand->bits)); |
102 | | |
103 | 267k | if (!nocomma |
104 | 267k | && (!paren |
105 | 136k | || ((operand->flags & MN10200_OPERAND_PAREN) == 0))) |
106 | 82.9k | (*info->fprintf_func) (info->stream, ","); |
107 | | |
108 | 267k | nocomma = 0; |
109 | | |
110 | 267k | if ((operand->flags & MN10200_OPERAND_DREG) != 0) |
111 | 75.0k | (*info->fprintf_func) (info->stream, "d%ld", value); |
112 | | |
113 | 192k | else if ((operand->flags & MN10200_OPERAND_AREG) != 0) |
114 | 59.8k | (*info->fprintf_func) (info->stream, "a%ld", value); |
115 | | |
116 | 132k | else if ((operand->flags & MN10200_OPERAND_PSW) != 0) |
117 | 253 | (*info->fprintf_func) (info->stream, "psw"); |
118 | | |
119 | 132k | else if ((operand->flags & MN10200_OPERAND_MDR) != 0) |
120 | 253 | (*info->fprintf_func) (info->stream, "mdr"); |
121 | | |
122 | 132k | else if ((operand->flags & MN10200_OPERAND_PAREN) != 0) |
123 | 107k | { |
124 | 107k | if (paren) |
125 | 53.8k | (*info->fprintf_func) (info->stream, ")"); |
126 | 53.8k | else |
127 | 53.8k | { |
128 | 53.8k | (*info->fprintf_func) (info->stream, "("); |
129 | 53.8k | nocomma = 1; |
130 | 53.8k | } |
131 | 107k | paren = !paren; |
132 | 107k | } |
133 | | |
134 | 24.5k | else if ((operand->flags & MN10200_OPERAND_PCREL) != 0) |
135 | 4.17k | (*info->print_address_func) |
136 | 4.17k | ((value + memaddr + mysize) & 0xffffff, info); |
137 | | |
138 | 20.3k | else if ((operand->flags & MN10200_OPERAND_MEMADDR) != 0) |
139 | 2.35k | (*info->print_address_func) (value, info); |
140 | | |
141 | 17.9k | else |
142 | 17.9k | (*info->fprintf_func) (info->stream, "%ld", value); |
143 | 267k | } |
144 | | /* All done. */ |
145 | 88.4k | break; |
146 | 88.4k | } |
147 | 5.08M | op++; |
148 | 5.08M | } |
149 | | |
150 | 89.1k | if (!match) |
151 | 752 | (*info->fprintf_func) (info->stream, _("unknown\t0x%04lx"), insn); |
152 | 89.1k | } |
153 | | |
154 | | int |
155 | | print_insn_mn10200 (bfd_vma memaddr, struct disassemble_info *info) |
156 | 89.2k | { |
157 | 89.2k | int status; |
158 | 89.2k | bfd_byte buffer[4]; |
159 | 89.2k | unsigned long insn; |
160 | 89.2k | unsigned long extension = 0; |
161 | 89.2k | unsigned int consume; |
162 | | |
163 | | /* First figure out how big the opcode is. */ |
164 | 89.2k | status = (*info->read_memory_func) (memaddr, buffer, 1, info); |
165 | 89.2k | if (status != 0) |
166 | 1 | { |
167 | 1 | (*info->memory_error_func) (status, memaddr, info); |
168 | 1 | return -1; |
169 | 1 | } |
170 | | |
171 | 89.2k | insn = *(unsigned char *) buffer; |
172 | | |
173 | | /* These are one byte insns. */ |
174 | 89.2k | if ((insn & 0xf0) == 0x00 |
175 | 89.2k | || (insn & 0xf0) == 0x10 |
176 | 89.2k | || (insn & 0xf0) == 0x20 |
177 | 89.2k | || (insn & 0xf0) == 0x30 |
178 | 89.2k | || ((insn & 0xf0) == 0x80 |
179 | 50.9k | && (insn & 0x0c) >> 2 != (insn & 0x03)) |
180 | 89.2k | || (insn & 0xf0) == 0x90 |
181 | 89.2k | || (insn & 0xf0) == 0xa0 |
182 | 89.2k | || (insn & 0xf0) == 0xb0 |
183 | 89.2k | || (insn & 0xff) == 0xeb |
184 | 89.2k | || (insn & 0xff) == 0xf6 |
185 | 89.2k | || (insn & 0xff) == 0xfe |
186 | 89.2k | || (insn & 0xff) == 0xff) |
187 | 62.1k | { |
188 | 62.1k | extension = 0; |
189 | 62.1k | consume = 1; |
190 | 62.1k | } |
191 | | |
192 | | /* These are two byte insns. */ |
193 | 27.1k | else if ((insn & 0xf0) == 0x40 |
194 | 27.1k | || (insn & 0xf0) == 0x50 |
195 | 27.1k | || (insn & 0xf0) == 0x60 |
196 | 27.1k | || (insn & 0xf0) == 0x70 |
197 | 27.1k | || (insn & 0xf0) == 0x80 |
198 | 27.1k | || (insn & 0xfc) == 0xd0 |
199 | 27.1k | || (insn & 0xfc) == 0xd4 |
200 | 27.1k | || (insn & 0xfc) == 0xd8 |
201 | 27.1k | || (insn & 0xfc) == 0xe0 |
202 | 27.1k | || (insn & 0xfc) == 0xe4 |
203 | 27.1k | || (insn & 0xff) == 0xe8 |
204 | 27.1k | || (insn & 0xff) == 0xe9 |
205 | 27.1k | || (insn & 0xff) == 0xea |
206 | 27.1k | || (insn & 0xff) == 0xf0 |
207 | 27.1k | || (insn & 0xff) == 0xf1 |
208 | 27.1k | || (insn & 0xff) == 0xf2 |
209 | 27.1k | || (insn & 0xff) == 0xf3) |
210 | 20.3k | { |
211 | 20.3k | status = (*info->read_memory_func) (memaddr, buffer, 2, info); |
212 | 20.3k | if (status != 0) |
213 | 22 | { |
214 | 22 | (*info->memory_error_func) (status, memaddr, info); |
215 | 22 | return -1; |
216 | 22 | } |
217 | 20.2k | insn = bfd_getb16 (buffer); |
218 | 20.2k | consume = 2; |
219 | 20.2k | } |
220 | | |
221 | | /* These are three byte insns with a 16bit operand in little |
222 | | endian form. */ |
223 | 6.81k | else if ((insn & 0xf0) == 0xc0 |
224 | 6.81k | || (insn & 0xfc) == 0xdc |
225 | 6.81k | || (insn & 0xfc) == 0xec |
226 | 6.81k | || (insn & 0xff) == 0xf8 |
227 | 6.81k | || (insn & 0xff) == 0xf9 |
228 | 6.81k | || (insn & 0xff) == 0xfa |
229 | 6.81k | || (insn & 0xff) == 0xfb |
230 | 6.81k | || (insn & 0xff) == 0xfc |
231 | 6.81k | || (insn & 0xff) == 0xfd) |
232 | 5.63k | { |
233 | 5.63k | status = (*info->read_memory_func) (memaddr + 1, buffer, 2, info); |
234 | 5.63k | if (status != 0) |
235 | 15 | { |
236 | 15 | (*info->memory_error_func) (status, memaddr, info); |
237 | 15 | return -1; |
238 | 15 | } |
239 | 5.61k | insn <<= 16; |
240 | 5.61k | insn |= bfd_getl16 (buffer); |
241 | 5.61k | extension = 0; |
242 | 5.61k | consume = 3; |
243 | 5.61k | } |
244 | | /* These are three byte insns too, but we don't have to mess with |
245 | | endianness stuff. */ |
246 | 1.18k | else if ((insn & 0xff) == 0xf5) |
247 | 245 | { |
248 | 245 | status = (*info->read_memory_func) (memaddr + 1, buffer, 2, info); |
249 | 245 | if (status != 0) |
250 | 2 | { |
251 | 2 | (*info->memory_error_func) (status, memaddr, info); |
252 | 2 | return -1; |
253 | 2 | } |
254 | 243 | insn <<= 16; |
255 | 243 | insn |= bfd_getb16 (buffer); |
256 | 243 | extension = 0; |
257 | 243 | consume = 3; |
258 | 243 | } |
259 | | |
260 | | /* These are four byte insns. */ |
261 | 942 | else if ((insn & 0xff) == 0xf7) |
262 | 394 | { |
263 | 394 | status = (*info->read_memory_func) (memaddr, buffer, 2, info); |
264 | 394 | if (status != 0) |
265 | 1 | { |
266 | 1 | (*info->memory_error_func) (status, memaddr, info); |
267 | 1 | return -1; |
268 | 1 | } |
269 | 393 | insn = bfd_getb16 (buffer); |
270 | 393 | insn <<= 16; |
271 | 393 | status = (*info->read_memory_func) (memaddr + 2, buffer, 2, info); |
272 | 393 | if (status != 0) |
273 | 4 | { |
274 | 4 | (*info->memory_error_func) (status, memaddr, info); |
275 | 4 | return -1; |
276 | 4 | } |
277 | 389 | insn |= bfd_getl16 (buffer); |
278 | 389 | extension = 0; |
279 | 389 | consume = 4; |
280 | 389 | } |
281 | | |
282 | | /* These are five byte insns. */ |
283 | 548 | else if ((insn & 0xff) == 0xf4) |
284 | 548 | { |
285 | 548 | status = (*info->read_memory_func) (memaddr, buffer, 2, info); |
286 | 548 | if (status != 0) |
287 | 1 | { |
288 | 1 | (*info->memory_error_func) (status, memaddr, info); |
289 | 1 | return -1; |
290 | 1 | } |
291 | 547 | insn = bfd_getb16 (buffer); |
292 | 547 | insn <<= 16; |
293 | | |
294 | 547 | status = (*info->read_memory_func) (memaddr + 4, buffer, 1, info); |
295 | 547 | if (status != 0) |
296 | 3 | { |
297 | 3 | (*info->memory_error_func) (status, memaddr, info); |
298 | 3 | return -1; |
299 | 3 | } |
300 | 544 | insn |= (*(unsigned char *)buffer << 8) & 0xff00; |
301 | | |
302 | 544 | status = (*info->read_memory_func) (memaddr + 3, buffer, 1, info); |
303 | 544 | if (status != 0) |
304 | 0 | { |
305 | 0 | (*info->memory_error_func) (status, memaddr, info); |
306 | 0 | return -1; |
307 | 0 | } |
308 | 544 | insn |= (*(unsigned char *)buffer) & 0xff; |
309 | | |
310 | 544 | status = (*info->read_memory_func) (memaddr + 2, buffer, 1, info); |
311 | 544 | if (status != 0) |
312 | 0 | { |
313 | 0 | (*info->memory_error_func) (status, memaddr, info); |
314 | 0 | return -1; |
315 | 0 | } |
316 | 544 | extension = (*(unsigned char *)buffer) & 0xff; |
317 | 544 | consume = 5; |
318 | 544 | } |
319 | 0 | else |
320 | 0 | { |
321 | 0 | (*info->fprintf_func) (info->stream, _("unknown\t0x%02lx"), insn); |
322 | 0 | return 1; |
323 | 0 | } |
324 | | |
325 | 89.1k | disassemble (memaddr, info, insn, extension, consume); |
326 | | |
327 | 89.1k | return consume; |
328 | 89.2k | } |