diff options
Diffstat (limited to 'binutils-2.17/gas/config/tc-h8300.c')
-rw-r--r-- | binutils-2.17/gas/config/tc-h8300.c | 2203 |
1 files changed, 0 insertions, 2203 deletions
diff --git a/binutils-2.17/gas/config/tc-h8300.c b/binutils-2.17/gas/config/tc-h8300.c deleted file mode 100644 index 7db600c7..00000000 --- a/binutils-2.17/gas/config/tc-h8300.c +++ /dev/null @@ -1,2203 +0,0 @@ -/* tc-h8300.c -- Assemble code for the Renesas H8/300 - Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 2000, - 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. - - This file is part of GAS, the GNU Assembler. - - GAS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - GAS is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GAS; see the file COPYING. If not, write to the Free - Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA - 02110-1301, USA. */ - -/* Written By Steve Chamberlain <sac@cygnus.com>. */ - -#include <stdio.h> -#include "as.h" -#include "subsegs.h" -#include "bfd.h" -#include "dwarf2dbg.h" - -#define DEFINE_TABLE -#define h8_opcodes ops -#include "opcode/h8300.h" -#include "safe-ctype.h" - -#ifdef OBJ_ELF -#include "elf/h8.h" -#endif - -const char comment_chars[] = ";"; -const char line_comment_chars[] = "#"; -const char line_separator_chars[] = ""; - -static void sbranch (int); -static void h8300hmode (int); -static void h8300smode (int); -static void h8300hnmode (int); -static void h8300snmode (int); -static void h8300sxmode (int); -static void h8300sxnmode (int); -static void pint (int); - -int Hmode; -int Smode; -int Nmode; -int SXmode; - -#define PSIZE (Hmode && !Nmode ? L_32 : L_16) - -static int bsize = L_8; /* Default branch displacement. */ - -struct h8_instruction -{ - int length; - int noperands; - int idx; - int size; - const struct h8_opcode *opcode; -}; - -static struct h8_instruction *h8_instructions; - -static void -h8300hmode (int arg ATTRIBUTE_UNUSED) -{ - Hmode = 1; - Smode = 0; - if (!bfd_set_arch_mach (stdoutput, bfd_arch_h8300, bfd_mach_h8300h)) - as_warn (_("could not set architecture and machine")); -} - -static void -h8300smode (int arg ATTRIBUTE_UNUSED) -{ - Smode = 1; - Hmode = 1; - if (!bfd_set_arch_mach (stdoutput, bfd_arch_h8300, bfd_mach_h8300s)) - as_warn (_("could not set architecture and machine")); -} - -static void -h8300hnmode (int arg ATTRIBUTE_UNUSED) -{ - Hmode = 1; - Smode = 0; - Nmode = 1; - if (!bfd_set_arch_mach (stdoutput, bfd_arch_h8300, bfd_mach_h8300hn)) - as_warn (_("could not set architecture and machine")); -} - -static void -h8300snmode (int arg ATTRIBUTE_UNUSED) -{ - Smode = 1; - Hmode = 1; - Nmode = 1; - if (!bfd_set_arch_mach (stdoutput, bfd_arch_h8300, bfd_mach_h8300sn)) - as_warn (_("could not set architecture and machine")); -} - -static void -h8300sxmode (int arg ATTRIBUTE_UNUSED) -{ - Smode = 1; - Hmode = 1; - SXmode = 1; - if (!bfd_set_arch_mach (stdoutput, bfd_arch_h8300, bfd_mach_h8300sx)) - as_warn (_("could not set architecture and machine")); -} - -static void -h8300sxnmode (int arg ATTRIBUTE_UNUSED) -{ - Smode = 1; - Hmode = 1; - SXmode = 1; - Nmode = 1; - if (!bfd_set_arch_mach (stdoutput, bfd_arch_h8300, bfd_mach_h8300sxn)) - as_warn (_("could not set architecture and machine")); -} - -static void -sbranch (int size) -{ - bsize = size; -} - -static void -pint (int arg ATTRIBUTE_UNUSED) -{ - cons (Hmode ? 4 : 2); -} - -/* This table describes all the machine specific pseudo-ops the assembler - has to support. The fields are: - pseudo-op name without dot - function to call to execute this pseudo-op - Integer arg to pass to the function. */ - -const pseudo_typeS md_pseudo_table[] = -{ - {"h8300h", h8300hmode, 0}, - {"h8300hn", h8300hnmode, 0}, - {"h8300s", h8300smode, 0}, - {"h8300sn", h8300snmode, 0}, - {"h8300sx", h8300sxmode, 0}, - {"h8300sxn", h8300sxnmode, 0}, - {"sbranch", sbranch, L_8}, - {"lbranch", sbranch, L_16}, - - {"int", pint, 0}, - {"data.b", cons, 1}, - {"data.w", cons, 2}, - {"data.l", cons, 4}, - {"form", listing_psize, 0}, - {"heading", listing_title, 0}, - {"import", s_ignore, 0}, - {"page", listing_eject, 0}, - {"program", s_ignore, 0}, - {0, 0, 0} -}; - -const char EXP_CHARS[] = "eE"; - -/* Chars that mean this number is a floating point constant - As in 0f12.456 - or 0d1.2345e12. */ -const char FLT_CHARS[] = "rRsSfFdDxXpP"; - -static struct hash_control *opcode_hash_control; /* Opcode mnemonics. */ - -/* This function is called once, at assembler startup time. This - should set up all the tables, etc. that the MD part of the assembler - needs. */ - -void -md_begin (void) -{ - unsigned int nopcodes; - struct h8_opcode *p, *p1; - struct h8_instruction *pi; - char prev_buffer[100]; - int idx = 0; - - if (!bfd_set_arch_mach (stdoutput, bfd_arch_h8300, bfd_mach_h8300)) - as_warn (_("could not set architecture and machine")); - - opcode_hash_control = hash_new (); - prev_buffer[0] = 0; - - nopcodes = sizeof (h8_opcodes) / sizeof (struct h8_opcode); - - h8_instructions = (struct h8_instruction *) - xmalloc (nopcodes * sizeof (struct h8_instruction)); - - pi = h8_instructions; - p1 = h8_opcodes; - /* We do a minimum amount of sorting on the opcode table; this is to - make it easy to describe the mova instructions without unnecessary - code duplication. - Sorting only takes place inside blocks of instructions of the form - X/Y, so for example mova/b, mova/w and mova/l can be intermixed. */ - while (p1) - { - struct h8_opcode *first_skipped = 0; - int len, cmplen = 0; - char *src = p1->name; - char *dst, *buffer; - - if (p1->name == 0) - break; - /* Strip off any . part when inserting the opcode and only enter - unique codes into the hash table. */ - dst = buffer = malloc (strlen (src) + 1); - while (*src) - { - if (*src == '.') - { - src++; - break; - } - if (*src == '/') - cmplen = src - p1->name + 1; - *dst++ = *src++; - } - *dst = 0; - len = dst - buffer; - if (cmplen == 0) - cmplen = len; - hash_insert (opcode_hash_control, buffer, (char *) pi); - strcpy (prev_buffer, buffer); - idx++; - - for (p = p1; p->name; p++) - { - /* A negative TIME is used to indicate that we've added this opcode - already. */ - if (p->time == -1) - continue; - if (strncmp (p->name, buffer, cmplen) != 0 - || (p->name[cmplen] != '\0' && p->name[cmplen] != '.' - && p->name[cmplen - 1] != '/')) - { - if (first_skipped == 0) - first_skipped = p; - break; - } - if (strncmp (p->name, buffer, len) != 0) - { - if (first_skipped == 0) - first_skipped = p; - continue; - } - - p->time = -1; - pi->size = p->name[len] == '.' ? p->name[len + 1] : 0; - pi->idx = idx; - - /* Find the number of operands. */ - pi->noperands = 0; - while (pi->noperands < 3 && p->args.nib[pi->noperands] != (op_type) E) - pi->noperands++; - - /* Find the length of the opcode in bytes. */ - pi->length = 0; - while (p->data.nib[pi->length * 2] != (op_type) E) - pi->length++; - - pi->opcode = p; - pi++; - } - p1 = first_skipped; - } - - /* Add entry for the NULL vector terminator. */ - pi->length = 0; - pi->noperands = 0; - pi->idx = 0; - pi->size = 0; - pi->opcode = 0; - - linkrelax = 1; -} - -struct h8_op -{ - op_type mode; - unsigned reg; - expressionS exp; -}; - -static void clever_message (const struct h8_instruction *, struct h8_op *); -static void fix_operand_size (struct h8_op *, int); -static void build_bytes (const struct h8_instruction *, struct h8_op *); -static void do_a_fix_imm (int, int, struct h8_op *, int); -static void check_operand (struct h8_op *, unsigned int, char *); -static const struct h8_instruction * get_specific (const struct h8_instruction *, struct h8_op *, int) ; -static char *get_operands (unsigned, char *, struct h8_op *); -static void get_operand (char **, struct h8_op *, int); -static int parse_reg (char *, op_type *, unsigned *, int); -static char *skip_colonthing (char *, int *); -static char *parse_exp (char *, struct h8_op *); - -static int constant_fits_width_p (struct h8_op *, unsigned int); -static int constant_fits_size_p (struct h8_op *, int, int); - -/* - parse operands - WREG r0,r1,r2,r3,r4,r5,r6,r7,fp,sp - r0l,r0h,..r7l,r7h - @WREG - @WREG+ - @-WREG - #const - ccr -*/ - -/* Try to parse a reg name. Return the number of chars consumed. */ - -static int -parse_reg (char *src, op_type *mode, unsigned int *reg, int direction) -{ - char *end; - int len; - - /* Cribbed from get_symbol_end. */ - if (!is_name_beginner (*src) || *src == '\001') - return 0; - end = src + 1; - while ((is_part_of_name (*end) && *end != '.') || *end == '\001') - end++; - len = end - src; - - if (len == 2 && TOLOWER (src[0]) == 's' && TOLOWER (src[1]) == 'p') - { - *mode = PSIZE | REG | direction; - *reg = 7; - return len; - } - if (len == 3 && - TOLOWER (src[0]) == 'c' && - TOLOWER (src[1]) == 'c' && - TOLOWER (src[2]) == 'r') - { - *mode = CCR; - *reg = 0; - return len; - } - if (len == 3 && - TOLOWER (src[0]) == 'e' && - TOLOWER (src[1]) == 'x' && - TOLOWER (src[2]) == 'r') - { - *mode = EXR; - *reg = 1; - return len; - } - if (len == 3 && - TOLOWER (src[0]) == 'v' && - TOLOWER (src[1]) == 'b' && - TOLOWER (src[2]) == 'r') - { - *mode = VBR; - *reg = 6; - return len; - } - if (len == 3 && - TOLOWER (src[0]) == 's' && - TOLOWER (src[1]) == 'b' && - TOLOWER (src[2]) == 'r') - { - *mode = SBR; - *reg = 7; - return len; - } - if (len == 2 && TOLOWER (src[0]) == 'f' && TOLOWER (src[1]) == 'p') - { - *mode = PSIZE | REG | direction; - *reg = 6; - return len; - } - if (len == 3 && TOLOWER (src[0]) == 'e' && TOLOWER (src[1]) == 'r' && - src[2] >= '0' && src[2] <= '7') - { - *mode = L_32 | REG | direction; - *reg = src[2] - '0'; - if (!Hmode) - as_warn (_("Reg not valid for H8/300")); - return len; - } - if (len == 2 && TOLOWER (src[0]) == 'e' && src[1] >= '0' && src[1] <= '7') - { - *mode = L_16 | REG | direction; - *reg = src[1] - '0' + 8; - if (!Hmode) - as_warn (_("Reg not valid for H8/300")); - return len; - } - - if (TOLOWER (src[0]) == 'r') - { - if (src[1] >= '0' && src[1] <= '7') - { - if (len == 3 && TOLOWER (src[2]) == 'l') - { - *mode = L_8 | REG | direction; - *reg = (src[1] - '0') + 8; - return len; - } - if (len == 3 && TOLOWER (src[2]) == 'h') - { - *mode = L_8 | REG | direction; - *reg = (src[1] - '0'); - return len; - } - if (len == 2) - { - *mode = L_16 | REG | direction; - *reg = (src[1] - '0'); - return len; - } - } - } - - return 0; -} - - -/* Parse an immediate or address-related constant and store it in OP. - If the user also specifies the operand's size, store that size - in OP->MODE, otherwise leave it for later code to decide. */ - -static char * -parse_exp (char *src, struct h8_op *op) -{ - char *save; - - save = input_line_pointer; - input_line_pointer = src; - expression (&op->exp); - if (op->exp.X_op == O_absent) - as_bad (_("missing operand")); - src = input_line_pointer; - input_line_pointer = save; - - return skip_colonthing (src, &op->mode); -} - - -/* If SRC starts with an explicit operand size, skip it and store the size - in *MODE. Leave *MODE unchanged otherwise. */ - -static char * -skip_colonthing (char *src, int *mode) -{ - if (*src == ':') - { - src++; - *mode &= ~SIZE; - if (src[0] == '8' && !ISDIGIT (src[1])) - *mode |= L_8; - else if (src[0] == '2' && !ISDIGIT (src[1])) - *mode |= L_2; - else if (src[0] == '3' && !ISDIGIT (src[1])) - *mode |= L_3; - else if (src[0] == '4' && !ISDIGIT (src[1])) - *mode |= L_4; - else if (src[0] == '5' && !ISDIGIT (src[1])) - *mode |= L_5; - else if (src[0] == '2' && src[1] == '4' && !ISDIGIT (src[2])) - *mode |= L_24; - else if (src[0] == '3' && src[1] == '2' && !ISDIGIT (src[2])) - *mode |= L_32; - else if (src[0] == '1' && src[1] == '6' && !ISDIGIT (src[2])) - *mode |= L_16; - else - as_bad (_("invalid operand size requested")); - - while (ISDIGIT (*src)) - src++; - } - return src; -} - -/* The many forms of operand: - - Rn Register direct - @Rn Register indirect - @(exp[:16], Rn) Register indirect with displacement - @Rn+ - @-Rn - @aa:8 absolute 8 bit - @aa:16 absolute 16 bit - @aa absolute 16 bit - - #xx[:size] immediate data - @(exp:[8], pc) pc rel - @@aa[:8] memory indirect. */ - -static int -constant_fits_width_p (struct h8_op *operand, unsigned int width) -{ - return ((operand->exp.X_add_number & ~width) == 0 - || (operand->exp.X_add_number | width) == (unsigned)(~0)); -} - -static int -constant_fits_size_p (struct h8_op *operand, int size, int no_symbols) -{ - offsetT num = operand->exp.X_add_number; - if (no_symbols - && (operand->exp.X_add_symbol != 0 || operand->exp.X_op_symbol != 0)) - return 0; - switch (size) - { - case L_2: - return (num & ~3) == 0; - case L_3: - return (num & ~7) == 0; - case L_3NZ: - return num >= 1 && num < 8; - case L_4: - return (num & ~15) == 0; - case L_5: - return num >= 1 && num < 32; - case L_8: - return (num & ~0xFF) == 0 || ((unsigned)num | 0x7F) == ~0u; - case L_8U: - return (num & ~0xFF) == 0; - case L_16: - return (num & ~0xFFFF) == 0 || ((unsigned)num | 0x7FFF) == ~0u; - case L_16U: - return (num & ~0xFFFF) == 0; - case L_32: - return 1; - default: - abort (); - } -} - -static void -get_operand (char **ptr, struct h8_op *op, int direction) -{ - char *src = *ptr; - op_type mode; - unsigned int num; - unsigned int len; - - op->mode = 0; - - /* Check for '(' and ')' for instructions ldm and stm. */ - if (src[0] == '(' && src[8] == ')') - ++ src; - - /* Gross. Gross. ldm and stm have a format not easily handled - by get_operand. We deal with it explicitly here. */ - if (TOLOWER (src[0]) == 'e' && TOLOWER (src[1]) == 'r' && - ISDIGIT (src[2]) && src[3] == '-' && - TOLOWER (src[4]) == 'e' && TOLOWER (src[5]) == 'r' && ISDIGIT (src[6])) - { - int low, high; - - low = src[2] - '0'; - high = src[6] - '0'; - - /* Check register pair's validity as per tech note TN-H8*-193A/E - from Renesas for H8S and H8SX hardware manual. */ - if ( !(low == 0 && (high == 1 || high == 2 || high == 3)) - && !(low == 1 && (high == 2 || high == 3 || high == 4) && SXmode) - && !(low == 2 && (high == 3 || ((high == 4 || high == 5) && SXmode))) - && !(low == 3 && (high == 4 || high == 5 || high == 6) && SXmode) - && !(low == 4 && (high == 5 || high == 6)) - && !(low == 4 && high == 7 && SXmode) - && !(low == 5 && (high == 6 || high == 7) && SXmode) - && !(low == 6 && high == 7 && SXmode)) - as_bad (_("Invalid register list for ldm/stm\n")); - - /* Even sicker. We encode two registers into op->reg. One - for the low register to save, the other for the high - register to save; we also set the high bit in op->reg - so we know this is "very special". */ - op->reg = 0x80000000 | (high << 8) | low; - op->mode = REG; - if (src[7] == ')') - *ptr = src + 8; - else - *ptr = src + 7; - return; - } - - len = parse_reg (src, &op->mode, &op->reg, direction); - if (len) - { - src += len; - if (*src == '.') - { - int size = op->mode & SIZE; - switch (src[1]) - { - case 'l': case 'L': - if (size != L_32) - as_warn (_("mismatch between register and suffix")); - op->mode = (op->mode & ~MODE) | LOWREG; - break; - case 'w': case 'W': - if (size != L_32 && size != L_16) - as_warn (_("mismatch between register and suffix")); - op->mode = (op->mode & ~MODE) | LOWREG; - op->mode = (op->mode & ~SIZE) | L_16; - break; - case 'b': case 'B': - op->mode = (op->mode & ~MODE) | LOWREG; - if (size != L_32 && size != L_8) - as_warn (_("mismatch between register and suffix")); - op->mode = (op->mode & ~MODE) | LOWREG; - op->mode = (op->mode & ~SIZE) | L_8; - break; - default: - as_warn ("invalid suffix after register."); - break; - } - src += 2; - } - *ptr = src; - return; - } - - if (*src == '@') - { - src++; - if (*src == '@') - { - *ptr = parse_exp (src + 1, op); - if (op->exp.X_add_number >= 0x100) - { - int divisor = 1; - - op->mode = VECIND; - /* FIXME : 2? or 4? */ - if (op->exp.X_add_number >= 0x400) - as_bad (_("address too high for vector table jmp/jsr")); - else if (op->exp.X_add_number >= 0x200) - divisor = 4; - else - divisor = 2; - - op->exp.X_add_number = op->exp.X_add_number / divisor - 0x80; - } - else - op->mode = MEMIND; - return; - } - - if (*src == '-' || *src == '+') - { - len = parse_reg (src + 1, &mode, &num, direction); - if (len == 0) - { - /* Oops, not a reg after all, must be ordinary exp. */ - op->mode = ABS | direction; - *ptr = parse_exp (src, op); - return; - } - - if (((mode & SIZE) != PSIZE) - /* For Normal mode accept 16 bit and 32 bit pointer registers. */ - && (!Nmode || ((mode & SIZE) != L_32))) - as_bad (_("Wrong size pointer register for architecture.")); - - op->mode = src[0] == '-' ? RDPREDEC : RDPREINC; - op->reg = num; - *ptr = src + 1 + len; - return; - } - if (*src == '(') - { - src++; - - /* See if this is @(ERn.x, PC). */ - len = parse_reg (src, &mode, &op->reg, direction); - if (len != 0 && (mode & MODE) == REG && src[len] == '.') - { - switch (TOLOWER (src[len + 1])) - { - case 'b': - mode = PCIDXB | direction; - break; - case 'w': - mode = PCIDXW | direction; - break; - case 'l': - mode = PCIDXL | direction; - break; - default: - mode = 0; - break; - } - if (mode - && src[len + 2] == ',' - && TOLOWER (src[len + 3]) != 'p' - && TOLOWER (src[len + 4]) != 'c' - && src[len + 5] != ')') - { - *ptr = src + len + 6; - op->mode |= mode; - return; - } - /* Fall through into disp case - the grammar is somewhat - ambiguous, so we should try whether it's a DISP operand - after all ("ER3.L" might be a poorly named label...). */ - } - - /* Disp. */ - - /* Start off assuming a 16 bit offset. */ - - src = parse_exp (src, op); - if (*src == ')') - { - op->mode |= ABS | direction; - *ptr = src + 1; - return; - } - - if (*src != ',') - { - as_bad (_("expected @(exp, reg16)")); - return; - } - src++; - - len = parse_reg (src, &mode, &op->reg, direction); - if (len == 0 || (mode & MODE) != REG) - { - as_bad (_("expected @(exp, reg16)")); - return; - } - src += len; - if (src[0] == '.') - { - switch (TOLOWER (src[1])) - { - case 'b': - op->mode |= INDEXB | direction; - break; - case 'w': - op->mode |= INDEXW | direction; - break; - case 'l': - op->mode |= INDEXL | direction; - break; - default: - as_bad (_("expected .L, .W or .B for register in indexed addressing mode")); - } - src += 2; - op->reg &= 7; - } - else - op->mode |= DISP | direction; - src = skip_colonthing (src, &op->mode); - - if (*src != ')' && '(') - { - as_bad (_("expected @(exp, reg16)")); - return; - } - *ptr = src + 1; - return; - } - len = parse_reg (src, &mode, &num, direction); - - if (len) - { - src += len; - if (*src == '+' || *src == '-') - { - if (((mode & SIZE) != PSIZE) - /* For Normal mode accept 16 bit and 32 bit pointer registers. */ - && (!Nmode || ((mode & SIZE) != L_32))) - as_bad (_("Wrong size pointer register for architecture.")); - op->mode = *src == '+' ? RSPOSTINC : RSPOSTDEC; - op->reg = num; - src++; - *ptr = src; - return; - } - if (((mode & SIZE) != PSIZE) - /* For Normal mode accept 16 bit and 32 bit pointer registers. */ - && (!Nmode || ((mode & SIZE) != L_32))) - as_bad (_("Wrong size pointer register for architecture.")); - - op->mode = direction | IND | PSIZE; - op->reg = num; - *ptr = src; - - return; - } - else - { - /* must be a symbol */ - - op->mode = ABS | direction; - *ptr = parse_exp (src, op); - return; - } - } - - if (*src == '#') - { - op->mode = IMM; - *ptr = parse_exp (src + 1, op); - return; - } - else if (strncmp (src, "mach", 4) == 0 || - strncmp (src, "macl", 4) == 0 || - strncmp (src, "MACH", 4) == 0 || - strncmp (src, "MACL", 4) == 0) - { - op->reg = TOLOWER (src[3]) == 'l'; - op->mode = MACREG; - *ptr = src + 4; - return; - } - else - { - op->mode = PCREL; - *ptr = parse_exp (src, op); - } -} - -static char * -get_operands (unsigned int noperands, char *op_end, struct h8_op *operand) -{ - char *ptr = op_end; - - switch (noperands) - { - case 0: - break; - - case 1: - ptr++; - get_operand (&ptr, operand + 0, SRC); - if (*ptr == ',') - { - ptr++; - get_operand (&ptr, operand + 1, DST); - } - break; - - case 2: - ptr++; - get_operand (&ptr, operand + 0, SRC); - if (*ptr == ',') - ptr++; - get_operand (&ptr, operand + 1, DST); - break; - - case 3: - ptr++; - get_operand (&ptr, operand + 0, SRC); - if (*ptr == ',') - ptr++; - get_operand (&ptr, operand + 1, DST); - if (*ptr == ',') - ptr++; - get_operand (&ptr, operand + 2, OP3); - break; - - default: - abort (); - } - - return ptr; -} - -/* MOVA has special requirements. Rather than adding twice the amount of - addressing modes, we simply special case it a bit. */ -static void -get_mova_operands (char *op_end, struct h8_op *operand) -{ - char *ptr = op_end; - - if (ptr[1] != '@' || ptr[2] != '(') - goto error; - ptr += 3; - operand[0].mode = 0; - ptr = parse_exp (ptr, &operand[0]); - - if (*ptr !=',') - goto error; - ptr++; - get_operand (&ptr, operand + 1, DST); - - if (*ptr =='.') - { - ptr++; - switch (*ptr++) - { - case 'b': case 'B': - operand[0].mode = (operand[0].mode & ~MODE) | INDEXB; - break; - case 'w': case 'W': - operand[0].mode = (operand[0].mode & ~MODE) | INDEXW; - break; - case 'l': case 'L': - operand[0].mode = (operand[0].mode & ~MODE) | INDEXL; - break; - default: - goto error; - } - } - else if ((operand[1].mode & MODE) == LOWREG) - { - switch (operand[1].mode & SIZE) - { - case L_8: - operand[0].mode = (operand[0].mode & ~MODE) | INDEXB; - break; - case L_16: - operand[0].mode = (operand[0].mode & ~MODE) | INDEXW; - break; - case L_32: - operand[0].mode = (operand[0].mode & ~MODE) | INDEXL; - break; - default: - goto error; - } - } - else - goto error; - - if (*ptr++ != ')' || *ptr++ != ',') - goto error; - get_operand (&ptr, operand + 2, OP3); - /* See if we can use the short form of MOVA. */ - if (((operand[1].mode & MODE) == REG || (operand[1].mode & MODE) == LOWREG) - && (operand[2].mode & MODE) == REG - && (operand[1].reg & 7) == (operand[2].reg & 7)) - { - operand[1].mode = operand[2].mode = 0; - operand[0].reg = operand[2].reg & 7; - } - return; - - error: - as_bad (_("expected valid addressing mode for mova: \"@(disp, ea.sz),ERn\"")); -} - -static void -get_rtsl_operands (char *ptr, struct h8_op *operand) -{ - int mode, len, type = 0; - unsigned int num, num2; - - ptr++; - if (*ptr == '(') - { - ptr++; - type = 1; - } - len = parse_reg (ptr, &mode, &num, SRC); - if (len == 0 || (mode & MODE) != REG) - { - as_bad (_("expected register")); - return; - } - ptr += len; - if (*ptr == '-') - { - len = parse_reg (++ptr, &mode, &num2, SRC); - if (len == 0 || (mode & MODE) != REG) - { - as_bad (_("expected register")); - return; - } - ptr += len; - /* CONST_xxx are used as placeholders in the opcode table. */ - num = num2 - num; - if (num > 3) - { - as_bad (_("invalid register list")); - return; - } - } - else - num2 = num, num = 0; - if (type == 1 && *ptr++ != ')') - { - as_bad (_("expected closing paren")); - return; - } - operand[0].mode = RS32; - operand[1].mode = RD32; - operand[0].reg = num; - operand[1].reg = num2; -} - -/* Passed a pointer to a list of opcodes which use different - addressing modes, return the opcode which matches the opcodes - provided. */ - -static const struct h8_instruction * -get_specific (const struct h8_instruction *instruction, - struct h8_op *operands, int size) -{ - const struct h8_instruction *this_try = instruction; - const struct h8_instruction *found_other = 0, *found_mismatched = 0; - int found = 0; - int this_index = instruction->idx; - int noperands = 0; - - /* There's only one ldm/stm and it's easier to just - get out quick for them. */ - if (OP_KIND (instruction->opcode->how) == O_LDM - || OP_KIND (instruction->opcode->how) == O_STM) - return this_try; - - while (noperands < 3 && operands[noperands].mode != 0) - noperands++; - - while (this_index == instruction->idx && !found) - { - int this_size; - - found = 1; - this_try = instruction++; - this_size = this_try->opcode->how & SN; - - if (this_try->noperands != noperands) - found = 0; - else if (this_try->noperands > 0) - { - int i; - - for (i = 0; i < this_try->noperands && found; i++) - { - op_type op = this_try->opcode->args.nib[i]; - int op_mode = op & MODE; - int op_size = op & SIZE; - int x = operands[i].mode; - int x_mode = x & MODE; - int x_size = x & SIZE; - - if (op_mode == LOWREG && (x_mode == REG || x_mode == LOWREG)) - { - if ((x_size == L_8 && (operands[i].reg & 8) == 0) - || (x_size == L_16 && (operands[i].reg & 8) == 8)) - as_warn (_("can't use high part of register in operand %d"), i); - - if (x_size != op_size) - found = 0; - } - else if (op_mode == REG) - { - if (x_mode == LOWREG) - x_mode = REG; - if (x_mode != REG) - found = 0; - - if (x_size == L_P) - x_size = (Hmode ? L_32 : L_16); - if (op_size == L_P) - op_size = (Hmode ? L_32 : L_16); - - /* The size of the reg is v important. */ - if (op_size != x_size) - found = 0; - } - else if (op_mode & CTRL) /* control register */ - { - if (!(x_mode & CTRL)) - found = 0; - - switch (x_mode) - { - case CCR: - if (op_mode != CCR && - op_mode != CCR_EXR && - op_mode != CC_EX_VB_SB) - found = 0; - break; - case EXR: - if (op_mode != EXR && - op_mode != CCR_EXR && - op_mode != CC_EX_VB_SB) - found = 0; - break; - case MACH: - if (op_mode != MACH && - op_mode != MACREG) - found = 0; - break; - case MACL: - if (op_mode != MACL && - op_mode != MACREG) - found = 0; - break; - case VBR: - if (op_mode != VBR && - op_mode != VBR_SBR && - op_mode != CC_EX_VB_SB) - found = 0; - break; - case SBR: - if (op_mode != SBR && - op_mode != VBR_SBR && - op_mode != CC_EX_VB_SB) - found = 0; - break; - } - } - else if ((op & ABSJMP) && (x_mode == ABS || x_mode == PCREL)) - { - operands[i].mode &= ~MODE; - operands[i].mode |= ABSJMP; - /* But it may not be 24 bits long. */ - if (x_mode == ABS && !Hmode) - { - operands[i].mode &= ~SIZE; - operands[i].mode |= L_16; - } - if ((operands[i].mode & SIZE) == L_32 - && (op_mode & SIZE) != L_32) - found = 0; - } - else if (x_mode == IMM && op_mode != IMM) - { - offsetT num = operands[i].exp.X_add_number; - if (op_mode == KBIT || op_mode == DBIT) - /* This is ok if the immediate value is sensible. */; - else if (op_mode == CONST_2) - found = num == 2; - else if (op_mode == CONST_4) - found = num == 4; - else if (op_mode == CONST_8) - found = num == 8; - else if (op_mode == CONST_16) - found = num == 16; - else - found = 0; - } - else if (op_mode == PCREL && op_mode == x_mode) - { - /* movsd, bsr/bc and bsr/bs only come in PCREL16 flavour: - If x_size is L_8, promote it. */ - if (OP_KIND (this_try->opcode->how) == O_MOVSD - || OP_KIND (this_try->opcode->how) == O_BSRBC - || OP_KIND (this_try->opcode->how) == O_BSRBS) - if (x_size == L_8) - x_size = L_16; - - /* The size of the displacement is important. */ - if (op_size != x_size) - found = 0; - } - else if ((op_mode == DISP || op_mode == IMM || op_mode == ABS - || op_mode == INDEXB || op_mode == INDEXW - || op_mode == INDEXL) - && op_mode == x_mode) - { - /* Promote a L_24 to L_32 if it makes us match. */ - if (x_size == L_24 && op_size == L_32) - { - x &= ~SIZE; - x |= x_size = L_32; - } - - if (((x_size == L_16 && op_size == L_16U) - || (x_size == L_8 && op_size == L_8U) - || (x_size == L_3 && op_size == L_3NZ)) - /* We're deliberately more permissive for ABS modes. */ - && (op_mode == ABS - || constant_fits_size_p (operands + i, op_size, - op & NO_SYMBOLS))) - x_size = op_size; - - if (x_size != 0 && op_size != x_size) - found = 0; - else if (x_size == 0 - && ! constant_fits_size_p (operands + i, op_size, - op & NO_SYMBOLS)) - found = 0; - } - else if (op_mode != x_mode) - { - found = 0; - } - } - } - if (found) - { - if ((this_try->opcode->available == AV_H8SX && ! SXmode) - || (this_try->opcode->available == AV_H8S && ! Smode) - || (this_try->opcode->available == AV_H8H && ! Hmode)) - found = 0, found_other = this_try; - else if (this_size != size && (this_size != SN && size != SN)) - found_mismatched = this_try, found = 0; - - } - } - if (found) - return this_try; - if (found_other) - { - as_warn (_("Opcode `%s' with these operand types not available in %s mode"), - found_other->opcode->name, - (! Hmode && ! Smode ? "H8/300" - : SXmode ? "H8sx" - : Smode ? "H8/300S" - : "H8/300H")); - } - else if (found_mismatched) - { - as_warn (_("mismatch between opcode size and operand size")); - return found_mismatched; - } - return 0; -} - -static void -check_operand (struct h8_op *operand, unsigned int width, char *string) -{ - if (operand->exp.X_add_symbol == 0 - && operand->exp.X_op_symbol == 0) - { - /* No symbol involved, let's look at offset, it's dangerous if - any of the high bits are not 0 or ff's, find out by oring or - anding with the width and seeing if the answer is 0 or all - fs. */ - - if (! constant_fits_width_p (operand, width)) - { - if (width == 255 - && (operand->exp.X_add_number & 0xff00) == 0xff00) - { - /* Just ignore this one - which happens when trying to - fit a 16 bit address truncated into an 8 bit address - of something like bset. */ - } - else if (strcmp (string, "@") == 0 - && width == 0xffff - && (operand->exp.X_add_number & 0xff8000) == 0xff8000) - { - /* Just ignore this one - which happens when trying to - fit a 24 bit address truncated into a 16 bit address - of something like mov.w. */ - } - else - { - as_warn (_("operand %s0x%lx out of range."), string, - (unsigned long) operand->exp.X_add_number); - } - } - } -} - -/* RELAXMODE has one of 3 values: - - 0 Output a "normal" reloc, no relaxing possible for this insn/reloc - - 1 Output a relaxable 24bit absolute mov.w address relocation - (may relax into a 16bit absolute address). - - 2 Output a relaxable 16/24 absolute mov.b address relocation - (may relax into an 8bit absolute address). */ - -static void -do_a_fix_imm (int offset, int nibble, struct h8_op *operand, int relaxmode) -{ - int idx; - int size; - int where; - char *bytes = frag_now->fr_literal + offset; - - char *t = ((operand->mode & MODE) == IMM) ? "#" : "@"; - - if (operand->exp.X_add_symbol == 0) - { - switch (operand->mode & SIZE) - { - case L_2: - check_operand (operand, 0x3, t); - bytes[0] |= (operand->exp.X_add_number & 3) << (nibble ? 0 : 4); - break; - case L_3: - case L_3NZ: - check_operand (operand, 0x7, t); - bytes[0] |= (operand->exp.X_add_number & 7) << (nibble ? 0 : 4); - break; - case L_4: - check_operand (operand, 0xF, t); - bytes[0] |= (operand->exp.X_add_number & 15) << (nibble ? 0 : 4); - break; - case L_5: - check_operand (operand, 0x1F, t); - bytes[0] |= operand->exp.X_add_number & 31; - break; - case L_8: - case L_8U: - check_operand (operand, 0xff, t); - bytes[0] |= operand->exp.X_add_number; - break; - case L_16: - case L_16U: - check_operand (operand, 0xffff, t); - bytes[0] |= operand->exp.X_add_number >> 8; - bytes[1] |= operand->exp.X_add_number >> 0; - break; - case L_24: - check_operand (operand, 0xffffff, t); - bytes[0] |= operand->exp.X_add_number >> 16; - bytes[1] |= operand->exp.X_add_number >> 8; - bytes[2] |= operand->exp.X_add_number >> 0; - break; - - case L_32: - /* This should be done with bfd. */ - bytes[0] |= operand->exp.X_add_number >> 24; - bytes[1] |= operand->exp.X_add_number >> 16; - bytes[2] |= operand->exp.X_add_number >> 8; - bytes[3] |= operand->exp.X_add_number >> 0; - if (relaxmode != 0) - { - idx = (relaxmode == 2) ? R_MOV24B1 : R_MOVL1; - fix_new_exp (frag_now, offset, 4, &operand->exp, 0, idx); - } - break; - } - } - else - { - switch (operand->mode & SIZE) - { - case L_24: - case L_32: - size = 4; - where = (operand->mode & SIZE) == L_24 ? -1 : 0; - if (relaxmode == 2) - idx = R_MOV24B1; - else if (relaxmode == 1) - idx = R_MOVL1; - else - idx = R_RELLONG; - break; - default: - as_bad (_("Can't work out size of operand.\n")); - case L_16: - case L_16U: - size = 2; - where = 0; - if (relaxmode == 2) - idx = R_MOV16B1; - else - idx = R_RELWORD; - operand->exp.X_add_number = - ((operand->exp.X_add_number & 0xffff) ^ 0x8000) - 0x8000; - operand->exp.X_add_number |= (bytes[0] << 8) | bytes[1]; - break; - case L_8: - size = 1; - where = 0; - idx = R_RELBYTE; - operand->exp.X_add_number = - ((operand->exp.X_add_number & 0xff) ^ 0x80) - 0x80; - operand->exp.X_add_number |= bytes[0]; - } - - fix_new_exp (frag_now, - offset + where, - size, - &operand->exp, - 0, - idx); - } -} - -/* Now we know what sort of opcodes it is, let's build the bytes. */ - -static void -build_bytes (const struct h8_instruction *this_try, struct h8_op *operand) -{ - int i; - char *output = frag_more (this_try->length); - op_type *nibble_ptr = this_try->opcode->data.nib; - op_type c; - unsigned int nibble_count = 0; - int op_at[3]; - int nib = 0; - int movb = 0; - char asnibbles[100]; - char *p = asnibbles; - int high, low; - - if (!Hmode && this_try->opcode->available != AV_H8) - as_warn (_("Opcode `%s' with these operand types not available in H8/300 mode"), - this_try->opcode->name); - else if (!Smode - && this_try->opcode->available != AV_H8 - && this_try->opcode->available != AV_H8H) - as_warn (_("Opcode `%s' with these operand types not available in H8/300H mode"), - this_try->opcode->name); - else if (!SXmode - && this_try->opcode->available != AV_H8 - && this_try->opcode->available != AV_H8H - && this_try->opcode->available != AV_H8S) - as_warn (_("Opcode `%s' with these operand types not available in H8/300S mode"), - this_try->opcode->name); - - while (*nibble_ptr != (op_type) E) - { - int d; - - nib = 0; - c = *nibble_ptr++; - - d = (c & OP3) == OP3 ? 2 : (c & DST) == DST ? 1 : 0; - - if (c < 16) - nib = c; - else - { - int c2 = c & MODE; - - if (c2 == REG || c2 == LOWREG - || c2 == IND || c2 == PREINC || c2 == PREDEC - || c2 == POSTINC || c2 == POSTDEC) - { - nib = operand[d].reg; - if (c2 == LOWREG) - nib &= 7; - } - - else if (c & CTRL) /* Control reg operand. */ - nib = operand[d].reg; - - else if ((c & DISPREG) == (DISPREG)) - { - nib = operand[d].reg; - } - else if (c2 == ABS) - { - operand[d].mode = c; - op_at[d] = nibble_count; - nib = 0; - } - else if (c2 == IMM || c2 == PCREL || c2 == ABS - || (c & ABSJMP) || c2 == DISP) - { - operand[d].mode = c; - op_at[d] = nibble_count; - nib = 0; - } - else if ((c & IGNORE) || (c & DATA)) - nib = 0; - - else if (c2 == DBIT) - { - switch (operand[0].exp.X_add_number) - { - case 1: - nib = c; - break; - case 2: - nib = 0x8 | c; - break; - default: - as_bad (_("Need #1 or #2 here")); - } - } - else if (c2 == KBIT) - { - switch (operand[0].exp.X_add_number) - { - case 1: - nib = 0; - break; - case 2: - nib = 8; - break; - case 4: - if (!Hmode) - as_warn (_("#4 not valid on H8/300.")); - nib = 9; - break; - - default: - as_bad (_("Need #1 or #2 here")); - break; - } - /* Stop it making a fix. */ - operand[0].mode = 0; - } - - if (c & MEMRELAX) - operand[d].mode |= MEMRELAX; - - if (c & B31) - nib |= 0x8; - - if (c & B21) - nib |= 0x4; - - if (c & B11) - nib |= 0x2; - - if (c & B01) - nib |= 0x1; - - if (c2 == MACREG) - { - if (operand[0].mode == MACREG) - /* stmac has mac[hl] as the first operand. */ - nib = 2 + operand[0].reg; - else - /* ldmac has mac[hl] as the second operand. */ - nib = 2 + operand[1].reg; - } - } - nibble_count++; - - *p++ = nib; - } - - /* Disgusting. Why, oh why didn't someone ask us for advice - on the assembler format. */ - if (OP_KIND (this_try->opcode->how) == O_LDM) - { - high = (operand[1].reg >> 8) & 0xf; - low = (operand[1].reg) & 0xf; - asnibbles[2] = high - low; - asnibbles[7] = high; - } - else if (OP_KIND (this_try->opcode->how) == O_STM) - { - high = (operand[0].reg >> 8) & 0xf; - low = (operand[0].reg) & 0xf; - asnibbles[2] = high - low; - asnibbles[7] = low; - } - - for (i = 0; i < this_try->length; i++) - output[i] = (asnibbles[i * 2] << 4) | asnibbles[i * 2 + 1]; - - /* Note if this is a movb or a bit manipulation instruction - there is a special relaxation which only applies. */ - if ( this_try->opcode->how == O (O_MOV, SB) - || this_try->opcode->how == O (O_BCLR, SB) - || this_try->opcode->how == O (O_BAND, SB) - || this_try->opcode->how == O (O_BIAND, SB) - || this_try->opcode->how == O (O_BILD, SB) - || this_try->opcode->how == O (O_BIOR, SB) - || this_try->opcode->how == O (O_BIST, SB) - || this_try->opcode->how == O (O_BIXOR, SB) - || this_try->opcode->how == O (O_BLD, SB) - || this_try->opcode->how == O (O_BNOT, SB) - || this_try->opcode->how == O (O_BOR, SB) - || this_try->opcode->how == O (O_BSET, SB) - || this_try->opcode->how == O (O_BST, SB) - || this_try->opcode->how == O (O_BTST, SB) - || this_try->opcode->how == O (O_BXOR, SB)) - movb = 1; - - /* Output any fixes. */ - for (i = 0; i < this_try->noperands; i++) - { - int x = operand[i].mode; - int x_mode = x & MODE; - - if (x_mode == IMM || x_mode == DISP) - do_a_fix_imm (output - frag_now->fr_literal + op_at[i] / 2, - op_at[i] & 1, operand + i, (x & MEMRELAX) != 0); - - else if (x_mode == ABS) - do_a_fix_imm (output - frag_now->fr_literal + op_at[i] / 2, - op_at[i] & 1, operand + i, - (x & MEMRELAX) ? movb + 1 : 0); - - else if (x_mode == PCREL) - { - int size16 = (x & SIZE) == L_16; - int size = size16 ? 2 : 1; - int type = size16 ? R_PCRWORD : R_PCRBYTE; - fixS *fixP; - - check_operand (operand + i, size16 ? 0x7fff : 0x7f, "@"); - - if (operand[i].exp.X_add_number & 1) - as_warn (_("branch operand has odd offset (%lx)\n"), - (unsigned long) operand->exp.X_add_number); -#ifndef OBJ_ELF - /* The COFF port has always been off by one, changing it - now would be an incompatible change, so we leave it as-is. - - We don't want to do this for ELF as we want to be - compatible with the proposed ELF format from Hitachi. */ - operand[i].exp.X_add_number -= 1; -#endif - if (size16) - { - operand[i].exp.X_add_number = - ((operand[i].exp.X_add_number & 0xffff) ^ 0x8000) - 0x8000; - } - else - { - operand[i].exp.X_add_number = - ((operand[i].exp.X_add_number & 0xff) ^ 0x80) - 0x80; - } - - /* For BRA/S. */ - if (! size16) - operand[i].exp.X_add_number |= output[op_at[i] / 2]; - - fixP = fix_new_exp (frag_now, - output - frag_now->fr_literal + op_at[i] / 2, - size, - &operand[i].exp, - 1, - type); - fixP->fx_signed = 1; - } - else if (x_mode == MEMIND) - { - check_operand (operand + i, 0xff, "@@"); - fix_new_exp (frag_now, - output - frag_now->fr_literal + 1, - 1, - &operand[i].exp, - 0, - R_MEM_INDIRECT); - } - else if (x_mode == VECIND) - { - check_operand (operand + i, 0x7f, "@@"); - /* FIXME: approximating the effect of "B31" here... - This is very hackish, and ought to be done a better way. */ - operand[i].exp.X_add_number |= 0x80; - fix_new_exp (frag_now, - output - frag_now->fr_literal + 1, - 1, - &operand[i].exp, - 0, - R_MEM_INDIRECT); - } - else if (x & ABSJMP) - { - int where = 0; - bfd_reloc_code_real_type reloc_type = R_JMPL1; - -#ifdef OBJ_ELF - /* To be compatible with the proposed H8 ELF format, we - want the relocation's offset to point to the first byte - that will be modified, not to the start of the instruction. */ - - if ((operand->mode & SIZE) == L_32) - { - where = 2; - reloc_type = R_RELLONG; - } - else - where = 1; -#endif - - /* This jmp may be a jump or a branch. */ - - check_operand (operand + i, - SXmode ? 0xffffffff : Hmode ? 0xffffff : 0xffff, - "@"); - - if (operand[i].exp.X_add_number & 1) - as_warn (_("branch operand has odd offset (%lx)\n"), - (unsigned long) operand->exp.X_add_number); - - if (!Hmode) - operand[i].exp.X_add_number = - ((operand[i].exp.X_add_number & 0xffff) ^ 0x8000) - 0x8000; - fix_new_exp (frag_now, - output - frag_now->fr_literal + where, - 4, - &operand[i].exp, - 0, - reloc_type); - } - } -} - -/* Try to give an intelligent error message for common and simple to - detect errors. */ - -static void -clever_message (const struct h8_instruction *instruction, - struct h8_op *operand) -{ - /* Find out if there was more than one possible opcode. */ - - if ((instruction + 1)->idx != instruction->idx) - { - int argn; - - /* Only one opcode of this flavour, try to guess which operand - didn't match. */ - for (argn = 0; argn < instruction->noperands; argn++) - { - switch (instruction->opcode->args.nib[argn]) - { - case RD16: - if (operand[argn].mode != RD16) - { - as_bad (_("destination operand must be 16 bit register")); - return; - - } - break; - - case RS8: - if (operand[argn].mode != RS8) - { - as_bad (_("source operand must be 8 bit register")); - return; - } - break; - - case ABS16DST: - if (operand[argn].mode != ABS16DST) - { - as_bad (_("destination operand must be 16bit absolute address")); - return; - } - break; - case RD8: - if (operand[argn].mode != RD8) - { - as_bad (_("destination operand must be 8 bit register")); - return; - } - break; - - case ABS16SRC: - if (operand[argn].mode != ABS16SRC) - { - as_bad (_("source operand must be 16bit absolute address")); - return; - } - break; - - } - } - } - as_bad (_("invalid operands")); -} - - -/* If OPERAND is part of an address, adjust its size and value given - that it addresses SIZE bytes. - - This function decides how big non-immediate constants are when no - size was explicitly given. It also scales down the assembly-level - displacement in an @(d:2,ERn) operand. */ - -static void -fix_operand_size (struct h8_op *operand, int size) -{ - if (SXmode && (operand->mode & MODE) == DISP) - { - /* If the user didn't specify an operand width, see if we - can use @(d:2,ERn). */ - if ((operand->mode & SIZE) == 0 - && operand->exp.X_add_symbol == 0 - && operand->exp.X_op_symbol == 0 - && (operand->exp.X_add_number == size - || operand->exp.X_add_number == size * 2 - || operand->exp.X_add_number == size * 3)) - operand->mode |= L_2; - - /* Scale down the displacement in an @(d:2,ERn) operand. - X_add_number then contains the desired field value. */ - if ((operand->mode & SIZE) == L_2) - { - if (operand->exp.X_add_number % size != 0) - as_warn (_("operand/size mis-match")); - operand->exp.X_add_number /= size; - } - } - - if ((operand->mode & SIZE) == 0) - switch (operand->mode & MODE) - { - case DISP: - case INDEXB: - case INDEXW: - case INDEXL: - case ABS: - /* Pick a 24-bit address unless we know that a 16-bit address - is safe. get_specific() will relax L_24 into L_32 where - necessary. */ - if (Hmode - && !Nmode - && (operand->exp.X_add_number < -32768 - || operand->exp.X_add_number > 32767 - || operand->exp.X_add_symbol != 0 - || operand->exp.X_op_symbol != 0)) - operand->mode |= L_24; - else - operand->mode |= L_16; - break; - - case PCREL: - /* This condition is long standing, though somewhat suspect. */ - if (operand->exp.X_add_number > -128 - && operand->exp.X_add_number < 127) - operand->mode |= L_8; - else - operand->mode |= L_16; - break; - } -} - - -/* This is the guts of the machine-dependent assembler. STR points to - a machine dependent instruction. This function is supposed to emit - the frags/bytes it assembles. */ - -void -md_assemble (char *str) -{ - char *op_start; - char *op_end; - struct h8_op operand[3]; - const struct h8_instruction *instruction; - const struct h8_instruction *prev_instruction; - - char *dot = 0; - char *slash = 0; - char c; - int size, i; - - /* Drop leading whitespace. */ - while (*str == ' ') - str++; - - /* Find the op code end. */ - for (op_start = op_end = str; - *op_end != 0 && *op_end != ' '; - op_end++) - { - if (*op_end == '.') - { - dot = op_end + 1; - *op_end = 0; - op_end += 2; - break; - } - else if (*op_end == '/' && ! slash) - slash = op_end; - } - - if (op_end == op_start) - { - as_bad (_("can't find opcode ")); - } - c = *op_end; - - *op_end = 0; - - /* The assembler stops scanning the opcode at slashes, so it fails - to make characters following them lower case. Fix them. */ - if (slash) - while (*++slash) - *slash = TOLOWER (*slash); - - instruction = (const struct h8_instruction *) - hash_find (opcode_hash_control, op_start); - - if (instruction == NULL) - { - as_bad (_("unknown opcode")); - return; - } - - /* We used to set input_line_pointer to the result of get_operands, - but that is wrong. Our caller assumes we don't change it. */ - - operand[0].mode = 0; - operand[1].mode = 0; - operand[2].mode = 0; - - if (OP_KIND (instruction->opcode->how) == O_MOVAB - || OP_KIND (instruction->opcode->how) == O_MOVAW - || OP_KIND (instruction->opcode->how) == O_MOVAL) - get_mova_operands (op_end, operand); - else if (OP_KIND (instruction->opcode->how) == O_RTEL - || OP_KIND (instruction->opcode->how) == O_RTSL) - get_rtsl_operands (op_end, operand); - else - get_operands (instruction->noperands, op_end, operand); - - *op_end = c; - prev_instruction = instruction; - - /* Now we have operands from instruction. - Let's check them out for ldm and stm. */ - if (OP_KIND (instruction->opcode->how) == O_LDM) - { - /* The first operand must be @er7+, and the - second operand must be a register pair. */ - if ((operand[0].mode != RSINC) - || (operand[0].reg != 7) - || ((operand[1].reg & 0x80000000) == 0)) - as_bad (_("invalid operand in ldm")); - } - else if (OP_KIND (instruction->opcode->how) == O_STM) - { - /* The first operand must be a register pair, - and the second operand must be @-er7. */ - if (((operand[0].reg & 0x80000000) == 0) - || (operand[1].mode != RDDEC) - || (operand[1].reg != 7)) - as_bad (_("invalid operand in stm")); - } - - size = SN; - if (dot) - { - switch (TOLOWER (*dot)) - { - case 'b': - size = SB; - break; - - case 'w': - size = SW; - break; - - case 'l': - size = SL; - break; - } - } - if (OP_KIND (instruction->opcode->how) == O_MOVAB || - OP_KIND (instruction->opcode->how) == O_MOVAW || - OP_KIND (instruction->opcode->how) == O_MOVAL) - { - switch (operand[0].mode & MODE) - { - case INDEXB: - default: - fix_operand_size (&operand[1], 1); - break; - case INDEXW: - fix_operand_size (&operand[1], 2); - break; - case INDEXL: - fix_operand_size (&operand[1], 4); - break; - } - } - else - { - for (i = 0; i < 3 && operand[i].mode != 0; i++) - switch (size) - { - case SN: - case SB: - default: - fix_operand_size (&operand[i], 1); - break; - case SW: - fix_operand_size (&operand[i], 2); - break; - case SL: - fix_operand_size (&operand[i], 4); - break; - } - } - - instruction = get_specific (instruction, operand, size); - - if (instruction == 0) - { - /* Couldn't find an opcode which matched the operands. */ - char *where = frag_more (2); - - where[0] = 0x0; - where[1] = 0x0; - clever_message (prev_instruction, operand); - - return; - } - - build_bytes (instruction, operand); - - dwarf2_emit_insn (instruction->length); -} - -symbolS * -md_undefined_symbol (char *name ATTRIBUTE_UNUSED) -{ - return 0; -} - -/* Various routines to kill one day */ -/* Equal to MAX_PRECISION in atof-ieee.c */ -#define MAX_LITTLENUMS 6 - -/* Turn a string in input_line_pointer into a floating point constant - of type TYPE, and store the appropriate bytes in *LITP. The number - of LITTLENUMS emitted is stored in *SIZEP. An error message is - returned, or NULL on OK. */ - -char * -md_atof (int type, char *litP, int *sizeP) -{ - int prec; - LITTLENUM_TYPE words[MAX_LITTLENUMS]; - LITTLENUM_TYPE *wordP; - char *t; - - switch (type) - { - case 'f': - case 'F': - case 's': - case 'S': - prec = 2; - break; - - case 'd': - case 'D': - case 'r': - case 'R': - prec = 4; - break; - - case 'x': - case 'X': - prec = 6; - break; - - case 'p': - case 'P': - prec = 6; - break; - - default: - *sizeP = 0; - return _("Bad call to MD_ATOF()"); - } - t = atof_ieee (input_line_pointer, type, words); - if (t) - input_line_pointer = t; - - *sizeP = prec * sizeof (LITTLENUM_TYPE); - for (wordP = words; prec--;) - { - md_number_to_chars (litP, (long) (*wordP++), sizeof (LITTLENUM_TYPE)); - litP += sizeof (LITTLENUM_TYPE); - } - return 0; -} - -const char *md_shortopts = ""; -struct option md_longopts[] = { - {NULL, no_argument, NULL, 0} -}; - -size_t md_longopts_size = sizeof (md_longopts); - -int -md_parse_option (int c ATTRIBUTE_UNUSED, char *arg ATTRIBUTE_UNUSED) -{ - return 0; -} - -void -md_show_usage (FILE *stream ATTRIBUTE_UNUSED) -{ -} - -void tc_aout_fix_to_chars (void); - -void -tc_aout_fix_to_chars (void) -{ - printf (_("call to tc_aout_fix_to_chars \n")); - abort (); -} - -void -md_convert_frag (bfd *headers ATTRIBUTE_UNUSED, - segT seg ATTRIBUTE_UNUSED, - fragS *fragP ATTRIBUTE_UNUSED) -{ - printf (_("call to md_convert_frag \n")); - abort (); -} - -valueT -md_section_align (segT segment, valueT size) -{ - int align = bfd_get_section_alignment (stdoutput, segment); - return ((size + (1 << align) - 1) & (-1 << align)); -} - -void -md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) -{ - char *buf = fixP->fx_where + fixP->fx_frag->fr_literal; - long val = *valP; - - switch (fixP->fx_size) - { - case 1: - *buf++ = val; - break; - case 2: - *buf++ = (val >> 8); - *buf++ = val; - break; - case 4: - *buf++ = (val >> 24); - *buf++ = (val >> 16); - *buf++ = (val >> 8); - *buf++ = val; - break; - default: - abort (); - } - - if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0) - fixP->fx_done = 1; -} - -int -md_estimate_size_before_relax (register fragS *fragP ATTRIBUTE_UNUSED, - register segT segment_type ATTRIBUTE_UNUSED) -{ - printf (_("call tomd_estimate_size_before_relax \n")); - abort (); -} - -/* Put number into target byte order. */ -void -md_number_to_chars (char *ptr, valueT use, int nbytes) -{ - number_to_chars_bigendian (ptr, use, nbytes); -} - -long -md_pcrel_from (fixS *fixP ATTRIBUTE_UNUSED) -{ - abort (); -} - -arelent * -tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp) -{ - arelent *rel; - bfd_reloc_code_real_type r_type; - - if (fixp->fx_addsy && fixp->fx_subsy) - { - if ((S_GET_SEGMENT (fixp->fx_addsy) != S_GET_SEGMENT (fixp->fx_subsy)) - || S_GET_SEGMENT (fixp->fx_addsy) == undefined_section) - { - as_bad_where (fixp->fx_file, fixp->fx_line, - "Difference of symbols in different sections is not supported"); - return NULL; - } - } - - rel = (arelent *) xmalloc (sizeof (arelent)); - rel->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); - *rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); - rel->address = fixp->fx_frag->fr_address + fixp->fx_where; - rel->addend = fixp->fx_offset; - - r_type = fixp->fx_r_type; - -#define DEBUG 0 -#if DEBUG - fprintf (stderr, "%s\n", bfd_get_reloc_code_name (r_type)); - fflush(stderr); -#endif - rel->howto = bfd_reloc_type_lookup (stdoutput, r_type); - if (rel->howto == NULL) - { - as_bad_where (fixp->fx_file, fixp->fx_line, - _("Cannot represent relocation type %s"), - bfd_get_reloc_code_name (r_type)); - return NULL; - } - - return rel; -} |