From 6700d36e840fad4694c68b12915efdb8ac2ff3ec Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 9 Aug 1995 23:22:13 +0000 Subject: [PATCH] * config/tc-m68k.c (m68k_abspcadd): New static variable. (m68k_quick): New static variable. (m68k_rel32): New static variable. (md_pseudo_table): Add opt and reg. (m68k_ip): Permit absolute symbols in 'l'/'L' recognition. Check m68k_quick in 'M' and 'Q' recognition. Check m68k_abspcadd in DISP handling. Check m68k_rel32 in BASE/POST/PRE handling. (md_begin): In MRI mode, initialize m68k_abspcadd and m68k_rel32. In MRI mode, change unsized branch aliases to be variable sized. (struct opt_action): Define. (opt_table): Define. (s_opt): New static function. (skip_to_comma): New static function. (opt_chip): New static function. (opt_list): New static function. (opt_list_symbols): New static function. (s_reg): New static function. * as.h (flag_keep_locals): Change from unsigned char to int. (flag_no_warnings): Likewise. --- gas/ChangeLog | 30 ++++ gas/config/tc-m68k.c | 375 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 400 insertions(+), 5 deletions(-) diff --git a/gas/ChangeLog b/gas/ChangeLog index 09e0b74284a..ccdf546d008 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,5 +1,35 @@ Wed Aug 9 10:51:48 1995 Ian Lance Taylor + * config/tc-m68k.c (m68k_abspcadd): New static variable. + (m68k_quick): New static variable. + (m68k_rel32): New static variable. + (md_pseudo_table): Add opt and reg. + (m68k_ip): Permit absolute symbols in 'l'/'L' recognition. Check + m68k_quick in 'M' and 'Q' recognition. Check m68k_abspcadd in + DISP handling. Check m68k_rel32 in BASE/POST/PRE handling. + (md_begin): In MRI mode, initialize m68k_abspcadd and m68k_rel32. + In MRI mode, change unsized branch aliases to be variable sized. + (struct opt_action): Define. + (opt_table): Define. + (s_opt): New static function. + (skip_to_comma): New static function. + (opt_chip): New static function. + (opt_list): New static function. + (opt_list_symbols): New static function. + (s_reg): New static function. + * as.h (flag_keep_locals): Change from unsigned char to int. + (flag_no_warnings): Likewise. + + * read.c (mri_line_label): Make non-static. + (potable): Add nopage, page, plen. + (s_org): Error if in MRI mode. + * read.h (mri_line_label): Declare. + * listing.c (listing_nopage): New function. + * listing.h (listing_nopage): Declare. + + * symbols.c (symbol_begin): Set sy_frag of abs_symbol to + &zero_address_frag. + * write.c (adjust_reloc_syms): Check that symbol is not NULL before checking sy_mri_common. (fixup_segment): Likewise. diff --git a/gas/config/tc-m68k.c b/gas/config/tc-m68k.c index 6412a5da0fe..3832755e398 100644 --- a/gas/config/tc-m68k.c +++ b/gas/config/tc-m68k.c @@ -76,6 +76,19 @@ int flag_reg_prefix_optional; /* The floating point coprocessor to use by default. */ static enum m68k_register m68k_float_copnum = COP1; +/* If this is non-zero, then references to number(%pc) will be taken + to refer to number, rather than to %pc + number. */ +static int m68k_abspcadd; + +/* If this is non-zero, then the quick forms of the move, add, and sub + instructions are used when possible. */ +static int m68k_quick = 1; + +/* If this is non-zero, then if the size is not specified for a base + or outer displacement, the assembler assumes that the size should + be 32 bits. */ +static int m68k_rel32 = 1; + /* Its an arbitrary name: This means I don't approve of it */ /* See flames below */ static struct obstack robyn; @@ -280,6 +293,8 @@ static void s_proc PARAMS ((int)); static void mri_chip PARAMS ((void)); static void s_chip PARAMS ((int)); static void s_fopt PARAMS ((int)); +static void s_opt PARAMS ((int)); +static void s_reg PARAMS ((int)); static int current_architecture; @@ -410,6 +425,8 @@ CONST pseudo_typeS md_pseudo_table[] = {"comline", s_space, 1}, {"fopt", s_fopt, 0}, {"mask2", s_ignore, 0}, + {"opt", s_opt, 0}, + {"reg", s_reg, 0}, {0, 0, 0} }; @@ -1036,6 +1053,14 @@ m68k_ip (instring) opP->mode = REGLST; } } + else if (opP->mode == ABSL + && opP->disp.size == SIZE_UNSPEC + && opP->disp.exp.X_op == O_constant) + { + /* This is what the MRI REG pseudo-op generates. */ + opP->mode = REGLST; + opP->mask = opP->disp.exp.X_add_number; + } else if (opP->mode != REGLST) losing++; else if (s[1] == '8' && (opP->mask & 0x0ffffff) != 0) @@ -1049,6 +1074,10 @@ m68k_ip (instring) losing++; else if (! expr8 (&opP->disp)) losing++; + else if (! m68k_quick + && instring[3] != 'q' + && instring[4] != 'q') + losing++; break; case 'O': @@ -1063,6 +1092,11 @@ m68k_ip (instring) || opP->disp.exp.X_add_number < 1 || opP->disp.exp.X_add_number > 8) losing++; + else if (! m68k_quick + && (strncmp (instring, "add", 3) == 0 + || strncmp (instring, "sub", 3) == 0) + && instring[3] != 'q') + losing++; break; case 'R': @@ -1409,6 +1443,20 @@ m68k_ip (instring) case DISP: nextword = get_num (&opP->disp, 80); + + if (opP->reg == PC + && ! isvar (&opP->disp) + && m68k_abspcadd) + { + opP->disp.exp.X_op = O_symbol; +#ifndef BFD_ASSEMBLER + opP->disp.exp.X_add_symbol = &abs_symbol; +#else + opP->disp.exp.X_add_symbol = + section_symbol (absolute_section); +#endif + } + /* Force into index mode. Hope this works */ /* We do the first bit for 32-bit displacements, and the @@ -1621,12 +1669,14 @@ m68k_ip (instring) switch (siz1) { case SIZE_UNSPEC: - if (isvar (&opP->disp) || !issword (baseo)) + if (isvar (&opP->disp) + ? m68k_rel32 + : ! issword (baseo)) { siz1 = SIZE_LONG; nextword |= 0x30; } - else if (baseo == 0) + else if (! isvar (&opP->disp) && baseo == 0) nextword |= 0x10; else { @@ -1651,12 +1701,14 @@ m68k_ip (instring) switch (siz2) { case SIZE_UNSPEC: - if (isvar (&opP->odisp) || !issword (outro)) + if (isvar (&opP->odisp) + ? m68k_rel32 + : ! issword (outro)) { siz2 = SIZE_LONG; nextword |= 0x3; } - else if (outro == 0) + else if (! isvar (&opP->disp) && outro == 0) nextword |= 0x1; else { @@ -2842,7 +2894,11 @@ md_begin () register char c; if (flag_mri) - flag_reg_prefix_optional = 1; + { + flag_reg_prefix_optional = 1; + m68k_abspcadd = 1; + m68k_rel32 = 0; + } op_hash = hash_new (); @@ -2890,6 +2946,43 @@ md_begin () as_fatal ("Internal Error: Can't hash %s: %s", alias, retval); } + /* In MRI mode, all unsized branches are variable sized. Normally, + they are word sized. */ + if (flag_mri) + { + static struct m68k_opcode_alias mri_aliases[] = + { + { "bhi", "jhi", }, + { "bls", "jls", }, + { "bcc", "jcc", }, + { "bcs", "jcs", }, + { "bne", "jne", }, + { "beq", "jeq", }, + { "bvc", "jvc", }, + { "bvs", "jvs", }, + { "bpl", "jpl", }, + { "bmi", "jmi", }, + { "bge", "jge", }, + { "blt", "jlt", }, + { "bgt", "jgt", }, + { "ble", "jle", }, + { "bra", "jra", }, + { "bsr", "jbsr", }, + }; + + for (i = 0; i < sizeof mri_aliases / sizeof mri_aliases[0]; i++) + { + const char *name = mri_aliases[i].primary; + const char *alias = mri_aliases[i].alias; + PTR val = hash_find (op_hash, name); + if (!val) + as_fatal ("Internal Error: Can't find %s in hash table", name); + retval = hash_jam (op_hash, alias, val); + if (retval) + as_fatal ("Internal Error: Can't hash %s: %s", alias, retval); + } + } + for (i = 0; i < sizeof (mklower_table); i++) mklower_table[i] = (isupper (c = (char) i)) ? tolower (c) : c; @@ -4067,6 +4160,278 @@ s_fopt (ignore) demand_empty_rest_of_line (); } + +/* The structure used to handle the MRI OPT pseudo-op. */ + +struct opt_action +{ + /* The name of the option. */ + const char *name; + + /* If this is not NULL, just call this function. The first argument + is the ARG field of this structure, the second argument is + whether the option was negated. */ + void (*pfn) PARAMS ((int arg, int on)); + + /* If this is not NULL, and the PFN field is NULL, set the variable + this points to. Set it to the ARG field if the option was not + negated, and the NOTARG field otherwise. */ + int *pvar; + + /* The value to pass to PFN or to assign to *PVAR. */ + int arg; + + /* The value to assign to *PVAR if the option is negated. If PFN is + NULL, and PVAR is not NULL, and ARG and NOTARG are the same, then + the option may not be negated. */ + int notarg; +}; + +/* The table used to handle the MRI OPT pseudo-op. */ + +static void skip_to_comma PARAMS ((int, int)); +static void opt_chip PARAMS ((int, int)); +static void opt_list PARAMS ((int, int)); +static void opt_list_symbols PARAMS ((int, int)); + +static const struct opt_action opt_table[] = +{ + { "abspcadd", 0, &m68k_abspcadd, 1, 0 }, + + /* We do relaxing, so there is little use for these options. */ + { "b", 0, 0, 0, 0 }, + { "brs", 0, 0, 0, 0 }, + { "brb", 0, 0, 0, 0 }, + { "brl", 0, 0, 0, 0 }, + { "brw", 0, 0, 0, 0 }, + + { "c", 0, 0, 0, 0 }, + { "cex", 0, 0, 0, 0 }, + { "case", 0, &symbols_case_sensitive, 1, 0 }, + { "cl", 0, 0, 0, 0 }, + { "cre", 0, 0, 0, 0 }, + { "d", 0, &flag_keep_locals, 1, 0 }, + { "e", 0, 0, 0, 0 }, + { "f", 0, &flag_short_refs, 1, 0 }, + { "frs", 0, &flag_short_refs, 1, 0 }, + { "frl", 0, &flag_short_refs, 0, 1 }, + { "g", 0, 0, 0, 0 }, + { "i", 0, 0, 0, 0 }, + { "m", 0, 0, 0, 0 }, + { "mex", 0, 0, 0, 0 }, + { "mc", 0, 0, 0, 0 }, + { "md", 0, 0, 0, 0 }, + { "next", skip_to_comma, 0, 0, 0 }, + { "o", 0, 0, 0, 0 }, + { "old", 0, 0, 0, 0 }, + { "op", skip_to_comma, 0, 0, 0 }, + { "pco", 0, 0, 0, 0 }, + { "p", opt_chip, 0, 0, 0 }, + { "pcr", 0, 0, 0, 0 }, + { "pcs", 0, 0, 0, 0 }, + { "r", 0, 0, 0, 0 }, + { "quick", 0, &m68k_quick, 1, 0 }, + { "rel32", 0, &m68k_rel32, 1, 0 }, + { "s", opt_list, 0, 0, 0 }, + { "t", opt_list_symbols, 0, 0, 0 }, + { "w", 0, &flag_no_warnings, 0, 1 }, + { "x", 0, 0, 0, 0 } +}; + +#define OPTCOUNT (sizeof opt_table / sizeof opt_table[0]) + +/* The MRI OPT pseudo-op. */ + +static void +s_opt (ignore) + int ignore; +{ + do + { + int t; + char *s; + char c; + int i; + const struct opt_action *o; + + SKIP_WHITESPACE (); + + t = 1; + if (*input_line_pointer == '-') + { + ++input_line_pointer; + t = 0; + } + else if (strncasecmp (input_line_pointer, "NO", 2) == 0) + { + input_line_pointer += 2; + t = 0; + } + + s = input_line_pointer; + c = get_symbol_end (); + + for (i = 0, o = opt_table; i < OPTCOUNT; i++, o++) + { + if (strcasecmp (s, o->name) == 0) + { + if (o->pfn) + { + /* Restore input_line_pointer now in case the option + takes arguments. */ + *input_line_pointer = c; + (*o->pfn) (o->arg, t); + } + else if (o->pvar != NULL) + { + if (! t && o->arg == o->notarg) + as_bad ("option `%s' may not be negated", s); + *input_line_pointer = c; + *o->pvar = t ? o->arg : o->notarg; + } + break; + } + } + if (i >= OPTCOUNT) + { + as_bad ("option `%s' not recognized", s); + *input_line_pointer = c; + } + } + while (*input_line_pointer++ == ','); + + /* Move back to terminating character. */ + --input_line_pointer; + demand_empty_rest_of_line (); +} + +/* Skip ahead to a comma. This is used for OPT options which we do + not suppor tand which take arguments. */ + +static void +skip_to_comma (arg, on) + int arg; + int on; +{ + while (*input_line_pointer != ',' + && ! is_end_of_line[(unsigned char) *input_line_pointer]) + ++input_line_pointer; +} + +/* Handle the OPT P=chip option. */ + +static void +opt_chip (arg, on) + int arg; + int on; +{ + if (*input_line_pointer != '=') + { + /* This is just OPT P, which we do not support. */ + return; + } + + ++input_line_pointer; + mri_chip (); +} + +/* Handle the OPT S option. */ + +static void +opt_list (arg, on) + int arg; + int on; +{ + listing_list (on); +} + +/* Handle the OPT T option. */ + +static void +opt_list_symbols (arg, on) + int arg; + int on; +{ + if (on) + listing |= LISTING_SYMBOLS; + else + listing &=~ LISTING_SYMBOLS; +} + +/* Handle the MRI REG pseudo-op. */ + +static void +s_reg (ignore) + int ignore; +{ + char *s; + int c; + struct m68k_op op; + unsigned long mask; + + if (mri_line_label == NULL) + { + as_bad ("missing label"); + ignore_rest_of_line (); + return; + } + + SKIP_WHITESPACE (); + + s = input_line_pointer; + while (isalnum ((unsigned char) *input_line_pointer) +#ifdef REGISTER_PREFIX + || *input_line_pointer == REGISTER_PREFIX +#endif + || *input_line_pointer == '/' + || *input_line_pointer == '-') + ++input_line_pointer; + c = *input_line_pointer; + *input_line_pointer = '\0'; + + if (m68k_ip_op (s, &op) != 0) + { + if (op.error == NULL) + as_bad ("bad register list"); + else + as_bad ("bad register list: %s", op.error); + *input_line_pointer = c; + ignore_rest_of_line (); + return; + } + + *input_line_pointer = c; + + if (op.mode == REGLST) + mask = op.mask; + else if (op.mode == DREG) + mask = 1 << (op.reg - DATA0); + else if (op.mode == AREG) + mask = 1 << (op.reg - ADDR0 + 8); + else if (op.mode == FPREG) + mask = 1 << (op.reg - FP0 + 16); + else if (op.mode == CONTROL + && op.reg == FPI) + mask = 1 << 24; + else if (op.mode == CONTROL + && op.reg == FPS) + mask = 1 << 25; + else if (op.mode == CONTROL + && op.reg == FPC) + mask = 1 << 26; + else + { + as_bad ("bad register list"); + ignore_rest_of_line (); + return; + } + + S_SET_SEGMENT (mri_line_label, absolute_section); + S_SET_VALUE (mri_line_label, mask); + mri_line_label->sy_frag = &zero_address_frag; + + demand_empty_rest_of_line (); +} /* * md_parse_option -- 2.30.2