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 (C) 1989-1992 Free Software Foundation, Inc.
6 This file is part of GAS, the GNU Assembler.
8 GAS is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
13 GAS is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GAS; see the file COPYING. If not, write to
20 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
23 #include "opcode/m88k.h"
29 enum reloc_type reloc;
34 static int calcop(struct m88k_opcode *format, char *param, struct m88k_insn *insn);
36 #else /* not __STDC__ */
40 #endif /* not __STDC__ */
53 struct field_val_assoc
59 struct field_val_assoc cr_regs[] =
86 struct field_val_assoc fcr_regs[] =
104 struct field_val_assoc cmpslot[] =
106 /* Integer Floating point */
115 {"hi", 8}, {"ou", 8},
116 {"ls", 9}, {"ib", 9},
117 {"lo", 10}, {"in", 10},
118 {"hs", 11}, {"ob", 11},
123 struct field_val_assoc cndmsk[] =
136 static struct hash_control *op_hash = NULL;
138 /* These bits should be turned off in the first address of every segment */
139 int md_seg_align = 7;
141 /* This is the number to put at the beginning of the a.out file */
142 long omagic = OMAGIC;
144 /* These chars start a comment anywhere in a source file (except inside
146 char comment_chars[] = ";";
148 /* These chars only start a comment at the beginning of a line. */
149 char line_comment_chars[] = "#";
151 /* Chars that can be used to separate mant from exp in floating point nums */
152 char EXP_CHARS[] = "eE";
154 /* Chars that mean this number is a floating point constant */
155 /* as in 0f123.456 */
156 /* or 0H1.234E-12 (see exp chars above) */
157 char FLT_CHARS[] = "dDfF";
159 extern void float_cons (), cons (), s_globl (), s_line (),
160 s_space (), s_set (), stringer (), s_lcomm ();
161 static void s_bss ();
163 const pseudo_typeS md_pseudo_table[] = {
164 {"align", s_align_bytes, 0 },
166 {"dfloat", float_cons, 'd'},
167 {"ffloat", float_cons, 'f'},
168 {"global", s_globl, 0},
171 {"string", stringer, 0},
173 {"zero", s_space, 0},
177 const int md_reloc_size = 12; /* Size of relocation record */
185 /* initialize hash table */
187 op_hash = hash_new ();
189 as_fatal ("Could not initialize hash table");
191 /* loop until you see the end of the list */
193 while (*m88k_opcodes[i].name)
195 char *name = m88k_opcodes[i].name;
197 /* hash each mnemonic and record its position */
199 retval = hash_insert (op_hash, name, &m88k_opcodes[i]);
201 if (retval != NULL && *retval != '\0')
202 as_fatal ("Can't hash instruction '%s':%s",
203 m88k_opcodes[i].name, retval);
205 /* skip to next unique mnemonic or end of list */
207 for (i++; !strcmp (m88k_opcodes[i].name, name); i++)
213 md_parse_option (argP, cntP, vecP)
218 as_warn ("unknown option: -%s", *argP);
226 char *param, *thisfrag;
227 struct m88k_opcode *format;
228 struct m88k_insn insn;
232 /* skip over instruction to find parameters */
234 for (param = op; *param != 0 && !isspace (*param); param++)
239 /* try to find the instruction in the hash table */
241 if ((format = (struct m88k_opcode *) hash_find (op_hash, op)) == NULL)
243 as_fatal ("Invalid mnemonic '%s'", op);
247 /* try parsing this instruction into insn */
249 insn.exp.X_add_symbol = 0;
250 insn.exp.X_subtract_symbol = 0;
251 insn.exp.X_add_number = 0;
253 insn.reloc = NO_RELOC;
255 while (!calcop(format, param, &insn))
257 /* if it doesn't parse try the next instruction */
259 if (!strcmp (format[0].name, format[1].name))
263 as_fatal ("Parameter syntax error");
268 /* grow the current frag and plop in the opcode */
270 thisfrag = frag_more (4);
271 md_number_to_chars (thisfrag, insn.opcode, 4);
273 /* if this instruction requires labels mark it for later */
283 thisfrag - frag_now->fr_literal + 2,
285 insn.exp.X_add_symbol,
286 insn.exp.X_subtract_symbol,
287 insn.exp.X_add_number,
294 thisfrag - frag_now->fr_literal,
296 insn.exp.X_add_symbol,
297 insn.exp.X_subtract_symbol,
298 insn.exp.X_add_number,
305 thisfrag - frag_now->fr_literal + 2,
307 insn.exp.X_add_symbol,
308 insn.exp.X_subtract_symbol,
309 insn.exp.X_add_number,
316 thisfrag - frag_now->fr_literal,
318 insn.exp.X_add_symbol,
319 insn.exp.X_subtract_symbol,
320 insn.exp.X_add_number,
326 as_fatal ("Unknown relocation type");
332 calcop (format, param, insn)
333 struct m88k_opcode *format;
335 struct m88k_insn *insn;
337 char *fmt = format->op_spec;
342 insn->opcode = format->opcode;
353 insn->opcode |= opcode;
362 param = get_reg (param, &val);
367 param = get_reg (param, &val);
372 param = get_reg (param, &val);
377 param = get_reg (param, &val);
378 opcode |= (val << 16) | val;
382 param = get_imm16 (param, insn);
386 param = get_bf (param, &val);
391 param = get_pcr (param, insn, RELOC_PC16);
395 param = get_pcr (param, insn, RELOC_PC26);
399 param = get_cmp (param, &val);
404 param = get_cnd (param, &val);
409 param = get_cr (param, &val);
414 param = get_fcr (param, &val);
419 param = get_vec9 (param, &val);
424 /* Having this here repeats the warning somtimes.
425 But can't we stand that? */
426 as_warn ("Use of obsolete instruction");
433 match_name (param, assoc_tab, valp)
435 struct field_val_assoc *assoc_tab;
444 name = assoc_tab[i].name;
447 name_len = strlen (name);
448 if (!strncmp (param, name, name_len))
450 *valp = assoc_tab[i].val;
451 return param + name_len;
457 get_reg (param, regnop)
467 regno = *param++ - '0';
478 regno = regno * 10 + c;
493 else if (c == 's' && param[0] == 'p')
503 get_imm16 (param, insn)
505 struct m88k_insn *insn;
507 enum reloc_type reloc = NO_RELOC;
512 if (!strncmp (param, "hi16", 4) && !isalnum (param[4]))
517 else if (!strncmp (param, "lo16", 4) && !isalnum (param[4]))
522 else if (!strncmp (param, "iw16", 4) && !isalnum (param[4]))
528 save_ptr = input_line_pointer;
529 input_line_pointer = param;
530 seg = expression (&insn->exp);
531 param = input_line_pointer;
532 input_line_pointer = save_ptr;
534 val = insn->exp.X_add_number;
536 if (seg == SEG_ABSOLUTE)
538 /* Insert the value now, and reset reloc to NO_RELOC. */
539 if (reloc == NO_RELOC)
541 /* Warn about too big expressions if not surrounded by xx16. */
543 as_warn ("Expression truncated to 16 bits");
546 if (reloc == RELOC_HI16)
549 insn->opcode |= val & 0xffff;
552 else if (reloc == NO_RELOC)
553 /* We accept a symbol even without lo16, hi16, etc, and assume
554 lo16 was intended. */
563 get_pcr (param, insn, reloc)
565 struct m88k_insn *insn;
566 enum reloc_type reloc;
568 char *saveptr, *saveparam;
571 saveptr = input_line_pointer;
572 input_line_pointer = param;
574 seg = expression (&insn->exp);
576 saveparam = input_line_pointer;
577 input_line_pointer = saveptr;
579 /* Botch: We should relocate now if SEG_ABSOLUTE. */
586 get_cmp (param, valp)
595 param = match_name (param, cmpslot, valp);
602 save_ptr = input_line_pointer;
603 input_line_pointer = param;
604 val = get_absolute_expression ();
605 param = input_line_pointer;
606 input_line_pointer = save_ptr;
610 as_warn ("Expression truncated to 5 bits");
620 get_cnd (param, valp)
626 if (isdigit (*param))
628 param = getval (param, &val);
632 as_warn ("Expression truncated to 5 bits");
638 if (isupper (*param))
639 *param = tolower (*param);
641 if (isupper (param[1]))
642 param[1] = tolower (param[1]);
644 param = match_name (param, cndmsk, valp);
673 else if (c == bc && depth <= 0)
680 get_bf_offset_expression (param, offsetp)
686 if (isalpha (param[0]))
688 if (isupper (param[0]))
689 param[0] = tolower (param[0]);
690 if (isupper (param[1]))
691 param[1] = tolower (param[1]);
693 param = match_name (param, cmpslot, offsetp);
699 input_line_pointer = param;
700 offset = get_absolute_expression ();
701 param = input_line_pointer;
718 xp = get_bf2 (param, '<');
720 save_ptr = input_line_pointer;
721 input_line_pointer = param;
724 /* We did not find '<'. We have an offset (width implicitly 32). */
725 param = get_bf_offset_expression (param, &offset);
728 input_line_pointer = save_ptr;
732 *xp++ = 0; /* Overwrite the '<' */
733 param = get_bf2 (xp, '>');
736 *param++ = 0; /* Overwrite the '>' */
738 width = get_absolute_expression ();
739 xp = get_bf_offset_expression (xp, &offset);
740 input_line_pointer = save_ptr;
746 *valp = ((width % 32) << 5) | (offset % 32);
752 get_cr (param, regnop)
758 /* int i; FIXME remove this */
759 /* int name_len; FIXME remove this */
761 if (!strncmp (param, "cr", 2))
765 regno = *param++ - '0';
776 regno = regno * 10 + c;
792 param = match_name (param, cr_regs, regnop);
798 get_fcr (param, regnop)
804 /* int i; FIXME remove this */
805 /* int name_len; FIXME: remove this */
807 if (!strncmp (param, "fcr", 3))
811 regno = *param++ - '0';
822 regno = regno * 10 + c;
838 param = match_name (param, fcr_regs, regnop);
844 get_vec9 (param, valp)
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;
858 as_warn ("Expression truncated to 9 bits");
860 *valp = val % (1 << 9);
866 (isdigit (z) ? (z) - '0' : \
867 islower (z) ? (z) - 'a' + 10 : \
868 isupper (z) ? (z) - 'A' + 10 : -1)
875 unsigned int val = 0;
882 if (c == 'x' || c == 'X')
918 md_number_to_chars (buf, val, nbytes)
942 md_number_to_imm (buf, val, nbytes, fixP, seg_type)
949 if (seg_type != N_TEXT || fixP->fx_r_type == NO_RELOC)
968 switch (fixP->fx_r_type)
993 buf[0] |= (val >> 26) & 0x03;
1007 as_fatal ("Bad relocation type");
1011 #endif /* comment */
1013 /* Apply a fixS to the frags, now that we know the value it ought to
1016 void md_apply_fix(fixP, val)
1020 char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
1022 fixP->fx_addnumber = val;
1025 switch (fixP->fx_r_type) {
1050 buf[0] |= (val >> 26) & 0x03;
1064 switch (fixP->fx_size) {
1079 as_bad("bad relocation type: 0x%02x", fixP->fx_r_type);
1084 } /* md_apply_fix() */
1087 md_number_to_disp (buf, val, nbytes)
1092 as_fatal ("md_number_to_disp not defined");
1093 md_number_to_chars (buf, val, nbytes);
1097 md_number_to_field (buf, val, nbytes)
1102 as_fatal ("md_number_to_field not defined");
1103 md_number_to_chars (buf, val, nbytes);
1106 #define MAX_LITTLENUMS 6
1108 /* Turn a string in input_line_pointer into a floating point constant of type
1109 type, and store the appropriate bytes in *litP. The number of LITTLENUMS
1110 emitted is stored in *sizeP. An error message is returned, or NULL on OK.
1113 md_atof (type, litP, sizeP)
1119 LITTLENUM_TYPE words[MAX_LITTLENUMS];
1120 LITTLENUM_TYPE *wordP;
1152 return "Bad call to MD_ATOF()";
1154 t=atof_ieee (input_line_pointer, type, words);
1156 input_line_pointer=t;
1158 *sizeP=prec * sizeof (LITTLENUM_TYPE);
1159 for (wordP=words;prec--;)
1161 md_number_to_chars (litP, (long) (*wordP++), sizeof (LITTLENUM_TYPE));
1162 litP+=sizeof (LITTLENUM_TYPE);
1164 return ""; /* Someone should teach Dean about null pointers */
1167 int md_short_jump_size = 4;
1170 md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol)
1172 long from_addr, to_addr;
1176 ptr[0] = 0xc0; ptr[1] = 0x00; ptr[2] = 0x00; ptr[3] = 0x00;
1178 ptr - frag->fr_literal,
1184 RELOC_PC26); /* Botch: Shouldn't this be RELOC_PC16? */
1187 int md_long_jump_size = 4;
1190 md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol)
1192 long from_addr, to_addr;
1196 ptr[0] = 0xc0; ptr[1] = 0x00; ptr[2] = 0x00; ptr[3] = 0x00;
1198 ptr - frag->fr_literal,
1208 md_estimate_size_before_relax (fragP, segment_type)
1212 as_fatal("Relaxation should never occur");
1216 const relax_typeS md_relax_table[] = {0};
1219 md_convert_frag (headers, fragP)
1220 object_headers *headers;
1223 as_fatal ("Relaxation should never occur");
1234 * Risc relocations are completely different, so it needs
1235 * this machine dependent routine to emit them.
1238 emit_relocations (fixP, segment_address_in_file)
1240 relax_addressT segment_address_in_file;
1242 struct reloc_info_m88k ri;
1244 extern char *next_object_file_charP;
1246 bzero ((char *) &ri, sizeof (ri));
1247 for (; fixP; fixP = fixP->fx_next) {
1249 if (fixP->fx_r_type >= NO_RELOC) {
1250 fprintf (stderr, "fixP->fx_r_type = %d\n", fixP->fx_r_type);
1254 if ((symbolP = fixP->fx_addsy) != NULL) {
1255 ri.r_address = fixP->fx_frag->fr_address +
1256 fixP->fx_where - segment_address_in_file;
1257 if ((symbolP->sy_type & N_TYPE) == N_UNDF) {
1259 ri.r_symbolnum = symbolP->sy_number;
1262 ri.r_symbolnum = symbolP->sy_type & N_TYPE;
1264 if (symbolP && symbolP->sy_frag) {
1265 ri.r_addend = symbolP->sy_frag->fr_address;
1267 ri.r_type = fixP->fx_r_type;
1268 if (fixP->fx_pcrel) {
1269 /* ri.r_addend -= fixP->fx_where; */
1270 ri.r_addend -= ri.r_address;
1272 ri.r_addend = fixP->fx_addnumber;
1275 /* md_ri_to_chars ((char *) &ri, ri); */
1276 append (&next_object_file_charP, (char *)& ri, sizeof (ri));
1281 #endif /* comment */
1283 /* Translate internal representation of relocation info to target format.
1285 On m88k: first 4 bytes are normal unsigned long address,
1286 next three bytes are index, most sig. byte first.
1287 Byte 7 is broken up with bit 7 as external,
1288 bits 6, 5, & 4 unused, and the lower four bits as relocation
1290 Next 4 bytes are long addend. */
1292 void tc_aout_fix_to_chars(where, fixP, segment_address_in_file)
1295 relax_addressT segment_address_in_file;
1302 know(fixP->fx_addsy);
1304 if (!S_IS_DEFINED(fixP->fx_addsy)) {
1306 r_index = fixP->fx_addsy->sy_number;
1309 r_index = S_GET_TYPE(fixP->fx_addsy);
1313 md_number_to_chars(where,
1314 r_address = fixP->fx_frag->fr_address + fixP->fx_where - segment_address_in_file,
1317 /* now the fun stuff */
1318 where[4] = (r_index >> 16) & 0x0ff;
1319 where[5] = (r_index >> 8) & 0x0ff;
1320 where[6] = r_index & 0x0ff;
1321 where[7] = ((r_extern << 7) & 0x80) | (0 & 0x70) | (fixP->fx_r_type & 0xf);
1324 if (fixP->fx_addsy->sy_frag) {
1325 r_addend = fixP->fx_addsy->sy_frag->fr_address;
1328 if (fixP->fx_pcrel) {
1329 r_addend -= r_address;
1331 r_addend = fixP->fx_addnumber;
1334 md_number_to_chars(&where[8], r_addend, 4);
1337 } /* tc_aout_fix_to_chars() */
1346 int temp, bss_align = 1;
1348 extern char is_end_of_line[256];
1350 name = input_line_pointer;
1351 c = get_symbol_end();
1352 p = input_line_pointer;
1355 if ( * input_line_pointer != ',' )
1357 as_warn("Expected comma after name");
1358 ignore_rest_of_line();
1361 input_line_pointer ++;
1362 if ((temp = get_absolute_expression()) < 0)
1364 as_warn("BSS length (%d.) <0! Ignored.", temp);
1365 ignore_rest_of_line();
1369 symbolP = symbol_find_or_make(name);
1371 if (*input_line_pointer == ',')
1373 input_line_pointer++;
1374 bss_align = get_absolute_expression();
1375 while (local_bss_counter % bss_align != 0)
1376 local_bss_counter++;
1379 if (!S_IS_DEFINED(symbolP)
1380 || (S_GET_SEGMENT(symbolP) == SEG_BSS
1381 && S_GET_VALUE(symbolP) == local_bss_counter)) {
1382 S_SET_VALUE(symbolP, local_bss_counter);
1383 S_SET_SEGMENT(symbolP, SEG_BSS);
1384 symbolP->sy_frag = &bss_address_frag;
1385 local_bss_counter += temp;
1387 as_warn( "Ignoring attempt to re-define symbol from %d. to %d.",
1388 S_GET_VALUE(symbolP), local_bss_counter );
1390 while (!is_end_of_line[*input_line_pointer])
1392 input_line_pointer++;
1398 /* We have no need to default values of symbols. */
1401 symbolS *md_undefined_symbol(name)
1405 } /* md_undefined_symbol() */
1407 /* Parse an operand that is machine-specific.
1408 We just return without modifying the expression if we have nothing
1412 void md_operand(expressionP)
1413 expressionS *expressionP;
1415 } /* md_operand() */
1417 /* Round up a section size to the appropriate boundary. */
1418 long md_section_align(segment, size)
1422 return((size + 7) & ~7); /* Round all sects to multiple of 8 */
1423 } /* md_section_align() */
1425 /* Exactly what point is a PC-relative offset relative TO?
1426 On the sparc, they're relative to the address of the offset, plus
1427 its size. This gets us to the following instruction.
1428 (??? Is this right? FIXME-SOON) */
1429 long md_pcrel_from(fixP)
1432 return(fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address);
1433 } /* md_pcrel_from() */
1435 /* end of tc-m88k.c */