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