]>
Commit | Line | Data |
---|---|---|
1c0d3aa6 NC |
1 | /* Instruction printing code for Score |
2 | Copyright 2006 Free Software Foundation, Inc. | |
3 | Contributed by: | |
4 | Mei Ligang ([email protected]) | |
5 | Pei-Lin Tsai ([email protected]) | |
6 | ||
7 | This file is part of libopcodes. | |
8 | ||
9 | This program is free software; you can redistribute it and/or modify it under | |
10 | the terms of the GNU General Public License as published by the Free | |
11 | Software Foundation; either version 2 of the License, or (at your option) | |
12 | any later version. | |
13 | ||
14 | This program is distributed in the hope that it will be useful, but WITHOUT | |
15 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
16 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
17 | more details. | |
18 | ||
19 | You should have received a copy of the GNU General Public License | |
20 | along with this program; if not, write to the Free Software | |
21 | Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA | |
22 | 02110-1301, USA. */ | |
23 | ||
24 | #include "sysdep.h" | |
25 | #include "dis-asm.h" | |
26 | #define DEFINE_TABLE | |
27 | #include "score-opc.h" | |
28 | #include "opintl.h" | |
29 | #include "bfd.h" | |
30 | ||
31 | /* FIXME: This shouldn't be done here. */ | |
32 | #include "elf-bfd.h" | |
33 | #include "elf/internal.h" | |
34 | #include "elf/score.h" | |
35 | ||
36 | #ifndef streq | |
37 | #define streq(a,b) (strcmp ((a), (b)) == 0) | |
38 | #endif | |
39 | ||
40 | #ifndef strneq | |
41 | #define strneq(a,b,n) (strncmp ((a), (b), (n)) == 0) | |
42 | #endif | |
43 | ||
44 | #ifndef NUM_ELEM | |
45 | #define NUM_ELEM(a) (sizeof (a) / sizeof (a)[0]) | |
46 | #endif | |
47 | ||
48 | typedef struct | |
49 | { | |
50 | const char *name; | |
51 | const char *description; | |
52 | const char *reg_names[32]; | |
53 | } score_regname; | |
54 | ||
55 | static score_regname regnames[] = | |
56 | { | |
57 | {"gcc", "Select register names used by GCC", | |
58 | {"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", | |
59 | "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", | |
60 | "r21", "r22", "r23", "r24", "r25", "r26", "r27", "gp", "r29", "r30", "r31"}}, | |
61 | }; | |
62 | ||
63 | static unsigned int regname_selected = 0; | |
64 | ||
65 | #define NUM_SCORE_REGNAMES NUM_ELEM (regnames) | |
66 | #define score_regnames regnames[regname_selected].reg_names | |
67 | ||
68 | /* Print one instruction from PC on INFO->STREAM. | |
69 | Return the size of the instruction. */ | |
70 | static int | |
71 | print_insn_score32 (bfd_vma pc, struct disassemble_info *info, long given) | |
72 | { | |
73 | struct score_opcode *insn; | |
74 | void *stream = info->stream; | |
75 | fprintf_ftype func = info->fprintf_func; | |
76 | ||
77 | for (insn = score_opcodes; insn->assembler; insn++) | |
78 | { | |
79 | if ((insn->mask & 0xffff0000) && (given & insn->mask) == insn->value) | |
80 | { | |
81 | char *c; | |
82 | ||
83 | for (c = insn->assembler; *c; c++) | |
84 | { | |
85 | if (*c == '%') | |
86 | { | |
87 | switch (*++c) | |
88 | { | |
89 | case 'j': | |
90 | { | |
91 | int target; | |
92 | ||
93 | if (info->flags & INSN_HAS_RELOC) | |
94 | pc = 0; | |
95 | target = (pc & 0xfe000000) | (given & 0x01fffffe); | |
96 | (*info->print_address_func) (target, info); | |
97 | } | |
98 | break; | |
99 | case 'b': | |
100 | { | |
101 | /* Sign-extend a 20-bit number. */ | |
102 | #define SEXT20(x) ((((x) & 0xfffff) ^ (~ 0x7ffff)) + 0x80000) | |
103 | int disp = ((given & 0x01ff8000) >> 5) | (given & 0x3fe); | |
104 | int target = (pc + SEXT20 (disp)); | |
105 | ||
106 | (*info->print_address_func) (target, info); | |
107 | } | |
108 | break; | |
109 | case '0': | |
110 | case '1': | |
111 | case '2': | |
112 | case '3': | |
113 | case '4': | |
114 | case '5': | |
115 | case '6': | |
116 | case '7': | |
117 | case '8': | |
118 | case '9': | |
119 | { | |
120 | int bitstart = *c++ - '0'; | |
121 | int bitend = 0; | |
122 | ||
123 | while (*c >= '0' && *c <= '9') | |
124 | bitstart = (bitstart * 10) + *c++ - '0'; | |
125 | ||
126 | switch (*c) | |
127 | { | |
128 | case '-': | |
129 | c++; | |
130 | while (*c >= '0' && *c <= '9') | |
131 | bitend = (bitend * 10) + *c++ - '0'; | |
132 | ||
133 | if (!bitend) | |
134 | abort (); | |
135 | ||
136 | switch (*c) | |
137 | { | |
138 | case 'r': | |
139 | { | |
140 | long reg; | |
141 | ||
142 | reg = given >> bitstart; | |
143 | reg &= (2 << (bitend - bitstart)) - 1; | |
144 | ||
145 | func (stream, "%s", score_regnames[reg]); | |
146 | } | |
147 | break; | |
148 | case 'd': | |
149 | { | |
150 | long reg; | |
151 | ||
152 | reg = given >> bitstart; | |
153 | reg &= (2 << (bitend - bitstart)) - 1; | |
154 | ||
155 | func (stream, "%ld", reg); | |
156 | } | |
157 | break; | |
158 | case 'i': | |
159 | { | |
160 | long reg; | |
161 | ||
162 | reg = given >> bitstart; | |
163 | reg &= (2 << (bitend - bitstart)) - 1; | |
164 | reg = ((reg ^ (1 << (bitend - bitstart))) - | |
165 | (1 << (bitend - bitstart))); | |
166 | ||
167 | if (((given & insn->mask) == 0x0c00000a) /* ldc1 */ | |
168 | || ((given & insn->mask) == 0x0c000012) /* ldc2 */ | |
169 | || ((given & insn->mask) == 0x0c00001c) /* ldc3 */ | |
170 | || ((given & insn->mask) == 0x0c00000b) /* stc1 */ | |
171 | || ((given & insn->mask) == 0x0c000013) /* stc2 */ | |
172 | || ((given & insn->mask) == 0x0c00001b)) /* stc3 */ | |
173 | reg <<= 2; | |
174 | ||
175 | func (stream, "%ld", reg); | |
176 | } | |
177 | break; | |
178 | case 'x': | |
179 | { | |
180 | long reg; | |
181 | ||
182 | reg = given >> bitstart; | |
183 | reg &= (2 << (bitend - bitstart)) - 1; | |
184 | ||
185 | func (stream, "%lx", reg); | |
186 | } | |
187 | break; | |
188 | default: | |
189 | abort (); | |
190 | } | |
191 | break; | |
192 | case '`': | |
193 | c++; | |
194 | if ((given & (1 << bitstart)) == 0) | |
195 | func (stream, "%c", *c); | |
196 | break; | |
197 | case '\'': | |
198 | c++; | |
199 | if ((given & (1 << bitstart)) != 0) | |
200 | func (stream, "%c", *c); | |
201 | break; | |
202 | default: | |
203 | abort (); | |
204 | } | |
205 | break; | |
206 | ||
207 | default: | |
208 | abort (); | |
209 | } | |
210 | } | |
211 | } | |
212 | else | |
213 | func (stream, "%c", *c); | |
214 | } | |
215 | return 4; | |
216 | } | |
217 | } | |
218 | ||
219 | #if (SCORE_SIMULATOR_ACTIVE) | |
220 | func (stream, _("<illegal instruction>")); | |
221 | return 4; | |
222 | #endif | |
223 | ||
224 | abort (); | |
225 | } | |
226 | ||
227 | static void | |
228 | print_insn_parallel_sym (struct disassemble_info *info) | |
229 | { | |
230 | void *stream = info->stream; | |
231 | fprintf_ftype func = info->fprintf_func; | |
232 | ||
233 | /* 10: 0000 nop! | |
234 | 4 space + 1 colon + 1 space + 1 tab + 8 opcode + 2 space + 1 tab. | |
235 | FIXME: the space number is not accurate. */ | |
236 | func (stream, "%s", " ||\n \t \t"); | |
237 | } | |
238 | ||
239 | /* Print one instruction from PC on INFO->STREAM. | |
240 | Return the size of the instruction. */ | |
241 | static int | |
242 | print_insn_score16 (bfd_vma pc, struct disassemble_info *info, long given) | |
243 | { | |
244 | struct score_opcode *insn; | |
245 | void *stream = info->stream; | |
246 | fprintf_ftype func = info->fprintf_func; | |
247 | ||
248 | given &= 0xffff; | |
249 | for (insn = score_opcodes; insn->assembler; insn++) | |
250 | { | |
251 | if (!(insn->mask & 0xffff0000) && (given & insn->mask) == insn->value) | |
252 | { | |
253 | char *c = insn->assembler; | |
254 | ||
255 | info->bytes_per_chunk = 2; | |
256 | info->bytes_per_line = 4; | |
257 | given &= 0xffff; | |
258 | ||
259 | for (; *c; c++) | |
260 | { | |
261 | if (*c == '%') | |
262 | { | |
263 | switch (*++c) | |
264 | { | |
265 | ||
266 | case 'j': | |
267 | { | |
268 | int target; | |
269 | ||
270 | if (info->flags & INSN_HAS_RELOC) | |
271 | pc = 0; | |
272 | ||
273 | target = (pc & 0xfffff000) | (given & 0x00000ffe); | |
274 | (*info->print_address_func) (target, info); | |
275 | } | |
276 | break; | |
277 | case 'b': | |
278 | { | |
279 | /* Sign-extend a 9-bit number. */ | |
280 | #define SEXT9(x) ((((x) & 0x1ff) ^ (~ 0xff)) + 0x100) | |
281 | int disp = (given & 0xff) << 1; | |
282 | int target = (pc + SEXT9 (disp)); | |
283 | ||
284 | (*info->print_address_func) (target, info); | |
285 | } | |
286 | break; | |
287 | ||
288 | case '0': | |
289 | case '1': | |
290 | case '2': | |
291 | case '3': | |
292 | case '4': | |
293 | case '5': | |
294 | case '6': | |
295 | case '7': | |
296 | case '8': | |
297 | case '9': | |
298 | { | |
299 | int bitstart = *c++ - '0'; | |
300 | int bitend = 0; | |
301 | ||
302 | while (*c >= '0' && *c <= '9') | |
303 | bitstart = (bitstart * 10) + *c++ - '0'; | |
304 | ||
305 | switch (*c) | |
306 | { | |
307 | case '-': | |
308 | { | |
309 | long reg; | |
310 | ||
311 | c++; | |
312 | while (*c >= '0' && *c <= '9') | |
313 | bitend = (bitend * 10) + *c++ - '0'; | |
314 | if (!bitend) | |
315 | abort (); | |
316 | reg = given >> bitstart; | |
317 | reg &= (2 << (bitend - bitstart)) - 1; | |
318 | switch (*c) | |
319 | { | |
320 | case 'R': | |
321 | func (stream, "%s", score_regnames[reg + 16]); | |
322 | break; | |
323 | case 'r': | |
324 | func (stream, "%s", score_regnames[reg]); | |
325 | break; | |
326 | case 'd': | |
327 | if (*(c + 1) == '\0') | |
328 | func (stream, "%ld", reg); | |
329 | else | |
330 | { | |
331 | c++; | |
332 | if (*c == '1') | |
333 | func (stream, "%ld", reg << 1); | |
334 | else if (*c == '2') | |
335 | func (stream, "%ld", reg << 2); | |
336 | } | |
337 | break; | |
338 | ||
339 | case 'x': | |
340 | if (*(c + 1) == '\0') | |
341 | func (stream, "%lx", reg); | |
342 | else | |
343 | { | |
344 | c++; | |
345 | if (*c == '1') | |
346 | func (stream, "%lx", reg << 1); | |
347 | else if (*c == '2') | |
348 | func (stream, "%lx", reg << 2); | |
349 | } | |
350 | break; | |
351 | case 'i': | |
352 | reg = ((reg ^ (1 << bitend)) - (1 << bitend)); | |
353 | func (stream, "%ld", reg); | |
354 | break; | |
355 | default: | |
356 | abort (); | |
357 | } | |
358 | } | |
359 | break; | |
360 | ||
361 | case '\'': | |
362 | c++; | |
363 | if ((given & (1 << bitstart)) != 0) | |
364 | func (stream, "%c", *c); | |
365 | break; | |
366 | default: | |
367 | abort (); | |
368 | } | |
369 | } | |
370 | break; | |
371 | default: | |
372 | abort (); | |
373 | } | |
374 | } | |
375 | else | |
376 | func (stream, "%c", *c); | |
377 | } | |
378 | ||
379 | return 2; | |
380 | } | |
381 | } | |
382 | #if (SCORE_SIMULATOR_ACTIVE) | |
383 | func (stream, _("<illegal instruction>")); | |
384 | return 2; | |
385 | #endif | |
386 | /* No match. */ | |
387 | abort (); | |
388 | } | |
389 | ||
390 | /* NOTE: There are no checks in these routines that | |
391 | the relevant number of data bytes exist. */ | |
392 | static int | |
393 | print_insn (bfd_vma pc, struct disassemble_info *info, bfd_boolean little) | |
394 | { | |
395 | unsigned char b[4]; | |
396 | long given; | |
397 | long ridparity; | |
398 | int status; | |
399 | bfd_boolean insn_pce_p = FALSE; | |
400 | bfd_boolean insn_16_p = FALSE; | |
401 | ||
402 | info->display_endian = little ? BFD_ENDIAN_LITTLE : BFD_ENDIAN_BIG; | |
403 | ||
404 | if (pc & 0x2) | |
405 | { | |
406 | info->bytes_per_chunk = 2; | |
407 | status = info->read_memory_func (pc, (bfd_byte *) b, 2, info); | |
408 | b[3] = b[2] = 0; | |
409 | insn_16_p = TRUE; | |
410 | } | |
411 | else | |
412 | { | |
413 | info->bytes_per_chunk = 4; | |
414 | status = info->read_memory_func (pc, (bfd_byte *) & b[0], 4, info); | |
415 | if (status != 0) | |
416 | { | |
417 | info->bytes_per_chunk = 2; | |
418 | status = info->read_memory_func (pc, (bfd_byte *) b, 2, info); | |
419 | b[3] = b[2] = 0; | |
420 | insn_16_p = TRUE; | |
421 | } | |
422 | } | |
423 | ||
424 | if (status != 0) | |
425 | { | |
426 | info->memory_error_func (status, pc, info); | |
427 | return -1; | |
428 | } | |
429 | ||
430 | if (little) | |
431 | { | |
432 | given = (b[0]) | (b[1] << 8) | (b[2] << 16) | (b[3] << 24); | |
433 | } | |
434 | else | |
435 | { | |
436 | given = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | (b[3]); | |
437 | } | |
438 | ||
439 | if ((given & 0x80008000) == 0x80008000) | |
440 | { | |
441 | insn_pce_p = FALSE; | |
442 | insn_16_p = FALSE; | |
443 | } | |
444 | else if ((given & 0x8000) == 0x8000) | |
445 | { | |
446 | insn_pce_p = TRUE; | |
447 | } | |
448 | else | |
449 | { | |
450 | insn_16_p = TRUE; | |
451 | } | |
452 | ||
453 | /* 16 bit instruction. */ | |
454 | if (insn_16_p) | |
455 | { | |
456 | if (little) | |
457 | { | |
458 | given = b[0] | (b[1] << 8); | |
459 | } | |
460 | else | |
461 | { | |
462 | given = (b[0] << 8) | b[1]; | |
463 | } | |
464 | ||
465 | status = print_insn_score16 (pc, info, given); | |
466 | } | |
467 | /* pce instruction. */ | |
468 | else if (insn_pce_p) | |
469 | { | |
470 | long other; | |
471 | ||
1c0d3aa6 | 472 | other = given & 0xFFFF; |
b138abaa | 473 | given = (given & 0xFFFF0000) >> 16; |
1c0d3aa6 NC |
474 | |
475 | status = print_insn_score16 (pc, info, given); | |
476 | print_insn_parallel_sym (info); | |
477 | status += print_insn_score16 (pc, info, other); | |
478 | /* disassemble_bytes() will output 4 byte per chunk for pce instructio. */ | |
479 | info->bytes_per_chunk = 4; | |
480 | } | |
481 | /* 32 bit instruction. */ | |
482 | else | |
483 | { | |
484 | /* Get rid of parity. */ | |
485 | ridparity = (given & 0x7FFF); | |
486 | ridparity |= (given & 0x7FFF0000) >> 1; | |
487 | given = ridparity; | |
488 | status = print_insn_score32 (pc, info, given); | |
489 | } | |
490 | ||
491 | return status; | |
492 | } | |
493 | ||
494 | int | |
495 | print_insn_big_score (bfd_vma pc, struct disassemble_info *info) | |
496 | { | |
497 | return print_insn (pc, info, FALSE); | |
498 | } | |
499 | ||
500 | int | |
501 | print_insn_little_score (bfd_vma pc, struct disassemble_info *info) | |
502 | { | |
503 | return print_insn (pc, info, TRUE); | |
504 | } |