diff -crN binutils.null/bfd/cpu-i51.c binutils-2.11.2.i51.new/bfd/cpu-i51.c *** binutils.null/bfd/cpu-i51.c Thu Jan 1 01:00:00 1970 --- binutils-2.11.2.i51.new/bfd/cpu-i51.c Wed Dec 26 16:20:51 2001 *************** *** 0 **** --- 1,39 ---- + /* BFD library support routines for the MCS-51 architecture. + Copyright (C) 2001 Free Software Foundation, Inc. + Contributed by Radek Benedikt + + This file is part of BFD, the Binary File Descriptor library. + + This program 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 of the License, or + (at your option) any later version. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + #include "bfd.h" + #include "sysdep.h" + #include "libbfd.h" + + const bfd_arch_info_type bfd_i51_arch = + { + 8, /* 8 bits in a word */ + 8, /* 8 bits in an address */ + 8, /* 8 bits in a byte */ + bfd_arch_i51, + 0, /* only 1 machine */ + "i51", + "i51", + 0, /* section align power */ + true, /* the one and only */ + bfd_default_compatible, + bfd_default_scan, + NULL, + }; diff -crN binutils.null/bfd/elf32-i51.c binutils-2.11.2.i51.new/bfd/elf32-i51.c *** binutils.null/bfd/elf32-i51.c Thu Jan 1 01:00:00 1970 --- binutils-2.11.2.i51.new/bfd/elf32-i51.c Sun Dec 30 10:47:56 2001 *************** *** 0 **** --- 1,1030 ---- + /* MCS-51 specific support for 32-bit ELF + Copyright (C) 2001 Free Software Foundation, Inc. + Contributed by Radek Benedikt + + This file is part of BFD, the Binary File Descriptor library. + + This program 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 of the License, or + (at your option) any later version. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + #include "bfd.h" + #include "sysdep.h" + #include "libbfd.h" + #include "elf-bfd.h" + #include "elf/i51.h" + + static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup + PARAMS ((bfd *abfd, bfd_reloc_code_real_type code)); + static void i51_info_to_howto_rela + PARAMS ((bfd *, arelent *, Elf32_Internal_Rela *)); + static asection *elf32_i51_gc_mark_hook + PARAMS ((bfd *, struct bfd_link_info *, Elf_Internal_Rela *, + struct elf_link_hash_entry *, Elf_Internal_Sym *)); + static boolean elf32_i51_gc_sweep_hook + PARAMS ((bfd *, struct bfd_link_info *, asection *, + const Elf_Internal_Rela *)); + static boolean elf32_i51_check_relocs + PARAMS ((bfd *, struct bfd_link_info *, asection *, + const Elf_Internal_Rela *)); + static bfd_reloc_status_type i51_final_link_relocate + PARAMS ((reloc_howto_type *, bfd *, asection *, bfd_byte *, + Elf_Internal_Rela *, bfd_vma)); + static boolean elf32_i51_relocate_section + PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, + Elf_Internal_Rela *, Elf_Internal_Sym *, asection **)); + static void bfd_elf_i51_final_write_processing + PARAMS ((bfd *, boolean)); + static boolean elf32_i51_object_p + PARAMS ((bfd *)); + void elf32_i51_symbol_processing + PARAMS ((bfd *, asymbol *)); + boolean elf32_i51_section_from_bfd_section + PARAMS ((bfd *, Elf32_Internal_Shdr *, asection *, int *)); + static boolean elf32_i51_add_symbol_hook + PARAMS ((bfd *, struct bfd_link_info *, const Elf_Internal_Sym *, + const char **, flagword *, asection **, bfd_vma *)); + + /* Use RELA instead of REL */ + #undef USE_REL + + static reloc_howto_type elf_i51_howto_table[] = + { + HOWTO (R_I51_NONE, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_I51_NONE", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + false), /* pcrel_offset */ + + /* A 1 bit indirect register relocation. */ + HOWTO (R_I51_R1, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_I51_R1", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + false), /* pcrel_offset */ + + /* A 3 bit register relocation. */ + HOWTO (R_I51_R3, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_I51_R3", /* name */ + false, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + false), /* pcrel_offset */ + + /* A 7 bit PC relative relocation. */ + HOWTO (R_I51_7_PCREL, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_I51_7_PCREL", /* name */ + false, /* partial_inplace */ + 0x0000, /* src_mask */ + 0x00ff, /* dst_mask */ + false), /* pcrel_offset */ + + /* A 11 bit absolute inpage relocation. */ + HOWTO (R_I51_11, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_I51_11", /* name */ + false, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* A 8 bit bit register relocation. */ + HOWTO (R_I51_8_BIT, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_I51_8_BIT", /* name */ + false, /* partial_inplace */ + 0x00ff, /* src_mask */ + 0x00ff, /* dst_mask */ + false), /* pcrel_offset */ + + /* A 8 bit absolute relocation. */ + HOWTO (R_I51_8, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_I51_8", /* name */ + false, /* partial_inplace */ + 0x00ff, /* src_mask */ + 0x00ff, /* dst_mask */ + false), /* pcrel_offset */ + + /* A 8 bit absolute LOW(word) relocation. */ + HOWTO (R_I51_L, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_I51_L", /* name */ + false, /* partial_inplace */ + 0x00ff, /* src_mask */ + 0x00ff, /* dst_mask */ + false), /* pcrel_offset */ + + /* A 8 bit absolute HIGH(word) relocation. */ + HOWTO (R_I51_H, /* type */ + 8, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_I51_H", /* name */ + false, /* partial_inplace */ + 0x00ff, /* src_mask */ + 0x00ff, /* dst_mask */ + false), /* pcrel_offset */ + + /* A 16 bit absolute relocation. */ + HOWTO (R_I51_16, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_I51_16", /* name */ + false, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false), /* pcrel_offset */ + + /* A 8 bit Byte2Bit relocation. */ + HOWTO (R_I51_8_B2B, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 8, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_I51_8_B2B", /* name */ + false, /* partial_inplace */ + 0x00ff, /* src_mask */ + 0x00ff, /* dst_mask */ + false), /* pcrel_offset */ + + /* A 13 bit absolute pcode relocation. */ + HOWTO (R_I51_13_PCODE, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + false, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_I51_13_PCODE", /* name */ + false, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + false) /* pcrel_offset */ + }; + + /* Map BFD reloc types to I51 ELF reloc types. */ + + struct i51_reloc_map + { + bfd_reloc_code_real_type bfd_reloc_val; + unsigned int elf_reloc_val; + }; + + static const struct i51_reloc_map i51_reloc_map[] = + { + { BFD_RELOC_NONE, R_I51_NONE }, + { BFD_RELOC_I51_R1, R_I51_R1 }, + { BFD_RELOC_I51_R3, R_I51_R3 }, + { BFD_RELOC_I51_7_PCREL, R_I51_7_PCREL }, + { BFD_RELOC_I51_11, R_I51_11 }, + { BFD_RELOC_I51_8_BIT, R_I51_8_BIT }, + { BFD_RELOC_8, R_I51_8 }, + { BFD_RELOC_I51_8_LOW, R_I51_L }, + { BFD_RELOC_I51_8_HIGH, R_I51_H }, + { BFD_RELOC_16, R_I51_16 }, + { BFD_RELOC_I51_8_B2B, R_I51_8_B2B }, + { BFD_RELOC_I51_13_PCODE, R_I51_13_PCODE } + }; + + static reloc_howto_type * + bfd_elf32_bfd_reloc_type_lookup (abfd, code) + bfd *abfd ATTRIBUTE_UNUSED; + bfd_reloc_code_real_type code; + { + unsigned int i; + + for (i = 0; + i < sizeof (i51_reloc_map) / sizeof (struct i51_reloc_map); + i++) + { + if (i51_reloc_map[i].bfd_reloc_val == code) + return &elf_i51_howto_table[i51_reloc_map[i].elf_reloc_val]; + } + return NULL; + } + + /* Set the howto pointer for an I51 ELF reloc. */ + + static void + i51_info_to_howto_rela (abfd, cache_ptr, dst) + bfd *abfd ATTRIBUTE_UNUSED; + arelent *cache_ptr; + Elf32_Internal_Rela *dst; + { + unsigned int r_type; + + r_type = ELF32_R_TYPE (dst->r_info); + BFD_ASSERT (r_type < (unsigned int) R_I51_max); + cache_ptr->howto = &elf_i51_howto_table[r_type]; + } + + static asection * + elf32_i51_gc_mark_hook (abfd, info, rel, h, sym) + bfd *abfd; + struct bfd_link_info *info ATTRIBUTE_UNUSED; + Elf_Internal_Rela *rel; + struct elf_link_hash_entry *h; + Elf_Internal_Sym *sym; + { + if (h != NULL) + { + switch (ELF32_R_TYPE (rel->r_info)) + { + default: + switch (h->root.type) + { + case bfd_link_hash_defined: + case bfd_link_hash_defweak: + return h->root.u.def.section; + + case bfd_link_hash_common: + return h->root.u.c.p->section; + + default: + break; + } + } + } + else + { + if (!(elf_bad_symtab (abfd) + && ELF_ST_BIND (sym->st_info) != STB_LOCAL) + && !((sym->st_shndx <= 0 || sym->st_shndx >= SHN_LORESERVE) + && sym->st_shndx != SHN_COMMON)) + { + return bfd_section_from_elf_index (abfd, sym->st_shndx); + } + } + return NULL; + } + + static boolean + elf32_i51_gc_sweep_hook (abfd, info, sec, relocs) + bfd *abfd ATTRIBUTE_UNUSED; + struct bfd_link_info *info ATTRIBUTE_UNUSED; + asection *sec ATTRIBUTE_UNUSED; + const Elf_Internal_Rela *relocs ATTRIBUTE_UNUSED; + { + /* We don't use got and plt entries for i51. */ + return true; + } + + /* Look through the relocs for a section during the first phase. + Since we don't do .gots or .plts, we just need to consider the + virtual table relocs for gc. */ + + static boolean + elf32_i51_check_relocs (abfd, info, sec, relocs) + bfd *abfd; + struct bfd_link_info *info; + asection *sec; + const Elf_Internal_Rela *relocs; + { + Elf_Internal_Shdr *symtab_hdr; + struct elf_link_hash_entry **sym_hashes, **sym_hashes_end; + const Elf_Internal_Rela *rel; + const Elf_Internal_Rela *rel_end; + + if (info->relocateable) + return true; + + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + sym_hashes = elf_sym_hashes (abfd); + sym_hashes_end = sym_hashes + symtab_hdr->sh_size/sizeof (Elf32_External_Sym); + if (!elf_bad_symtab (abfd)) + sym_hashes_end -= symtab_hdr->sh_info; + + rel_end = relocs + sec->reloc_count; + for (rel = relocs; rel < rel_end; rel++) + { + struct elf_link_hash_entry *h; + unsigned long r_symndx; + + r_symndx = ELF32_R_SYM (rel->r_info); + if (r_symndx < symtab_hdr->sh_info) + h = NULL; + else + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + } + + return true; + } + + /* Perform a single relocation. By default we use the standard BFD + routines, but a few relocs, we have to do them ourselves. */ + + static bfd_reloc_status_type + i51_final_link_relocate (howto, input_bfd, input_section, + contents, rel, relocation) + reloc_howto_type * howto; + bfd * input_bfd; + asection * input_section; + bfd_byte * contents; + Elf_Internal_Rela * rel; + bfd_vma relocation; + { + bfd_reloc_status_type r = bfd_reloc_ok; + bfd_vma x; + bfd_signed_vma srel; + + switch (howto->type) + { + case R_I51_7_PCREL: + contents += rel->r_offset; + srel = (bfd_signed_vma) relocation; + srel += rel->r_addend; + srel -= rel->r_offset; + srel -= (input_section->output_section->vma + + input_section->output_offset); + /* + fprintf (stderr, "7PCREL contents: %lx rel->r_offset: %lx relocation: %lx\n", + contents, rel->r_offset, (bfd_signed_vma)relocation); + fprintf (stderr, "7PCREL rel->r_addend: %lx srel: %lx\n", + rel->r_addend, srel); + fprintf (stderr, "7PCREL input_section->output_section->vma: %lx input_section->output_offset: %lx\n", + input_section->output_section->vma, input_section->output_offset); + */ + /* Check for overflow. */ + if (srel > ((1 << 7) - 1) || (srel < - (1 << 7))) + return bfd_reloc_overflow; + + // x = bfd_get_8 (input_bfd, contents); + bfd_put_8 (input_bfd, srel, contents); + break; + + case R_I51_11: + contents += rel->r_offset; + srel = (bfd_signed_vma) relocation; + srel += rel->r_addend; + /* + fprintf (stderr, "R11 contents: %lx rel->r_offset: %lx relocation: %lx\n", + contents, rel->r_offset, (bfd_signed_vma)relocation); + fprintf (stderr, "R11 rel->r_addend: %lx srel: %lx\n", + rel->r_addend, srel); + fprintf (stderr, "R11 input_section->output_section->vma: %lx input_section->output_offset: %lx\n", + input_section->output_section->vma, input_section->output_offset); + */ + /* Check for overflow. */ + if (((srel ^ (rel->r_offset + input_section->output_section->vma + input_section->output_offset)) & 0x0000F800l) !=0) + { + /* + fprintf ("Err: %lx %lx %lx\n", srel, + (rel->r_offset + input_section->output_section->vma + input_section->output_offset), + ((srel ^ (rel->r_offset + input_section->output_section->vma + input_section->output_offset)) & 0x0000F800l)); + */ + return bfd_reloc_overflow; + } + + srel = (((srel & 0x0700) << 5) | (srel & 0x00FF)); + x = bfd_get_16 (input_bfd, contents); + x = (x & 0x1F00) | srel; + bfd_put_16 (input_bfd, x, contents); + break; + + case R_I51_8_B2B: + contents += rel->r_offset; + srel = (bfd_signed_vma) relocation; + srel += rel->r_addend; + x = bfd_get_8 (input_bfd, contents); + /* Check for overflow. */ + if (srel < 0x20) return bfd_reloc_outofrange; + if ((srel < 0x30) && (((srel - 0x20) * 8 + x) > 0x80)) return bfd_reloc_overflow; + if ((srel >= 0x30) && (srel < 0x80)) return bfd_reloc_outofrange; + if ((srel + x) > 0x100) return bfd_reloc_overflow; + if (srel < 0x30) + bfd_put_8 (input_bfd, ((srel - 0x20) * 8 + x), contents); + else + bfd_put_8 (input_bfd, (srel + x), contents); + break; + + case R_I51_13_PCODE: + contents += rel->r_offset; + srel = (bfd_signed_vma) relocation; + srel += rel->r_addend; + /* Check for overflow. */ + if (srel < 0x0100) return bfd_reloc_outofrange; + if (srel > 0x1FFF) return bfd_reloc_overflow; + + x = bfd_get_16 (input_bfd, contents); + x = (x & 0xE000) | srel; + bfd_put_16 (input_bfd, x, contents); + break; + + default: + r = _bfd_final_link_relocate (howto, input_bfd, input_section, + contents, rel->r_offset, + relocation, rel->r_addend); + } + + return r; + } + + /* Relocate an I51 ELF section. */ + static boolean + elf32_i51_relocate_section (output_bfd, info, input_bfd, input_section, + contents, relocs, local_syms, local_sections) + bfd *output_bfd ATTRIBUTE_UNUSED; + struct bfd_link_info *info; + bfd *input_bfd; + asection *input_section; + bfd_byte *contents; + Elf_Internal_Rela *relocs; + Elf_Internal_Sym *local_syms; + asection **local_sections; + { + Elf_Internal_Shdr * symtab_hdr; + struct elf_link_hash_entry ** sym_hashes; + Elf_Internal_Rela * rel; + Elf_Internal_Rela * relend; + + symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr; + sym_hashes = elf_sym_hashes (input_bfd); + relend = relocs + input_section->reloc_count; + + for (rel = relocs; rel < relend; rel ++) + { + reloc_howto_type * howto; + unsigned long r_symndx; + Elf_Internal_Sym * sym; + asection * sec; + struct elf_link_hash_entry * h; + bfd_vma relocation; + bfd_reloc_status_type r; + const char * name = NULL; + int r_type; + + r_type = ELF32_R_TYPE (rel->r_info); + r_symndx = ELF32_R_SYM (rel->r_info); + + if (info->relocateable) + { + /* This is a relocateable link. We don't have to change + anything, unless the reloc is against a section symbol, + in which case we have to adjust according to where the + section symbol winds up in the output section. */ + if (r_symndx < symtab_hdr->sh_info) + { + sym = local_syms + r_symndx; + + if (ELF_ST_TYPE (sym->st_info) == STT_SECTION) + { + sec = local_sections [r_symndx]; + rel->r_addend += sec->output_offset + sym->st_value; + } + } + + continue; + } + + /* This is a final link. */ + howto = elf_i51_howto_table + ELF32_R_TYPE (rel->r_info); + h = NULL; + sym = NULL; + sec = NULL; + + if (r_symndx < symtab_hdr->sh_info) + { + sym = local_syms + r_symndx; + sec = local_sections [r_symndx]; + relocation = (sec->output_section->vma + + sec->output_offset + + sym->st_value); + + name = bfd_elf_string_from_elf_section + (input_bfd, symtab_hdr->sh_link, sym->st_name); + name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name; + } + else + { + h = sym_hashes [r_symndx - symtab_hdr->sh_info]; + + while (h->root.type == bfd_link_hash_indirect + || h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + + name = h->root.root.string; + + if (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + { + sec = h->root.u.def.section; + relocation = (h->root.u.def.value + + sec->output_section->vma + + sec->output_offset); + } + else if (h->root.type == bfd_link_hash_undefweak) + { + relocation = 0; + } + else + { + if (! ((*info->callbacks->undefined_symbol) + (info, h->root.root.string, input_bfd, + input_section, rel->r_offset, true))) + return false; + relocation = 0; + } + } + + r = i51_final_link_relocate (howto, input_bfd, input_section, + contents, rel, relocation); + + if (r != bfd_reloc_ok) + { + const char * msg = (const char *) NULL; + + switch (r) + { + case bfd_reloc_overflow: + r = info->callbacks->reloc_overflow + (info, name, howto->name, (bfd_vma) 0, + input_bfd, input_section, rel->r_offset); + break; + + case bfd_reloc_undefined: + r = info->callbacks->undefined_symbol + (info, name, input_bfd, input_section, rel->r_offset, true); + break; + + case bfd_reloc_outofrange: + msg = _("internal error: out of range error"); + break; + + case bfd_reloc_notsupported: + msg = _("internal error: unsupported relocation error"); + break; + + case bfd_reloc_dangerous: + msg = _("internal error: dangerous relocation"); + break; + + default: + msg = _("internal error: unknown error"); + break; + } + + if (msg) + r = info->callbacks->warning + (info, msg, name, input_bfd, input_section, rel->r_offset); + + if (! r) + return false; + } + } + + return true; + } + + /* The final processing done just before writing out a I51 ELF object + file. This gets the I51 architecture right based on the machine + number. */ + + static void + bfd_elf_i51_final_write_processing (abfd, linker) + bfd *abfd; + boolean linker ATTRIBUTE_UNUSED; + { + unsigned long val; + + elf_elfheader (abfd)->e_machine = EM_I51; + } + + /* Set the right machine number. */ + + static boolean + elf32_i51_object_p (abfd) + bfd *abfd; + { + return true; + } + + static boolean + i51_elf_section_from_shdr (abfd, hdr, name) + bfd *abfd; + Elf32_Internal_Shdr *hdr; + char *name; + { + asection *newsect; + flagword flags; + + if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name)) + return false; + + newsect = hdr->bfd_section; + flags = bfd_get_section_flags (abfd, newsect); + + if (hdr->sh_flags & SHF_CDATA) flags |= SEC_IS_COMMON; + + bfd_set_section_flags (abfd, newsect, flags); + + return true; + } + + static boolean + i51_elf_fake_sections (abfd, shdr, asect) + bfd *abfd ATTRIBUTE_UNUSED; + Elf32_Internal_Shdr *shdr; + asection *asect; + { + register const char * name; + + name = bfd_get_section_name (abfd, asect); + + if (strcmp (name, ".rbbs") == 0) + { + shdr->sh_flags |= SHF_RDATA; + } + else if (strcmp (name, ".bbbs") == 0) + { + shdr->sh_flags |= SHF_BDATA; + } + else if (strcmp (name, ".ibbs") == 0) + { + shdr->sh_flags |= SHF_IDATA; + } + else if (strcmp (name, ".xbbs") == 0) + { + shdr->sh_flags |= SHF_XDATA; + } + else if (strcmp (name, ".ebbs") == 0) + { + shdr->sh_flags |= SHF_EDATA; + } + + return true; + } + + + /* Given a BFD section, try to locate the corresponding ELF section + index. */ + + boolean + elf32_i51_section_from_bfd_section (abfd, hdr, sec, retval) + bfd *abfd ATTRIBUTE_UNUSED; + Elf32_Internal_Shdr *hdr ATTRIBUTE_UNUSED; + asection *sec; + int *retval; + { + if (strcmp (bfd_get_section_name (abfd, sec), ".regbank") == 0) + { + *retval = SHN_I51_REGBANK; + return true; + } + else if (strcmp (bfd_get_section_name (abfd, sec), ".rbss") == 0) + { + *retval = SHN_I51_RDATA_C; + return true; + } + else if (strcmp (bfd_get_section_name (abfd, sec), ".bbss") == 0) + { + *retval = SHN_I51_BDATA_C; + return true; + } + else if (strcmp (bfd_get_section_name (abfd, sec), ".ibss") == 0) + { + *retval = SHN_I51_IDATA_C; + return true; + } + else if (strcmp (bfd_get_section_name (abfd, sec), ".xbss") == 0) + { + *retval = SHN_I51_XDATA_C; + return true; + } + else if (strcmp (bfd_get_section_name (abfd, sec), ".ebss") == 0) + { + *retval = SHN_I51_EDATA_C; + return true; + } + else if (strcmp (bfd_get_section_name (abfd, sec), ".bitbss") == 0) + { + *retval = SHN_I51_BITDATA_C; + return true; + } + return false; + } + + + static asection i51_elf_scom_section; + static asymbol i51_elf_scom_symbol; + static asymbol *i51_elf_scom_symbol_ptr; + + static asection i51_elf_rcom_section; + static asymbol i51_elf_rcom_symbol; + static asymbol *i51_elf_rcom_symbol_ptr; + + static asection i51_elf_bcom_section; + static asymbol i51_elf_bcom_symbol; + static asymbol *i51_elf_bcom_symbol_ptr; + + static asection i51_elf_icom_section; + static asymbol i51_elf_icom_symbol; + static asymbol *i51_elf_icom_symbol_ptr; + + static asection i51_elf_xcom_section; + static asymbol i51_elf_xcom_symbol; + static asymbol *i51_elf_xcom_symbol_ptr; + + static asection i51_elf_ecom_section; + static asymbol i51_elf_ecom_symbol; + static asymbol *i51_elf_ecom_symbol_ptr; + + static asection i51_elf_bitcom_section; + static asymbol i51_elf_bitcom_symbol; + static asymbol *i51_elf_bitcom_symbol_ptr; + + /* Handle the special I51 section numbers that a symbol may use. */ + + void + elf32_i51_symbol_processing (abfd, asym) + bfd *abfd ATTRIBUTE_UNUSED; + asymbol *asym; + { + elf_symbol_type *elfsym; + + elfsym = (elf_symbol_type *) asym; + + switch (elfsym->internal_elf_sym.st_shndx) + { + case SHN_I51_REGBANK: + if (i51_elf_scom_section.name == NULL) + { + /* Initialize the register common section. */ + i51_elf_scom_section.name = ".regbank"; + i51_elf_scom_section.flags = SEC_IS_COMMON; + i51_elf_scom_section.output_section = &i51_elf_scom_section; + i51_elf_scom_section.alignment_power = 0; + i51_elf_scom_section.symbol = &i51_elf_scom_symbol; + i51_elf_scom_section.symbol_ptr_ptr = &i51_elf_scom_symbol_ptr; + i51_elf_scom_symbol.name = ".regbank"; + i51_elf_scom_symbol.flags = BSF_SECTION_SYM; + i51_elf_scom_symbol.section = &i51_elf_scom_section; + i51_elf_scom_symbol_ptr = &i51_elf_scom_symbol; + } + asym->section = &i51_elf_scom_section; + asym->value = elfsym->internal_elf_sym.st_size; + break; + case SHN_I51_RDATA_C: + if (i51_elf_rcom_section.name == NULL) + { + /* Initialize the rdata common section. */ + i51_elf_rcom_section.name = ".rbss"; + i51_elf_rcom_section.flags = SEC_IS_COMMON; + i51_elf_rcom_section.output_section = &i51_elf_rcom_section; + i51_elf_rcom_section.alignment_power = 0; + i51_elf_rcom_section.symbol = &i51_elf_rcom_symbol; + i51_elf_rcom_section.symbol_ptr_ptr = &i51_elf_rcom_symbol_ptr; + i51_elf_rcom_symbol.name = ".rbss"; + i51_elf_rcom_symbol.flags = BSF_SECTION_SYM; + i51_elf_rcom_symbol.section = &i51_elf_rcom_section; + i51_elf_rcom_symbol_ptr = &i51_elf_rcom_symbol; + } + asym->section = &i51_elf_rcom_section; + asym->value = elfsym->internal_elf_sym.st_size; + break; + case SHN_I51_BDATA_C: + if (i51_elf_bcom_section.name == NULL) + { + /* Initialize the bdata common section. */ + i51_elf_bcom_section.name = ".bbss"; + i51_elf_bcom_section.flags = SEC_IS_COMMON; + i51_elf_bcom_section.output_section = &i51_elf_bcom_section; + i51_elf_bcom_section.alignment_power = 0; + i51_elf_bcom_section.symbol = &i51_elf_bcom_symbol; + i51_elf_bcom_section.symbol_ptr_ptr = &i51_elf_bcom_symbol_ptr; + i51_elf_bcom_symbol.name = ".bbss"; + i51_elf_bcom_symbol.flags = BSF_SECTION_SYM; + i51_elf_bcom_symbol.section = &i51_elf_bcom_section; + i51_elf_bcom_symbol_ptr = &i51_elf_bcom_symbol; + } + asym->section = &i51_elf_bcom_section; + asym->value = elfsym->internal_elf_sym.st_size; + break; + case SHN_I51_IDATA_C: + if (i51_elf_icom_section.name == NULL) + { + /* Initialize the idata common section. */ + i51_elf_icom_section.name = ".ibss"; + i51_elf_icom_section.flags = SEC_IS_COMMON; + i51_elf_icom_section.output_section = &i51_elf_icom_section; + i51_elf_icom_section.alignment_power = 0; + i51_elf_icom_section.symbol = &i51_elf_icom_symbol; + i51_elf_icom_section.symbol_ptr_ptr = &i51_elf_icom_symbol_ptr; + i51_elf_icom_symbol.name = ".ibss"; + i51_elf_icom_symbol.flags = BSF_SECTION_SYM; + i51_elf_icom_symbol.section = &i51_elf_icom_section; + i51_elf_icom_symbol_ptr = &i51_elf_icom_symbol; + } + asym->section = &i51_elf_icom_section; + asym->value = elfsym->internal_elf_sym.st_size; + break; + case SHN_I51_XDATA_C: + if (i51_elf_xcom_section.name == NULL) + { + /* Initialize the xdata common section. */ + i51_elf_xcom_section.name = ".xbss"; + i51_elf_xcom_section.flags = SEC_IS_COMMON; + i51_elf_xcom_section.output_section = &i51_elf_xcom_section; + i51_elf_xcom_section.alignment_power = 0; + i51_elf_xcom_section.symbol = &i51_elf_xcom_symbol; + i51_elf_xcom_section.symbol_ptr_ptr = &i51_elf_xcom_symbol_ptr; + i51_elf_xcom_symbol.name = ".xbss"; + i51_elf_xcom_symbol.flags = BSF_SECTION_SYM; + i51_elf_xcom_symbol.section = &i51_elf_xcom_section; + i51_elf_xcom_symbol_ptr = &i51_elf_xcom_symbol; + } + asym->section = &i51_elf_xcom_section; + asym->value = elfsym->internal_elf_sym.st_size; + break; + case SHN_I51_EDATA_C: + if (i51_elf_ecom_section.name == NULL) + { + /* Initialize the edata common section. */ + i51_elf_ecom_section.name = ".ebss"; + i51_elf_ecom_section.flags = SEC_IS_COMMON; + i51_elf_ecom_section.output_section = &i51_elf_ecom_section; + i51_elf_ecom_section.alignment_power = 0; + i51_elf_ecom_section.symbol = &i51_elf_ecom_symbol; + i51_elf_ecom_section.symbol_ptr_ptr = &i51_elf_ecom_symbol_ptr; + i51_elf_ecom_symbol.name = ".ebss"; + i51_elf_ecom_symbol.flags = BSF_SECTION_SYM; + i51_elf_ecom_symbol.section = &i51_elf_ecom_section; + i51_elf_ecom_symbol_ptr = &i51_elf_ecom_symbol; + } + asym->section = &i51_elf_ecom_section; + asym->value = elfsym->internal_elf_sym.st_size; + break; + case SHN_I51_BITDATA_C: + if (i51_elf_bitcom_section.name == NULL) + { + /* Initialize the bdata common section. */ + i51_elf_bitcom_section.name = ".bitbss"; + i51_elf_bitcom_section.flags = SEC_IS_COMMON; + i51_elf_bitcom_section.output_section = &i51_elf_bitcom_section; + i51_elf_bitcom_section.alignment_power = 0; + i51_elf_bitcom_section.symbol = &i51_elf_bitcom_symbol; + i51_elf_bitcom_section.symbol_ptr_ptr = &i51_elf_bitcom_symbol_ptr; + i51_elf_bitcom_symbol.name = ".bitbss"; + i51_elf_bitcom_symbol.flags = BSF_SECTION_SYM; + i51_elf_bitcom_symbol.section = &i51_elf_bitcom_section; + i51_elf_bitcom_symbol_ptr = &i51_elf_bitcom_symbol; + } + asym->section = &i51_elf_bitcom_section; + asym->value = elfsym->internal_elf_sym.st_size; + break; + } + } + + static boolean + elf32_i51_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp) + bfd *abfd; + struct bfd_link_info *info; + const Elf_Internal_Sym *sym; + const char **namep; + flagword *flagsp ATTRIBUTE_UNUSED; + asection **secp; + bfd_vma *valp; + + { + switch (sym->st_shndx) + { + case SHN_I51_REGBANK: + *secp = bfd_make_section_old_way (abfd, ".regbank"); + (*secp)->flags |= SEC_IS_COMMON; + *valp = sym->st_size; + break; + case SHN_I51_RDATA_C: + *secp = bfd_make_section_old_way (abfd, ".rbss"); + (*secp)->flags |= SEC_IS_COMMON; + *valp = sym->st_size; + break; + case SHN_I51_BDATA_C: + *secp = bfd_make_section_old_way (abfd, ".bbss"); + (*secp)->flags |= (SEC_IS_COMMON); + *valp = sym->st_size; + break; + case SHN_I51_IDATA_C: + *secp = bfd_make_section_old_way (abfd, ".ibss"); + (*secp)->flags |= SEC_IS_COMMON; + *valp = sym->st_size; + break; + case SHN_I51_XDATA_C: + *secp = bfd_make_section_old_way (abfd, ".xbss"); + (*secp)->flags |= SEC_IS_COMMON; + *valp = sym->st_size; + break; + case SHN_I51_EDATA_C: + *secp = bfd_make_section_old_way (abfd, ".ebss"); + (*secp)->flags |= SEC_IS_COMMON; + *valp = sym->st_size; + break; + case SHN_I51_BITDATA_C: + *secp = bfd_make_section_old_way (abfd, ".bitbss"); + (*secp)->flags |= SEC_IS_COMMON; + *valp = sym->st_size; + break; + } + return true; + } + + #define ELF_ARCH bfd_arch_i51 + #define ELF_MACHINE_CODE EM_I51 + #define ELF_MAXPAGESIZE 1 + + #define TARGET_BIG_SYM bfd_elf32_i51_vec + #define TARGET_BIG_NAME "elf32-i51" + + #define elf_info_to_howto i51_info_to_howto_rela + #define elf_info_to_howto_rel NULL + #define elf_backend_relocate_section elf32_i51_relocate_section + #define elf_backend_gc_mark_hook elf32_i51_gc_mark_hook + #define elf_backend_gc_sweep_hook elf32_i51_gc_sweep_hook + #define elf_backend_check_relocs elf32_i51_check_relocs + #define elf_backend_can_gc_sections 1 + #define elf_backend_final_write_processing \ + bfd_elf_i51_final_write_processing + #define elf_backend_object_p elf32_i51_object_p + + #define elf_backend_fake_sections i51_elf_fake_sections + #define elf_backend_section_from_shdr i51_elf_section_from_shdr + #define elf_backend_symbol_processing elf32_i51_symbol_processing + #define elf_backend_section_from_bfd_section elf32_i51_section_from_bfd_section + #define elf_backend_add_symbol_hook elf32_i51_add_symbol_hook + #include "elf32-target.h" diff -crN binutils.null/gas/config/tc-i51.c binutils-2.11.2.i51.new/gas/config/tc-i51.c *** binutils.null/gas/config/tc-i51.c Thu Jan 1 01:00:00 1970 --- binutils-2.11.2.i51.new/gas/config/tc-i51.c Sun Dec 30 10:49:19 2001 *************** *** 0 **** --- 1,2609 ---- + /* tc-i51.c -- Assembler code for the MCS-51 + + Copyright (C) 2001 Free Software Foundation, Inc. + Contributed by Radek Benedikt + + 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. */ + + #include + #include + #include "as.h" + #include "subsegs.h" + #include "elf/i51.h" + + //#define ASMDBG 1 + + /* forward declaration */ + static int check_range PARAMS ((long, int)); + static void fixup8 PARAMS ((expressionS *, int, int)); + static void fixup11 PARAMS ((expressionS *, unsigned int, int, int)); + static void fixup16 PARAMS ((expressionS *, int, int)); + static void i51_using PARAMS ((int)); + static void i51_bss PARAMS ((int)); + static void i51_rbss PARAMS ((int)); + static void i51_bbss PARAMS ((int)); + static void i51_ibss PARAMS ((int)); + static void i51_xbss PARAMS ((int)); + static void i51_ebss PARAMS ((int)); + static void i51_bitbss PARAMS ((int)); + static void i51_rdata PARAMS ((int)); + static void i51_bdata PARAMS ((int)); + static void i51_idata PARAMS ((int)); + static void i51_xdata PARAMS ((int)); + static void i51_edata PARAMS ((int)); + static void i51_bitdata PARAMS ((int)); + static void i51_eeprom PARAMS ((int)); + static void i51_pcode PARAMS ((int)); + static void i51_bit PARAMS ((int)); + void i51_common (int); + + #ifndef TC_PARSE_CONS_EXPRESSION + #ifdef BITFIELD_CONS_EXPRESSIONS + #define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) parse_bitfield_cons (EXP, NBYTES) + static void + parse_bitfield_cons PARAMS ((expressionS *exp, unsigned int nbytes)); + #endif + #ifdef REPEAT_CONS_EXPRESSIONS + #define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) parse_repeat_cons (EXP, NBYTES) + static void + parse_repeat_cons PARAMS ((expressionS *exp, unsigned int nbytes)); + #endif + + /* If we haven't gotten one yet, just call expression. */ + #ifndef TC_PARSE_CONS_EXPRESSION + #define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) expression (EXP) + #endif + #endif + + const char comment_chars[] = ";"; + const char line_comment_chars[] = "#"; + const char line_separator_chars[] = "$"; + const char EXP_CHARS[] = "eE"; + const char FLT_CHARS[] = "dD"; + + const char *md_shortopts = ""; + struct option md_longopts[] = + { + { NULL, no_argument, NULL, 0 } + }; + + /* The target specific pseudo-ops which we support. */ + const pseudo_typeS md_pseudo_table[] = + { + { "bit", i51_bit, 0 }, + { "using", i51_using, 0 }, + { "rcomm", i51_common, 0x01 }, + { "rcommon", i51_common, 0x01 }, + { "bitcomm", i51_common, 0x02 }, + { "bitcommon",i51_common, 0x02 }, + { "comm", i51_common, 0x00 }, + { "common", i51_common, 0x00 }, + { "icomm", i51_common, 0x03 }, + { "icommon", i51_common, 0x03 }, + { "xcomm", i51_common, 0x04 }, + { "xcommon", i51_common, 0x04 }, + { "ecomm", i51_common, 0x05 }, + { "ecommon", i51_common, 0x05 }, + { "bcomm", i51_common, 0x06 }, + { "bcommon", i51_common, 0x06 }, + { "bss", i51_bss, 0 }, + { "rbss", i51_rbss, 0 }, + { "bbss", i51_bbss, 0 }, + { "ibss", i51_ibss, 0 }, + { "xbss", i51_xbss, 0 }, + { "ebss", i51_ebss, 0 }, + { "bitbss", i51_bitbss, 0 }, + { "rdata", i51_rdata, 0 }, + { "bdata", i51_bdata, 0 }, + { "idata", i51_idata, 0 }, + { "xdata", i51_xdata, 0 }, + { "edata", i51_edata, 0 }, + { "bitdata", i51_bitdata, 0 }, + { "eeprom", i51_eeprom, 0 }, + { "pcode", i51_pcode, 0 }, + { NULL, NULL, 0 } + }; + + + size_t md_longopts_size = sizeof (md_longopts); + + #define I51_OP_IMM8 0x0001 + #define I51_OP_JUMP_REL 0x0002 + #define I51_OP_JUMP_INPAGE 0x0003 + #define I51_OP_IMM16 0x0004 + #define I51_OP_BIT 0x0005 + #define I51_OP_HIGH_ADDR 0x0100 + #define I51_OP_LOW_ADDR 0x0200 + #define I51_OP_B2B 0x0400 + + struct i51_opcodes_s + { + char *name; + char *args; + int insn_size; /* In bytes */ + unsigned char mreloc; /* modify & reloc mode */ + unsigned char bin_opcode; + }; + + struct i51_directop_s + { + char *op; + char ref; + unsigned char value; + }; + + #define I51_INS(NAME, ARGS, SIZE, OPCODE, MRELOC, BIN, MASK) \ + {NAME, ARGS, SIZE, MRELOC, BIN}, + + struct i51_opcodes_s i51_opcodes[] = + { + #include "opcode/i51.h" + {NULL, NULL, 0, 0, 0} + }; + + struct i51_directop_s i51_directop[] = + { + {"A", 'A', 0}, + {"AB", 'C', 0}, + {"R0", 'R', 0}, + {"R1", 'R', 1}, + {"R2", 'R', 2}, + {"R3", 'R', 3}, + {"R4", 'R', 4}, + {"R5", 'R', 5}, + {"R6", 'R', 6}, + {"R7", 'R', 7}, + {"C", 'r', 0}, + {"DPTR", 'P', 0}, + {"@A+DPTR",'@', 0}, + {"@A+PC", 'X', 0}, + {"@R0" , 'I', 0}, + {"@R1", 'I', 1}, + {"/C", '/', 0}, + {"@DPTR", 'T', 0}, + // BYTE register bank addressable registers + {"AR0", 'U', 0}, + {"AR1", 'U', 1}, + {"AR2", 'U', 2}, + {"AR3", 'U', 3}, + {"AR4", 'U', 4}, + {"AR5", 'U', 5}, + {"AR6", 'U', 6}, + {"AR7", 'U', 7}, + // BYTE addressable registers + {"P0", 'D',0x80}, + {"SP", 'D',0x81}, + {"DPL", 'D',0x82}, + {"DP0L", 'D',0x82}, // as called by Atmel + {"DPH", 'D',0x83}, + {"DP0H", 'D',0x83}, // as called by Atmel + {"DP1L", 'D',0x84}, // at89S8252 specific register + {"DP1H", 'D',0x85}, // at89S8252 specific register + {"SPDR", 'D',0x86}, // at89S8252 specific register + {"PCON", 'D',0x87}, + {"TCON", 'D',0x88}, + {"TMOD", 'D',0x89}, + {"TL0", 'D',0x8A}, + {"TL1", 'D',0x8B}, + {"TH0", 'D',0x8C}, + {"TH1", 'D',0x8D}, + {"P1", 'D',0x90}, + {"WMCON", 'D',0x96}, // at89S8252 specific register + {"SCON", 'D',0x98}, + {"SBUF", 'D',0x99}, + {"P2", 'D',0xA0}, + {"IE", 'D',0xA8}, + {"SPSR", 'D',0xAA}, // at89S8252 specific register + {"P3", 'D',0xB0}, + {"IP", 'D',0xB8}, + {"T2CON", 'D',0xC8}, + {"T2MOD", 'D',0xC9}, + {"RCAP2L", 'D',0xCA}, + {"RCAP2H", 'D',0xCB}, + {"TL2", 'D',0xCC}, + {"TH2", 'D',0xCD}, + {"PSW", 'D',0xD0}, + {"SPCR", 'D',0xD5}, // at89S8252 specific register + {"ACC", 'D',0xE0}, + {"B", 'D',0xF0}, + // BIT addressable registers + // P0 + {"P0.0", 'B',0x80}, + {"P0.1", 'B',0x81}, + {"P0.2", 'B',0x82}, + {"P0.3", 'B',0x83}, + {"P0.4", 'B',0x84}, + {"P0.5", 'B',0x85}, + {"P0.6", 'B',0x86}, + {"P0.7", 'B',0x87}, + // TCON + {"IT0", 'B',0x88}, + {"IE0", 'B',0x89}, + {"IT1", 'B',0x8A}, + {"IE1", 'B',0x8B}, + {"TR0", 'B',0x8C}, + {"TF0", 'B',0x8D}, + {"TR1", 'B',0x8E}, + {"TF1", 'B',0x8F}, + // P1 + {"P1.0", 'B',0x90}, + {"P1.1", 'B',0x91}, + {"P1.2", 'B',0x92}, + {"P1.3", 'B',0x93}, + {"P1.4", 'B',0x94}, + {"P1.5", 'B',0x95}, + {"P1.6", 'B',0x96}, + {"P1.7", 'B',0x97}, + {"T2", 'B',0x90}, + {"T2EX", 'B',0x91}, + // SCON + {"RI", 'B',0x98}, + {"TI", 'B',0x99}, + {"RB8", 'B',0x9A}, + {"TB8", 'B',0x9B}, + {"REN", 'B',0x9C}, + {"SM2", 'B',0x9D}, + {"SM1", 'B',0x9E}, + {"SM0", 'B',0x9F}, + // P2 + {"P2.0", 'B',0xA0}, + {"P2.1", 'B',0xA1}, + {"P2.2", 'B',0xA2}, + {"P2.3", 'B',0xA3}, + {"P2.4", 'B',0xA4}, + {"P2.5", 'B',0xA5}, + {"P2.6", 'B',0xA6}, + {"P2.7", 'B',0xA7}, + // IE + {"EX0", 'B',0xA8}, + {"ET0", 'B',0xA9}, + {"EX1", 'B',0xAA}, + {"ET1", 'B',0xAB}, + {"ES", 'B',0xAC}, + {"ET2", 'B',0xAD}, + {"EA", 'B',0xAF}, + // P3 + {"P3.0", 'B',0xB0}, + {"P3.1", 'B',0xB1}, + {"P3.2", 'B',0xB2}, + {"P3.3", 'B',0xB3}, + {"P3.4", 'B',0xB4}, + {"P3.5", 'B',0xB5}, + {"P3.6", 'B',0xB6}, + {"P3.7", 'B',0xB7}, + {"RXD", 'B',0xB0}, + {"TXD", 'B',0xB1}, + {"INT0", 'B',0xB2}, + {"INT1", 'B',0xB3}, + {"T0", 'B',0xB4}, + {"T1", 'B',0xB5}, + {"WR", 'B',0xB6}, + {"RD", 'B',0xB7}, + // IP + {"PX0", 'B',0xB8}, + {"PT0", 'B',0xB9}, + {"PX1", 'B',0xBA}, + {"PT1", 'B',0xBB}, + {"PS", 'B',0xBC}, + {"PT2", 'B',0xBD}, + // T2CON + {"T2CON.0",'B',0xC8}, + {"T2CON.1",'B',0xC9}, + {"T2CON.2",'B',0xCA}, + {"T2CON.3",'B',0xCB}, + {"T2CON.4",'B',0xCC}, + {"T2CON.5",'B',0xCD}, + {"T2CON.6",'B',0xCE}, + {"T2CON.7",'B',0xCF}, + {"CP_RL2", 'B',0xC8}, + {"C_T2", 'B',0xC9}, + {"TR2", 'B',0xCA}, + {"EXEN2", 'B',0xCB}, + {"TCLK", 'B',0xCC}, + {"RCLK", 'B',0xCD}, + {"EXF2", 'B',0xCE}, + {"TF2", 'B',0xCF}, + // PSW + {"P", 'B',0xD0}, + {"FL", 'B',0xD1}, + {"OV", 'B',0xD2}, + {"RS0", 'B',0xD3}, + {"RS1", 'B',0xD4}, + {"F0", 'B',0xD5}, + {"AC", 'B',0xD6}, + {"CY", 'B',0xD7}, + // ACC + {"ACC.0", 'B',0xE0}, + {"ACC.1", 'B',0xE1}, + {"ACC.2", 'B',0xE2}, + {"ACC.3", 'B',0xE3}, + {"ACC.4", 'B',0xE4}, + {"ACC.5", 'B',0xE5}, + {"ACC.6", 'B',0xE6}, + {"ACC.7", 'B',0xE7}, + // B + {"B.0", 'B',0xF0}, + {"B.1", 'B',0xF1}, + {"B.2", 'B',0xF2}, + {"B.3", 'B',0xF3}, + {"B.4", 'B',0xF4}, + {"B.5", 'B',0xF5}, + {"B.6", 'B',0xF6}, + {"B.7", 'B',0xF7}, + // + {NULL, '\0',0} + }; + + /* Opcode hash table. */ + static struct hash_control *i51_hash; + /* Operand hash table. */ + static struct hash_control *i51_operand; + + /* local variables */ + unsigned char regbank = 0xFF; + unsigned char regused = 0x00; + /* md_assemble */ + struct i51_opcodes_s *opcode; + struct i51_directop_s *oper; + char op[11]; + expressionS op_expr1; + expressionS op_expr2; + expressionS op_expr3; + expressionS op_expr4; + char *line; + unsigned char regno; + unsigned char op1mode; + unsigned char op2mode; + int op1hlmode; + int op2hlmode; + int b2b_offset; + enum PADRMODE { + DIRECTWORD, + DIRECTBYTE, + DIRECTSWAP, + DIRECTSHL8, + INDIRECTWORD, + INDIRECTBYTE, + INDIRECTSWAP + } p1mode, p2mode, p3mode, p4mode; + + /* Stuff for .regbank symbols. */ + static asection scom_section; + static asymbol scom_symbol; + /* Stuff for .rbbs symbols. */ + static segT rbss_section = NULL; + static asection rcom_section; + static asymbol rcom_symbol; + /* Stuff for .bbbs symbols. */ + static segT bbss_section = NULL; + static asection bcom_section; + static asymbol bcom_symbol; + /* Stuff for .ibbs symbols. */ + static segT ibss_section = NULL; + static asection icom_section; + static asymbol icom_symbol; + /* Stuff for .xbbs symbols. */ + static segT xbss_section = NULL; + static asection xcom_section; + static asymbol xcom_symbol; + /* Stuff for .ebbs symbols. */ + static segT ebss_section = NULL; + static asection ecom_section; + static asymbol ecom_symbol; + /* Stuff for .bitbbs symbols. */ + static segT bitbss_section = NULL; + static asection bitcom_section; + static asymbol bitcom_symbol; + /* Stuff for .?data */ + static segT rdata_section = NULL; + static segT bdata_section = NULL; + static segT idata_section = NULL; + static segT xdata_section = NULL; + static segT edata_section = NULL; + static segT eeprom_section = NULL; + static segT bitdata_section = NULL; + + /* local function */ + void i51_build_ins (struct i51_opcodes_s *, unsigned char, expressionS *, expressionS *); + void i51_parse_operand1 (void); + void i51_parse_operand2 (void); + static inline char * skip_space (char *); + long md_pcrel_from_section (fixS *, segT); + void pcodeOperand (expressionS *, enum PADRMODE *, int); + void writePcodeOperand (expressionS *, enum PADRMODE *, int swapable ATTRIBUTE_UNUSED); + unsigned short decodePcodeOperand (expressionS *, enum PADRMODE *, int); + + static inline char * + skip_space (s) + char *s; + { + while (*s == ' ' || *s == '\t') + ++s; + return s; + } + + /* Extract one word from FROM and copy it to TO. */ + + static char * + extract_word (char *from, char *to, int limit) + { + char *op_start; + char *op_end; + int size = 0; + + /* Drop leading whitespace. */ + from = skip_space (from); + *to = 0; + + /* Find the op code end. */ + for (op_start = op_end = from; *op_end != 0 && is_part_of_name (*op_end);) + { + to[size++] = *op_end++; + if (size + 1 >= limit) + break; + } + + to[size] = 0; + return op_end; + } + + /* Extract one word from FROM and copy it to TO. */ + + static char * + extract_op (char *from, char *to, int limit) + { + char *op_start; + char *op_end; + int size = 0; + + /* Drop leading whitespace. */ + from = skip_space (from); + *to = 0; + + /* Find the op code end. */ + for (op_start = op_end = from; *op_end != 0 && *op_end != ',' && *op_end != ' ';) + { + to[size++] = toupper(*op_end++); + if (size + 1 >= limit) + break; + } + + to[size] = 0; + return op_end; + } + + int + md_estimate_size_before_relax (fragp, seg) + fragS *fragp ATTRIBUTE_UNUSED; + asection *seg ATTRIBUTE_UNUSED; + { + abort (); + return 0; + } + + void + md_show_usage (stream) + FILE *stream; + { + fprintf (stream, + _("A51 options:\n" + " NONE\n")); + } + + + int + md_parse_option (c, arg) + int c; + char *arg; + { + return 0; + } + + + void + md_begin () + { + struct i51_opcodes_s *opcode; + struct i51_directop_s *oper; + i51_hash = hash_new (); + i51_operand = hash_new (); + + /* Insert unique names into hash table. This hash table then provides a + quick index to the first opcode with a particular name in the opcode + table. */ + for (opcode = i51_opcodes; opcode->name; opcode++) + hash_insert (i51_hash, opcode->name, (char *) opcode); + /* Insert unique names into hash table. This hash table then provides a + quick index to the operand table. */ + for (oper = i51_directop; oper->op; oper++) + hash_insert (i51_operand, oper->op, (char *) oper); + + /* We must construct a fake section similar to bfd_com_section + but with the name .regbank. */ + scom_section = bfd_com_section; + scom_section.name = ".regbank"; + scom_section.output_section = &scom_section; + scom_section.symbol = &scom_symbol; + scom_section.symbol_ptr_ptr = &scom_section.symbol; + scom_symbol = *bfd_com_section.symbol; + scom_symbol.name = ".regbank"; + scom_symbol.section = &scom_section; + /* We must construct a fake section similar to bfd_com_section + but with the name .rbss. */ + rcom_section = bfd_com_section; + rcom_section.name = ".rbss"; + rcom_section.output_section = &rcom_section; + rcom_section.symbol = &rcom_symbol; + rcom_section.symbol_ptr_ptr = &rcom_section.symbol; + rcom_symbol = *bfd_com_section.symbol; + rcom_symbol.name = ".rbss"; + rcom_symbol.section = &rcom_section; + /* We must construct a fake section similar to bfd_com_section + but with the name .bbss. */ + bcom_section = bfd_com_section; + bcom_section.name = ".bbss"; + bcom_section.output_section = &bcom_section; + bcom_section.symbol = &bcom_symbol; + bcom_section.symbol_ptr_ptr = &bcom_section.symbol; + bcom_symbol = *bfd_com_section.symbol; + bcom_symbol.name = ".bbss"; + bcom_symbol.section = &bcom_section; + /* We must construct a fake section similar to bfd_com_section + but with the name .ibss. */ + icom_section = bfd_com_section; + icom_section.name = ".ibss"; + icom_section.output_section = &icom_section; + icom_section.symbol = &icom_symbol; + icom_section.symbol_ptr_ptr = &icom_section.symbol; + icom_symbol = *bfd_com_section.symbol; + icom_symbol.name = ".ibss"; + icom_symbol.section = &icom_section; + /* We must construct a fake section similar to bfd_com_section + but with the name .xbss. */ + xcom_section = bfd_com_section; + xcom_section.name = ".xbss"; + xcom_section.output_section = &xcom_section; + xcom_section.symbol = &xcom_symbol; + xcom_section.symbol_ptr_ptr = &xcom_section.symbol; + xcom_symbol = *bfd_com_section.symbol; + xcom_symbol.name = ".xbss"; + xcom_symbol.section = &xcom_section; + /* We must construct a fake section similar to bfd_com_section + but with the name .ebss. */ + ecom_section = bfd_com_section; + ecom_section.name = ".ebss"; + ecom_section.output_section = &ecom_section; + ecom_section.symbol = &ecom_symbol; + ecom_section.symbol_ptr_ptr = &ecom_section.symbol; + ecom_symbol = *bfd_com_section.symbol; + ecom_symbol.name = ".ebss"; + ecom_symbol.section = &ecom_section; + /* We must construct a fake section similar to bfd_com_section + but with the name .bitbss. */ + bitcom_section = bfd_com_section; + bitcom_section.name = ".bitbss"; + bitcom_section.output_section = &bitcom_section; + bitcom_section.symbol = &bitcom_symbol; + bitcom_section.symbol_ptr_ptr = &bitcom_section.symbol; + bitcom_symbol = *bfd_com_section.symbol; + bitcom_symbol.name = ".bitbss"; + bitcom_symbol.section = &bitcom_section; + } + + void + md_assemble (str) + char *str; + { + #ifdef ASMDBG + fprintf(stderr, "%s\n",str); + #endif + op_expr1.X_op = O_max; + op_expr2.X_op = O_max; + + str = skip_space (extract_word (str, op, sizeof (op))); + + if (!op[0]) + { + as_bad (_("can't find opcode ")); + return; + } + + regno = 0; + + opcode = (struct i51_opcodes_s *) hash_find (i51_hash, op); + + if (opcode == NULL) + { + as_bad (_("unknown opcode `%s'"), op); + return; + } + else + { + op1mode = 'N'; + op2mode = 'N'; + line = skip_space (str); + if (*line != 0) + { + if (opcode->args[0] == 'N') + { + as_bad (_("garbage at end of line")); + return; + } + i51_parse_operand1 (); + line = skip_space (line); + if ((*line) && (opcode->args[1] == 'N')) + { + as_bad (_("garbage at end of line")); + return; + } + if (*line == ',') + { + line++; + i51_parse_operand2 (); + line = skip_space (line); + if ((*line) && (opcode->args[2] == 'N')) + { + as_bad (_("garbage at end of line")); + return; + } + if (opcode->args[2] == 'J') + { + if (*line == ',') + { + input_line_pointer = line+1; + //PARSE EXPRESION 2 + expression (&op_expr2); + line = input_line_pointer; + if (op_expr1.X_op == O_absent) + { + as_bad (_("missing operand 3")); + return; + } + } + else + { + as_bad (_("missing operand 3")); + return; + } + } + } + else if (opcode->args[1] != 'N') + { + as_bad (_("missing operand 2")); + return; + } + #ifdef ASMDBG + fprintf(stderr, "args: %s reg: %i\n\n", opcode->args, regno); + #endif + input_line_pointer = line; + } + else + { + if (opcode->args[0] != 'N') + { + as_bad (_("missing operand 1")); + return; + } + } + if ((op1mode == opcode->args[0]) && (op2mode == opcode->args[1])) + { + i51_build_ins (opcode, regno, &op_expr1, &op_expr2); + } + else + { + #ifdef ASMDBG + fprintf(stderr,"invalid instruction operands %c/%c %c/%c", op1mode, opcode->args[0], op2mode, opcode->args[1]); + #endif + as_bad (_("invalid instruction operands")); + return; + } + } + } + + /* GAS will call this function for each section at the end of the assembly, + to permit the CPU backend to adjust the alignment of a section. */ + + valueT + md_section_align (seg, addr) + asection *seg; + valueT addr; + { + int align = bfd_get_section_alignment (stdoutput, seg); + return ((addr + (1 << align) - 1) & (-1 << align)); + } + + /* If you define this macro, it should return the offset between the + address of a PC relative fixup and the position from which the PC + relative adjustment should be made. On many processors, the base + of a PC relative instruction is the next instruction, so this + macro would return the length of an instruction. */ + + long + md_pcrel_from_section (fixp, sec) + fixS *fixp; + segT sec; + { + if (fixp->fx_addsy != (symbolS *) NULL + && (!S_IS_DEFINED (fixp->fx_addsy) + || (S_GET_SEGMENT (fixp->fx_addsy) != sec))) + return 0; + return fixp->fx_frag->fr_address + fixp->fx_where + 1; + } + + /* GAS will call this for each fixup. It should store the correct + value in the object file. */ + + int + md_apply_fix3 (fixp, valuep, seg) + fixS *fixp; + valueT *valuep; + segT seg; + { + unsigned char *where; + unsigned long insn; + long value; + + if (fixp->fx_addsy == (symbolS *) NULL) + { + value = *valuep; + fixp->fx_done = 1; + } + else if (fixp->fx_pcrel) + { + segT s = S_GET_SEGMENT (fixp->fx_addsy); + + if (fixp->fx_addsy && (s == seg || s == absolute_section)) + { + value = S_GET_VALUE (fixp->fx_addsy) + *valuep; + fixp->fx_done = 1; + } + else + value = *valuep; + } + else + { + value = fixp->fx_offset; + + if (fixp->fx_subsy != (symbolS *) NULL) + { + if (S_GET_SEGMENT (fixp->fx_subsy) == absolute_section) + { + value -= S_GET_VALUE (fixp->fx_subsy); + fixp->fx_done = 1; + } + else + { + /* We don't actually support subtracting a symbol. */ + as_bad_where (fixp->fx_file, fixp->fx_line, + _("expression too complex")); + } + } + } + + switch (fixp->fx_r_type) + { + default: + fixp->fx_no_overflow = 1; + break; + } + + if (fixp->fx_done) + { + /* Fetch the instruction, insert the fully resolved operand + value, and stuff the instruction back again. */ + where = fixp->fx_frag->fr_literal + fixp->fx_where; + insn = bfd_getb16 (where); + + switch (fixp->fx_r_type) + { + case BFD_RELOC_I51_8_LOW: + // bfd_putb8 ((bfd_vma) value, (unsigned char *) where); + ((bfd_byte *) where)[0] = (bfd_byte) (value & 0xFF); + break; + + case BFD_RELOC_I51_8_HIGH: + if (value < -65536 || value > 65535) + as_bad_where (fixp->fx_file, fixp->fx_line, + _("operand out of range: %ld"), value); + value >>= 8; + /* Fall through. */ + + case BFD_RELOC_8: + case BFD_RELOC_I51_8_BIT: + if (value < -256 || value > 255) + as_bad_where (fixp->fx_file, fixp->fx_line, + _("operand out of range: %ld"), value); + // bfd_putb8 ((bfd_vma) value, (unsigned char *) where); + ((bfd_byte *) where)[0] = (bfd_byte) (value & 0xFF); + break; + + case BFD_RELOC_I51_7_PCREL: + if (value < -128 || value > 127) + as_bad_where (fixp->fx_file, fixp->fx_line, + _("operand out of range: %ld"), value); + // bfd_putb8 ((bfd_vma) value, (unsigned char *) where); + ((bfd_byte *) where)[0] = (bfd_byte) value; + #ifdef ASMDBG + fprintf(stderr, "fbdreloc7: %lx\n", value); + #endif + break; + + case BFD_RELOC_16: + bfd_putb16 ((bfd_vma) value, where); + break; + + case BFD_RELOC_I51_11: + value = (((value & 0x0700) << 5) | (value & 0x00FF)); + value |= insn; + bfd_putb16 ((bfd_vma) value, where); + break; + + default: + as_fatal (_("line %d: unknown relocation type: 0x%x"), + fixp->fx_line, fixp->fx_r_type); + break; + } + } + else + { + switch (fixp->fx_r_type) + { + default: + break; + } + fixp->fx_addnumber = value; + } + return 0; + } + + /* 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) + int type; + char *litp; + int *sizep; + { + int prec; + LITTLENUM_TYPE words[4]; + char *t; + int i; + + switch (type) + { + case 'f': + prec = 2; + break; + + case 'd': + prec = 4; + 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 * 2; + + if (target_big_endian) + { + for (i = 0; i < prec; i++) + { + md_number_to_chars (litp, (valueT) words[i], 2); + litp += 2; + } + } + else + { + for (i = prec - 1; i >= 0; i--) + { + md_number_to_chars (litp, (valueT) words[i], 2); + litp += 2; + } + } + + return NULL; + } + + static void + i51_bit (ignore) + int ignore ATTRIBUTE_UNUSED; + { + expressionS exp; + + if (is_it_end_of_statement ()) + { + demand_empty_rest_of_line (); + return; + } + + do + { + TC_PARSE_CONS_EXPRESSION (&exp, (unsigned int) 1); + if (exp.X_op == O_constant) + { + if ((exp.X_add_number > 1) || (exp.X_add_number < 0)) + { + as_bad (_("bit value is not in range 0..1 %ld"), exp.X_add_number); + return; + } + } + emit_expr (&exp, (unsigned int) 1); + } + while (*input_line_pointer++ == ','); + + input_line_pointer--; /* Put terminator back into stream. */ + + demand_empty_rest_of_line (); + } + + symbolS * + md_undefined_symbol (name) + char *name; + { + extract_op (name, op, sizeof (op)); + oper = (struct i51_directop_s *) hash_find (i51_operand, op); + if (oper == NULL) return 0; + if ((oper->ref == 'D') || (oper->ref == 'B')) + { + return (symbol_new (name, absolute_section, oper->value, &zero_address_frag)); + } + else if (oper->ref == 'U') + { + if (regbank == 0xFF) + { + as_bad (_("missing .using")); + return 0; + } + return (symbol_new (name, absolute_section, regbank + oper->value, &zero_address_frag)); + } + else return 0; + } + + void + md_convert_frag (abfd, sec, fragP) + bfd *abfd ATTRIBUTE_UNUSED; + asection *sec ATTRIBUTE_UNUSED; + fragS *fragP ATTRIBUTE_UNUSED; + { + abort (); + } + + /* A `BFD_ASSEMBLER' GAS will call this to generate a reloc. GAS + will pass the resulting reloc to `bfd_install_relocation'. This + currently works poorly, as `bfd_install_relocation' often does the + wrong thing, and instances of `tc_gen_reloc' have been written to + work around the problems, which in turns makes it difficult to fix + `bfd_install_relocation'. */ + + /* If while processing a fixup, a reloc really needs to be created + then it is done here. */ + + arelent * + tc_gen_reloc (seg, fixp) + asection *seg ATTRIBUTE_UNUSED; + fixS *fixp; + { + arelent *reloc; + + reloc = (arelent *) xmalloc (sizeof (arelent)); + + reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); + *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); + + reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; + reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type); + if (reloc->howto == (reloc_howto_type *) NULL) + { + as_bad_where (fixp->fx_file, fixp->fx_line, + _("reloc %d not supported by object file format"), + (int) fixp->fx_r_type); + return NULL; + } + + if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT + || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY) + reloc->address = fixp->fx_offset; + + reloc->addend = fixp->fx_offset; + + if (fixp->fx_pcrel) + reloc->addend -= 1; + + return reloc; + } + + void + i51_parse_operand1 (void) + { + int temp; + + input_line_pointer = line; + line = extract_op (line, op, sizeof (op)); + oper = (struct i51_directop_s *) hash_find (i51_operand, op); + op1hlmode = 0; + if (oper == NULL) + { + if (op[0] == '@') + { + as_bad (_("indirect prefix not allowed 1: `%s'"), op); + return; + } + else if (op[0] == '#') + { + input_line_pointer++; + op1mode = '#'; /* # - #data */ + + //scan hi/low prefix + if (strncmp (input_line_pointer, "HIGH(", 5) == 0) { input_line_pointer += 4; op1hlmode = I51_OP_HIGH_ADDR;} + else if (strncmp (input_line_pointer, "LOW(", 4) == 0) { input_line_pointer += 3; op1hlmode = I51_OP_LOW_ADDR;} + + while (((opcode->insn_size & 0x80) == 0) && ( opcode->args[0] != op1mode)) opcode++; + if (opcode->args[0] != op1mode) + { + as_bad (_("direct prefix not allowed 1: `%s'"), op); + return; + } + } + else + { + op1mode = ' '; + + //scan hi/low prefix + if (strncmp (input_line_pointer, "HIGH(", 5) == 0) { input_line_pointer += 4; op1hlmode = I51_OP_HIGH_ADDR;} + else if (strncmp (input_line_pointer, "LOW(", 4) == 0) { input_line_pointer += 3; op1hlmode = I51_OP_LOW_ADDR;} + else if (strncmp (input_line_pointer, "B2B(", 4) == 0) { input_line_pointer += 4; op1hlmode = I51_OP_B2B;} + + while (((opcode->insn_size & 0x80) == 0) && + ( opcode->args[0] != 'B') && /* B - bit */ + ( opcode->args[0] != 'D') && /* D - data */ + ( opcode->args[0] != 'J') && /* J - jump rel */ + ( opcode->args[0] != '1') && /* 1 - jump addr 11 */ + ( opcode->args[0] != '6') /* 6 - jump addr 16 */ + ) opcode++; + } + if ((opcode->insn_size & 0x80) != 0) + { + op1mode = opcode->args[0]; + } + else if (( opcode->args[0] != 'B') && ( opcode->args[0] != 'D')) + { + op1mode = opcode->args[0]; + } + //PARSE EXPRESION 1 + expression (&op_expr1); + if (op_expr1.X_op == O_absent) + { + as_bad (_("missing operand 1")); + return; + } + + if (op1hlmode == I51_OP_B2B) + { + SKIP_WHITESPACE (); + if (*input_line_pointer != ',') + { + as_bad (_("Expected comma after symbol-name")); + ignore_rest_of_line (); + return; + } + input_line_pointer++; /* skip ',' */ + if ((temp = get_absolute_expression ()) < 0) + { + as_bad (_("BYTE2BIT offset (%d.) <0! Ignored."), temp); + ignore_rest_of_line (); + return; + } + SKIP_WHITESPACE (); + if (*input_line_pointer != ')') + { + as_bad (_("Expected ) after offset")); + ignore_rest_of_line (); + return; + } + input_line_pointer++; /* skip ')' */ + b2b_offset = temp; + } + + line = input_line_pointer; + + #ifdef ASMDBG + fprintf(stderr, "op1: %c %s\n", op1mode, op); + //fprintf(stderr, "op1: %c %s %s\n", op1mode, op, S_GET_NAME(op_expr1.X_add_symbol)); + #endif + } + else + { + op1mode = oper->ref; + if(op1mode == 'U') op1mode = 'D'; + while (((opcode->insn_size & 0x80) == 0) && ( opcode->args[0] != op1mode)) opcode++; + if (opcode->args[0] != op1mode) + { + as_bad (_("unknown instruction operand 1: `%s'"), op); + return; + } + if ((op1mode == 'R') || (op1mode == 'I')) + { + regno = oper->value; + } + else if (oper->ref == 'U') + { + if (regbank == 0xFF) + { + as_bad (_("missing .using")); + return; + } + op_expr1.X_op = O_constant; + op_expr1.X_add_number = regbank + oper->value; + } + else if ((op1mode == 'D') || (op1mode == 'B')) + { + op_expr1.X_op = O_constant; + op_expr1.X_add_number = oper->value; + } + #ifdef ASMDBG + fprintf(stderr, "op1: %c %s\n", op1mode, op); + #endif + } + } + + void + i51_parse_operand2 (void) + { + int temp; + + input_line_pointer = line; + line = extract_op (line, op, sizeof (op)); + oper = (struct i51_directop_s *) hash_find (i51_operand, op); + op2hlmode = 0; + if (oper == NULL) + { + if (op[0] == '@') + { + as_bad (_("indirect prefix not allowed 2: `%s'"), op); + return; + } + else if (op[0] == '#') + { + input_line_pointer++; + op2mode = op[0]; /* # - #data */ + + //scan hi/low prefix + if (strncmp (input_line_pointer, "HIGH(", 5) == 0) { input_line_pointer += 4; op2hlmode = I51_OP_HIGH_ADDR;} + else if (strncmp (input_line_pointer, "LOW(", 4) == 0) { input_line_pointer += 3; op2hlmode = I51_OP_LOW_ADDR;} + + while (((opcode->insn_size & 0x80) == 0) && ( opcode->args[1] != op2mode)) opcode++; + if (opcode->args[1] != op2mode) + { + as_bad (_("direct prefix not allowed 2: `%s'"), op); + return; + } + if (op1mode == ' ') op1mode = 'D'; + } + else if (op[0] == '/') + { + op2mode = op[0]; /* - - /bit */ + while (((opcode->insn_size & 0x80) == 0) && ( opcode->args[1] != op2mode)) opcode++; + if (opcode->args[1] != op2mode) + { + as_bad (_("negation prefix not allowed 2: `%s'"), op); + return; + } + if (op1mode == ' ') op1mode = 'B'; + input_line_pointer++; + } + else + { + //op2mode = ' '; + + //scan hi/low prefix + if (strncmp (input_line_pointer, "HIGH(", 5) == 0) + { + input_line_pointer += 4; + op2hlmode = I51_OP_HIGH_ADDR; + } + else if (strncmp (input_line_pointer, "LOW(", 4) == 0) + { + input_line_pointer += 3; + op2hlmode = I51_OP_LOW_ADDR; + } + else if ((op_expr1.X_op == O_max) && (strncmp (input_line_pointer, "B2B(", 4) == 0)) + { + input_line_pointer += 4; + op2hlmode = I51_OP_B2B; + } + + while (((opcode->insn_size & 0x80) == 0) && + ( opcode->args[1] != 'B') && /* B - bit */ + ( opcode->args[1] != 'D') && /* D - data */ + ( opcode->args[1] != 'J') && /* J - jump rel */ + ( opcode->args[1] != 'd') /* d - data16 */ + ) opcode++; + } + op2mode = opcode->args[1]; + + if (op1mode == ' ') op1mode = opcode->args[0]; + + //PARSE EXPRESION 1 / 2 + if (op_expr1.X_op == O_max) + { + op1hlmode = op2hlmode; + expression (&op_expr1); + if (op_expr1.X_op == O_absent) + { + as_bad (_("missing operand 2")); + return; + } + if (op2hlmode == I51_OP_B2B) + { + SKIP_WHITESPACE (); + if (*input_line_pointer != ',') + { + as_bad (_("Expected comma after symbol-name")); + ignore_rest_of_line (); + return; + } + input_line_pointer++; /* skip ',' */ + if ((temp = get_absolute_expression ()) < 0) + { + as_bad (_("BYTE2BIT offset (%d.) <0! Ignored."), temp); + ignore_rest_of_line (); + return; + } + SKIP_WHITESPACE (); + if (*input_line_pointer != ')') + { + as_bad (_("Expected ) after offset")); + ignore_rest_of_line (); + return; + } + input_line_pointer++; /* skip ')' */ + b2b_offset = temp; + } + } + else + { + expression (&op_expr2); + if (op_expr2.X_op == O_absent) + { + as_bad (_("missing operand 2")); + return; + } + } + + line = input_line_pointer; + + #ifdef ASMDBG + fprintf(stderr, "op2: %c %s\n", op2mode, op); + #endif + } + else + { + op2mode = oper->ref; + if(op2mode == 'U') op2mode = 'D'; + while (((opcode->insn_size & 0x80) == 0) && ( opcode->args[1] != op2mode)) opcode++; + if (opcode->args[1] != op2mode) + { + as_bad (_("unknown instruction operand 2: `%s'"), op); + return; + } + if ((opcode->args[0] != op1mode) && + ((op1mode != ' ') || ((opcode->args[0] != 'B') && (opcode->args[0] != 'D'))) ) + { + as_bad (_("unknown instruction operand 2: `%s'"), op); + return; + } + if (op1mode == ' ') op1mode = opcode->args[0]; + if ((op2mode == 'R') || (op2mode == 'I')) + { + regno = oper->value; + } + else if (oper->ref == 'U') + { + if (regbank == 0xFF) + { + as_bad (_("missing .using")); + return; + } + if (op_expr1.X_op == O_max) + { + op_expr1.X_op = O_constant; + op_expr1.X_add_number = regbank + oper->value; + } + else + { + op_expr2.X_op = O_constant; + op_expr2.X_add_number = regbank + oper->value; + } + } + else if ((op2mode == 'D') || (op2mode == 'B')) + { + if (op_expr1.X_op == O_max) + { + op_expr1.X_op = O_constant; + op_expr1.X_add_number = oper->value; + } + else + { + op_expr2.X_op = O_constant; + op_expr2.X_add_number = oper->value; + } + } + #ifdef ASMDBG + fprintf(stderr, "op2: %c %s\n", op2mode, op); + #endif + } + } + + void + i51_build_ins (opcode, regnumber, op_expr1, op_expr2) + struct i51_opcodes_s *opcode; + unsigned char regnumber; + expressionS *op_expr1; + expressionS *op_expr2; + { + unsigned char bin_opcode; + char *frag; + + bin_opcode = opcode->bin_opcode; + /* place register operand to instruction code */ + switch (opcode->mreloc) { + case 'I': // register indirect - IIIIIIIr + case 'i': // reg. indirect, data - IIIIIIIr dddddddd + case 'X': // reg. indirect, r. jump 8 bit - IIIIIIIr dddddddd aaaaaaaa + regnumber &= 0x01; + bin_opcode |= regnumber; + break; + case 'R': // register - IIIIIrrr + case 'r': // register,data - IIIIIrrr dddddddd + case 'Y': // register, rel. jump 8 bit - IIIIIrrr dddddddd aaaaaaaa + case 'W': // register, rel. jump 8 bit - IIIIIrrr aaaaaaaa + regnumber &= 0x07; + bin_opcode |= regnumber; + break; + default: + break; + } + + switch (opcode->mreloc) { + case '7': //relative jump 8 bit - IIIIIIII aaaaaaaa + case 'W': //register, rel. jump 8 bit - IIIIIrrr aaaaaaaa + case '1': //jump 11 bit - aaaIIIII aaaaaaaa + case '6': //data/jump 16 bit - IIIIIIII aaaaaaaa aaaaaaaa + if (op1hlmode) + { + as_bad (_("HI/LOW/B2B prefix not allowed")); + return; + } + default: + break; + } + + switch (opcode->mreloc) { + case 'N': //none - IIIIIIII + case 'I': //register indirect - IIIIIIIr + case 'R': //register - IIIIIrrr + frag = frag_more (1); + number_to_chars_bigendian (frag, bin_opcode, 1); + break; + + case 'D': //data 8 bit - IIIIIIII dddddddd + case 'i': //reg. indirect, data - IIIIIIIr dddddddd + case 'r': //register,data - IIIIIrrr dddddddd + frag = frag_more (1); + number_to_chars_bigendian (frag, bin_opcode, 1); + fixup8 (op_expr1, I51_OP_IMM8, op1hlmode); + break; + + case '7': //relative jump 8 bit - IIIIIIII aaaaaaaa + case 'W': //register, rel. jump 8 bit - IIIIIrrr aaaaaaaa + frag = frag_more (1); + number_to_chars_bigendian (frag, bin_opcode, 1); + fixup8 (op_expr1, I51_OP_JUMP_REL, 0); + break; + + case '1': //jump 11 bit - aaaIIIII aaaaaaaa + fixup11(op_expr1, bin_opcode, I51_OP_JUMP_INPAGE, 0); + break; + + case 'B': //bitdata 8 bit - IIIIIIII bbbbbbbb + frag = frag_more (1); + number_to_chars_bigendian (frag, bin_opcode, 1); + fixup8 (op_expr1, I51_OP_BIT, op1hlmode); + break; + + case 'd': //data,data 8 bit - IIIIIIII dddddddd dddddddd + frag = frag_more (1); + number_to_chars_bigendian (frag, bin_opcode, 1); + fixup8 (op_expr2, I51_OP_IMM8, op2hlmode); + fixup8 (op_expr1, I51_OP_IMM8, op1hlmode); + break; + + case 'a': //adr,data 8 bit - IIIIIIII aaaaaaaa dddddddd + frag = frag_more (1); + number_to_chars_bigendian (frag, bin_opcode, 1); + fixup8 (op_expr1, I51_OP_IMM8, op1hlmode); + fixup8 (op_expr2, I51_OP_IMM8, op2hlmode); + break; + + case 'J': //bit, r. jump 8 bit - IIIIIIII bbbbbbbb aaaaaaaa + frag = frag_more (1); + number_to_chars_bigendian (frag, bin_opcode, 1); + fixup8 (op_expr1, I51_OP_BIT, op1hlmode); + fixup8 (op_expr2, I51_OP_JUMP_REL, 0); + break; + + case 'X': //reg. indirect, r. jump 8 bit - IIIIIIIr dddddddd aaaaaaaa + case 'Y': //register, rel. jump 8 bit - IIIIIrrr dddddddd aaaaaaaa + case 'Z': //data 8 bit, r. jump 8 bit - IIIIIIII dddddddd aaaaaaaa + frag = frag_more (1); + number_to_chars_bigendian (frag, bin_opcode, 1); + fixup8 (op_expr1, I51_OP_IMM8, op1hlmode); + fixup8 (op_expr2, I51_OP_JUMP_REL, 0); + break; + + case '6': //data/jump 16 bit - IIIIIIII aaaaaaaa aaaaaaaa + frag = frag_more (1); + number_to_chars_bigendian (frag, bin_opcode, 1); + fixup16 (op_expr1, I51_OP_IMM16, 0); + break; + } + } + + /* Checks that the number 'num' fits for a given mode. */ + static int + check_range (num, mode) + long num; + int mode; + { + switch (mode) + { + case I51_OP_IMM8: + case I51_OP_BIT: + return (((num & 0xFFFFFF00) == 0) || ((num & 0xFFFFFF00) == 0xFFFFFF00)) ? 1 : 0; + + case I51_OP_JUMP_REL: + return (num >= -128 && num <= 127) ? 1 : 0; + + case I51_OP_JUMP_INPAGE: + return ((num & 0xFFFFF800) == 0); + + case I51_OP_IMM16: + case I51_OP_HIGH_ADDR: + return (((num & 0xFFFF0000) == 0) || ((num & 0xFFFF0000) == 0xFFFF0000)) ? 1 : 0; + + case I51_OP_LOW_ADDR: + return 1; + + default: + return 0; + } + } + + /* Gas fixup generation. */ + + /* Put a 1 byte expression described by 'oper'. If this expression contains + unresolved symbols, generate an 8-bit fixup. */ + static void + fixup8 (oper, mode, opmode) + expressionS *oper; + int mode; + int opmode; + { + char *f; + + f = frag_more (1); + + if (oper->X_op == O_constant) + { + switch (opmode) { + case I51_OP_HIGH_ADDR: + if (!check_range (oper->X_add_number, opmode)) + { + as_bad (_("HIGH Operand out of 8-bit range: `%ld'."), + oper->X_add_number); + } + number_to_chars_bigendian (f, ((oper->X_add_number >> 8)) & 0xFF, 1); + break; + case I51_OP_LOW_ADDR: + if (!check_range (oper->X_add_number, opmode)) + { + as_bad (_("LOW Operand out of 8-bit range: `%ld'."), + oper->X_add_number); + } + number_to_chars_bigendian (f, (oper->X_add_number & 0xFF), 1); + break; + case I51_OP_B2B: + if ((oper->X_add_number < 0x20) || + ((oper->X_add_number < 0x30) && (((oper->X_add_number - 0x20) * 8 + b2b_offset) > 0x80)) || + ((oper->X_add_number >= 0x30) && (oper->X_add_number < 0x80)) || + ((oper->X_add_number + b2b_offset) > 0x100) ) + { + as_bad (_("Operand out of bit range: B2B(%ld,%d)."), + oper->X_add_number, b2b_offset); + } + if (oper->X_add_number < 0x30) + { + number_to_chars_bigendian (f, ((oper->X_add_number - 0x20) * 8 + b2b_offset), 1); + } + else + { + number_to_chars_bigendian (f, (oper->X_add_number + b2b_offset), 1); + } + break; + default: + if (!check_range (oper->X_add_number, mode)) + { + as_bad (_("Operand out of 8-bit range: `%ld'."), + oper->X_add_number); + } + number_to_chars_bigendian (f, (oper->X_add_number & 0xFF), 1); + break; + } + } + else if (oper->X_op != O_register) + { + switch (mode) { + case I51_OP_IMM8: + /* Now create an 8-bit fixup. If there was some %hi or %lo + modifier, generate the reloc accordingly. */ + fix_new_exp (frag_now, f - frag_now->fr_literal, 1, + oper, false, + ((opmode & I51_OP_HIGH_ADDR) + ? BFD_RELOC_I51_8_HIGH + : ((opmode & I51_OP_LOW_ADDR) + ? BFD_RELOC_I51_8_LOW : BFD_RELOC_8))); + number_to_chars_bigendian (f, 0, 1); + break; + case I51_OP_JUMP_REL: + /* Now create an 8-bit relative jump fixup */ + fix_new_exp (frag_now, f - frag_now->fr_literal, 1, + oper, true, BFD_RELOC_I51_7_PCREL); + number_to_chars_bigendian (f, 0, 1); + break; + case I51_OP_BIT: + /* Now create an 8-bit bit B2B area fixup */ + fix_new_exp (frag_now, f - frag_now->fr_literal, 1, + oper, false, + (opmode & I51_OP_B2B + ? BFD_RELOC_I51_8_B2B : BFD_RELOC_I51_8_BIT)); + number_to_chars_bigendian (f, (opmode & I51_OP_B2B + ? b2b_offset : 0), 1); + break; + } + } + else + { + as_fatal (_("Operand `%x' not recognized in fixup8."), oper->X_op); + } + } + + /* Put a 11 bit expression described by 'oper'. If this expression contains + unresolved symbols, generate an 11-bit fixup. */ + static void + fixup11 (oper, opcode, mode, opmode) + expressionS *oper; + unsigned int opcode; + int mode; + int opmode ATTRIBUTE_UNUSED; + { + char *f; + + f = frag_more (2); + + if (oper->X_op == O_constant) + { + if (!check_range (oper->X_add_number, mode)) + { + as_bad (_("Operand out of 11-bit range: `%ld'."), + oper->X_add_number); + } + number_to_chars_bigendian (f, ((oper->X_add_number & 0x0700) << 5) | (opcode << 8) | (oper->X_add_number & 0x00FF), 2); + } + else if (oper->X_op != O_register) + { + switch (mode) { + case I51_OP_JUMP_INPAGE: + /* Now create an 11-bit inpage jump fixup */ + fix_new_exp (frag_now, f - frag_now->fr_literal, 1, + oper, false,BFD_RELOC_I51_11); + number_to_chars_bigendian (f, (opcode << 8), 2); + break; + } + } + else + { + as_fatal (_("Operand `%x' not recognized in fixup8."), oper->X_op); + } + } + + /* Put a 2 byte expression described by 'oper'. If this expression contains + unresolved symbols, generate a 16-bit fixup. */ + static void + fixup16 (oper, mode, opmode) + expressionS *oper; + int mode; + int opmode ATTRIBUTE_UNUSED; + { + char *f; + + f = frag_more (2); + + if (oper->X_op == O_constant) + { + if (!check_range (oper->X_add_number, mode)) + { + as_bad (_("Operand out of 16-bit range: `%ld'."), + oper->X_add_number); + } + number_to_chars_bigendian (f, oper->X_add_number & 0x0FFFF, 2); + } + else if (oper->X_op != O_register) + { + fixS *fixp; + + /* Now create a 16-bit fixup. */ + fixp = fix_new_exp (frag_now, f - frag_now->fr_literal, 2, + oper, + false, + BFD_RELOC_16); + number_to_chars_bigendian (f, 0, 2); + } + else + { + as_fatal (_("Operand `%x' not recognized in fixup16."), oper->X_op); + } + } + + int + i51_section_flags (flags, attr, type) + int flags; + int attr; + int type ATTRIBUTE_UNUSED; + { + if (attr & SHF_REGBANK) + flags |= SEC_IS_COMMON; + + return flags; + } + + static void + i51_using (par) + int par ATTRIBUTE_UNUSED; + { + switch (*input_line_pointer++) + { + case '0': /* Reg bank 0 */ + regbank = 0; + break; + case '1': /* Reg bank 1 */ + regbank = 8; + break; + case '2': /* Reg bank 2 */ + regbank = 16; + break; + case '3': /* Reg bank 3 */ + regbank = 24; + break; + default: + as_bad ("unsupported register bank"); + return; + } + if (regbank > regused) regused = regbank; + } + + /* + void + i51_set (name) + char *name; + { + register symbolS *symbolP; + + if ((symbol_find (name) == NULL) && (md_undefined_symbol (name) == NULL)) + { + symbolP = symbol_new (name, absolute_section, 0, &zero_address_frag); + symbol_table_insert (symbolP); + } + } + */ + + void + i51_cleanup () + { + symbolS *symbolP; + + if (regbank != 0xFF) + { + + symbolP = symbol_find_or_make ("__RB__"); + + S_SET_VALUE (symbolP, (valueT) regused+8); + S_SET_EXTERNAL (symbolP); + S_SET_SEGMENT (symbolP, &scom_section); + + know (symbolP->sy_frag == &zero_address_frag); + + regbank = 0xFF; + regused = 0; + } + } + + void + i51_common (common_segment) + int common_segment; + { + char *name; + char c; + char *p; + int temp, size; + symbolS *symbolP; + int align; + + if (flag_mri) + { + as_bad (_("not implemented in MRI mode")); + return; + } + + name = input_line_pointer; + c = get_symbol_end (); + /* just after name is now '\0' */ + p = input_line_pointer; + *p = c; + SKIP_WHITESPACE (); + if (*input_line_pointer != ',') + { + as_bad (_("Expected comma after symbol-name")); + ignore_rest_of_line (); + return; + } + input_line_pointer++; /* skip ',' */ + if ((temp = get_absolute_expression ()) < 0) + { + as_bad (_(".COMMon length (%d.) <0! Ignored."), temp); + ignore_rest_of_line (); + return; + } + size = temp; + *p = 0; + symbolP = symbol_find_or_make (name); + *p = c; + if (S_IS_DEFINED (symbolP) && ! S_IS_COMMON (symbolP)) + { + as_bad (_("Ignoring attempt to re-define symbol")); + ignore_rest_of_line (); + return; + } + if (S_GET_VALUE (symbolP) != 0) + { + if (S_GET_VALUE (symbolP) != (valueT) size) + { + as_warn (_("Length of .comm \"%s\" is already %ld. Not changed to %d."), + S_GET_NAME (symbolP), (long) S_GET_VALUE (symbolP), size); + } + } + know (symbolP->sy_frag == &zero_address_frag); + if (*input_line_pointer != ',') + temp = 0; + else + { + input_line_pointer++; + SKIP_WHITESPACE (); + temp = get_absolute_expression (); + if (temp < 0) + { + temp = 0; + as_warn (_("Common alignment negative; 0 assumed")); + } + } + if (temp) + { + /* convert to a power of 2 alignment */ + for (align = 0; (temp & 1) == 0; temp >>= 1, ++align); + if (temp != 1) + { + as_bad (_("Common alignment not a power of 2")); + ignore_rest_of_line (); + return; + } + } + else + align = 0; + if (symbol_get_obj (symbolP)->local) + { + segT old_sec; + int old_subsec; + char *pfrag; + flagword applicable; + + /* allocate_?bss: */ + old_sec = now_seg; + old_subsec = now_subseg; + + applicable = bfd_applicable_section_flags (stdoutput); + applicable &= SEC_ALLOC; + + switch (common_segment & 0x7F) + { + case 0: //comm + record_alignment (bss_section, align); + subseg_set (bss_section, 0); + if (align) + frag_align (align, 0, 0); + if (S_GET_SEGMENT (symbolP) == bss_section) + symbol_get_frag (symbolP)->fr_symbol = 0; + symbol_set_frag (symbolP, frag_now); + pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP, + (offsetT) size, (char *) 0); + *pfrag = 0; + S_SET_SIZE (symbolP, size); + S_SET_SEGMENT (symbolP, bss_section); + break; + case 1: //rcomm + if (rbss_section == NULL) + { + rbss_section = subseg_new (".rbss", 0); + bfd_set_section_flags (stdoutput, rbss_section, applicable); + seg_info (rbss_section)->bss = 1; + } + record_alignment (rbss_section, align); + subseg_set (rbss_section, 0); + if (align) + frag_align (align, 0, 0); + if (S_GET_SEGMENT (symbolP) == rbss_section) + symbol_get_frag (symbolP)->fr_symbol = 0; + symbol_set_frag (symbolP, frag_now); + pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP, + (offsetT) size, (char *) 0); + *pfrag = 0; + S_SET_SIZE (symbolP, size); + S_SET_SEGMENT (symbolP, rbss_section); + break; + case 2: //bitcomm + if (bitbss_section == NULL) + { + bitbss_section = subseg_new (".bitbss", 0); + bfd_set_section_flags (stdoutput, bitbss_section, applicable); + seg_info (bitbss_section)->bss = 1; + } + record_alignment (bitbss_section, align); + subseg_set (bitbss_section, 0); + if (align) + frag_align (align, 0, 0); + if (S_GET_SEGMENT (symbolP) == bitbss_section) + symbol_get_frag (symbolP)->fr_symbol = 0; + symbol_set_frag (symbolP, frag_now); + pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP, + (offsetT) size, (char *) 0); + *pfrag = 0; + S_SET_SIZE (symbolP, size); + S_SET_SEGMENT (symbolP, bitbss_section); + break; + case 3: //icomm + if (ibss_section == NULL) + { + ibss_section = subseg_new (".ibss", 0); + bfd_set_section_flags (stdoutput, ibss_section, applicable); + seg_info (ibss_section)->bss = 1; + } + record_alignment (ibss_section, align); + subseg_set (ibss_section, 0); + if (align) + frag_align (align, 0, 0); + if (S_GET_SEGMENT (symbolP) == ibss_section) + symbol_get_frag (symbolP)->fr_symbol = 0; + symbol_set_frag (symbolP, frag_now); + pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP, + (offsetT) size, (char *) 0); + *pfrag = 0; + S_SET_SIZE (symbolP, size); + S_SET_SEGMENT (symbolP, ibss_section); + break; + case 4: //xcomm + if (xbss_section == NULL) + { + xbss_section = subseg_new (".xbss", 0); + bfd_set_section_flags (stdoutput, xbss_section, applicable); + seg_info (xbss_section)->bss = 1; + } + record_alignment (xbss_section, align); + subseg_set (xbss_section, 0); + if (align) + frag_align (align, 0, 0); + if (S_GET_SEGMENT (symbolP) == xbss_section) + symbol_get_frag (symbolP)->fr_symbol = 0; + symbol_set_frag (symbolP, frag_now); + pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP, + (offsetT) size, (char *) 0); + *pfrag = 0; + S_SET_SIZE (symbolP, size); + S_SET_SEGMENT (symbolP, xbss_section); + break; + case 5: //ecomm + if (ebss_section == NULL) + { + ebss_section = subseg_new (".ebss", 0); + bfd_set_section_flags (stdoutput, ebss_section, applicable); + seg_info (ebss_section)->bss = 1; + } + record_alignment (ebss_section, align); + subseg_set (ebss_section, 0); + if (align) + frag_align (align, 0, 0); + if (S_GET_SEGMENT (symbolP) == ebss_section) + symbol_get_frag (symbolP)->fr_symbol = 0; + symbol_set_frag (symbolP, frag_now); + pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP, + (offsetT) size, (char *) 0); + *pfrag = 0; + S_SET_SIZE (symbolP, size); + S_SET_SEGMENT (symbolP, ebss_section); + break; + case 6: //bcomm + if (bbss_section == NULL) + { + bbss_section = subseg_new (".bbss", 0); + bfd_set_section_flags (stdoutput, bbss_section, applicable); + seg_info (bbss_section)->bss = 1; + } + record_alignment (bbss_section, align); + subseg_set (bbss_section, 0); + if (align) + frag_align (align, 0, 0); + if (S_GET_SEGMENT (symbolP) == bbss_section) + symbol_get_frag (symbolP)->fr_symbol = 0; + symbol_set_frag (symbolP, frag_now); + pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP, + (offsetT) size, (char *) 0); + *pfrag = 0; + S_SET_SIZE (symbolP, size); + S_SET_SEGMENT (symbolP, bbss_section); + break; + } + S_CLEAR_EXTERNAL (symbolP); + subseg_set (old_sec, old_subsec); + } + else + { + S_SET_VALUE (symbolP, (valueT) size); + S_SET_ALIGN (symbolP, temp); + S_SET_EXTERNAL (symbolP); + switch (common_segment) { + case 0: //comm + S_SET_SEGMENT (symbolP, bfd_com_section_ptr); + break; + case 1: //rcomm + S_SET_SEGMENT (symbolP, &rcom_section); + break; + case 2: //bitcomm + S_SET_SEGMENT (symbolP, &bitcom_section); + break; + case 3: //icomm + S_SET_SEGMENT (symbolP, &icom_section); + break; + case 4: //xcomm + S_SET_SEGMENT (symbolP, &xcom_section); + break; + case 5: //ecomm + S_SET_SEGMENT (symbolP, &ecom_section); + break; + case 6: //bcomm + S_SET_SEGMENT (symbolP, &bcom_section); + break; + } + } + + symbol_get_bfdsym (symbolP)->flags |= BSF_OBJECT; + + demand_empty_rest_of_line (); + return; + } + + void + i51_rbss (ignore) + int ignore ATTRIBUTE_UNUSED; + { + flagword applicable; + if (rbss_section == NULL) + { + applicable = bfd_applicable_section_flags (stdoutput); + applicable &= SEC_ALLOC; + rbss_section = subseg_new (".rbss", 0); + bfd_set_section_flags (stdoutput, rbss_section, applicable); + seg_info (rbss_section)->bss = 1; + } + obj_elf_section_change_hook (); + subseg_set (rbss_section, (subsegT) get_absolute_expression ()); + demand_empty_rest_of_line (); + } + + void + i51_bss (ignore) + int ignore ATTRIBUTE_UNUSED; + { + obj_elf_section_change_hook (); + subseg_set (bss_section, (subsegT) get_absolute_expression ()); + demand_empty_rest_of_line (); + } + + void + i51_bbss (ignore) + int ignore ATTRIBUTE_UNUSED; + { + flagword applicable; + if (bbss_section == NULL) + { + applicable = bfd_applicable_section_flags (stdoutput); + applicable &= SEC_ALLOC; + bbss_section = subseg_new (".bbss", 0); + bfd_set_section_flags (stdoutput, bbss_section, applicable); + seg_info (bbss_section)->bss = 1; + } + obj_elf_section_change_hook (); + subseg_set (bbss_section, (subsegT) get_absolute_expression ()); + demand_empty_rest_of_line (); + } + + void + i51_ibss (ignore) + int ignore ATTRIBUTE_UNUSED; + { + flagword applicable; + if (ibss_section == NULL) + { + applicable = bfd_applicable_section_flags (stdoutput); + applicable &= SEC_ALLOC; + ibss_section = subseg_new (".ibss", 0); + bfd_set_section_flags (stdoutput, ibss_section, applicable); + seg_info (ibss_section)->bss = 1; + } + obj_elf_section_change_hook (); + subseg_set (ibss_section, (subsegT) get_absolute_expression ()); + demand_empty_rest_of_line (); + } + + void + i51_xbss (ignore) + int ignore ATTRIBUTE_UNUSED; + { + flagword applicable; + if (xbss_section == NULL) + { + applicable = bfd_applicable_section_flags (stdoutput); + applicable &= SEC_ALLOC; + xbss_section = subseg_new (".xbss", 0); + bfd_set_section_flags (stdoutput, xbss_section, applicable); + seg_info (xbss_section)->bss = 1; + } + obj_elf_section_change_hook (); + subseg_set (xbss_section, (subsegT) get_absolute_expression ()); + demand_empty_rest_of_line (); + } + + void + i51_ebss (ignore) + int ignore ATTRIBUTE_UNUSED; + { + flagword applicable; + if (ebss_section == NULL) + { + applicable = bfd_applicable_section_flags (stdoutput); + applicable &= SEC_ALLOC; + ebss_section = subseg_new (".ebss", 0); + bfd_set_section_flags (stdoutput, ebss_section, applicable); + seg_info (ebss_section)->bss = 1; + } + obj_elf_section_change_hook (); + subseg_set (ebss_section, (subsegT) get_absolute_expression ()); + demand_empty_rest_of_line (); + } + + void + i51_bitbss (ignore) + int ignore ATTRIBUTE_UNUSED; + { + flagword applicable; + if (bitbss_section == NULL) + { + applicable = bfd_applicable_section_flags (stdoutput); + applicable &= SEC_ALLOC; + bitbss_section = subseg_new (".bitbss", 0); + bfd_set_section_flags (stdoutput, bitbss_section, applicable); + seg_info (bitbss_section)->bss = 1; + } + obj_elf_section_change_hook (); + subseg_set (bitbss_section, (subsegT) get_absolute_expression ()); + demand_empty_rest_of_line (); + } + + void + i51_rdata (ignore) + int ignore ATTRIBUTE_UNUSED; + { + flagword applicable; + if (rdata_section == NULL) + { + applicable = bfd_applicable_section_flags (stdoutput); + applicable &= (SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA); + rdata_section = subseg_new (".rdata", 0); + bfd_set_section_flags (stdoutput, rdata_section, applicable); + } + obj_elf_section_change_hook (); + subseg_set (rdata_section, (subsegT) get_absolute_expression ()); + demand_empty_rest_of_line (); + } + + void + i51_bdata (ignore) + int ignore ATTRIBUTE_UNUSED; + { + flagword applicable; + if (bdata_section == NULL) + { + applicable = bfd_applicable_section_flags (stdoutput); + applicable &= (SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA); + bdata_section = subseg_new (".bdata", 0); + bfd_set_section_flags (stdoutput, bdata_section, applicable); + } + obj_elf_section_change_hook (); + subseg_set (bdata_section, (subsegT) get_absolute_expression ()); + demand_empty_rest_of_line (); + } + + void + i51_idata (ignore) + int ignore ATTRIBUTE_UNUSED; + { + flagword applicable; + if (idata_section == NULL) + { + applicable = bfd_applicable_section_flags (stdoutput); + applicable &= (SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA); + idata_section = subseg_new (".idata", 0); + bfd_set_section_flags (stdoutput, idata_section, applicable); + } + obj_elf_section_change_hook (); + subseg_set (idata_section, (subsegT) get_absolute_expression ()); + demand_empty_rest_of_line (); + } + + void + i51_xdata (ignore) + int ignore ATTRIBUTE_UNUSED; + { + flagword applicable; + if (xdata_section == NULL) + { + applicable = bfd_applicable_section_flags (stdoutput); + applicable &= (SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA); + xdata_section = subseg_new (".xdata", 0); + bfd_set_section_flags (stdoutput, xdata_section, applicable); + } + obj_elf_section_change_hook (); + subseg_set (xdata_section, (subsegT) get_absolute_expression ()); + demand_empty_rest_of_line (); + } + + void + i51_edata (ignore) + int ignore ATTRIBUTE_UNUSED; + { + flagword applicable; + if (edata_section == NULL) + { + applicable = bfd_applicable_section_flags (stdoutput); + applicable &= (SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA); + edata_section = subseg_new (".edata", 0); + bfd_set_section_flags (stdoutput, edata_section, applicable); + } + obj_elf_section_change_hook (); + subseg_set (edata_section, (subsegT) get_absolute_expression ()); + demand_empty_rest_of_line (); + } + + void + i51_bitdata (ignore) + int ignore ATTRIBUTE_UNUSED; + { + flagword applicable; + if (bitdata_section == NULL) + { + applicable = bfd_applicable_section_flags (stdoutput); + applicable &= (SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA); + bitdata_section = subseg_new (".bitdata", 0); + bfd_set_section_flags (stdoutput, bitdata_section, applicable); + } + obj_elf_section_change_hook (); + subseg_set (bitdata_section, (subsegT) get_absolute_expression ()); + demand_empty_rest_of_line (); + } + + void + i51_eeprom (ignore) + int ignore ATTRIBUTE_UNUSED; + { + flagword applicable; + if (eeprom_section == NULL) + { + applicable = bfd_applicable_section_flags (stdoutput); + applicable &= (SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA); + eeprom_section = subseg_new (".eeprom", 0); + bfd_set_section_flags (stdoutput, eeprom_section, applicable); + } + obj_elf_section_change_hook (); + subseg_set (eeprom_section, (subsegT) get_absolute_expression ()); + demand_empty_rest_of_line (); + } + + void + pcodeOperand (oper, mode, separator) + expressionS *oper; + enum PADRMODE *mode; + int separator; + { + SKIP_WHITESPACE (); + if ((*input_line_pointer != '\0') && (*input_line_pointer != '\x0D') && (*input_line_pointer != '\x0A') && (*input_line_pointer != ';')) + { + if (separator) + { + if (*input_line_pointer != ',') + { + as_bad (_("Expected comma after pcode operand")); + ignore_rest_of_line (); + return; + } + input_line_pointer++; /* skip ',' */ + SKIP_WHITESPACE (); + } + //search #, #BYTE, #SWAP, #SHL8, BYTE, SWAP, SHL8, @BYTE, @SWAP, @ + if (strncmp (input_line_pointer, "#BYTE", 5) == 0) { *mode = DIRECTBYTE; input_line_pointer += 5; } + else if (strncmp (input_line_pointer, "#SWAP", 5) == 0) { *mode = DIRECTSWAP; input_line_pointer += 5; } + else if (strncmp (input_line_pointer, "#SHL8", 5) == 0) { *mode = DIRECTSHL8; input_line_pointer += 5; } + else if (strncmp (input_line_pointer, "#WORD", 5) == 0) { *mode = DIRECTWORD; input_line_pointer += 5; } + else if (strncmp (input_line_pointer, "#", 1) == 0) { *mode = DIRECTWORD; input_line_pointer += 1; } + else if (strncmp (input_line_pointer, "BYTE", 4) == 0) { *mode = DIRECTBYTE; input_line_pointer += 4; } + else if (strncmp (input_line_pointer, "SWAP", 4) == 0) { *mode = DIRECTSWAP; input_line_pointer += 4; } + else if (strncmp (input_line_pointer, "SHL8", 4) == 0) { *mode = DIRECTSHL8; input_line_pointer += 4; } + else if (strncmp (input_line_pointer, "WORD", 4) == 0) { *mode = DIRECTWORD; input_line_pointer += 4; } + else if (strncmp (input_line_pointer, "@BYTE", 5) == 0) { *mode = INDIRECTBYTE; input_line_pointer += 5; } + else if (strncmp (input_line_pointer, "@SWAP", 5) == 0) { *mode = INDIRECTSWAP; input_line_pointer += 5; } + else if (strncmp (input_line_pointer, "@WORD", 5) == 0) { *mode = INDIRECTWORD; input_line_pointer += 5; } + else if (strncmp (input_line_pointer, "@", 1) == 0) { *mode = INDIRECTWORD; input_line_pointer += 1; } + else { *mode = DIRECTWORD; } + SKIP_WHITESPACE (); + expression (oper); + } + else + { + oper->X_op = O_constant; + oper->X_add_number = 0; + *mode = DIRECTBYTE; + } + } + + + void + writePcodeOperand (oper, mode, swapable) + expressionS *oper; + enum PADRMODE *mode; + int swapable ATTRIBUTE_UNUSED; + { + char *f; + fixS *fixp; + + switch (*mode) { + case DIRECTBYTE: + case DIRECTSHL8: + case INDIRECTWORD: + case INDIRECTSWAP: + // byte mode + if (oper->X_op == O_constant) + { + if (0x00FF & oper->X_add_number) + { + f = frag_more (1); + number_to_chars_bigendian (f, 0x00FF & oper->X_add_number, 1); + } + } + else + { + f = frag_more (1); + /* Now create a 8-bit fixup. */ + fixp = fix_new_exp (frag_now, f - frag_now->fr_literal, 1, + oper, + false, + BFD_RELOC_8); + number_to_chars_bigendian (f, 0, 1); + } + break; + case INDIRECTBYTE: + // indirect byte mode + if (oper->X_op == O_constant) + { + if (0x00FF & oper->X_add_number) + { + f = frag_more (1); + number_to_chars_bigendian (f, 0x00FF & (oper->X_add_number - 1), 1); + } + } + else + { + f = frag_more (1); + /* Now create a 8-bit fixup. */ + fixp = fix_new_exp (frag_now, f - frag_now->fr_literal, 1, + oper, + false, + BFD_RELOC_8); + number_to_chars_bigendian (f, -1, 1); + } + break; + case DIRECTWORD: + // word mode + if (oper->X_op == O_constant) + { + if (0xFF00 & oper->X_add_number) //MSB + { + f = frag_more (1); + number_to_chars_bigendian (f, 0x00FF & (oper->X_add_number >> 8), 1); + } + if (0x00FF & oper->X_add_number) //LSB + { + f = frag_more (1); + number_to_chars_bigendian (f, 0x00FF & oper->X_add_number, 1); + } + } + else + { + f = frag_more (2); + /* Now create a 16-bit fixup. */ + fixp = fix_new_exp (frag_now, f - frag_now->fr_literal, 2, + oper, + false, + BFD_RELOC_16); + number_to_chars_bigendian (f, 0, 2); + } + break; + case DIRECTSWAP: + //direct swap word mode + if (oper->X_op == O_constant) + { //direct swap mode + if (0x00FF & oper->X_add_number) //LSB + { + f = frag_more (1); + number_to_chars_bigendian (f, 0x00FF & oper->X_add_number, 1); + } + if (0xFF00 & oper->X_add_number) //MSB + { + f = frag_more (1); + number_to_chars_bigendian (f, 0x00FF & (oper->X_add_number >> 8), 1); + } + } + else + { + f = frag_more (2); + /* Now create a 16-bit fixup. */ + fixp = fix_new_exp (frag_now, f - frag_now->fr_literal, 2, + oper, + false, + BFD_RELOC_16); + number_to_chars_bigendian (f, 0, 2); + } + break; + } + } + + unsigned short + decodePcodeOperand (oper, mode, swapable) + expressionS *oper; + enum PADRMODE *mode; + int swapable; + { + unsigned short pflags; + + pflags = 0; + + switch (*mode) { + case DIRECTBYTE: + case INDIRECTWORD: + case INDIRECTBYTE: + if (oper->X_op == O_constant) + { + if (!check_range (oper->X_add_number, I51_OP_IMM8)) + { + as_bad (_("operand out of 8-bit range: `%ld'."), + oper->X_add_number); + } + if (0x00FF & oper->X_add_number) + { + pflags |= 0x40; + } + } + else + { + pflags |= 0x40; + } + break; + case INDIRECTSWAP: + if (oper->X_op == O_constant) + { + if (!check_range (oper->X_add_number, I51_OP_IMM8)) + { + as_bad (_("operand out of 8-bit range: `%ld'."), + oper->X_add_number); + } + if (0x00FF & oper->X_add_number) + { + pflags |= 0x40; //allocate 8 bit + } + pflags |= 0x02; //set swap flag + } + else + { + if (swapable == 0) + { + as_bad (_("Pcode operand 2 isn't swapable")); + } + pflags |= 0x42; //allocate 8 bit and set swap flag + } + break; + case DIRECTSHL8: + if (oper->X_op == O_constant) + { + if (!check_range (oper->X_add_number, I51_OP_IMM8)) + { + as_bad (_("operand out of 8-bit range: `%ld'."), + oper->X_add_number); + } + if (0x00FF & oper->X_add_number) + { + pflags |= 0x80; + } + } + else + { + pflags |= 0x80; + } + break; + case DIRECTWORD: + //word mode + if (oper->X_op == O_constant) + { + if (!check_range (oper->X_add_number, I51_OP_IMM16)) + { + as_bad (_("operand out of 16-bit range: `%ld'."), + oper->X_add_number); + } + //direct no swap mode + if (0xFF00 & oper->X_add_number) pflags |= 0x80; //MSB + if (0x00FF & oper->X_add_number) pflags |= 0x40; //LSB + } + else + { + pflags |= 0xC0; + } + break; + case DIRECTSWAP: + //word mode + if (oper->X_op == O_constant) + { + if (!check_range (oper->X_add_number, I51_OP_IMM16)) + { + as_bad (_("operand out of 16-bit range: `%ld'."), + oper->X_add_number); + } + //direct swap mode (#SWAP) + if (0x00FF & oper->X_add_number) pflags |= 0x80; //LSB + if (0xFF00 & oper->X_add_number) pflags |= 0x40; //MSB + pflags |= 0x02; //swap flag + } + else + { + if (swapable == 0) + { + as_bad (_("Pcode operand 2 isn't swapable")); + } + pflags |= 0xC2; //allocate 16 bit and set swap flag + } + break; + } + switch (*mode) { + case INDIRECTWORD: + case INDIRECTBYTE: + case INDIRECTSWAP: + pflags |= 0x8000; //indirect flag + default: + break; + } + return pflags; + } + + void + i51_pcode (ignore) + int ignore ATTRIBUTE_UNUSED; + { + char *f; + unsigned short pflags; + unsigned short temppflags; + + expression (&op_expr1); + pcodeOperand (&op_expr2, &p2mode, 0); + pcodeOperand (&op_expr3, &p3mode, 1); + pcodeOperand (&op_expr4, &p4mode, 1); + demand_empty_rest_of_line (); + + pflags = decodePcodeOperand (&op_expr2, &p2mode, 1); + temppflags = decodePcodeOperand (&op_expr3, &p3mode, 0); + pflags |= (temppflags & 0x00C0) >> 2; //data allocation + pflags |= (temppflags & 0x8000) >> 1; //indirect flag + temppflags = decodePcodeOperand (&op_expr4, &p4mode, 1); + pflags |= (temppflags & 0x00C0) >> 4; //data allocation + pflags |= (temppflags & 0x8000) >> 2; //indirect flag + pflags |= (temppflags & 0x0002) >> 1; //swap flag + + /* pcode exec address */ + f = frag_more (2); + temppflags = pflags & 0xE000; + if (op_expr1.X_op == O_constant) + { + if (op_expr1.X_add_number > 0x1FFF) + { + as_bad (_("Pcode exec address out of 13-bit range: `%ld'."), + op_expr4.X_add_number); + } + if (op_expr1.X_add_number < 0x0100) + { + as_bad (_("Pcode exec addrss uderflow: `%ld'."), + op_expr4.X_add_number); + } + temppflags |= op_expr1.X_add_number & 0x1FFF; + number_to_chars_bigendian (f, temppflags, 2); + } + else if (op_expr1.X_op != O_register) + { + fixS *fixp; + + /* Now create a 13-bit fixup. */ + fixp = fix_new_exp (frag_now, f - frag_now->fr_literal, 2, + &op_expr1, + false, + BFD_RELOC_I51_13_PCODE); + number_to_chars_bigendian (f, temppflags, 2); + } + else + { + as_fatal (_("Operand `%x' not recognized in pcode."), op_expr1.X_op); + } + + /* pcode flags */ + f = frag_more (1); + number_to_chars_bigendian (f, pflags & 0xFF, 1); + /* 1th pcode operand */ + writePcodeOperand (&op_expr2, &p2mode, 1); + /* 2nd pcode operand */ + writePcodeOperand (&op_expr3, &p3mode, 0); + /* 3th pcode operand */ + writePcodeOperand (&op_expr4, &p4mode, 1); + } diff -crN binutils.null/gas/config/tc-i51.h binutils-2.11.2.i51.new/gas/config/tc-i51.h *** binutils.null/gas/config/tc-i51.h Thu Jan 1 01:00:00 1970 --- binutils-2.11.2.i51.new/gas/config/tc-i51.h Sun Dec 30 10:49:56 2001 *************** *** 0 **** --- 1,165 ---- + /* This file is tc-i51.h + Copyright (C) 2001 Free Software Foundation, Inc. + + Contributed by Radek Benedikt + + 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. */ + + #ifndef BFD_ASSEMBLER + #error MCS-51 support requires BFD_ASSEMBLER + #endif + + #define TC_I51 + /* By convention, you should define this macro in the `.h' file. For + example, `tc-m68k.h' defines `TC_M68K'. You might have to use this + if it is necessary to add CPU specific code to the object format + file. */ + + #define TARGET_FORMAT "elf32-i51" + /* This macro is the BFD target name to use when creating the output + file. This will normally depend upon the `OBJ_FMT' macro. */ + + #define TARGET_ARCH bfd_arch_i51 + /* This macro is the BFD architecture to pass to `bfd_set_arch_mach'. */ + + #define TARGET_MACH 0 + /* This macro is the BFD machine number to pass to + `bfd_set_arch_mach'. If it is not defined, GAS will use 0. */ + + #define TARGET_BYTES_BIG_ENDIAN 1 + /* You should define this macro to be non-zero if the target is big + endian, and zero if the target is little endian. */ + + #define ONLY_STANDARD_ESCAPES + /* If you define this macro, GAS will warn about the use of + nonstandard escape sequences in a string. */ + + /* Support for SHF_REGBANK */ + extern int i51_section_flags PARAMS ((int, int, int)); + + //#define md_elf_section_letter(LETTER, PTR_MSG) i51_section_letter (LETTER, PTR_MSG) + //#define md_elf_section_word(STR, LEN) i51_section_word (STR, LEN) + #define md_elf_section_flags(FLAGS, ATTR, TYPE) i51_section_flags (FLAGS, ATTR, TYPE) + + #define md_operand(x) + /* GAS will call this function for any expression that can not be + recognized. When the function is called, `input_line_pointer' + will point to the start of the expression. */ + + //void i51_parse_cons_expression (expressionS *exp, int nbytes); + //#define TC_PARSE_CONS_EXPRESSION(EXPR,N) avr_parse_cons_expression (EXPR,N) + /* + You may define this macro to parse an expression used in a data + allocation pseudo-op such as `.word'. You can use this to + recognize relocation directives that may appear in such directives.*/ + + //void avr_cons_fix_new(fragS *frag,int where, int nbytes, expressionS *exp); + + //#define TC_CONS_FIX_NEW(FRAG,WHERE,N,EXP) avr_cons_fix_new(FRAG,WHERE,N,EXP) + /* You may define this macro to generate a fixup for a data + allocation pseudo-op. */ + + #define md_number_to_chars number_to_chars_bigendian + /* This should just call either `number_to_chars_bigendian' or + `number_to_chars_littleendian', whichever is appropriate. On + targets like the MIPS which support options to change the + endianness, which function to call is a runtime decision. On + other targets, `md_number_to_chars' can be a simple macro. */ + + #define WORKING_DOT_WORD + /* + `md_short_jump_size' + `md_long_jump_size' + `md_create_short_jump' + `md_create_long_jump' + If `WORKING_DOT_WORD' is defined, GAS will not do broken word + processing (*note Broken words::.). Otherwise, you should set + `md_short_jump_size' to the size of a short jump (a jump that is + just long enough to jump around a long jmp) and + `md_long_jump_size' to the size of a long jump (a jump that can go + anywhere in the function), You should define + `md_create_short_jump' to create a short jump around a long jump, + and define `md_create_long_jump' to create a long jump. */ + + #define MD_APPLY_FIX3 + + //#define TC_HANDLES_FX_DONE + + //#undef RELOC_EXPANSION_POSSIBLE + /* If you define this macro, it means that `tc_gen_reloc' may return + multiple relocation entries for a single fixup. In this case, the + return value of `tc_gen_reloc' is a pointer to a null terminated + array. */ + + #define MD_PCREL_FROM_SECTION(FIXP, SEC) md_pcrel_from_section(FIXP, SEC) + /* If you define this macro, it should return the offset between the + address of a PC relative fixup and the position from which the PC + relative adjustment should be made. On many processors, the base + of a PC relative instruction is the next instruction, so this + macro would return the length of an instruction. */ + + //extern long md_pcrel_from_section PARAMS ((struct fix *, segT)); + + /* Specific sections: + bit register area */ + #define ELF_TC_SPECIAL_SECTIONS \ + /* internal (onchip) memory */ \ + /* 0x00..0x1F register, direct, indirect addresable */ \ + { ".rdata", SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, \ + { ".rbss", SHT_NOBITS, SHF_ALLOC + SHF_WRITE }, \ + /* 0x20..0x2F bit, direct, indirect addressable */ \ + { ".bdata", SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, \ + { ".bbss", SHT_NOBITS, SHF_ALLOC + SHF_WRITE }, \ + /* 0x30..0x7F direct, indirect addresable */ \ + /* * * standart section * * */ \ + /* .data */ \ + /* .bss */ \ + /* 0x80..0xFF indirect addressable */ \ + { ".idata", SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, \ + { ".ibss", SHT_NOBITS, SHF_ALLOC + SHF_WRITE }, \ + /* external (but in some case onchip) memory */ \ + /* 0x0000..0xFFFF external memory, movx addressable */ \ + { ".xdata", SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, \ + { ".xbss", SHT_NOBITS, SHF_ALLOC + SHF_WRITE }, \ + /* 0x0000..0xFFFF optional onchip "external" memory, movx addressable */ \ + { ".edata", SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, \ + { ".ebss", SHT_NOBITS, SHF_ALLOC + SHF_WRITE }, \ + /* 0x0000..0xFFFF optionla onchip eeprom memory, movx addressable */ \ + { ".eeprom", SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, + + #define LISTING_WORD_SIZE 1 + /* The number of bytes to put into a word in a listing. This affects + the way the bytes are clumped together in the listing. For + example, a value of 2 might print `1234 5678' where a value of 1 + would print `12 34 56 78'. The default value is 4. */ + + //#define LEX_DOLLAR 0 + /* AVR port uses `$' as a logical line separator */ + + //#define TC_IMPLICIT_LCOMM_ALIGNMENT(SIZE, P2VAR) (P2VAR) = 0 + /* An `.lcomm' directive with no explicit alignment parameter will + use this macro to set P2VAR to the alignment that a request for + SIZE bytes will have. The alignment is expressed as a power of + two. If no alignment should take place, the macro definition + should do nothing. Some targets define a `.bss' directive that is + also affected by this macro. The default definition will set + P2VAR to the truncated power of two of sizes up to eight bytes. */ + + extern void i51_cleanup PARAMS ((void)); + #define md_cleanup() i51_cleanup() + #define md_after_pass_hook() i51_cleanup() diff -crN binutils.null/include/elf/i51.h binutils-2.11.2.i51.new/include/elf/i51.h *** binutils.null/include/elf/i51.h Thu Jan 1 01:00:00 1970 --- binutils-2.11.2.i51.new/include/elf/i51.h Sun Dec 30 10:48:51 2001 *************** *** 0 **** --- 1,58 ---- + /* MCS-51 ELF support for BFD. + Copyright (C) 2001 Free Software Foundation, Inc. + Contributed by Radek Benedikt + + This file is part of BFD, the Binary File Descriptor library. + + This program 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 of the License, or + (at your option) any later version. + + This program 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 this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + #ifndef _ELF_I51_H + #define _ELF_I51_H + + #include "elf/reloc-macros.h" + + /* Relocations. */ + START_RELOC_NUMBERS (elf_i51_reloc_type) + RELOC_NUMBER (R_I51_NONE, 0) + RELOC_NUMBER (R_I51_R1, 1) + RELOC_NUMBER (R_I51_R3, 2) + RELOC_NUMBER (R_I51_7_PCREL, 3) + RELOC_NUMBER (R_I51_11, 4) + RELOC_NUMBER (R_I51_8_BIT, 5) + RELOC_NUMBER (R_I51_8, 6) + RELOC_NUMBER (R_I51_L, 7) + RELOC_NUMBER (R_I51_H, 8) + RELOC_NUMBER (R_I51_16, 9) + RELOC_NUMBER (R_I51_8_B2B, 10) + RELOC_NUMBER (R_I51_13_PCODE, 11) + END_RELOC_NUMBERS (R_I51_max) + + #define SHF_CDATA 0xE0000000 /* Processor-specific - common data mask */ + #define SHF_REGBANK 0x20000000 /* Processor-specific - register bank */ + #define SHF_RDATA 0x40000000 /* Processor-specific - rdata */ + #define SHF_BDATA 0x60000000 /* Processor-specific - bdata */ + #define SHF_IDATA 0x80000000 /* Processor-specific - idata */ + #define SHF_XDATA 0xA0000000 /* Processor-specific - xdata */ + #define SHF_EDATA 0xC0000000 /* Processor-specific - edata */ + + #define SHN_I51_REGBANK 0xff00 /* Register bank common */ + #define SHN_I51_RDATA_C 0xff01 /* rdata common */ + #define SHN_I51_BDATA_C 0xff02 /* bdata common */ + #define SHN_I51_IDATA_C 0xff03 /* idata common */ + #define SHN_I51_XDATA_C 0xff04 /* xdata common */ + #define SHN_I51_EDATA_C 0xff05 /* edata common */ + #define SHN_I51_BITDATA_C 0xff06 /* bitdata common */ + + #endif /* _ELF_I51_H */ diff -crN binutils.null/include/opcode/i51.h binutils-2.11.2.i51.new/include/opcode/i51.h *** binutils.null/include/opcode/i51.h Thu Jan 1 01:00:00 1970 --- binutils-2.11.2.i51.new/include/opcode/i51.h Wed Dec 26 16:20:51 2001 *************** *** 0 **** --- 1,153 ---- + /* ARGS: + A - A reg + B - bit + C - AB reg + D - data + N - none + R - R0..R7 + r - C reg + P - DPTR + @ - @A+DPTR + X - @A+PC + I - @R0, @R1 + J - jump rel + / - /C + T - @DPTR + # - #data + d - data16 + 1 - jump addr 11 + 6 - jump addr 16 + */ + + /* MRELOC + N - none - IIIIIIII + I - register indirect - IIIIIIIr + i - reg. indirect, data - IIIIIIIr dddddddd + R - register - IIIIIrrr + r - register,data - IIIIIrrr dddddddd + 7 - relative jump 8 bit - IIIIIIII aaaaaaaa + 1 - jump 11 bit - aaaIIIII aaaaaaaa + 6 - data/jump 16 bit - IIIIIIII aaaaaaaa aaaaaaaa + D - data 8 bit - IIIIIIII dddddddd + d - data,data 8 bit - IIIIIIII dddddddd dddddddd + a - addr,data 8 bit - IIIIIIII aaaaaaaa dddddddd + B - bitdata 8 bit - IIIIIIII bbbbbbbb + J - bit, r. jump 8 bit - IIIIIIII bbbbbbbb aaaaaaaa + X - reg. indirect, r. jump 8 bit - IIIIIIIr dddddddd aaaaaaaa + Y - register, rel. jump 8 bit - IIIIIrrr dddddddd aaaaaaaa + Z - data 8 bit, r. jump 8 bit - IIIIIIII dddddddd aaaaaaaa + W - register, rel. jump 8 bit - IIIIIrrr aaaaaaaa + */ + + I51_INS ("acall", "1NN", 0x82, "aaa10001", '1', 0x11, 0x1F) + I51_INS ("add", "ARN", 0x01, "00101rrr", 'R', 0x28, 0xF8) + I51_INS ("add", "AIN", 0x01, "0010011r", 'I', 0x26, 0xFE) + I51_INS ("add", "ADN", 0x02, "00100101", 'D', 0x25, 0xFF) + I51_INS ("add", "A#N", 0x82, "00100100", 'D', 0x24, 0xFF) + I51_INS ("addc", "ARN", 0x01, "00111rrr", 'R', 0x38, 0xF8) + I51_INS ("addc", "AIN", 0x01, "0011011r", 'I', 0x36, 0xFE) + I51_INS ("addc", "ADN", 0x02, "00110101", 'D', 0x35, 0xFF) + I51_INS ("addc", "A#N", 0x82, "00110100", 'D', 0x34, 0xFF) + I51_INS ("ajmp", "1NN", 0x82, "aaa00001", '1', 0x01, 0x1F) + I51_INS ("anl", "ARN", 0x01, "01011rrr", 'R', 0x58, 0xF8) + I51_INS ("anl", "AIN", 0x01, "0101011i", 'I', 0x56, 0xFE) + I51_INS ("anl", "ADN", 0x02, "01010101", 'D', 0x55, 0xFF) + I51_INS ("anl", "A#N", 0x02, "01010100", 'D', 0x54, 0xFF) + I51_INS ("anl", "rBN", 0x02, "10000010", 'B', 0x82, 0xFF) + I51_INS ("anl", "r/N", 0x02, "10110000", 'B', 0xB0, 0xFF) + I51_INS ("anl", "DAN", 0x02, "01010010", 'D', 0x52, 0xFF) + I51_INS ("anl", "D#N", 0x83, "01010011", 'a', 0x53, 0xFF) + I51_INS ("cjne", "A#J", 0x03, "10110100", 'Z', 0xB4, 0xFF) + I51_INS ("cjne", "R#J", 0x03, "10111rrr", 'Y', 0xB8, 0xF8) + I51_INS ("cjne", "I#J", 0x03, "1011011r", 'X', 0xB6, 0xFE) + I51_INS ("cjne", "ADJ", 0x83, "10110101", 'Z', 0xB5, 0xFF) + I51_INS ("clr", "ANN", 0x01, "11100100", 'N', 0xE4, 0xFF) + I51_INS ("clr", "rNN", 0x01, "11000011", 'N', 0xC3, 0xFF) + I51_INS ("clr", "BNN", 0x82, "11000010", 'B', 0xC2, 0xFF) + I51_INS ("cpl", "ANN", 0x01, "11110100", 'N', 0xF4, 0xFF) + I51_INS ("cpl", "rNN", 0x01, "10110011", 'N', 0xB3, 0xFF) + I51_INS ("cpl", "BNN", 0x82, "10110010", 'B', 0xB2, 0xFF) + I51_INS ("da", "ANN", 0x81, "11010100", 'N', 0xD4, 0xFF) + I51_INS ("dec", "ANN", 0x01, "00010100", 'N', 0x14, 0xFF) + I51_INS ("dec", "RNN", 0x01, "00011rrr", 'R', 0x18, 0xF8) + I51_INS ("dec", "INN", 0x01, "0001011r", 'I', 0x16, 0xFE) + I51_INS ("dec", "DNN", 0x82, "00010101", 'D', 0x15, 0xFF) + I51_INS ("div", "CNN", 0x81, "10000100", 'N', 0x84, 0xFF) + I51_INS ("djnz", "RJN", 0x02, "11011rrr", 'W', 0xD8, 0xF8) + I51_INS ("djnz", "DJN", 0x83, "11010101", 'Z', 0xD5, 0xFF) + I51_INS ("inc", "ANN", 0x01, "00000100", 'N', 0x04, 0xFF) + I51_INS ("inc", "RNN", 0x01, "00001rrr", 'R', 0x08, 0xF8) + I51_INS ("inc", "INN", 0x01, "0000011r", 'I', 0x06, 0xFE) + I51_INS ("inc", "PNN", 0x01, "10100011", 'N', 0xA3, 0xFF) + I51_INS ("inc", "DNN", 0x82, "00000101", 'D', 0x05, 0xFF) + I51_INS ("jb", "BJN", 0x83, "00100000", 'J', 0x20, 0xFF) + I51_INS ("jbc", "BJN", 0x83, "00010000", 'J', 0x10, 0xFF) + I51_INS ("jc", "JNN", 0x82, "01000000", '7', 0x40, 0xFF) + I51_INS ("jmp", "@NN", 0x81, "01110011", 'N', 0x73, 0xFF) + I51_INS ("jnb", "BJN", 0x83, "00110000", 'J', 0x30, 0xFF) + I51_INS ("jnc", "JNN", 0x82, "01010000", '7', 0x50, 0xFF) + I51_INS ("jnz", "JNN", 0x82, "01110000", '7', 0x70, 0xFF) + I51_INS ("jz", "JNN", 0x82, "01100000", '7', 0x60, 0xFF) + I51_INS ("lcall", "6NN", 0x83, "00010010", '6', 0x12, 0xFF) + I51_INS ("ljmp", "6NN", 0x83, "00000010", '6', 0x02, 0xFF) + I51_INS ("mov", "ARN", 0x01, "11101rrr", 'R', 0xE8, 0xF8) + I51_INS ("mov", "AIN", 0x01, "1110011r", 'I', 0xE6, 0xFE) + I51_INS ("mov", "ADN", 0x02, "11100101", 'D', 0xE5, 0xFF) + I51_INS ("mov", "A#N", 0x02, "01110100", 'D', 0x74, 0xFF) + I51_INS ("mov", "RAN", 0x01, "11111rrr", 'R', 0xF8, 0xF8) + I51_INS ("mov", "RDN", 0x02, "10101rrr", 'r', 0xA8, 0xF8) + I51_INS ("mov", "R#N", 0x02, "01111rrr", 'r', 0x78, 0xF8) + I51_INS ("mov", "IAN", 0x01, "1111011r", 'I', 0xF6, 0xFE) + I51_INS ("mov", "IDN", 0x02, "1010011r", 'r', 0xA6, 0xFE) + I51_INS ("mov", "I#N", 0x02, "0111011r", 'r', 0x76, 0xFE) + I51_INS ("mov", "rBN", 0x02, "10100010", 'B', 0xA2, 0xFF) + I51_INS ("mov", "P#N", 0x03, "10010000", '6', 0x90, 0xFF) + I51_INS ("mov", "BrN", 0x02, "10010010", 'B', 0x92, 0xFF) + I51_INS ("mov", "DAN", 0x02, "11110101", 'D', 0xF5, 0xFF) + I51_INS ("mov", "DRN", 0x02, "10001rrr", 'r', 0x88, 0xF8) + I51_INS ("mov", "DIN", 0x02, "1000011r", 'r', 0x86, 0xFE) + I51_INS ("mov", "DDN", 0x03, "10000101", 'd', 0x85, 0xFF) + I51_INS ("mov", "D#N", 0x83, "01110101", 'a', 0x75, 0xFF) + I51_INS ("movc", "A@N", 0x01, "10010011", 'N', 0x93, 0xFF) + I51_INS ("movc", "AXN", 0x81, "10000011", 'N', 0x83, 0xFF) + I51_INS ("movx", "AIN", 0x01, "1110001r", 'I', 0xE2, 0xFE) + I51_INS ("movx", "ATN", 0x01, "11100000", 'N', 0xE0, 0xFF) + I51_INS ("movx", "IAN", 0x01, "1111001r", 'I', 0xF2, 0xFE) + I51_INS ("movx", "TAN", 0x81, "11110000", 'N', 0xF0, 0xFF) + I51_INS ("mul", "CNN", 0x81, "10100100", 'N', 0xA4, 0xFF) + I51_INS ("nop", "NNN", 0x81, "00000000", 'N', 0x00, 0xFF) + I51_INS ("orl", "ARN", 0x01, "01001rrr", 'R', 0x48, 0xF8) + I51_INS ("orl", "AIN", 0x01, "0100011i", 'I', 0x46, 0xFE) + I51_INS ("orl", "ADN", 0x02, "01000101", 'D', 0x45, 0xFF) + I51_INS ("orl", "A#N", 0x02, "01000100", 'D', 0x44, 0xFF) + I51_INS ("orl", "rBN", 0x02, "01110010", 'B', 0x72, 0xFF) + I51_INS ("orl", "r/N", 0x02, "10100000", 'B', 0xA0, 0xFF) + I51_INS ("orl", "DAN", 0x02, "01000010", 'D', 0x42, 0xFF) + I51_INS ("orl", "D#N", 0x83, "01000011", 'a', 0x43, 0xFF) + I51_INS ("pop", "DNN", 0x82, "11010000", 'D', 0xD0, 0xFF) + I51_INS ("push", "DNN", 0x82, "11000000", 'D', 0xC0, 0xFF) + I51_INS ("ret", "NNN", 0x81, "00100010", 'N', 0x22, 0xFF) + I51_INS ("reti", "NNN", 0x81, "00110010", 'N', 0x32, 0xFF) + I51_INS ("rl", "ANN", 0x81, "00100011", 'N', 0x23, 0xFF) + I51_INS ("rlc", "ANN", 0x81, "00110011", 'N', 0x33, 0xFF) + I51_INS ("rr", "ANN", 0x81, "00000011", 'N', 0x03, 0xFF) + I51_INS ("rrc", "ANN", 0x81, "00010011", 'N', 0x13, 0xFF) + I51_INS ("setb", "rNN", 0x01, "11010011", 'N', 0xD3, 0xFF) + I51_INS ("setb", "BNN", 0x82, "11010010", 'B', 0xD2, 0xFF) + I51_INS ("sjmp", "JNN", 0x82, "10000000", '7', 0x80, 0xFF) + I51_INS ("subb", "ARN", 0x01, "10011rrr", 'R', 0x98, 0xF8) + I51_INS ("subb", "AIN", 0x01, "1001011r", 'I', 0x96, 0xFE) + I51_INS ("subb", "ADN", 0x02, "10010101", 'D', 0x95, 0xFF) + I51_INS ("subb", "A#N", 0x82, "10010100", 'D', 0x94, 0xFF) + I51_INS ("swap", "ANN", 0x81, "11000100", 'N', 0xC4, 0xFF) + I51_INS ("xch", "ARN", 0x01, "11001rrr", 'R', 0xC8, 0xF8) + I51_INS ("xch", "AIN", 0x01, "1100011r", 'I', 0xC6, 0xFE) + I51_INS ("xch", "ADN", 0x82, "11000101", 'D', 0xC5, 0xFF) + I51_INS ("xchd", "AIN", 0x81, "1101011r", 'I', 0xD6, 0xFE) + I51_INS ("xrl", "ARN", 0x01, "01101rrr", 'R', 0x68, 0xF8) + I51_INS ("xrl", "AIN", 0x01, "0110011i", 'I', 0x66, 0xFE) + I51_INS ("xrl", "ADN", 0x02, "01100101", 'D', 0x65, 0xFF) + I51_INS ("xrl", "A#N", 0x02, "01100100", 'D', 0x64, 0xFF) + I51_INS ("xrl", "DAN", 0x02, "01100010", 'D', 0x62, 0xFF) + I51_INS ("xrl", "D#N", 0x83, "01100011", 'a', 0x63, 0xFF) + diff -crN binutils.null/ld/emulparams/elf32_i51.sh binutils-2.11.2.i51.new/ld/emulparams/elf32_i51.sh *** binutils.null/ld/emulparams/elf32_i51.sh Thu Jan 1 01:00:00 1970 --- binutils-2.11.2.i51.new/ld/emulparams/elf32_i51.sh Wed Dec 26 16:20:51 2001 *************** *** 0 **** --- 1,13 ---- + SCRIPT_NAME=elf32i51 + TEMPLATE_NAME=generic + OUTPUT_FORMAT="elf32-i51" + ARCH=i51 + MACHINE= + TEXT_START_ADDR=0 + TEXT_LENGTH=8K + DATA_LENGTH=256 + XDATA_LENGTH=64K + EDATA_LENGTH=64K + EEPROM_LENGTH=2K + EMBEDDED=yes + MAXPAGESIZE=0x0800 diff -crN binutils.null/ld/scripttempl/elf32i51.sc binutils-2.11.2.i51.new/ld/scripttempl/elf32i51.sc *** binutils.null/ld/scripttempl/elf32i51.sc Thu Jan 1 01:00:00 1970 --- binutils-2.11.2.i51.new/ld/scripttempl/elf32i51.sc Wed Dec 26 16:20:51 2001 *************** *** 0 **** --- 1,235 ---- + cat < text} + + .reg ${RELOCATING+ 0} : + ${RELOCATING+ AT (ADDR (.text) + SIZEOF (.text))} + { + *(.regbank) + ${RELOCATING+ PROVIDE (__reg_start = .) ; } + *(.rdata*) + ${RELOCATING+ PROVIDE (__reg_end = .) ; } + } ${RELOCATING+ > data} + + .rbss ${RELOCATING+ SIZEOF(.reg)} : + { + ${RELOCATING+ PROVIDE (__rbss_start = .) ; } + *(.rbss*) + ${RELOCATING+ PROVIDE (__rbss_end = .) ; } + } ${RELOCATING+ > data} + + .bdata ${RELOCATING+ ((MAX (0x20, ( SIZEOF(.rbss) + ADDR(.rbss)))))} : + { + ${RELOCATING+ PROVIDE (__bdata_start = .) ; } + *(.bdata*) + ${RELOCATING+ PROVIDE (__bdata_end = .) ; } + } ${RELOCATING+ > data} + + .bbss ${RELOCATING+ (SIZEOF(.bdata) + ADDR(.bdata))} : + { + ${RELOCATING+ PROVIDE (__bbss_start = .) ; } + *(.bbss*) + ${RELOCATING+ PROVIDE (__bbss_end = .) ; } + } ${RELOCATING+ > data} + + .bit ${RELOCATING+ ((((SIZEOF(.bbss) + ADDR(.bbss)) - 0x20) * 8 ))} : + { + ${RELOCATING+ PROVIDE (__bit_start = .) ; } + *(.bitdata*) + ${RELOCATING+ PROVIDE (__bit_end = .) ; } + } ${RELOCATING+ > bit} + + .bitbss ${RELOCATING+ SIZEOF(.bit) + ADDR(.bit)} : + { + ${RELOCATING+ PROVIDE (__bbss_start = .) ; } + *(.bitbss*) + ${RELOCATING+ PROVIDE (__bbss_end = .) ; } + } ${RELOCATING+ > bit} + + .data ${RELOCATING+ (((SIZEOF(.bit) + SIZEOF(.bitbss) + 7) / 8) + SIZEOF(.bbss) + ADDR(.bbss))} : + { + ${RELOCATING+ PROVIDE (__data_start = .) ; } + *(.data) + *(.gnu.linkonce.d*) + ${RELOCATING+ PROVIDE (__data_end = .) ; } + } ${RELOCATING+ > data} + + .bss ${RELOCATING+ SIZEOF(.data) + ADDR(.data)} : + { + ${RELOCATING+ PROVIDE (__bss_start = .) ; } + *(.bss*) + *(COMMON) + ${RELOCATING+ PROVIDE (__bss_end = .) ; } + } ${RELOCATING+ > data} + + .idata ${RELOCATING+ SIZEOF(.bss) + ADDR(.bss)} : + { + ${RELOCATING+ PROVIDE (__idata_start = .) ; } + *(.idata) + ${RELOCATING+ PROVIDE (__idata_end = .) ; } + } ${RELOCATING+ > data} + + .ibss ${RELOCATING+ SIZEOF(.idata) + ADDR(.idata)} : + { + ${RELOCATING+ PROVIDE (__ibss_start = .) ; } + *(.ibss) + ${RELOCATING+ PROVIDE (__ibss_end = .) ; } + ${RELOCATING+ PROVIDE (stack = .) ; } + } ${RELOCATING+ > data} + + .xdata ${RELOCATING-0}: + { + ${RELOCATING+ PROVIDE (__xdata_start = .) ; } + *(.xdata*) + ${RELOCATING+ PROVIDE (__xdata_end = .) ; } + } ${RELOCATING+ > xdata} + + .ixdata ${RELOCATING+ SIZEOF(.xdata)}: + { + ${RELOCATING+ PROVIDE (__ixdata_start = .) ; } + *(.xbss*) + ${RELOCATING+ PROVIDE (__ixdata_end = .) ; } + } ${RELOCATING+ > xdata} + + .edata ${RELOCATING-0}: + { + ${RELOCATING+ PROVIDE (__edata_start = .) ; } + *(.edata*) + ${RELOCATING+ PROVIDE (__edata_end = .) ; } + } ${RELOCATING+ > edata} + + .iedata ${RELOCATING+ SIZEOF(.edata)}: + { + ${RELOCATING+ PROVIDE (__iedata_start = .) ; } + *(.ebss*) + ${RELOCATING+ PROVIDE (__iedata_end = .) ; } + } ${RELOCATING+ > edata} + + .eeprom ${RELOCATING-0}: + { + ${RELOCATING+ PROVIDE (__eeprom_start = .) ; } + *(.eeprom*) + ${RELOCATING+ PROVIDE (__eeprom_end = .) ; } + } ${RELOCATING+ > eeprom} + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info) *(.gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + } + EOF + diff -crN binutils.null/opcodes/i51-dis.c binutils-2.11.2.i51.new/opcodes/i51-dis.c *** binutils.null/opcodes/i51-dis.c Thu Jan 1 01:00:00 1970 --- binutils-2.11.2.i51.new/opcodes/i51-dis.c Wed Dec 26 16:20:51 2001 *************** *** 0 **** --- 1,282 ---- + /* Disassemble MCS-51 instructions. + Copyright 2001 Free Software Foundation, Inc. + + Contributed by Radek Benedikt + + This program 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 of the License, or + (at your option) any later version. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + #include + #include "sysdep.h" + #include "dis-asm.h" + #include "opintl.h" + + + struct i51_opcodes_s + { + char *name; + char *args; + int insn_size; /* in bytes */ + unsigned char bin_opcode; + unsigned char bin_mask; + }; + + #define I51_INS(NAME, ARGS, SIZE, OPCODE, MRELOC, BIN, MASK) \ + {NAME, ARGS, SIZE, BIN, MASK}, + + struct i51_opcodes_s i51_opcodes[] = + { + #include "opcode/i51.h" + {NULL, NULL, 0, 0, 0} + }; + + static unsigned char + i51dis_opcode (addr, info) + bfd_vma addr; + disassemble_info *info; + { + bfd_byte buffer[1]; + int status; + status = info->read_memory_func(addr, buffer, 1, info); + if (status != 0) + { + info->memory_error_func(status, addr, info); + return -1; + } + return buffer[0]; + } + + static unsigned short + i51dis_op16 (addr, info) + bfd_vma addr; + disassemble_info *info; + { + bfd_byte buffer[2]; + int status; + status = info->read_memory_func(addr, buffer, 2, info); + if (status != 0) + { + info->memory_error_func(status, addr, info); + return -1; + } + return bfd_getb16(buffer); + } + + int + print_insn_i51(addr, info) + bfd_vma addr; + disassemble_info *info; + { + unsigned int insn; + unsigned int opdata; + unsigned char rel_addr; + struct i51_opcodes_s *opcode; + void *stream = info->stream; + fprintf_ftype prin = info->fprintf_func; + int ok = 0; + int offset = 0; + char op1[10], op2[10], op3[10], comment1[40], comment2[40]; + int inslen = 1; + + insn = i51dis_opcode (addr, info); + addr++; + for (opcode = i51_opcodes; opcode->name; opcode++) + { + if ((insn & opcode->bin_mask) == opcode->bin_opcode) + break; + } + + op1[0] = 0; + op2[0] = 0; + op3[0] = 0; + comment1[0] = 0; + comment2[0] = 0; + + if (opcode->name) + { + inslen = (opcode->insn_size) & 0x03; + ok = 1; + switch (opcode->args[0]) { + case 'N': //none + break; + case 'A': //A reg + sprintf (op1,"A"); + break; + case 'C': //AB reg + sprintf (op1,"AB"); + break; + case 'r': //C reg + sprintf (op1,"C"); + break; + case 'P': //DPTR + sprintf (op1,"DPTR"); + break; + case '@': //@A+DPTR + sprintf (op1,"@A+DPTR"); + break; + case 'T': //@DPTR + sprintf (op1,"@DPTR"); + break; + case 'D': //data + case 'B': //bit + opdata = i51dis_opcode (addr, info); + addr++; + offset++; + sprintf (op1,"0x%02X",opdata); + break; + case 'R': //R0..R7 + sprintf (op1,"R%c",(insn&0x07)+'0'); + break; + case 'I': //@R0, @R1 + sprintf (op1,"@R%c",(insn&0x01)+'0'); + break; + case 'J': //jump rel + opdata = i51dis_opcode (addr, info); + addr++; + // + rel_addr = opdata+2; + if (rel_addr & 0x80) { + sprintf (op1,".-0x%02X",0x100-rel_addr); + sprintf (comment1, "0x%04lX", addr + opdata - 0x100); + } else { + sprintf (op1,".+0x%02X",rel_addr); + sprintf (comment1, "0x%04lX", addr + opdata); + } + break; + case '1': //jump addr 11 + opdata = i51dis_opcode (addr, info); + addr++; + sprintf (op1,"0x%04lX", (addr&0xF800)+(((insn>>5)&0x07)<<8)+opdata); + break; + case '6': //jump addr 16 + opdata = i51dis_op16 (addr, info); + addr++; + sprintf (op1,"0x%04X",opdata); + break; + } + switch (opcode->args[1]) { + case 'N': //none + break; + case 'A': //A reg + sprintf (op2,"A"); + break; + case 'r': //C reg + sprintf (op2,"C"); + break; + case '@': //@A+DPTR + sprintf (op2,"@A+DPTR"); + break; + case 'X': //@A+PC + sprintf (op2,"@A+PC"); + break; + case '/': // /C + sprintf (op2,"/C"); + break; + case 'T': //@DPTR + sprintf (op2,"@DPTR"); + break; + case 'B': //bit + case 'D': //data + opdata = i51dis_opcode (addr, info); + addr++; + offset++; + sprintf (op2,"0x%02X",opdata); + break; + case 'R': //R0..R7 + sprintf (op2,"R%c",(insn&0x07)+'0'); + break; + case 'I': //@R0, @R1 + sprintf (op2,"@R%c",(insn&0x01)+'0'); + break; + case 'J': //jump rel + opdata = i51dis_opcode (addr, info); + addr++; + // + rel_addr = opdata+2+offset; + if (rel_addr & 0x80) { + sprintf (op2,".-0x%02X",0x100-rel_addr); + sprintf (comment1, "0x%04lX", addr + opdata - 0x100); + } else { + sprintf (op2,".+0x%02X",rel_addr); + sprintf (comment1, "0x%04lX", addr + opdata); + } + break; + case '#': //#data + if(opcode->args[0] == 'P') { + opdata = i51dis_op16 (addr, info); + addr+=2; + sprintf (op2,"#0x%04X",opdata); + } else { + opdata = i51dis_opcode (addr, info); + addr++; + offset++; + sprintf (op2,"#0x%02X",opdata); + if ((opdata >= ' ') && (opdata < 0x7F)) { + sprintf (comment1, "#%u\t#'%c'", opdata, opdata); + } else { + sprintf (comment1, "#%u", opdata); + } + } + break; + } + switch (opcode->args[2]) { + case 'N': //none + break; + case 'J': //jump rel + opdata = i51dis_opcode (addr, info); + addr++; + // + rel_addr = opdata+2+offset; + if (rel_addr & 0x80) { + sprintf (op3,".-0x%02X",0x100-rel_addr); + sprintf (comment1, "0x%04lX", addr + opdata - 0x100); + } else { + sprintf (op3,".+0x%02X",rel_addr); + sprintf (comment1, "0x%04lX", addr + opdata); + } + break; + } + } + + if (!ok) + { + /* Unknown opcode, or invalid combination of operands. */ + sprintf (op1, "0x%02X", insn); + sprintf (comment1, "????"); + comment2[0] = 0; + } + + (*prin) (stream, "%s", ok ? opcode->name : ".byte"); + + if (*op1) + (*prin) (stream, "\t%s", op1); + + if (*op2) + (*prin) (stream, ", %s", op2); + + if (*op3) + (*prin) (stream, ", %s", op3); + + if (*comment1) { + if (*op2) + (*prin) (stream, "\t; %s", comment1); + else + (*prin) (stream, "\t\t; %s", comment1); + } + + if (*comment2) + (*prin) (stream, " %s", comment2); + + return inslen; + }