diff options
author | Niklas Hallqvist <niklas@cvs.openbsd.org> | 1996-01-08 11:10:27 +0000 |
---|---|---|
committer | Niklas Hallqvist <niklas@cvs.openbsd.org> | 1996-01-08 11:10:27 +0000 |
commit | 8b46c09925a80623c289e346c12921bc09fd1678 (patch) | |
tree | 01507d0da339cc7e5e6f5d16dfa625f94910b091 /gnu/usr.bin/binutils/gas/config/tc-h8300.c | |
parent | 5d56227f9458a53138642c1b4488b4a30f85f334 (diff) |
Initial GNU binutils 2.6 import
Diffstat (limited to 'gnu/usr.bin/binutils/gas/config/tc-h8300.c')
-rw-r--r-- | gnu/usr.bin/binutils/gas/config/tc-h8300.c | 1458 |
1 files changed, 1458 insertions, 0 deletions
diff --git a/gnu/usr.bin/binutils/gas/config/tc-h8300.c b/gnu/usr.bin/binutils/gas/config/tc-h8300.c new file mode 100644 index 00000000000..cab657b00e3 --- /dev/null +++ b/gnu/usr.bin/binutils/gas/config/tc-h8300.c @@ -0,0 +1,1458 @@ +/* tc-h8300.c -- Assemble code for the Hitachi H8/300 + Copyright (C) 1991, 1992 Free Software Foundation. + + 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +/* + Written By Steve Chamberlain + sac@cygnus.com + */ + +#include <stdio.h> +#include "as.h" +#include "bfd.h" +#define DEFINE_TABLE +#define h8_opcodes ops +#include "opcode/h8300.h" +#include <ctype.h> + +const char comment_chars[] = +{';', 0}; +const char line_separator_chars[] = +{0}; +const char line_comment_chars[] = "#"; + +/* 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 + */ + +void cons (); + +int Hmode; +#define PSIZE (Hmode ? L_32 : L_16) +#define DMODE (L_16) +#define DSYMMODE (Hmode ? L_24 : L_16) +int bsize = L_8; /* default branch displacement */ + + +void +h8300hmode () +{ + Hmode = 1; +} + + +void +sbranch (size) + int size; +{ + bsize = size; +} + +static void pint () +{ + cons (Hmode ? 4 : 2); +} + +const pseudo_typeS md_pseudo_table[] = +{ + + {"h8300h", h8300hmode, 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 int md_reloc_size; + +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 () +{ + struct h8_opcode *opcode; + char prev_buffer[100]; + int idx = 0; + + opcode_hash_control = hash_new (); + prev_buffer[0] = 0; + + for (opcode = h8_opcodes; opcode->name; opcode++) + { + /* Strip off any . part when inserting the opcode and only enter + unique codes into the hash table + */ + char *src = opcode->name; + unsigned int len = strlen (src); + char *dst = malloc (len + 1); + char *buffer = dst; + + opcode->size = 0; + while (*src) + { + if (*src == '.') + { + src++; + opcode->size = *src; + break; + } + *dst++ = *src++; + } + *dst++ = 0; + if (strcmp (buffer, prev_buffer)) + { + hash_insert (opcode_hash_control, buffer, (char *) opcode); + strcpy (prev_buffer, buffer); + idx++; + } + opcode->idx = idx; + + + /* Find the number of operands */ + opcode->noperands = 0; + while (opcode->args.nib[opcode->noperands] != E) + opcode->noperands++; + /* Find the length of the opcode in bytes */ + opcode->length = 0; + while (opcode->data.nib[opcode->length * 2] != E) + opcode->length++; + } + + linkrelax = 1; +} + + +struct h8_exp +{ + char *e_beg; + char *e_end; + expressionS e_exp; +}; +int dispreg; +int opsize; /* Set when a register size is seen */ + + +struct h8_op +{ + op_type mode; + unsigned reg; + expressionS exp; +}; + +/* + parse operands + WREG r0,r1,r2,r3,r4,r5,r6,r7,fp,sp + r0l,r0h,..r7l,r7h + @WREG + @WREG+ + @-WREG + #const + + */ + +/* try and parse a reg name, returns number of chars consumed */ +int +parse_reg (src, mode, reg, direction) + char *src; + op_type *mode; + unsigned int *reg; + int direction; + +{ + if (src[0] == 's' && src[1] == 'p') + { + *mode = PSIZE | REG | direction; + *reg = 7; + return 2; + } + if (src[0] == 'c' && src[1] == 'c' && src[2] == 'r') + { + *mode = CCR; + *reg = 0; + return 3; + } + if (src[0] == 'f' && src[1] == 'p') + { + *mode = PSIZE | REG | direction; + *reg = 6; + return 2; + } + if (src[0] == 'e' + && src[1] == 'r' + && src[2] >= '0' && src[2] <= '7') + { + *mode = L_32 | REG | direction; + *reg = src[2] - '0'; + if (!Hmode) + as_warn ("Reg only legal for H8/300-H"); + + return 3; + } + if (src[0] == 'e' + && src[1] >= '0' && src[1] <= '7') + { + *mode = L_16 | REG | direction; + *reg = src[1] - '0' + 8; + if (!Hmode) + as_warn ("Reg only legal for H8/300-H"); + return 2; + } + + if (src[0] == 'r') + { + if (src[1] >= '0' && src[1] <= '7') + { + if (src[2] == 'l') + { + *mode = L_8 | REG | direction; + *reg = (src[1] - '0') + 8; + return 3; + } + if (src[2] == 'h') + { + *mode = L_8 | REG | direction; + *reg = (src[1] - '0'); + return 3; + } + *mode = L_16 | REG | direction; + *reg = (src[1] - '0'); + return 2; + } + } + return 0; +} + +char * +parse_exp (s, op) + char *s; + expressionS * op; +{ + char *save = input_line_pointer; + char *new; + + input_line_pointer = s; + expression (op); + if (op->X_op == O_absent) + as_bad ("missing operand"); + new = input_line_pointer; + input_line_pointer = save; + return new; +} + +static char * +skip_colonthing (ptr, exp, mode) + char *ptr; + expressionS *exp; + int *mode; +{ + if (*ptr == ':') + { + ptr++; + *mode &= ~SIZE; + if (*ptr == '8') + { + ptr++; + /* ff fill any 8 bit quantity */ + /* exp->X_add_number -= 0x100;*/ + *mode |= L_8; + } + else + { + if (*ptr == '2') + { + *mode |= L_24; + } + else if (*ptr == '1') + { + *mode |= L_16; + } + while (isdigit (*ptr)) + ptr++; + } + } + return ptr; +} + +/* 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 + + */ + +char * +colonmod24 (op, src) + struct h8_op *op; + char *src; + +{ + int mode = 0; + src = skip_colonthing (src, &op->exp, &mode); + + if (!mode) + { + /* Choose a default mode */ + if (op->exp.X_add_number < -32768 + || op->exp.X_add_number > 32767) + { + if (Hmode) + mode = L_24; + else + mode = L_16; + } + else if (op->exp.X_add_symbol + || op->exp.X_op_symbol) + mode = DSYMMODE; + else + mode = DMODE; + } + op->mode |= mode; + return src; + +} + + +static void +get_operand (ptr, op, dst, direction) + char **ptr; + struct h8_op *op; + unsigned int dst; + int direction; +{ + char *src = *ptr; + op_type mode; + unsigned int num; + unsigned int len; + + op->mode = E; + + len = parse_reg (src, &op->mode, &op->reg, direction); + if (len) + { + *ptr = src + len; + return; + } + + if (*src == '@') + { + src++; + if (*src == '@') + { + src++; + src = parse_exp (src, &op->exp); + + src = skip_colonthing (src, &op->exp, &op->mode); + + *ptr = src; + + op->mode = MEMIND; + return; + + } + + + if (*src == '-') + { + src++; + len = parse_reg (src, &mode, &num, direction); + if (len == 0) + { + /* Oops, not a reg after all, must be ordinary exp */ + src--; + /* must be a symbol */ + op->mode = ABS | PSIZE | direction; + *ptr = skip_colonthing (parse_exp (src, &op->exp), + &op->exp, &op->mode); + + return; + + + } + + + if ((mode & SIZE) != PSIZE) + as_bad ("Wrong size pointer register for architecture."); + op->mode = RDDEC; + op->reg = num; + *ptr = src + len; + return; + } + if (*src == '(') + { + /* Disp */ + src++; + + /* Start off assuming a 16 bit offset */ + + + src = parse_exp (src, &op->exp); + + src = colonmod24 (op, src); + + if (*src == ')') + { + src++; + op->mode |= ABS | direction; + *ptr = src; + return; + } + + if (*src != ',') + { + as_bad ("expected @(exp, reg16)"); + return; + + } + src++; + + len = parse_reg (src, &mode, &op->reg, direction); + if (len == 0 || !(mode & REG)) + { + as_bad ("expected @(exp, reg16)"); + return; + } + op->mode |= DISP | direction; + dispreg = op->reg; + src += len; + src = skip_colonthing (src, &op->exp, &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) + as_bad ("Wrong size pointer register for architecture."); + op->mode = RSINC; + op->reg = num; + *ptr = src; + return; + } + if ((mode & SIZE) != PSIZE) + 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; + src = parse_exp (src, &op->exp); + + *ptr = colonmod24 (op, src); + + return; + } + } + + + if (*src == '#') + { + src++; + op->mode = IMM; + src = parse_exp (src, &op->exp); + *ptr = skip_colonthing (src, &op->exp, &op->mode); + + return; + } + else + { + src = parse_exp (src, &op->exp); + /* Trailing ':' size ? */ + if (*src == ':') + { + if (src[1] == '1' && src[2] == '6') + { + op->mode = PCREL | L_16; + src += 3; + } + else if (src[1] == '8') + { + op->mode = PCREL | L_8; + src += 2; + } + else + { + as_bad ("expect :8 or :16 here"); + } + } + else + { + op->mode = PCREL | bsize; + } + *ptr = src; + } +} + + +static +char * +get_operands (noperands, op_end, operand) + unsigned int noperands; + char *op_end; + struct h8_op *operand; +{ + char *ptr = op_end; + + switch (noperands) + { + case 0: + operand[0].mode = 0; + operand[1].mode = 0; + break; + + case 1: + ptr++; + get_operand (&ptr, operand + 0, 0, SRC); + if (*ptr == ',') + { + ptr++; + get_operand (&ptr, operand + 1, 1, DST); + } + else + { + operand[1].mode = 0; + } + + break; + case 2: + ptr++; + get_operand (&ptr, operand + 0, 0, SRC); + if (*ptr == ',') + ptr++; + get_operand (&ptr, operand + 1, 1, DST); + break; + + default: + abort (); + } + + + return ptr; +} + +/* Passed a pointer to a list of opcodes which use different + addressing modes, return the opcode which matches the opcodes + provided + */ +static +struct h8_opcode * +get_specific (opcode, operands) + struct h8_opcode *opcode; + struct h8_op *operands; +{ + struct h8_opcode *this_try = opcode; + int found = 0; + + unsigned int this_index = opcode->idx; + + while (this_index == opcode->idx && !found) + { + unsigned int i; + found = 1; + + this_try = opcode++; + for (i = 0; i < this_try->noperands && found; i++) + { + op_type op = this_try->args.nib[i]; + int x = operands[i].mode; + + if ((op & (DISP | REG)) == (DISP | REG) + && ((x & (DISP | REG)) == (DISP | REG))) + { + dispreg = operands[i].reg; + } + else if (op & REG) + { + if (!(x & REG)) + found = 0; + + if (x & L_P) + { + x = (x & ~L_P) | (Hmode ? L_32 : L_16); + } + if (op & L_P) + { + op = (op & ~L_P) | (Hmode ? L_32 : L_16); + } + + opsize = op & SIZE; + + /* The size of the reg is v important */ + if ((op & SIZE) != (x & SIZE)) + found = 0; + } + else if ((op & ABSJMP) && (x & ABS)) + { + operands[i].mode &= ~ABS; + operands[i].mode |= ABSJMP; + /* But it may not be 24 bits long */ + if (!Hmode) + { + operands[i].mode &= ~SIZE; + operands[i].mode |= L_16; + } + + + } + else if ((op & (KBIT | DBIT)) && (x & IMM)) + { + /* This is ok if the immediate value is sensible */ + + } + else if (op & PCREL) + { + + /* The size of the displacement is important */ + if ((op & SIZE) != (x & SIZE)) + found = 0; + + } + else if ((op & (DISP | IMM | ABS)) + && (op & (DISP | IMM | ABS)) == (x & (DISP | IMM | ABS))) + { + /* Got a diplacement,will fit if no size or same size as try */ + if (op & ABS && op & L_8) + { + /* We want an 8 bit abs here, but one which looks like 16 bits will do fine */ + if (x & L_16) + found= 1; + } + else + if ((x & SIZE) != 0 + && ((op & SIZE) != (x & SIZE))) + found = 0; + } +#if 0 + else if ((op & ABSMOV) && (x & ABS)) + { + /* An absmov is only */ + /* Ok */ + } +#endif + else if ((op & MODE) != (x & MODE)) + { + found = 0; + } + + } + } + if (found) + return this_try; + else + return 0; +} + +static void +check_operand (operand, width, string) + 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 ((operand->exp.X_add_number & ~width) != 0 && + (operand->exp.X_add_number | width) != (~0)) + { + 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 + { + as_warn ("operand %s0x%lx out of range.", string, + (unsigned long) operand->exp.X_add_number); + } + } + } + +} + +static void +do_a_fix_imm (offset, operand, relaxing) + int offset; + struct h8_op *operand; + int relaxing; +{ + int idx; + int size; + int where; + + + char *t = operand->mode & IMM ? "#" : "@"; + + if (operand->exp.X_add_symbol == 0) + { + char *bytes = frag_now->fr_literal + offset; + switch (operand->mode & SIZE) + { + case L_2: + check_operand (operand, 0x3, t); + bytes[0] |= (operand->exp.X_add_number) << 4; + break; + case L_3: + check_operand (operand, 0x7, t); + bytes[0] |= (operand->exp.X_add_number) << 4; + break; + case L_8: + check_operand (operand, 0xff, t); + bytes[0] = operand->exp.X_add_number; + break; + case L_16: + 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; + break; + } + + } + else + { + switch (operand->mode & SIZE) + { + + case L_24: + size = 4; + where = -1; + idx = relaxing ? R_MOVLB1 : R_RELLONG; + break; + default: + as_bad("Can't work out size of operand.\n"); + case L_32: + size = 4; + where = 0; + idx = R_RELLONG; + break; + case L_16: + size = 2; + where = 0; + idx = relaxing ? R_MOVB1 : R_RELWORD; + break; + case L_8: + size = 1; + where = 0; + idx = R_RELBYTE; + } + + /* Sign extend any expression */ + operand->exp.X_add_number = (short)operand->exp.X_add_number; + fix_new_exp (frag_now, + offset + where, + size, + &operand->exp, + 0, + idx); + } + +} + +/* Now we know what sort of opcodes it is, lets build the bytes - + */ +static void +build_bytes (this_try, operand) + struct h8_opcode *this_try; + struct h8_op *operand; +{ + unsigned int i; + + char *output = frag_more (this_try->length); + op_type *nibble_ptr = this_try->data.nib; + op_type c; + unsigned int nibble_count = 0; + int absat; + int immat; + int nib; + char asnibbles[30]; + char *p = asnibbles; + + if (!(this_try->inbase || Hmode)) + { + as_warn ("Opcode `%s' only available in this mode on H8/300-H", + this_try->name); + } + + while (*nibble_ptr != E) + { + int d; + c = *nibble_ptr++; + + d = (c & DST) != 0; + + if (c < 16) + { + nib = c; + } + else + { + + if (c & (REG | IND | INC | DEC)) + { + nib = operand[d].reg; + } + else if ((c & DISPREG) == (DISPREG)) + { + nib = dispreg; + } + + else if (c & ABSMOV) + { + operand[d].mode &= ~ABS; + operand[d].mode |= ABSMOV; + immat = nibble_count / 2; + nib = 0; + } + else if (c & ABS ) + { + operand[d].mode = c; + absat = nibble_count / 2; + nib = 0; + } + else if (c & (IMM | PCREL | ABS | ABSJMP | DISP)) + { + operand[d].mode = c; + immat = nibble_count / 2; + nib = 0; + } + else if (c & IGNORE) + { + nib = 0; + } + else if (c & 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 (c & 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 only valid in h8/300 mode."); + nib = 9; + break; + + default: + as_bad ("Need #1 or #2 here"); + break; + } + /* stop it making a fix */ + operand[0].mode = 0; + } + + if (c & B31) + { + nib |= 0x8; + } + } + nibble_count++; + + *p++ = nib; + } + + for (i = 0; i < this_try->length; i++) + { + output[i] = (asnibbles[i * 2] << 4) | asnibbles[i * 2 + 1]; + } + + /* output any fixes */ + for (i = 0; i < 2; i++) + { + int x = operand[i].mode; + + if (x & (IMM | DISP)) + { + do_a_fix_imm (output - frag_now->fr_literal + immat, operand + i, 0); + } + else if (x & ABS) + { + do_a_fix_imm (output - frag_now->fr_literal + absat, operand + i, 0); + } + else if (x & PCREL) + { + int size16 = x & L_16; + int where = size16 ? 2 : 1; + int size = size16 ? 2 : 1; + int type = size16 ? R_PCRWORD : R_PCRBYTE; + + 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); + } + + operand[i].exp.X_add_number = + (char) (operand[i].exp.X_add_number - 1); + fix_new_exp (frag_now, + output - frag_now->fr_literal + where, + size, + &operand[i].exp, + 1, + type); + } + else if (x & MEMIND) + { + + check_operand (operand + i, 0xff, "@@"); + fix_new_exp (frag_now, + output - frag_now->fr_literal + 1, + 1, + &operand[i].exp, + 0, + R_RELBYTE); + } + + else if (x & ABSMOV) + { + /* This mov is either absolute long or thru a memory loc */ + do_a_fix_imm (output - frag_now->fr_literal + immat, operand + i, 1); + } + + else if (x & ABSJMP) + { + /* This jmp may be a jump or a branch */ + + check_operand (operand + i, 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 = (short) operand[i].exp.X_add_number; + fix_new_exp (frag_now, + output - frag_now->fr_literal, + 4, + &operand[i].exp, + 0, + R_JMPL1); + } + } + +} + +/* + try and give an intelligent error message for common and simple to + detect errors + */ + +static void +clever_message (opcode, operand) + struct h8_opcode *opcode; + struct h8_op *operand; +{ + /* Find out if there was more than one possible opccode */ + + if ((opcode + 1)->idx != opcode->idx) + { + unsigned int argn; + + /* Only one opcode of this flavour, try and guess which operand + didn't match */ + for (argn = 0; argn < opcode->noperands; argn++) + { + switch (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"); +} + +/* This is the guts of the machine-dependent assembler. STR points to a + machine dependent instruction. This funciton is supposed to emit + the frags/bytes it assembles to. + */ + + + +void +md_assemble (str) + char *str; +{ + char *op_start; + char *op_end; + struct h8_op operand[2]; + struct h8_opcode *opcode; + struct h8_opcode *prev_opcode; + + char *dot = 0; + char c; + + /* 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; + } + } + + ; + + if (op_end == op_start) + { + as_bad ("can't find opcode "); + } + c = *op_end; + + *op_end = 0; + + opcode = (struct h8_opcode *) hash_find (opcode_hash_control, + op_start); + + if (opcode == NULL) + { + as_bad ("unknown opcode"); + return; + } + + /* We use to set input_line_pointer to the result of get_operands, + but that is wrong. Our caller assumes we don't change it. */ + + (void) get_operands (opcode->noperands, op_end, operand); + *op_end = c; + prev_opcode = opcode; + + opcode = get_specific (opcode, operand); + + if (opcode == 0) + { + /* Couldn't find an opcode which matched the operands */ + char *where = frag_more (2); + + where[0] = 0x0; + where[1] = 0x0; + clever_message (prev_opcode, operand); + + return; + } + if (opcode->size && dot) + { + if (opcode->size != *dot) + { + as_warn ("mismatch between opcode size and operand size"); + } + } + + build_bytes (opcode, operand); + +} + +void +tc_crawl_symbol_chain (headers) + object_headers * headers; +{ + printf ("call to tc_crawl_symbol_chain \n"); +} + +symbolS * +md_undefined_symbol (name) + char *name; +{ + return 0; +} + +void +tc_headers_hook (headers) + object_headers * headers; +{ + printf ("call to tc_headers_hook \n"); +} + +/* 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 (type, litP, sizeP) + char type; + char *litP; + int *sizeP; +{ + int prec; + LITTLENUM_TYPE words[MAX_LITTLENUMS]; + LITTLENUM_TYPE *wordP; + char *t; + char *atof_ieee (); + + 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 (c, arg) + int c; + char *arg; +{ + return 0; +} + +void +md_show_usage (stream) + FILE *stream; +{ +} + +int md_short_jump_size; + +void +tc_aout_fix_to_chars () +{ + printf ("call to tc_aout_fix_to_chars \n"); + abort (); +} + +void +md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol) + char *ptr; + addressT from_addr; + addressT to_addr; + fragS *frag; + symbolS *to_symbol; +{ + as_fatal ("failed sanity check."); +} + +void +md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol) + char *ptr; + addressT from_addr, to_addr; + fragS *frag; + symbolS *to_symbol; +{ + as_fatal ("failed sanity check."); +} + +void +md_convert_frag (headers, seg, fragP) + object_headers *headers; + segT seg; + fragS *fragP; +{ + printf ("call to md_convert_frag \n"); + abort (); +} + +valueT +md_section_align (seg, size) + segT seg; + valueT size; +{ + return ((size + (1 << section_alignment[(int) seg]) - 1) & (-1 << section_alignment[(int) seg])); + +} + +void +md_apply_fix (fixP, val) + fixS *fixP; + long val; +{ + char *buf = fixP->fx_where + fixP->fx_frag->fr_literal; + + 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 (); + } +} + +int md_long_jump_size; + +int +md_estimate_size_before_relax (fragP, segment_type) + register fragS *fragP; + register segT segment_type; +{ + printf ("call tomd_estimate_size_before_relax \n"); + abort (); +} + +/* Put number into target byte order */ + +void +md_number_to_chars (ptr, use, nbytes) + char *ptr; + valueT use; + int nbytes; +{ + number_to_chars_bigendian (ptr, use, nbytes); +} +long +md_pcrel_from (fixP) + fixS *fixP; +{ + abort (); +} + + +void +tc_reloc_mangle (fix_ptr, intr, base) + fixS *fix_ptr; + struct internal_reloc *intr; + bfd_vma base; + +{ + symbolS *symbol_ptr; + + symbol_ptr = fix_ptr->fx_addsy; + + /* If this relocation is attached to a symbol then it's ok + to output it */ + if (fix_ptr->fx_r_type == RELOC_32) + { + /* cons likes to create reloc32's whatever the size of the reloc.. + */ + switch (fix_ptr->fx_size) + { + + case 2: + intr->r_type = R_RELWORD; + break; + case 1: + intr->r_type = R_RELBYTE; + break; + default: + abort (); + + } + + } + else + { + intr->r_type = fix_ptr->fx_r_type; + } + + intr->r_vaddr = fix_ptr->fx_frag->fr_address + fix_ptr->fx_where + base; + intr->r_offset = fix_ptr->fx_offset; + + if (symbol_ptr) + intr->r_symndx = symbol_ptr->sy_number; + else + intr->r_symndx = -1; + + +} + +/* end of tc-h8300.c */ |