/src/binutils-gdb/opcodes/m10200-dis.c
Line | Count | Source |
1 | | /* Disassemble MN10200 instructions. |
2 | | Copyright (C) 1996-2026 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 | 316k | { |
34 | 316k | struct mn10200_opcode *op = (struct mn10200_opcode *)mn10200_opcodes; |
35 | 316k | const struct mn10200_operand *operand; |
36 | 316k | int match = 0; |
37 | | |
38 | | /* Find the opcode. */ |
39 | 17.2M | while (op->name) |
40 | 17.2M | { |
41 | 17.2M | int mysize, extra_shift; |
42 | | |
43 | 17.2M | if (op->format == FMT_1) |
44 | 1.77M | mysize = 1; |
45 | 15.4M | else if (op->format == FMT_2 |
46 | 13.1M | || op->format == FMT_4) |
47 | 7.18M | mysize = 2; |
48 | 8.26M | else if (op->format == FMT_3 |
49 | 7.23M | || op->format == FMT_5) |
50 | 2.62M | mysize = 3; |
51 | 5.64M | else if (op->format == FMT_6) |
52 | 2.40M | mysize = 4; |
53 | 3.23M | else if (op->format == FMT_7) |
54 | 3.23M | mysize = 5; |
55 | 0 | else |
56 | 0 | abort (); |
57 | | |
58 | 17.2M | if (op->format == FMT_2 || op->format == FMT_5) |
59 | 3.87M | extra_shift = 8; |
60 | 13.3M | else if (op->format == FMT_3 |
61 | 12.3M | || op->format == FMT_6 |
62 | 9.91M | || op->format == FMT_7) |
63 | 6.66M | extra_shift = 16; |
64 | 6.67M | else |
65 | 6.67M | extra_shift = 0; |
66 | | |
67 | 17.2M | if ((op->mask & insn) == op->opcode |
68 | 337k | && size == (unsigned int) mysize) |
69 | 315k | { |
70 | 315k | const unsigned char *opindex_ptr; |
71 | 315k | unsigned int nocomma; |
72 | 315k | int paren = 0; |
73 | | |
74 | 315k | match = 1; |
75 | 315k | (*info->fprintf_func) (info->stream, "%s\t", op->name); |
76 | | |
77 | | /* Now print the operands. */ |
78 | 315k | for (opindex_ptr = op->operands, nocomma = 1; |
79 | 1.31M | *opindex_ptr != 0; |
80 | 995k | opindex_ptr++) |
81 | 995k | { |
82 | 995k | unsigned long value; |
83 | | |
84 | 995k | operand = &mn10200_operands[*opindex_ptr]; |
85 | | |
86 | 995k | if ((operand->flags & MN10200_OPERAND_DREG) != 0 |
87 | 724k | || (operand->flags & MN10200_OPERAND_AREG) != 0) |
88 | 498k | value = ((insn >> (operand->shift + extra_shift)) |
89 | 498k | & ((1 << operand->bits) - 1)); |
90 | 497k | else if ((operand->flags & MN10200_OPERAND_EXTENDED) != 0) |
91 | 535 | { |
92 | 535 | value = (insn & 0xffff) << 8; |
93 | 535 | value |= extension; |
94 | 535 | } |
95 | 497k | else |
96 | 497k | value = ((insn >> (operand->shift)) |
97 | 497k | & ((1L << operand->bits) - 1L)); |
98 | | |
99 | 995k | if ((operand->flags & MN10200_OPERAND_SIGNED) != 0) |
100 | 73.6k | value = ((long)(value << (32 - operand->bits)) |
101 | 73.6k | >> (32 - operand->bits)); |
102 | | |
103 | 995k | if (!nocomma |
104 | 513k | && (!paren |
105 | 258k | || ((operand->flags & MN10200_OPERAND_PAREN) == 0))) |
106 | 306k | (*info->fprintf_func) (info->stream, ","); |
107 | | |
108 | 995k | nocomma = 0; |
109 | | |
110 | 995k | if ((operand->flags & MN10200_OPERAND_DREG) != 0) |
111 | 271k | (*info->fprintf_func) (info->stream, "d%ld", value); |
112 | | |
113 | 724k | else if ((operand->flags & MN10200_OPERAND_AREG) != 0) |
114 | 226k | (*info->fprintf_func) (info->stream, "a%ld", value); |
115 | | |
116 | 497k | else if ((operand->flags & MN10200_OPERAND_PSW) != 0) |
117 | 464 | (*info->fprintf_func) (info->stream, "psw"); |
118 | | |
119 | 497k | else if ((operand->flags & MN10200_OPERAND_MDR) != 0) |
120 | 150 | (*info->fprintf_func) (info->stream, "mdr"); |
121 | | |
122 | 497k | else if ((operand->flags & MN10200_OPERAND_PAREN) != 0) |
123 | 412k | { |
124 | 412k | if (paren) |
125 | 206k | (*info->fprintf_func) (info->stream, ")"); |
126 | 206k | else |
127 | 206k | { |
128 | 206k | (*info->fprintf_func) (info->stream, "("); |
129 | 206k | nocomma = 1; |
130 | 206k | } |
131 | 412k | paren = !paren; |
132 | 412k | } |
133 | | |
134 | 84.8k | else if ((operand->flags & MN10200_OPERAND_PCREL) != 0) |
135 | 12.0k | (*info->print_address_func) |
136 | 12.0k | ((value + memaddr + mysize) & 0xffffff, info); |
137 | | |
138 | 72.8k | else if ((operand->flags & MN10200_OPERAND_MEMADDR) != 0) |
139 | 6.74k | (*info->print_address_func) (value, info); |
140 | | |
141 | 66.0k | else |
142 | 66.0k | (*info->fprintf_func) (info->stream, "%ld", value); |
143 | 995k | } |
144 | | /* All done. */ |
145 | 315k | break; |
146 | 315k | } |
147 | 16.9M | op++; |
148 | 16.9M | } |
149 | | |
150 | 316k | if (!match) |
151 | 1.27k | (*info->fprintf_func) (info->stream, _("unknown\t0x%04lx"), insn); |
152 | 316k | } |
153 | | |
154 | | int |
155 | | print_insn_mn10200 (bfd_vma memaddr, struct disassemble_info *info) |
156 | 316k | { |
157 | 316k | int status; |
158 | 316k | bfd_byte buffer[4]; |
159 | 316k | unsigned long insn; |
160 | 316k | unsigned long extension = 0; |
161 | 316k | unsigned int consume; |
162 | | |
163 | | /* First figure out how big the opcode is. */ |
164 | 316k | status = (*info->read_memory_func) (memaddr, buffer, 1, info); |
165 | 316k | if (status != 0) |
166 | 1 | { |
167 | 1 | (*info->memory_error_func) (status, memaddr, info); |
168 | 1 | return -1; |
169 | 1 | } |
170 | | |
171 | 316k | insn = *(unsigned char *) buffer; |
172 | | |
173 | | /* These are one byte insns. */ |
174 | 316k | if ((insn & 0xf0) == 0x00 |
175 | 215k | || (insn & 0xf0) == 0x10 |
176 | 201k | || (insn & 0xf0) == 0x20 |
177 | 185k | || (insn & 0xf0) == 0x30 |
178 | 169k | || ((insn & 0xf0) == 0x80 |
179 | 11.8k | && (insn & 0x0c) >> 2 != (insn & 0x03)) |
180 | 161k | || (insn & 0xf0) == 0x90 |
181 | 147k | || (insn & 0xf0) == 0xa0 |
182 | 137k | || (insn & 0xf0) == 0xb0 |
183 | 128k | || (insn & 0xff) == 0xeb |
184 | 127k | || (insn & 0xff) == 0xf6 |
185 | 126k | || (insn & 0xff) == 0xfe |
186 | 124k | || (insn & 0xff) == 0xff) |
187 | 226k | { |
188 | 226k | extension = 0; |
189 | 226k | consume = 1; |
190 | 226k | } |
191 | | |
192 | | /* These are two byte insns. */ |
193 | 89.9k | else if ((insn & 0xf0) == 0x40 |
194 | 74.9k | || (insn & 0xf0) == 0x50 |
195 | 67.3k | || (insn & 0xf0) == 0x60 |
196 | 53.5k | || (insn & 0xf0) == 0x70 |
197 | 40.3k | || (insn & 0xf0) == 0x80 |
198 | 36.8k | || (insn & 0xfc) == 0xd0 |
199 | 35.2k | || (insn & 0xfc) == 0xd4 |
200 | 33.3k | || (insn & 0xfc) == 0xd8 |
201 | 32.0k | || (insn & 0xfc) == 0xe0 |
202 | 29.3k | || (insn & 0xfc) == 0xe4 |
203 | 27.1k | || (insn & 0xff) == 0xe8 |
204 | 25.2k | || (insn & 0xff) == 0xe9 |
205 | 23.9k | || (insn & 0xff) == 0xea |
206 | 23.2k | || (insn & 0xff) == 0xf0 |
207 | 22.1k | || (insn & 0xff) == 0xf1 |
208 | 21.0k | || (insn & 0xff) == 0xf2 |
209 | 20.4k | || (insn & 0xff) == 0xf3) |
210 | 70.9k | { |
211 | 70.9k | status = (*info->read_memory_func) (memaddr, buffer, 2, info); |
212 | 70.9k | if (status != 0) |
213 | 53 | { |
214 | 53 | (*info->memory_error_func) (status, memaddr, info); |
215 | 53 | return -1; |
216 | 53 | } |
217 | 70.9k | insn = bfd_getb16 (buffer); |
218 | 70.9k | consume = 2; |
219 | 70.9k | } |
220 | | |
221 | | /* These are three byte insns with a 16bit operand in little |
222 | | endian form. */ |
223 | 18.9k | else if ((insn & 0xf0) == 0xc0 |
224 | 12.2k | || (insn & 0xfc) == 0xdc |
225 | 10.6k | || (insn & 0xfc) == 0xec |
226 | 8.55k | || (insn & 0xff) == 0xf8 |
227 | 7.73k | || (insn & 0xff) == 0xf9 |
228 | 6.96k | || (insn & 0xff) == 0xfa |
229 | 6.20k | || (insn & 0xff) == 0xfb |
230 | 5.45k | || (insn & 0xff) == 0xfc |
231 | 4.17k | || (insn & 0xff) == 0xfd) |
232 | 16.7k | { |
233 | 16.7k | status = (*info->read_memory_func) (memaddr + 1, buffer, 2, info); |
234 | 16.7k | if (status != 0) |
235 | 28 | { |
236 | 28 | (*info->memory_error_func) (status, memaddr, info); |
237 | 28 | return -1; |
238 | 28 | } |
239 | 16.7k | insn <<= 16; |
240 | 16.7k | insn |= bfd_getl16 (buffer); |
241 | 16.7k | extension = 0; |
242 | 16.7k | consume = 3; |
243 | 16.7k | } |
244 | | /* These are three byte insns too, but we don't have to mess with |
245 | | endianness stuff. */ |
246 | 2.23k | else if ((insn & 0xff) == 0xf5) |
247 | 837 | { |
248 | 837 | status = (*info->read_memory_func) (memaddr + 1, buffer, 2, info); |
249 | 837 | if (status != 0) |
250 | 2 | { |
251 | 2 | (*info->memory_error_func) (status, memaddr, info); |
252 | 2 | return -1; |
253 | 2 | } |
254 | 835 | insn <<= 16; |
255 | 835 | insn |= bfd_getb16 (buffer); |
256 | 835 | extension = 0; |
257 | 835 | consume = 3; |
258 | 835 | } |
259 | | |
260 | | /* These are four byte insns. */ |
261 | 1.39k | else if ((insn & 0xff) == 0xf7) |
262 | 746 | { |
263 | 746 | status = (*info->read_memory_func) (memaddr, buffer, 2, info); |
264 | 746 | if (status != 0) |
265 | 3 | { |
266 | 3 | (*info->memory_error_func) (status, memaddr, info); |
267 | 3 | return -1; |
268 | 3 | } |
269 | 743 | insn = bfd_getb16 (buffer); |
270 | 743 | insn <<= 16; |
271 | 743 | status = (*info->read_memory_func) (memaddr + 2, buffer, 2, info); |
272 | 743 | if (status != 0) |
273 | 2 | { |
274 | 2 | (*info->memory_error_func) (status, memaddr, info); |
275 | 2 | return -1; |
276 | 2 | } |
277 | 741 | insn |= bfd_getl16 (buffer); |
278 | 741 | extension = 0; |
279 | 741 | consume = 4; |
280 | 741 | } |
281 | | |
282 | | /* These are five byte insns. */ |
283 | 648 | else if ((insn & 0xff) == 0xf4) |
284 | 648 | { |
285 | 648 | status = (*info->read_memory_func) (memaddr, buffer, 2, info); |
286 | 648 | if (status != 0) |
287 | 3 | { |
288 | 3 | (*info->memory_error_func) (status, memaddr, info); |
289 | 3 | return -1; |
290 | 3 | } |
291 | 645 | insn = bfd_getb16 (buffer); |
292 | 645 | insn <<= 16; |
293 | | |
294 | 645 | status = (*info->read_memory_func) (memaddr + 4, buffer, 1, info); |
295 | 645 | if (status != 0) |
296 | 3 | { |
297 | 3 | (*info->memory_error_func) (status, memaddr, info); |
298 | 3 | return -1; |
299 | 3 | } |
300 | 642 | insn |= (*(unsigned char *)buffer << 8) & 0xff00; |
301 | | |
302 | 642 | status = (*info->read_memory_func) (memaddr + 3, buffer, 1, info); |
303 | 642 | if (status != 0) |
304 | 0 | { |
305 | 0 | (*info->memory_error_func) (status, memaddr, info); |
306 | 0 | return -1; |
307 | 0 | } |
308 | 642 | insn |= (*(unsigned char *)buffer) & 0xff; |
309 | | |
310 | 642 | status = (*info->read_memory_func) (memaddr + 2, buffer, 1, info); |
311 | 642 | if (status != 0) |
312 | 0 | { |
313 | 0 | (*info->memory_error_func) (status, memaddr, info); |
314 | 0 | return -1; |
315 | 0 | } |
316 | 642 | extension = (*(unsigned char *)buffer) & 0xff; |
317 | 642 | consume = 5; |
318 | 642 | } |
319 | 0 | else |
320 | 0 | { |
321 | 0 | (*info->fprintf_func) (info->stream, _("unknown\t0x%02lx"), insn); |
322 | 0 | return 1; |
323 | 0 | } |
324 | | |
325 | 316k | disassemble (memaddr, info, insn, extension, consume); |
326 | | |
327 | 316k | return consume; |
328 | 316k | } |