diff options
author | Steve Chamberlain <steve@cygnus> | 1991-10-06 19:02:50 +0000 |
---|---|---|
committer | Steve Chamberlain <steve@cygnus> | 1991-10-06 19:02:50 +0000 |
commit | cd8761e140b7879395258361adb6abc2b25d538f (patch) | |
tree | c0dce240659e839f9287abc2b320ac1d4baf6296 /gas | |
parent | 706a356bfb4a17e80202b3250f9862fdcde81385 (diff) | |
download | gdb-cd8761e140b7879395258361adb6abc2b25d538f.zip gdb-cd8761e140b7879395258361adb6abc2b25d538f.tar.gz gdb-cd8761e140b7879395258361adb6abc2b25d538f.tar.bz2 |
Initial revision
Diffstat (limited to 'gas')
-rw-r--r-- | gas/config/h8300.mt | 4 | ||||
-rw-r--r-- | gas/config/obj-ieee.c | 537 | ||||
-rw-r--r-- | gas/config/obj-ieee.h | 25 | ||||
-rw-r--r-- | gas/config/tc-h8300.c | 662 |
4 files changed, 1228 insertions, 0 deletions
diff --git a/gas/config/h8300.mt b/gas/config/h8300.mt new file mode 100644 index 0000000..1e6eb3c --- /dev/null +++ b/gas/config/h8300.mt @@ -0,0 +1,4 @@ +TARG_CPU_DEPENDENTS=$(srcdir)/../include/h8300-opcode.h +LOCAL_LOADLIBES=$(srcdir)/../bfd/$(srcdir)/libbfd.a +TDEFINES=-DBFD -DMANY_SEGMENTS + diff --git a/gas/config/obj-ieee.c b/gas/config/obj-ieee.c new file mode 100644 index 0000000..4530224 --- /dev/null +++ b/gas/config/obj-ieee.c @@ -0,0 +1,537 @@ +/* obj-format for ieee-695 records. + Copyright (C) 1991 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +/* + created by + + steve chamberlain steve@cygnus.com +*/ + +/* + this will hopefully become the port through which bfd and gas talk, + for the moment, only ieee is known to work well. +*/ + +#include "bfd.h" +#include "as.h" +#include "subsegs.h" +#include "output-file.h" +#include "frags.h" + +bfd *abfd; + +/* How many addresses does the .align take? */ +static relax_addressT relax_align(address, alignment) +register relax_addressT address; /* Address now. */ +register long alignment; /* Alignment (binary). */ +{ + relax_addressT mask; + relax_addressT new_address; + + mask = ~ ( (~0) << alignment ); + new_address = (address + mask) & (~ mask); + return (new_address - address); +} /* relax_align() */ + +/* calculate the size of the frag chain and create a bfd section + to contain all of it */ +static void DEFUN(size_section,(abfd, idx), + bfd *abfd AND + unsigned int idx) +{ + asection *sec; + unsigned int size = 0; + fragS *frag = segment_info[idx].frag_root; + while (frag) { + if (frag->fr_address != size) { + printf("Out of step\n"); + size = frag->fr_address; + } + size += frag->fr_fix; + switch (frag->fr_type) { + case rs_fill: + case rs_org: + size += frag->fr_offset * frag->fr_var; + break; + case rs_align: + size += relax_align(size, frag->fr_offset); + } + frag = frag->fr_next; + } + if (size) { + char *name = segment_info[idx].name; + if (name == (char *)NULL) { + name = ".data"; + } + segment_info[idx].user_stuff = (char *)(sec = bfd_make_section(abfd, name)); + /* Make it output through itself */ + sec->output_section = sec; + sec->flags |= SEC_HAS_CONTENTS; + bfd_set_section_size(abfd, sec, size); + } +} + +/* run through a frag chain and write out the data to go with it */ +static void DEFUN(fill_section,(abfd, idx), + bfd *abfd AND + unsigned int idx) +{ + asection *sec = segment_info[idx].user_stuff; + if (sec) { + fragS *frag = segment_info[idx].frag_root; + unsigned int offset = 0; + while (frag) { + unsigned int fill_size; + unsigned int count; + switch (frag->fr_type) { + case rs_fill: + case rs_align: + case rs_org: + if(frag->fr_fix) + { + bfd_set_section_contents(abfd, + sec, + frag->fr_literal, + frag->fr_address, + frag->fr_fix); + } + offset += frag->fr_fix; + fill_size = frag->fr_var; + if (fill_size) + { + unsigned int off = frag->fr_fix; + for (count = frag->fr_offset; count; count--) + { + bfd_set_section_contents(abfd, sec, + frag->fr_literal + + frag->fr_fix, + frag->fr_address + off, + fill_size); + off += fill_size; + } + } + break; + default: + abort(); + } + frag = frag->fr_next; + } + } +} + +/* Count the relocations in a chain */ + +static unsigned int DEFUN(count_entries_in_chain,(idx), + unsigned int idx) +{ + unsigned int nrelocs; + fixS *fixup_ptr; + + /* Count the relocations */ + fixup_ptr = segment_info[idx].fix_root; + nrelocs = 0; + while (fixup_ptr != (fixS *)NULL) + { + fixup_ptr = fixup_ptr->fx_next; + nrelocs ++ ; + } + return nrelocs; +} + +/* output all the relocations for a section */ +void DEFUN(do_relocs_for,(idx), + unsigned int idx) +{ + unsigned int nrelocs; + arelent **reloc_ptr_vector; + arelent *reloc_vector; + asymbol **ptrs; + asection *section = (asection *)(segment_info[idx].user_stuff); + unsigned int i; + fixS *from; + if (section) { + nrelocs = count_entries_in_chain(idx); + + reloc_ptr_vector = (arelent**)malloc((nrelocs+1) * sizeof(arelent *)); + reloc_vector = (arelent*)malloc(nrelocs * sizeof(arelent)); + ptrs = (asymbol **)malloc(nrelocs * sizeof(asymbol *)); + from = segment_info[idx].fix_root; + for (i = 0; i < nrelocs; i++) + { + arelent *to = reloc_vector + i; + asymbol *s ; + reloc_ptr_vector[i] = to; + to->howto = (reloc_howto_type *)(from->fx_r_type); + + /* We can't represent complicated things in a reloc yet */ + /* if (from->fx_addsy == 0 || + from->fx_subsy != 0) abort(); + */ + s = &( from->fx_addsy->sy_symbol.sy); + to->address = ((char *)( from->fx_frag->fr_address + + from->fx_where)) + - ((char *)(&(from->fx_frag->fr_literal))); + to->addend = from->fx_offset ; + /* If we know the symbol which we want to relocate to, turn this + reloaction into a section relative. + + If this relocation is pcrelative, and we know the + destination, we still want to keep the relocation - since + the linker might relax some of the bytes, but it stops + being pc relative and turns into an absolute relocation. + + */ + if (s) { + if ((s->flags & BSF_UNDEFINED)==0) { + to->section = s->section; + to->addend = s->value ; + to->sym_ptr_ptr = 0; + if (to->howto->pcrel_offset) { + /* This is a pcrel relocation, the addend should be adjusted */ + to->addend -= to->address +1; + } + } + else { + to->section = 0; + *ptrs = &(from->fx_addsy->sy_symbol.sy); + to->sym_ptr_ptr = ptrs; + + if (to->howto->pcrel_offset) { + /* This is a pcrel relocation, the addend should be adjusted */ + to->addend -= to->address -1; + } + } + + } + else { + to->section = 0; + } + + ptrs++; + from = from->fx_next; + } + + /* attatch to the section */ + section->orelocation = reloc_ptr_vector; + section->reloc_count = nrelocs; + section->flags |= SEC_LOAD; + } +} + +/* do the symbols.. */ +static void DEFUN(do_symbols, (abfd), + bfd *abfd) +{ + extern symbolS *symbol_rootP; + symbolS *ptr; + asymbol **symbol_ptr_vec; + asymbol *symbol_vec; + unsigned int count = 0; + unsigned int index; + + + for (ptr = symbol_rootP; + ptr != (symbolS *)NULL; + ptr = ptr->sy_next) + { + if (SEG_NORMAL(ptr->sy_symbol.seg)) + { + ptr->sy_symbol.sy.section = + (asection *)(segment_info[ptr->sy_symbol.seg].user_stuff); + ptr->sy_symbol.sy.value += ptr->sy_frag->fr_address; + if (ptr->sy_symbol.sy.flags == 0) { + ptr->sy_symbol.sy.flags = BSF_LOCAL ; + } + } + else { + switch (ptr->sy_symbol.seg) { + case SEG_ABSOLUTE: + ptr->sy_symbol.sy.flags |= BSF_ABSOLUTE; + ptr->sy_symbol.sy.section = 0; + break; + case SEG_UNKNOWN: + ptr->sy_symbol.sy.flags = BSF_UNDEFINED ; + ptr->sy_symbol.sy.section = 0; + break; + default: + abort(); + } + count++; + } + } + symbol_ptr_vec = (asymbol **)malloc((count+1) * sizeof(asymbol *)); + + index = 0; + for (ptr = symbol_rootP; + ptr != (symbolS *)NULL; + ptr = ptr->sy_next) + { + symbol_ptr_vec[index] = &(ptr->sy_symbol.sy); + index++; + } + symbol_ptr_vec[index] =0; + abfd->outsymbols = symbol_ptr_vec; + abfd->symcount = count; +} + +/* The generic as->bfd converter. Other backends may have special case + code */ + +void DEFUN_VOID(bfd_as_write_hook) +{ + int i; + + for (i = SEG_E0; i < SEG_UNKNOWN; i++) { + size_section(abfd, i); + } + + + for (i = SEG_E0; i < SEG_UNKNOWN; i++) + fill_section(abfd,i); + + do_symbols(abfd); + + for (i = SEG_E0; i < SEG_UNKNOWN; i++) + do_relocs_for(i); + +} + + + +S_GET_VALUE(x) +symbolS *x; +{ + return x->sy_symbol.sy.value; +} + +S_SET_SEGMENT(x,y) +symbolS *x ; +int y; +{ + x->sy_symbol.seg = y; +} + +S_IS_DEFINED(x) +symbolS *x; +{ + if (SEG_NORMAL(x->sy_symbol.seg)) + { + return 1; + } + switch (x->sy_symbol.seg) + { + case SEG_UNKNOWN: + return 0; + default: + abort(); + } +} + +S_IS_EXTERNAL(x) { abort(); } +S_GET_DESC(x) { abort() ; } + +S_GET_SEGMENT(x) +symbolS *x; + { return x->sy_symbol.seg; } + +S_SET_EXTERNAL(x) +symbolS *x; +{ +x->sy_symbol.sy.flags |= BSF_GLOBAL | BSF_EXPORT; +} + +S_SET_NAME(x,y) +symbolS*x; +char *y; { +x->sy_symbol.sy.name = y; } + +S_SET_VALUE(s,v) +symbolS *s; +long v; +{ + s->sy_symbol.sy.value = v; +} + +S_GET_OTHER(x) { abort() ;} +S_IS_DEBUG(x) { abort(); } + +char *segment_name() { abort(); } + +void obj_read_begin_hook() { } + +static void obj_ieee_section(ignore) +int ignore; +{ + extern char *input_line_pointer; + extern char is_end_of_line[]; + char *p= input_line_pointer; + char *s = p; + int i; + /* Look up the name, if it doesn't exist, make it */ + while (*p &&* p != ' ' && *p != ',' && !is_end_of_line[*p]) { + p++; + } + for (i = SEG_E0; i < SEG_UNKNOWN; i++) { + if (segment_info[i].hadone){ + if (strncmp(segment_info[i].name, s, p-s) ==0) { + goto ok; + + } + } + else break; + } + if (i == SEG_UNKNOWN) { + as_bad("too many sections"); + return; + } + + segment_info[i].hadone = 1; + segment_info[i].name = malloc(p-s + 1); + memcpy(segment_info[i].name, s, p-s); + segment_info[i].name[p-s] = 0; + ok: + subseg_new(i,0); + while (!is_end_of_line[*p]) + p++; + input_line_pointer = p; + +} + + +void cons(); +void s_ignore(); + + +/* + * stringer() + * + * We read 0 or more ',' seperated, double-quoted strings. + * + * Caller should have checked need_pass_2 is FALSE because we don't check it. + */ + +void stringer(); +void s_globl(); +const pseudo_typeS obj_pseudo_table[] = +{ + {"section", obj_ieee_section, 0}, + {"data.b", cons, 1}, + {"data.w", cons, 2}, + {"data.l", cons, 4}, + {"export", s_globl, 0}, + {"option", s_ignore, 0}, + {"end", s_ignore, 0}, + {"import", s_ignore, 0}, + {"sdata", stringer, 0}, + 0, + +}; + + + +void obj_symbol_new_hook(symbolP) +symbolS *symbolP; +{ + symbolP->sy_symbol.sy.the_bfd = abfd; +} + + + + + +#if 1 +extern void DEFUN_VOID(write_object_file) +{ + int i; + struct frchain *frchain_ptr; + struct frag *frag_ptr; + + abfd = bfd_openw(out_file_name, "ieee"); + + if (abfd == 0) { + as_perror ("FATAL: Can't create %s", out_file_name); + exit(42); + } + bfd_set_format(abfd, bfd_object); + bfd_set_arch_mach(abfd, bfd_arch_h8300, 0); + subseg_new(1,0); + subseg_new(2,0); + subseg_new(3,0); + for (frchain_ptr = frchain_root; + frchain_ptr != (struct frchain *)NULL; + frchain_ptr = frchain_ptr->frch_next) { + /* Run through all the sub-segments and align them up. Also close any + open frags. We tack a .fill onto the end of the frag chain so + that any .align's size can be worked by looking at the next + frag */ + + subseg_new(frchain_ptr->frch_seg, frchain_ptr->frch_subseg); +#define SUB_SEGMENT_ALIGN 2 + frag_align(SUB_SEGMENT_ALIGN,0); + frag_wane(frag_now); + frag_now->fr_fix = 0; + know( frag_now->fr_next == NULL ); + } + + /* Now build one big frag chain for each segment, linked through + fr_next. */ + for (i = SEG_E0; i < SEG_UNKNOWN; i++) + { + + fragS ** prev_frag_ptr_ptr ; + struct frchain *next_frchain_ptr; + + /* struct frag **head_ptr = segment_info[i].frag_root;*/ + + segment_info[i].frag_root = segment_info[i].frchainP->frch_root; +#if 0 + /* Im not sure what this is for */ + for (frchain_ptr = segment_info[i].frchainP->frch_root; + frchain_ptr != (struct frchain *)NULL; + frchain_ptr = frchain_ptr->frch_next) + { + *head_ptr = frchain_ptr; + head_ptr = &frchain_ptr->next; + } + + +#endif + } + + for (i = SEG_E0; i < SEG_UNKNOWN; i++) { + relax_segment(segment_info[i].frag_root, i); + } + + /* Now the addresses of the frags are correct within the segment */ + + bfd_as_write_hook(); + bfd_close(abfd); +} + +#endif + +H_SET_TEXT_SIZE(a,b) { abort(); } +H_GET_TEXT_SIZE() { abort(); } +H_SET_BSS_SIZE() { abort(); } +H_SET_STRING_SIZE() { abort(); } +H_SET_RELOCATION_SIZE() { abort(); } +H_SET_MAGIC_NUMBER() { abort(); } +H_GET_FILE_SIZE() { abort(); } +H_GET_TEXT_RELOCATION_SIZE() { abort(); } diff --git a/gas/config/obj-ieee.h b/gas/config/obj-ieee.h new file mode 100644 index 0000000..c796e33 --- /dev/null +++ b/gas/config/obj-ieee.h @@ -0,0 +1,25 @@ +#define BFD 1 + + +#include <bfd.h> + +typedef struct +{ +asymbol sy; +int seg; +} obj_symbol_type; + +#define S_GET_NAME(s) (((s)->sy_symbol.sy.name)) + +typedef struct { +int x; +} +object_headers; + +#define DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE 1 + + +int lineno_rootP; + + +#define IEEE_STYLE diff --git a/gas/config/tc-h8300.c b/gas/config/tc-h8300.c new file mode 100644 index 0000000..b68307d --- /dev/null +++ b/gas/config/tc-h8300.c @@ -0,0 +1,662 @@ +/* tc-h8300.c -- Assemble code for the Hitachi h8/300 + Copyright (C) 1991 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +/* + Written By Steve Chamberlain + steve@cygnus.com + */ + +#include <stdio.h> +#include "as.h" +#include "bfd.h" +#include "h8300-opcode.h" +#include <ctype.h> + +char comment_chars[] = { ';',0 }; + +/* 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[] = { + { 0, 0, 0 } +}; + +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 */ + char FLT_CHARS[] = "rRsSfFdDxXpP"; + + +const relax_typeS md_relax_table[1]; + + +static struct hash_control *opcode_hash_control; /* Opcode mnemonics */ +static struct hash_control *register_hash_control; /* Register name hash table */ + + +/* + 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 +*/ + +reloc_howto_type *r16; +reloc_howto_type *r8; +reloc_howto_type *r8ff; +reloc_howto_type *r8pcrel; + +void md_begin () +{ + bfd_arch_info_struct_type *ai; + const struct h8_opcode *opcode; + + opcode_hash_control = hash_new(); + for (opcode = h8_opcodes; opcode->name; opcode++) { + hash_insert(opcode_hash_control, opcode->name, (char *)opcode); + } + + ai = bfd_lookup_arch(bfd_arch_h8300,0); + + r16 = ai->reloc_type_lookup(ai, BFD_RELOC_16); + r8 = ai->reloc_type_lookup(ai, BFD_RELOC_8); + r8ff = ai->reloc_type_lookup(ai, BFD_RELOC_8_FFnn); + r8pcrel = ai->reloc_type_lookup(ai, BFD_RELOC_8_PCREL); + + +} + + +struct h8_exp { + char *e_beg; + char *e_end; + expressionS e_exp; +}; +struct h8_op +{ +op_enum_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 + +*/ + +op_enum_type r8_sord[] = {RS8, RD8}; +op_enum_type r16_sord[] = {RS16, RD16}; +op_enum_type rind_sord[] = {RSIND, RDIND}; +op_enum_type abs_sord[2] = {ABS16SRC, ABS16DST}; +op_enum_type disp_sord[] = {DISPSRC, DISPDST}; +/* try and parse a reg name, returns number of chars consumed */ +int DEFUN(parse_reg,(src, mode, reg, dst), + char *src AND + op_enum_type *mode AND + unsigned int *reg AND + int dst) +{ + if (src[0] == 's' && src[1] == 'p') { + *mode = r16_sord[dst]; + *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 = r16_sord[dst]; + *reg = 6; + return 2; + } + if (src[0] == 'r') { + if (src[1] >= '0' && src[1] <= '7') { + if(src[2] == 'l') { + *mode = r8_sord[dst]; + *reg = (src[1] - '0') + 8; + return 3; + } + if(src[2] == 'h') { + *mode = r8_sord[dst]; + *reg = (src[1] - '0') ; + return 3; + } + *mode = r16_sord[dst]; + *reg = (src[1] - '0'); + return 2; + } + } + return 0; +} + +char * +DEFUN(parse_exp,(s, op), + char *s AND + expressionS *op) +{ + char *save = input_line_pointer; + char *new; + segT seg; + input_line_pointer = s; + seg = expr(0,op); + new = input_line_pointer; + input_line_pointer = save; + if (SEG_NORMAL(seg)) + return new; + switch (seg) { + case SEG_ABSOLUTE: + case SEG_UNKNOWN: + case SEG_DIFFERENCE: + case SEG_BIG: + case SEG_REGISTER: + return new; + case SEG_ABSENT: + as_bad("Missing operand"); + return new; + default: + as_bad("Don't understand operand of type %s", segment_name (seg)); + return new; + } +} + + +static void +DEFUN(get_operand,(ptr, op, dst), + char **ptr AND + struct h8_op *op AND + unsigned int dst) +{ + char *src = *ptr; + op_enum_type mode; + unsigned int num; + unsigned int len; + op->mode = E; + + while (*src == ' ') src++; + len = parse_reg(src, &op->mode, &op->reg, dst); + if (len) { + *ptr = src + len; + return ; + } + + if (*src == '@') { + src++; + if (*src == '-') { + src++; + len = parse_reg(src, &mode, &num, dst); + if (len == 0 || mode != r16_sord[dst]) { + as_bad("@- needs word register"); + } + op->mode = RDDEC; + op->reg = num; + *ptr = src + len; + return; + } + if (*src == '(' && ')') { + /* Disp */ + src++; + src = parse_exp(src, &op->exp); + + if (*src == ')') { + src++; + op->mode = abs_sord[dst]; + *ptr = src; + return; + } + if (*src != ',') { + as_bad("expected @(exp, reg16)"); + } + src++; + len = parse_reg(src, &mode, &op->reg, dst); + if (len == 0 || mode != r16_sord[dst]) + { + as_bad("expected @(exp, reg16)"); + } + op->mode = disp_sord[dst]; + src += len; + if (*src != ')' && '(') { + as_bad("expected @(exp, reg16)"); + + } + *ptr = src +1; + + return; + } + len = parse_reg(src, &mode, &num, dst); + + if(len) { + src += len; + if (*src == '+') { + src++; + if (mode != RS16) { + as_bad("@Rn+ needs word register"); + } + op->mode = RSINC; + op->reg = num; + *ptr = src; + return; + } + if (mode != r16_sord[dst]) { + as_bad("@Rn needs word register"); + } + op->mode =rind_sord[dst]; + op->reg = num; + *ptr = src; + return; + } + else { + /* must be a symbol */ + op->mode = abs_sord[dst]; + *ptr = parse_exp(src, &op->exp); + return; + } + } + + + if (*src == '#') { + src++; + op->mode = IMM16; + *ptr = parse_exp(src, &op->exp); + return; + } + else { + *ptr = parse_exp(src, &op->exp); + op->mode = DISP8; + } +} + +/* 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 +DEFUN(md_assemble,(str), + char *str) +{ + char *op_start; + char *op_end; + struct h8_opcode * opcode; + /* 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 == op_start) { + as_bad("can't find opcode "); + } + *op_end = 0; + opcode = (struct h8_opcode *) hash_find(opcode_hash_control, + op_start); + + if (opcode == NULL) { + as_bad("unknown opcode"); + return; + } + + + { + int ok = 1; + int j,i; + int dispreg = 0; + struct h8_op operand[2]; + char *ptr = op_end+1; + if (opcode->noperands) + get_operand(& ptr, &operand[0],0); + else operand[0].mode = 0; + if (opcode->noperands==2) { + if (*ptr == ',') ptr++; + get_operand(& ptr, &operand[1], 1); + } + else operand[1].mode = 0; + + + + { + struct h8_opcode *this_try ; + int found = 0; + for (j = 0; j < opcode->nopcodes && !found; j++) { + this_try = opcode + j; + for (i = 0; i < opcode->noperands; i++) { + op_enum_type op = (this_try->args.nib[i]) & ~(B30|B31); + switch (op) { + case Hex0: + case Hex1: + case Hex2: + case Hex3: + case Hex4: + case Hex5: + case Hex6: + case Hex7: + case Hex8: + case Hex9: + case HexA: + case HexB: + case HexC: + case HexD: + case HexE: + case HexF: + break; + case DISPSRC: + case DISPDST: + dispreg = operand[i].reg; + case RD8: + case RS8: + case RDIND: + case RSIND: + case RD16: + case RS16: + case CCR: + case RSINC: + case RDDEC: + if (operand[i].mode != op) goto fail; + break; + case KBIT: + case IMM8: + case IMM16: + case IMM3: + if (operand[i].mode != IMM16) goto fail; + break; + case ABS16SRC: + case ABS8SRC: + if (operand[i].mode != ABS16SRC) goto fail; + break; + case ABS16DST: + case ABS8DST: + if (operand[i].mode != ABS16DST) goto fail; + + break; + } + } + found =1; + fail: ; + } + if (found == 0) + as_bad("illegal operands for opcode"); + + + /* Now we know what sort of opcodes etc, lets build the bytes - + actually we know how big the instruction will be too. So we + can get + */ + { + char *output = frag_more(this_try->length); + char *output_ptr = output; + op_enum_type *nibble_ptr = this_try->data.nib; + char part; + op_enum_type c; + char high; + int nib; + top: ; + while (*nibble_ptr != E) { + int nibble; + for (nibble = 0; nibble <2; nibble++) { + c = *nibble_ptr & ~(B30|B31); + switch (c) { + default: + abort(); + + case 0: + case 1: + case 2: case 3: case 4: case 5: case 6: + case 7: case 8: case 9: case 10: case 11: + case 12: case 13: case 14: case 15: + nib = c; + break; + case DISPREG: + nib = dispreg; + break; + case IMM8: + /* if no symbol then put value in place */ + if (operand[0].exp.X_add_symbol == 0) { + operand[0].mode = 0; /* stop it making a fix */ + *output_ptr++ = (operand[0].exp.X_add_number); + nibble_ptr += 2; + goto top; + } + nib = 0; + break; + + case DISPDST: + /* if no symbol then put value in place */ + if (operand[1].exp.X_add_symbol == 0) { + operand[1].mode = 0; /* stop it making a fix */ + *output_ptr++ =(operand[1].exp.X_add_number)>>8; + *output_ptr++ = (operand[1].exp.X_add_number); + nibble_ptr += 4; + goto top; + } + + nib = 0; + break; + case IMM3: + + if (operand[0].exp.X_add_symbol == 0) { + operand[0].mode = 0; /* stop it making a fix */ + nib = (operand[0].exp.X_add_number); + } + else as_bad("can't have symbol for bit number"); + break; + + case DISPSRC: + case IMM16: + /* if no symbol then put value in place */ + if (operand[0].exp.X_add_symbol == 0) { + operand[0].mode = 0; /* stop it making a fix */ + *output_ptr++ =(operand[0].exp.X_add_number)>>8; + *output_ptr++ = (operand[0].exp.X_add_number); + nibble_ptr += 4; + goto top; + } + + + case ABS16SRC: + case ABS16DST: + + case ABS8DST: + case ABS8SRC: + case IGNORE: + + + nib = 0; + break; + case DISP8: + nib = 0; + break; + + + case RS8: + case RS16: + case RSIND: + case RSINC: + case RDIND: + nib= operand[0].reg; + break; + case RD8: + case RD16: + case RDDEC: + nib = operand[1].reg; + + break; + case E: + abort(); + break; + } + if (*nibble_ptr & B31) nib|=0x8; + if (nibble == 0) { + *output_ptr = nib << 4; + } + else { + *output_ptr |= nib; + output_ptr++; + } + nibble_ptr++; + } + + } + + /* output any fixes */ + { + int i; + for (i = 0; i < 2; i++) { + switch (operand[i].mode) { + case 0: + break; + case DISP8: + fix_new(frag_now, + output+1, + 1, + operand[i].exp.X_add_symbol, + operand[i].exp.X_subtract_symbol, + operand[i].exp.X_add_number, + 0, + (int)r8pcrel); + break; + case ABS16SRC: + case ABS16DST: + case IMM16: + case DISPSRC: + case DISPDST: + fix_new(frag_now, + output+2, + 2, + operand[i].exp.X_add_symbol, + operand[i].exp.X_subtract_symbol, + operand[i].exp.X_add_number, + 0, + (int)r16); + break; + case RS8: + case RD8: + case RS16: + case RD16: + case RDDEC: + case RSINC: + case RDIND: + case RSIND: + break; + default: + abort(); + } + } + } + + } + } + } +} + +void +DEFUN(tc_crawl_symbol_chain, (headers), +object_headers *headers) +{ + printf("call to tc_crawl_symbol_chain \n"); +} + +symbolS *DEFUN(md_undefined_symbol,(name), + char *name) +{ +return 0; +} + +void +DEFUN(tc_headers_hook,(headers), + object_headers *headers) +{ + printf("call to tc_headers_hook \n"); +} +void +DEFUN_VOID(md_end) +{ +} + +/* Various routines to kill one day */ + +char *md_atof () { printf("call to md_atof \n"); abort(); } +int md_parse_option () { printf("call to md_parse_option \n"); abort(); } + +int md_short_jump_size; + +void tc_aout_fix_to_chars () { printf("call to tc_aout_fix_to_chars \n"); + abort(); } +void md_create_long_jump () { printf("call to md_create_long_jump \n"); + abort(); } +void md_convert_frag () { printf("call to md_convert_frag \n"); abort(); } + +long +DEFUN(md_section_align,(seg, size), + segT seg AND + long size) +{ + return((size + (1 << section_alignment[(int) seg]) - 1) & (-1 << section_alignment[(int) seg])); + +} + +void md_apply_fix () { printf("call to md_apply_fix \n"); abort(); } + +void DEFUN(md_operand, (expressionP),expressionS *expressionP) +{ } + +int md_long_jump_size; +int md_estimate_size_before_relax () { printf("call tomd_estimate_size_before_relax \n"); abort(); } +/* Put number into target byte order */ +void DEFUN(md_number_to_chars,(ptr, use, nbytes), + char *ptr AND + int use AND + unsigned int nbytes) +{ + switch (nbytes) { + case 4: *ptr++ = (use >> 24) & 0xff; + case 3: *ptr++ = (use >> 16) & 0xff; + case 2: *ptr++ = (use >> 8) & 0xff; + case 1: *ptr++ = (use >> 0) & 0xff; + break; + default: + abort(); + } +} + +long md_pcrel_from () { printf("call to md_pcrel_from \n"); abort(); } +void md_create_short_jump () { printf("call to md_create_short_jump \n"); + abort(); } + +void tc_coff_symbol_emit_hook() { } |