Commit | Line | Data |
---|---|---|
252b5132 RH |
1 | /* m88k.c -- Assembler for the Motorola 88000 |
2 | Contributed by Devon Bowen of Buffalo University | |
3 | and Torbjorn Granlund of the Swedish Institute of Computer Science. | |
f7e42eb4 | 4 | Copyright 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1999, |
ea1562b3 | 5 | 2000, 2001, 2002, 2003, 2005 |
252b5132 RH |
6 | Free Software Foundation, Inc. |
7 | ||
ea1562b3 | 8 | This file is part of GAS, the GNU Assembler. |
252b5132 | 9 | |
ea1562b3 NC |
10 | GAS is free software; you can redistribute it and/or modify |
11 | it under the terms of the GNU General Public License as published by | |
12 | the Free Software Foundation; either version 2, or (at your option) | |
13 | any later version. | |
252b5132 | 14 | |
ea1562b3 NC |
15 | GAS is distributed in the hope that it will be useful, |
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 | GNU General Public License for more details. | |
252b5132 | 19 | |
ea1562b3 NC |
20 | You should have received a copy of the GNU General Public License |
21 | along with GAS; see the file COPYING. If not, write to the Free | |
4b4da160 NC |
22 | Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA |
23 | 02110-1301, USA. */ | |
252b5132 | 24 | |
252b5132 | 25 | #include "as.h" |
3882b010 | 26 | #include "safe-ctype.h" |
252b5132 RH |
27 | #include "subsegs.h" |
28 | #include "m88k-opcode.h" | |
29 | ||
30 | struct field_val_assoc | |
31 | { | |
32 | char *name; | |
33 | unsigned val; | |
34 | }; | |
35 | ||
36 | struct field_val_assoc cr_regs[] = | |
37 | { | |
38 | {"PID", 0}, | |
39 | {"PSR", 1}, | |
40 | {"EPSR", 2}, | |
41 | {"SSBR", 3}, | |
42 | {"SXIP", 4}, | |
43 | {"SNIP", 5}, | |
44 | {"SFIP", 6}, | |
45 | {"VBR", 7}, | |
46 | {"DMT0", 8}, | |
47 | {"DMD0", 9}, | |
48 | {"DMA0", 10}, | |
49 | {"DMT1", 11}, | |
50 | {"DMD1", 12}, | |
51 | {"DMA1", 13}, | |
52 | {"DMT2", 14}, | |
53 | {"DMD2", 15}, | |
54 | {"DMA2", 16}, | |
55 | {"SR0", 17}, | |
56 | {"SR1", 18}, | |
57 | {"SR2", 19}, | |
58 | {"SR3", 20}, | |
59 | ||
60 | {NULL, 0}, | |
61 | }; | |
62 | ||
63 | struct field_val_assoc fcr_regs[] = | |
64 | { | |
65 | {"FPECR", 0}, | |
66 | {"FPHS1", 1}, | |
67 | {"FPLS1", 2}, | |
68 | {"FPHS2", 3}, | |
69 | {"FPLS2", 4}, | |
70 | {"FPPT", 5}, | |
71 | {"FPRH", 6}, | |
72 | {"FPRL", 7}, | |
73 | {"FPIT", 8}, | |
74 | ||
75 | {"FPSR", 62}, | |
76 | {"FPCR", 63}, | |
77 | ||
78 | {NULL, 0}, | |
79 | }; | |
80 | ||
81 | struct field_val_assoc cmpslot[] = | |
82 | { | |
ea1562b3 | 83 | /* Integer Floating point. */ |
252b5132 RH |
84 | {"nc", 0}, |
85 | {"cp", 1}, | |
86 | {"eq", 2}, | |
87 | {"ne", 3}, | |
88 | {"gt", 4}, | |
89 | {"le", 5}, | |
90 | {"lt", 6}, | |
91 | {"ge", 7}, | |
92 | {"hi", 8}, {"ou", 8}, | |
93 | {"ls", 9}, {"ib", 9}, | |
94 | {"lo", 10}, {"in", 10}, | |
95 | {"hs", 11}, {"ob", 11}, | |
96 | {"be", 12}, {"ue", 12}, | |
97 | {"nb", 13}, {"lg", 13}, | |
98 | {"he", 14}, {"ug", 14}, | |
99 | {"nh", 15}, {"ule", 15}, | |
100 | {"ul", 16}, | |
101 | {"uge", 17}, | |
102 | ||
103 | {NULL, 0}, | |
104 | }; | |
105 | ||
106 | struct field_val_assoc cndmsk[] = | |
107 | { | |
108 | {"gt0", 1}, | |
109 | {"eq0", 2}, | |
110 | {"ge0", 3}, | |
111 | {"lt0", 12}, | |
112 | {"ne0", 13}, | |
113 | {"le0", 14}, | |
114 | ||
115 | {NULL, 0}, | |
116 | }; | |
117 | ||
118 | struct m88k_insn | |
119 | { | |
120 | unsigned long opcode; | |
121 | expressionS exp; | |
122 | enum reloc_type reloc; | |
123 | }; | |
124 | ||
252b5132 RH |
125 | extern char *myname; |
126 | static struct hash_control *op_hash = NULL; | |
127 | ||
ea1562b3 | 128 | /* These bits should be turned off in the first address of every segment. */ |
252b5132 RH |
129 | int md_seg_align = 7; |
130 | ||
131 | /* These chars start a comment anywhere in a source file (except inside | |
453520d7 | 132 | another comment. */ |
252b5132 RH |
133 | const char comment_chars[] = ";"; |
134 | ||
82efde3a | 135 | /* These chars only start a comment at the beginning of a line. */ |
252b5132 RH |
136 | const char line_comment_chars[] = "#"; |
137 | ||
138 | const char line_separator_chars[] = ""; | |
139 | ||
ea1562b3 | 140 | /* Chars that can be used to separate mant from exp in floating point nums. */ |
252b5132 RH |
141 | const char EXP_CHARS[] = "eE"; |
142 | ||
ea1562b3 NC |
143 | /* Chars that mean this number is a floating point constant. |
144 | as in 0f123.456 | |
145 | or 0H1.234E-12 (see exp chars above). */ | |
252b5132 RH |
146 | const char FLT_CHARS[] = "dDfF"; |
147 | ||
252b5132 | 148 | void |
ea1562b3 | 149 | md_begin (void) |
252b5132 RH |
150 | { |
151 | const char *retval = NULL; | |
152 | unsigned int i = 0; | |
153 | ||
453520d7 | 154 | /* Initialize hash table. */ |
252b5132 RH |
155 | op_hash = hash_new (); |
156 | ||
252b5132 RH |
157 | while (*m88k_opcodes[i].name) |
158 | { | |
159 | char *name = m88k_opcodes[i].name; | |
160 | ||
453520d7 | 161 | /* Hash each mnemonic and record its position. */ |
252b5132 RH |
162 | retval = hash_insert (op_hash, name, &m88k_opcodes[i]); |
163 | ||
164 | if (retval != NULL) | |
165 | as_fatal (_("Can't hash instruction '%s':%s"), | |
166 | m88k_opcodes[i].name, retval); | |
167 | ||
453520d7 | 168 | /* Skip to next unique mnemonic or end of list. */ |
252b5132 RH |
169 | for (i++; !strcmp (m88k_opcodes[i].name, name); i++) |
170 | ; | |
171 | } | |
172 | } | |
173 | \f | |
5a38dc70 | 174 | const char *md_shortopts = ""; |
ea1562b3 NC |
175 | struct option md_longopts[] = |
176 | { | |
252b5132 RH |
177 | {NULL, no_argument, NULL, 0} |
178 | }; | |
bc805888 | 179 | size_t md_longopts_size = sizeof (md_longopts); |
252b5132 RH |
180 | |
181 | int | |
ea1562b3 | 182 | md_parse_option (int c ATTRIBUTE_UNUSED, char *arg ATTRIBUTE_UNUSED) |
252b5132 RH |
183 | { |
184 | return 0; | |
185 | } | |
186 | ||
187 | void | |
ea1562b3 | 188 | md_show_usage (FILE *stream ATTRIBUTE_UNUSED) |
252b5132 RH |
189 | { |
190 | } | |
191 | \f | |
ea1562b3 NC |
192 | static char * |
193 | get_o6 (char *param, unsigned *valp) | |
252b5132 | 194 | { |
ea1562b3 NC |
195 | unsigned val; |
196 | char *save_ptr; | |
252b5132 | 197 | |
ea1562b3 NC |
198 | save_ptr = input_line_pointer; |
199 | input_line_pointer = param; | |
200 | val = get_absolute_expression (); | |
201 | param = input_line_pointer; | |
202 | input_line_pointer = save_ptr; | |
252b5132 | 203 | |
ea1562b3 NC |
204 | if (val & 0x3) |
205 | as_warn (_("Removed lower 2 bits of expression")); | |
252b5132 | 206 | |
ea1562b3 NC |
207 | *valp = val; |
208 | ||
209 | return (param); | |
210 | } | |
211 | ||
212 | static char * | |
213 | get_vec9 (char *param, unsigned *valp) | |
214 | { | |
215 | unsigned val; | |
216 | char *save_ptr; | |
217 | ||
218 | save_ptr = input_line_pointer; | |
219 | input_line_pointer = param; | |
220 | val = get_absolute_expression (); | |
221 | param = input_line_pointer; | |
222 | input_line_pointer = save_ptr; | |
223 | ||
224 | if (val >= 1 << 9) | |
225 | as_warn (_("Expression truncated to 9 bits")); | |
226 | ||
227 | *valp = val % (1 << 9); | |
228 | ||
229 | return param; | |
230 | } | |
231 | ||
232 | static char * | |
233 | get_bf2 (char *param, int bc) | |
234 | { | |
235 | int depth = 0; | |
236 | int c; | |
237 | ||
238 | for (;;) | |
252b5132 | 239 | { |
ea1562b3 NC |
240 | c = *param; |
241 | if (c == 0) | |
242 | return param; | |
243 | else if (c == '(') | |
244 | depth++; | |
245 | else if (c == ')') | |
246 | depth--; | |
247 | else if (c == bc && depth <= 0) | |
248 | return param; | |
249 | param++; | |
252b5132 | 250 | } |
ea1562b3 | 251 | } |
252b5132 | 252 | |
ea1562b3 NC |
253 | static char * |
254 | match_name (char *param, | |
255 | struct field_val_assoc *assoc_tab, | |
256 | unsigned *valp) | |
257 | { | |
258 | int i; | |
259 | char *name; | |
260 | int name_len; | |
252b5132 | 261 | |
ea1562b3 | 262 | for (i = 0;; i++) |
252b5132 | 263 | { |
ea1562b3 NC |
264 | name = assoc_tab[i].name; |
265 | if (name == NULL) | |
266 | return NULL; | |
267 | name_len = strlen (name); | |
268 | if (!strncmp (param, name, name_len)) | |
252b5132 | 269 | { |
ea1562b3 NC |
270 | *valp = assoc_tab[i].val; |
271 | return param + name_len; | |
252b5132 RH |
272 | } |
273 | } | |
ea1562b3 | 274 | } |
252b5132 | 275 | |
ea1562b3 NC |
276 | static char * |
277 | get_bf_offset_expression (char *param, unsigned *offsetp) | |
278 | { | |
279 | unsigned offset; | |
252b5132 | 280 | |
ea1562b3 | 281 | if (ISALPHA (param[0])) |
252b5132 | 282 | { |
ea1562b3 NC |
283 | param[0] = TOLOWER (param[0]); |
284 | param[1] = TOLOWER (param[1]); | |
252b5132 | 285 | |
ea1562b3 | 286 | param = match_name (param, cmpslot, offsetp); |
252b5132 | 287 | |
ea1562b3 | 288 | return param; |
252b5132 | 289 | } |
ea1562b3 NC |
290 | else |
291 | { | |
292 | input_line_pointer = param; | |
293 | offset = get_absolute_expression (); | |
294 | param = input_line_pointer; | |
295 | } | |
296 | ||
297 | *offsetp = offset; | |
298 | return param; | |
252b5132 RH |
299 | } |
300 | ||
ea1562b3 NC |
301 | static char * |
302 | get_bf (char *param, unsigned *valp) | |
252b5132 | 303 | { |
ea1562b3 NC |
304 | unsigned offset = 0; |
305 | unsigned width = 0; | |
306 | char *xp; | |
307 | char *save_ptr; | |
252b5132 | 308 | |
ea1562b3 | 309 | xp = get_bf2 (param, '<'); |
252b5132 | 310 | |
ea1562b3 NC |
311 | save_ptr = input_line_pointer; |
312 | input_line_pointer = param; | |
313 | if (*xp == 0) | |
252b5132 | 314 | { |
ea1562b3 NC |
315 | /* We did not find '<'. We have an offset (width implicitly 32). */ |
316 | param = get_bf_offset_expression (param, &offset); | |
317 | input_line_pointer = save_ptr; | |
318 | if (param == NULL) | |
319 | return NULL; | |
320 | } | |
321 | else | |
322 | { | |
323 | *xp++ = 0; /* Overwrite the '<'. */ | |
324 | param = get_bf2 (xp, '>'); | |
325 | if (*param == 0) | |
326 | return NULL; | |
327 | *param++ = 0; /* Overwrite the '>'. */ | |
252b5132 | 328 | |
ea1562b3 NC |
329 | width = get_absolute_expression (); |
330 | xp = get_bf_offset_expression (xp, &offset); | |
331 | input_line_pointer = save_ptr; | |
252b5132 | 332 | |
ea1562b3 NC |
333 | if (xp + 1 != param) |
334 | return NULL; | |
335 | } | |
252b5132 | 336 | |
ea1562b3 | 337 | *valp = ((width % 32) << 5) | (offset % 32); |
252b5132 | 338 | |
ea1562b3 NC |
339 | return param; |
340 | } | |
252b5132 | 341 | |
ea1562b3 NC |
342 | static char * |
343 | get_cr (char *param, unsigned *regnop) | |
344 | { | |
345 | unsigned regno; | |
346 | unsigned c; | |
252b5132 | 347 | |
ea1562b3 NC |
348 | if (!strncmp (param, "cr", 2)) |
349 | { | |
350 | param += 2; | |
252b5132 | 351 | |
ea1562b3 NC |
352 | regno = *param++ - '0'; |
353 | if (regno < 10) | |
354 | { | |
355 | if (regno == 0) | |
356 | { | |
357 | *regnop = 0; | |
358 | return param; | |
359 | } | |
360 | c = *param - '0'; | |
361 | if (c < 10) | |
362 | { | |
363 | regno = regno * 10 + c; | |
364 | if (c < 64) | |
365 | { | |
366 | *regnop = regno; | |
367 | return param + 1; | |
368 | } | |
369 | } | |
370 | else | |
371 | { | |
372 | *regnop = regno; | |
373 | return param; | |
374 | } | |
375 | } | |
376 | return NULL; | |
377 | } | |
252b5132 | 378 | |
ea1562b3 | 379 | param = match_name (param, cr_regs, regnop); |
252b5132 | 380 | |
ea1562b3 NC |
381 | return param; |
382 | } | |
252b5132 | 383 | |
ea1562b3 NC |
384 | static char * |
385 | get_fcr (char *param, unsigned *regnop) | |
386 | { | |
387 | unsigned regno; | |
388 | unsigned c; | |
252b5132 | 389 | |
ea1562b3 NC |
390 | if (!strncmp (param, "fcr", 3)) |
391 | { | |
392 | param += 3; | |
252b5132 | 393 | |
ea1562b3 NC |
394 | regno = *param++ - '0'; |
395 | if (regno < 10) | |
396 | { | |
397 | if (regno == 0) | |
398 | { | |
399 | *regnop = 0; | |
400 | return param; | |
401 | } | |
402 | c = *param - '0'; | |
403 | if (c < 10) | |
404 | { | |
405 | regno = regno * 10 + c; | |
406 | if (c < 64) | |
407 | { | |
408 | *regnop = regno; | |
409 | return param + 1; | |
410 | } | |
411 | } | |
412 | else | |
413 | { | |
414 | *regnop = regno; | |
415 | return param; | |
416 | } | |
417 | } | |
418 | return NULL; | |
419 | } | |
252b5132 | 420 | |
ea1562b3 | 421 | param = match_name (param, fcr_regs, regnop); |
252b5132 | 422 | |
ea1562b3 NC |
423 | return param; |
424 | } | |
252b5132 | 425 | |
ea1562b3 NC |
426 | #define hexval(z) \ |
427 | (ISDIGIT (z) ? (z) - '0' : \ | |
428 | ISLOWER (z) ? (z) - 'a' + 10 : \ | |
429 | ISUPPER (z) ? (z) - 'A' + 10 : (unsigned) -1) | |
252b5132 | 430 | |
ea1562b3 NC |
431 | static char * |
432 | getval (char *param, unsigned int *valp) | |
433 | { | |
434 | unsigned int val = 0; | |
435 | unsigned int c; | |
252b5132 | 436 | |
ea1562b3 NC |
437 | c = *param++; |
438 | if (c == '0') | |
439 | { | |
440 | c = *param++; | |
441 | if (c == 'x' || c == 'X') | |
442 | { | |
443 | c = *param++; | |
444 | c = hexval (c); | |
445 | while (c < 16) | |
446 | { | |
447 | val = val * 16 + c; | |
448 | c = *param++; | |
449 | c = hexval (c); | |
450 | } | |
451 | } | |
452 | else | |
453 | { | |
454 | c -= '0'; | |
455 | while (c < 8) | |
456 | { | |
457 | val = val * 8 + c; | |
458 | c = *param++ - '0'; | |
459 | } | |
460 | } | |
461 | } | |
462 | else | |
463 | { | |
464 | c -= '0'; | |
465 | while (c < 10) | |
466 | { | |
467 | val = val * 10 + c; | |
468 | c = *param++ - '0'; | |
252b5132 RH |
469 | } |
470 | } | |
ea1562b3 NC |
471 | |
472 | *valp = val; | |
473 | return param - 1; | |
252b5132 RH |
474 | } |
475 | ||
476 | static char * | |
ea1562b3 | 477 | get_cnd (char *param, unsigned *valp) |
252b5132 | 478 | { |
ea1562b3 | 479 | unsigned int val; |
252b5132 | 480 | |
ea1562b3 | 481 | if (ISDIGIT (*param)) |
252b5132 | 482 | { |
ea1562b3 NC |
483 | param = getval (param, &val); |
484 | ||
485 | if (val >= 32) | |
252b5132 | 486 | { |
ea1562b3 NC |
487 | as_warn (_("Expression truncated to 5 bits")); |
488 | val %= 32; | |
252b5132 RH |
489 | } |
490 | } | |
ea1562b3 NC |
491 | else |
492 | { | |
493 | param[0] = TOLOWER (param[0]); | |
494 | param[1] = TOLOWER (param[1]); | |
495 | ||
496 | param = match_name (param, cndmsk, valp); | |
497 | ||
498 | if (param == NULL) | |
499 | return NULL; | |
500 | ||
501 | val = *valp; | |
502 | } | |
503 | ||
504 | *valp = val << 21; | |
505 | return param; | |
252b5132 RH |
506 | } |
507 | ||
508 | static char * | |
ea1562b3 | 509 | get_reg (char *param, unsigned *regnop, unsigned int reg_prefix) |
252b5132 | 510 | { |
bd59b34f | 511 | unsigned c; |
252b5132 RH |
512 | unsigned regno; |
513 | ||
514 | c = *param++; | |
515 | if (c == reg_prefix) | |
516 | { | |
517 | regno = *param++ - '0'; | |
518 | if (regno < 10) | |
519 | { | |
520 | if (regno == 0) | |
521 | { | |
522 | *regnop = 0; | |
523 | return param; | |
524 | } | |
525 | c = *param - '0'; | |
526 | if (c < 10) | |
527 | { | |
528 | regno = regno * 10 + c; | |
529 | if (c < 32) | |
530 | { | |
531 | *regnop = regno; | |
532 | return param + 1; | |
533 | } | |
534 | } | |
535 | else | |
536 | { | |
537 | *regnop = regno; | |
538 | return param; | |
539 | } | |
540 | } | |
541 | return NULL; | |
542 | } | |
543 | else if (c == 's' && param[0] == 'p') | |
544 | { | |
545 | *regnop = 31; | |
546 | return param + 1; | |
547 | } | |
548 | ||
549 | return 0; | |
550 | } | |
551 | ||
552 | static char * | |
ea1562b3 | 553 | get_imm16 (char *param, struct m88k_insn *insn) |
252b5132 RH |
554 | { |
555 | enum reloc_type reloc = NO_RELOC; | |
556 | unsigned int val; | |
557 | char *save_ptr; | |
558 | ||
3882b010 | 559 | if (!strncmp (param, "hi16", 4) && !ISALNUM (param[4])) |
252b5132 RH |
560 | { |
561 | reloc = RELOC_HI16; | |
562 | param += 4; | |
563 | } | |
3882b010 | 564 | else if (!strncmp (param, "lo16", 4) && !ISALNUM (param[4])) |
252b5132 RH |
565 | { |
566 | reloc = RELOC_LO16; | |
567 | param += 4; | |
568 | } | |
3882b010 | 569 | else if (!strncmp (param, "iw16", 4) && !ISALNUM (param[4])) |
252b5132 RH |
570 | { |
571 | reloc = RELOC_IW16; | |
572 | param += 4; | |
573 | } | |
574 | ||
575 | save_ptr = input_line_pointer; | |
576 | input_line_pointer = param; | |
577 | expression (&insn->exp); | |
578 | param = input_line_pointer; | |
579 | input_line_pointer = save_ptr; | |
580 | ||
581 | val = insn->exp.X_add_number; | |
582 | ||
583 | if (insn->exp.X_op == O_constant) | |
584 | { | |
585 | /* Insert the value now, and reset reloc to NO_RELOC. */ | |
586 | if (reloc == NO_RELOC) | |
587 | { | |
588 | /* Warn about too big expressions if not surrounded by xx16. */ | |
589 | if (val > 0xffff) | |
590 | as_warn (_("Expression truncated to 16 bits")); | |
591 | } | |
592 | ||
593 | if (reloc == RELOC_HI16) | |
594 | val >>= 16; | |
595 | ||
596 | insn->opcode |= val & 0xffff; | |
597 | reloc = NO_RELOC; | |
598 | } | |
599 | else if (reloc == NO_RELOC) | |
600 | /* We accept a symbol even without lo16, hi16, etc, and assume | |
601 | lo16 was intended. */ | |
602 | reloc = RELOC_LO16; | |
603 | ||
604 | insn->reloc = reloc; | |
605 | ||
606 | return param; | |
607 | } | |
608 | ||
609 | static char * | |
ea1562b3 | 610 | get_pcr (char *param, struct m88k_insn *insn, enum reloc_type reloc) |
252b5132 RH |
611 | { |
612 | char *saveptr, *saveparam; | |
613 | ||
614 | saveptr = input_line_pointer; | |
615 | input_line_pointer = param; | |
616 | ||
617 | expression (&insn->exp); | |
618 | ||
619 | saveparam = input_line_pointer; | |
620 | input_line_pointer = saveptr; | |
621 | ||
622 | /* Botch: We should relocate now if O_constant. */ | |
623 | insn->reloc = reloc; | |
624 | ||
625 | return saveparam; | |
626 | } | |
627 | ||
628 | static char * | |
ea1562b3 | 629 | get_cmp (char *param, unsigned *valp) |
252b5132 RH |
630 | { |
631 | unsigned int val; | |
632 | char *save_ptr; | |
633 | ||
634 | save_ptr = param; | |
635 | ||
636 | param = match_name (param, cmpslot, valp); | |
637 | val = *valp; | |
638 | ||
639 | if (param == NULL) | |
640 | { | |
641 | param = save_ptr; | |
642 | ||
643 | save_ptr = input_line_pointer; | |
644 | input_line_pointer = param; | |
645 | val = get_absolute_expression (); | |
646 | param = input_line_pointer; | |
647 | input_line_pointer = save_ptr; | |
648 | ||
649 | if (val >= 32) | |
650 | { | |
651 | as_warn (_("Expression truncated to 5 bits")); | |
652 | val %= 32; | |
653 | } | |
654 | } | |
655 | ||
656 | *valp = val << 21; | |
657 | return param; | |
658 | } | |
659 | ||
ea1562b3 NC |
660 | static int |
661 | calcop (struct m88k_opcode *format, | |
662 | char *param, | |
663 | struct m88k_insn *insn) | |
252b5132 | 664 | { |
ea1562b3 NC |
665 | char *fmt = format->op_spec; |
666 | int f; | |
667 | unsigned val; | |
668 | unsigned opcode; | |
669 | unsigned int reg_prefix = 'r'; | |
252b5132 | 670 | |
ea1562b3 NC |
671 | insn->opcode = format->opcode; |
672 | opcode = 0; | |
252b5132 RH |
673 | |
674 | for (;;) | |
675 | { | |
ea1562b3 NC |
676 | if (param == 0) |
677 | return 0; | |
678 | f = *fmt++; | |
679 | switch (f) | |
680 | { | |
681 | case 0: | |
682 | insn->opcode |= opcode; | |
683 | return (*param == 0 || *param == '\n'); | |
252b5132 | 684 | |
ea1562b3 NC |
685 | default: |
686 | if (f != *param++) | |
687 | return 0; | |
688 | break; | |
252b5132 | 689 | |
ea1562b3 NC |
690 | case 'd': |
691 | param = get_reg (param, &val, reg_prefix); | |
692 | reg_prefix = 'r'; | |
693 | opcode |= val << 21; | |
694 | break; | |
252b5132 | 695 | |
ea1562b3 NC |
696 | case 'o': |
697 | param = get_o6 (param, &val); | |
698 | opcode |= ((val >> 2) << 7); | |
699 | break; | |
252b5132 | 700 | |
ea1562b3 NC |
701 | case 'x': |
702 | reg_prefix = 'x'; | |
703 | break; | |
252b5132 | 704 | |
ea1562b3 NC |
705 | case '1': |
706 | param = get_reg (param, &val, reg_prefix); | |
707 | reg_prefix = 'r'; | |
708 | opcode |= val << 16; | |
709 | break; | |
252b5132 | 710 | |
ea1562b3 NC |
711 | case '2': |
712 | param = get_reg (param, &val, reg_prefix); | |
713 | reg_prefix = 'r'; | |
714 | opcode |= val; | |
715 | break; | |
252b5132 | 716 | |
ea1562b3 NC |
717 | case '3': |
718 | param = get_reg (param, &val, 'r'); | |
719 | opcode |= (val << 16) | val; | |
720 | break; | |
252b5132 | 721 | |
ea1562b3 NC |
722 | case 'I': |
723 | param = get_imm16 (param, insn); | |
724 | break; | |
252b5132 | 725 | |
ea1562b3 NC |
726 | case 'b': |
727 | param = get_bf (param, &val); | |
728 | opcode |= val; | |
729 | break; | |
252b5132 | 730 | |
ea1562b3 NC |
731 | case 'p': |
732 | param = get_pcr (param, insn, RELOC_PC16); | |
733 | break; | |
252b5132 | 734 | |
ea1562b3 NC |
735 | case 'P': |
736 | param = get_pcr (param, insn, RELOC_PC26); | |
737 | break; | |
252b5132 | 738 | |
ea1562b3 NC |
739 | case 'B': |
740 | param = get_cmp (param, &val); | |
741 | opcode |= val; | |
742 | break; | |
252b5132 | 743 | |
ea1562b3 NC |
744 | case 'M': |
745 | param = get_cnd (param, &val); | |
746 | opcode |= val; | |
747 | break; | |
252b5132 | 748 | |
ea1562b3 NC |
749 | case 'c': |
750 | param = get_cr (param, &val); | |
751 | opcode |= val << 5; | |
752 | break; | |
252b5132 | 753 | |
ea1562b3 NC |
754 | case 'f': |
755 | param = get_fcr (param, &val); | |
756 | opcode |= val << 5; | |
757 | break; | |
252b5132 | 758 | |
ea1562b3 NC |
759 | case 'V': |
760 | param = get_vec9 (param, &val); | |
761 | opcode |= val; | |
762 | break; | |
763 | ||
764 | case '?': | |
765 | /* Having this here repeats the warning somtimes. | |
766 | But can't we stand that? */ | |
767 | as_warn (_("Use of obsolete instruction")); | |
768 | break; | |
769 | } | |
770 | } | |
252b5132 RH |
771 | } |
772 | ||
ea1562b3 NC |
773 | void |
774 | md_assemble (char *op) | |
252b5132 | 775 | { |
ea1562b3 NC |
776 | char *param, *thisfrag; |
777 | char c; | |
778 | struct m88k_opcode *format; | |
779 | struct m88k_insn insn; | |
252b5132 | 780 | |
ea1562b3 | 781 | assert (op); |
252b5132 | 782 | |
ea1562b3 NC |
783 | /* Skip over instruction to find parameters. */ |
784 | for (param = op; *param != 0 && !ISSPACE (*param); param++) | |
785 | ; | |
786 | c = *param; | |
787 | *param++ = '\0'; | |
252b5132 | 788 | |
ea1562b3 NC |
789 | /* Try to find the instruction in the hash table. */ |
790 | if ((format = (struct m88k_opcode *) hash_find (op_hash, op)) == NULL) | |
791 | { | |
792 | as_bad (_("Invalid mnemonic '%s'"), op); | |
793 | return; | |
794 | } | |
252b5132 | 795 | |
ea1562b3 NC |
796 | /* Try parsing this instruction into insn. */ |
797 | insn.exp.X_add_symbol = 0; | |
798 | insn.exp.X_op_symbol = 0; | |
799 | insn.exp.X_add_number = 0; | |
800 | insn.exp.X_op = O_illegal; | |
801 | insn.reloc = NO_RELOC; | |
252b5132 | 802 | |
ea1562b3 | 803 | while (!calcop (format, param, &insn)) |
252b5132 | 804 | { |
ea1562b3 NC |
805 | /* If it doesn't parse try the next instruction. */ |
806 | if (!strcmp (format[0].name, format[1].name)) | |
807 | format++; | |
252b5132 RH |
808 | else |
809 | { | |
ea1562b3 NC |
810 | as_fatal (_("Parameter syntax error")); |
811 | return; | |
252b5132 RH |
812 | } |
813 | } | |
ea1562b3 NC |
814 | |
815 | /* Grow the current frag and plop in the opcode. */ | |
816 | thisfrag = frag_more (4); | |
817 | md_number_to_chars (thisfrag, insn.opcode, 4); | |
818 | ||
819 | /* If this instruction requires labels mark it for later. */ | |
820 | switch (insn.reloc) | |
252b5132 | 821 | { |
ea1562b3 NC |
822 | case NO_RELOC: |
823 | break; | |
252b5132 | 824 | |
ea1562b3 NC |
825 | case RELOC_LO16: |
826 | case RELOC_HI16: | |
827 | fix_new_exp (frag_now, | |
828 | thisfrag - frag_now->fr_literal + 2, | |
829 | 2, | |
830 | &insn.exp, | |
831 | 0, | |
832 | insn.reloc); | |
833 | break; | |
834 | ||
835 | case RELOC_IW16: | |
836 | fix_new_exp (frag_now, | |
837 | thisfrag - frag_now->fr_literal, | |
838 | 4, | |
839 | &insn.exp, | |
840 | 0, | |
841 | insn.reloc); | |
842 | break; | |
843 | ||
844 | case RELOC_PC16: | |
845 | fix_new_exp (frag_now, | |
846 | thisfrag - frag_now->fr_literal + 2, | |
847 | 2, | |
848 | &insn.exp, | |
849 | 1, | |
850 | insn.reloc); | |
851 | break; | |
852 | ||
853 | case RELOC_PC26: | |
854 | fix_new_exp (frag_now, | |
855 | thisfrag - frag_now->fr_literal, | |
856 | 4, | |
857 | &insn.exp, | |
858 | 1, | |
859 | insn.reloc); | |
860 | break; | |
861 | ||
862 | default: | |
863 | as_fatal (_("Unknown relocation type")); | |
864 | break; | |
865 | } | |
252b5132 RH |
866 | } |
867 | ||
868 | void | |
ea1562b3 | 869 | md_number_to_chars (char *buf, valueT val, int nbytes) |
252b5132 RH |
870 | { |
871 | number_to_chars_bigendian (buf, val, nbytes); | |
872 | } | |
873 | ||
252b5132 RH |
874 | #define MAX_LITTLENUMS 6 |
875 | ||
876 | /* Turn a string in input_line_pointer into a floating point constant of type | |
877 | type, and store the appropriate bytes in *litP. The number of LITTLENUMS | |
ea1562b3 NC |
878 | emitted is stored in *sizeP . An error message is returned, or NULL on OK. */ |
879 | ||
252b5132 | 880 | char * |
ea1562b3 | 881 | md_atof (int type, char *litP, int *sizeP) |
252b5132 RH |
882 | { |
883 | int prec; | |
884 | LITTLENUM_TYPE words[MAX_LITTLENUMS]; | |
885 | LITTLENUM_TYPE *wordP; | |
886 | char *t; | |
887 | ||
888 | switch (type) | |
889 | { | |
890 | case 'f': | |
891 | case 'F': | |
892 | case 's': | |
893 | case 'S': | |
894 | prec = 2; | |
895 | break; | |
896 | ||
897 | case 'd': | |
898 | case 'D': | |
899 | case 'r': | |
900 | case 'R': | |
901 | prec = 4; | |
902 | break; | |
903 | ||
904 | case 'x': | |
905 | case 'X': | |
906 | prec = 6; | |
907 | break; | |
908 | ||
909 | case 'p': | |
910 | case 'P': | |
911 | prec = 6; | |
912 | break; | |
913 | ||
914 | default: | |
915 | *sizeP = 0; | |
916 | return _("Bad call to MD_ATOF()"); | |
917 | } | |
918 | t = atof_ieee (input_line_pointer, type, words); | |
919 | if (t) | |
920 | input_line_pointer = t; | |
921 | ||
922 | *sizeP = prec * sizeof (LITTLENUM_TYPE); | |
923 | for (wordP = words; prec--;) | |
924 | { | |
925 | md_number_to_chars (litP, (long) (*wordP++), sizeof (LITTLENUM_TYPE)); | |
926 | litP += sizeof (LITTLENUM_TYPE); | |
927 | } | |
928 | return 0; | |
929 | } | |
930 | ||
931 | int md_short_jump_size = 4; | |
932 | ||
933 | void | |
ea1562b3 NC |
934 | md_create_short_jump (char *ptr, |
935 | addressT from_addr ATTRIBUTE_UNUSED, | |
936 | addressT to_addr ATTRIBUTE_UNUSED, | |
937 | fragS *frag, | |
938 | symbolS *to_symbol) | |
252b5132 RH |
939 | { |
940 | ptr[0] = (char) 0xc0; | |
941 | ptr[1] = 0x00; | |
942 | ptr[2] = 0x00; | |
943 | ptr[3] = 0x00; | |
944 | fix_new (frag, | |
945 | ptr - frag->fr_literal, | |
946 | 4, | |
947 | to_symbol, | |
948 | (offsetT) 0, | |
949 | 0, | |
950 | RELOC_PC26); /* Botch: Shouldn't this be RELOC_PC16? */ | |
951 | } | |
952 | ||
953 | int md_long_jump_size = 4; | |
954 | ||
955 | void | |
ea1562b3 NC |
956 | md_create_long_jump (char *ptr, |
957 | addressT from_addr ATTRIBUTE_UNUSED, | |
958 | addressT to_addr ATTRIBUTE_UNUSED, | |
959 | fragS *frag, | |
960 | symbolS *to_symbol) | |
252b5132 RH |
961 | { |
962 | ptr[0] = (char) 0xc0; | |
963 | ptr[1] = 0x00; | |
964 | ptr[2] = 0x00; | |
965 | ptr[3] = 0x00; | |
966 | fix_new (frag, | |
967 | ptr - frag->fr_literal, | |
968 | 4, | |
969 | to_symbol, | |
970 | (offsetT) 0, | |
971 | 0, | |
972 | RELOC_PC26); | |
973 | } | |
974 | ||
975 | int | |
ea1562b3 NC |
976 | md_estimate_size_before_relax (fragS *fragP ATTRIBUTE_UNUSED, |
977 | segT segment_type ATTRIBUTE_UNUSED) | |
252b5132 RH |
978 | { |
979 | as_fatal (_("Relaxation should never occur")); | |
ea1562b3 | 980 | return -1; |
252b5132 RH |
981 | } |
982 | ||
252b5132 RH |
983 | #ifdef M88KCOFF |
984 | ||
985 | /* These functions are needed if we are linking with obj-coffbfd.c. | |
986 | That file may be replaced by a more BFD oriented version at some | |
67c1ffbe | 987 | point. If that happens, these functions should be reexamined. |
252b5132 RH |
988 | |
989 | Ian Lance Taylor, Cygnus Support, 13 July 1993. */ | |
990 | ||
991 | /* Given a fixS structure (created by a call to fix_new, above), | |
992 | return the BFD relocation type to use for it. */ | |
993 | ||
994 | short | |
ea1562b3 | 995 | tc_coff_fix2rtype (fixS *fixp) |
252b5132 RH |
996 | { |
997 | switch (fixp->fx_r_type) | |
998 | { | |
999 | case RELOC_LO16: | |
1000 | return R_LVRT16; | |
1001 | case RELOC_HI16: | |
1002 | return R_HVRT16; | |
1003 | case RELOC_PC16: | |
1004 | return R_PCR16L; | |
1005 | case RELOC_PC26: | |
1006 | return R_PCR26L; | |
1007 | case RELOC_32: | |
1008 | return R_VRT32; | |
1009 | case RELOC_IW16: | |
1010 | return R_VRT16; | |
1011 | default: | |
1012 | abort (); | |
1013 | } | |
1014 | } | |
1015 | ||
1016 | /* Apply a fixS to the object file. Since COFF does not use addends | |
1017 | in relocs, the addend is actually stored directly in the object | |
1018 | file itself. */ | |
1019 | ||
1020 | void | |
55cf6793 | 1021 | md_apply_fix (fixS *fixP, valueT * valP, segT seg ATTRIBUTE_UNUSED) |
252b5132 | 1022 | { |
f021c2a7 | 1023 | long val = * (long *) valP; |
252b5132 RH |
1024 | char *buf; |
1025 | ||
94f592af NC |
1026 | buf = fixP->fx_frag->fr_literal + fixP->fx_where; |
1027 | fixP->fx_offset = 0; | |
252b5132 | 1028 | |
94f592af | 1029 | switch (fixP->fx_r_type) |
252b5132 RH |
1030 | { |
1031 | case RELOC_IW16: | |
94f592af | 1032 | fixP->fx_offset = val >> 16; |
252b5132 RH |
1033 | buf[2] = val >> 8; |
1034 | buf[3] = val; | |
1035 | break; | |
1036 | ||
1037 | case RELOC_LO16: | |
94f592af | 1038 | fixP->fx_offset = val >> 16; |
252b5132 RH |
1039 | buf[0] = val >> 8; |
1040 | buf[1] = val; | |
1041 | break; | |
1042 | ||
1043 | case RELOC_HI16: | |
94f592af | 1044 | fixP->fx_offset = val >> 16; |
252b5132 RH |
1045 | buf[0] = val >> 8; |
1046 | buf[1] = val; | |
1047 | break; | |
1048 | ||
1049 | case RELOC_PC16: | |
1050 | buf[0] = val >> 10; | |
1051 | buf[1] = val >> 2; | |
1052 | break; | |
1053 | ||
1054 | case RELOC_PC26: | |
1055 | buf[0] |= (val >> 26) & 0x03; | |
1056 | buf[1] = val >> 18; | |
1057 | buf[2] = val >> 10; | |
1058 | buf[3] = val >> 2; | |
1059 | break; | |
1060 | ||
1061 | case RELOC_32: | |
1062 | buf[0] = val >> 24; | |
1063 | buf[1] = val >> 16; | |
1064 | buf[2] = val >> 8; | |
1065 | buf[3] = val; | |
1066 | break; | |
1067 | ||
1068 | default: | |
1069 | abort (); | |
1070 | } | |
94f592af NC |
1071 | |
1072 | if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0) | |
1073 | fixP->fx_done = 1; | |
252b5132 RH |
1074 | } |
1075 | ||
1076 | /* Where a PC relative offset is calculated from. On the m88k they | |
1077 | are calculated from just after the instruction. */ | |
1078 | ||
1079 | long | |
ea1562b3 | 1080 | md_pcrel_from (fixS *fixp) |
252b5132 RH |
1081 | { |
1082 | switch (fixp->fx_r_type) | |
1083 | { | |
1084 | case RELOC_PC16: | |
1085 | return fixp->fx_frag->fr_address + fixp->fx_where - 2; | |
1086 | case RELOC_PC26: | |
1087 | return fixp->fx_frag->fr_address + fixp->fx_where; | |
1088 | default: | |
1089 | abort (); | |
1090 | } | |
252b5132 RH |
1091 | } |
1092 | ||
0a9ef439 | 1093 | /* Fill in rs_align_code fragments. */ |
252b5132 | 1094 | |
0a9ef439 | 1095 | void |
ea1562b3 | 1096 | m88k_handle_align (fragS *fragp) |
252b5132 | 1097 | { |
0a9ef439 RH |
1098 | static const unsigned char nop_pattern[] = { 0xf4, 0x00, 0x58, 0x00 }; |
1099 | ||
1100 | int bytes; | |
1101 | char *p; | |
1102 | ||
1103 | if (fragp->fr_type != rs_align_code) | |
1104 | return; | |
1105 | ||
1106 | bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix; | |
1107 | p = fragp->fr_literal + fragp->fr_fix; | |
1108 | ||
1109 | if (bytes & 3) | |
252b5132 | 1110 | { |
0a9ef439 RH |
1111 | int fix = bytes & 3; |
1112 | memset (p, 0, fix); | |
1113 | p += fix; | |
1114 | bytes -= fix; | |
1115 | fragp->fr_fix += fix; | |
252b5132 | 1116 | } |
0a9ef439 RH |
1117 | |
1118 | memcpy (p, nop_pattern, 4); | |
1119 | fragp->fr_var = 4; | |
252b5132 RH |
1120 | } |
1121 | ||
1122 | #endif /* M88KCOFF */ | |
ea1562b3 NC |
1123 | |
1124 | const pseudo_typeS md_pseudo_table[] = | |
1125 | { | |
1126 | {"align", s_align_bytes, 4}, | |
1127 | {"def", s_set, 0}, | |
1128 | {"dfloat", float_cons, 'd'}, | |
1129 | {"ffloat", float_cons, 'f'}, | |
1130 | {"half", cons, 2}, | |
1131 | {"bss", s_lcomm, 1}, | |
1132 | {"string", stringer, 0}, | |
1133 | {"word", cons, 4}, | |
1134 | /* Force set to be treated as an instruction. */ | |
1135 | {"set", NULL, 0}, | |
1136 | {".set", s_set, 0}, | |
1137 | {NULL, NULL, 0} | |
1138 | }; |