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