| diff --git a/bfd/Makefile.am b/bfd/Makefile.am |
| index 435b30b..488c4ab 100644 |
| --- a/bfd/Makefile.am |
| +++ b/bfd/Makefile.am |
| @@ -92,6 +92,7 @@ ALL_MACHINES = \ |
| cpu-maxq.lo \ |
| cpu-mcore.lo \ |
| cpu-mips.lo \ |
| + cpu-nios2.lo \ |
| cpu-mmix.lo \ |
| cpu-mt.lo \ |
| cpu-msp430.lo \ |
| @@ -156,6 +157,7 @@ ALL_MACHINES_CFILES = \ |
| cpu-maxq.c \ |
| cpu-mcore.c \ |
| cpu-mips.c \ |
| + cpu-nios2.c \ |
| cpu-mmix.c \ |
| cpu-mt.c \ |
| cpu-msp430.c \ |
| @@ -270,6 +272,7 @@ BFD32_BACKENDS = \ |
| elf32-mips.lo \ |
| elf32-mt.lo \ |
| elf32-msp430.lo \ |
| + elf32-nios2.lo \ |
| elf32-openrisc.lo \ |
| elf32-or32.lo \ |
| elf32-pj.lo \ |
| @@ -446,6 +449,7 @@ BFD32_BACKENDS_CFILES = \ |
| elf32-mips.c \ |
| elf32-mt.c \ |
| elf32-msp430.c \ |
| + elf32-nios2.c \ |
| elf32-openrisc.c \ |
| elf32-or32.c \ |
| elf32-pj.c \ |
| @@ -1065,6 +1069,7 @@ cpu-m10300.lo: cpu-m10300.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h |
| cpu-maxq.lo: cpu-maxq.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h |
| cpu-mcore.lo: cpu-mcore.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h |
| cpu-mips.lo: cpu-mips.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h |
| +cpu-nios2.lo: cpu-nios2.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h |
| cpu-mmix.lo: cpu-mmix.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h |
| cpu-mt.lo: cpu-mt.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h |
| cpu-msp430.lo: cpu-msp430.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h |
| @@ -1428,6 +1433,10 @@ elf32-msp430.lo: elf32-msp430.c $(INCDIR)/filenames.h \ |
| $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ |
| $(INCDIR)/bfdlink.h $(INCDIR)/elf/msp430.h $(INCDIR)/elf/reloc-macros.h \ |
| elf32-target.h |
| +elf32-nios2.lo: elf32-nios2.c $(INCDIR)/filenames.h $(INCDIR)/bfdlink.h \ |
| + genlink.h elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \ |
| + $(INCDIR)/elf/external.h $(INCDIR)/elf/nios2.h \ |
| + $(INCDIR)/elf/reloc-macros.h elf32-target.h |
| elf32-openrisc.lo: elf32-openrisc.c $(INCDIR)/filenames.h \ |
| $(INCDIR)/hashtab.h elf-bfd.h $(INCDIR)/elf/common.h \ |
| $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h \ |
| diff --git a/bfd/Makefile.in b/bfd/Makefile.in |
| index 5bde689..5e57321 100644 |
| --- a/bfd/Makefile.in |
| +++ b/bfd/Makefile.in |
| @@ -327,6 +327,7 @@ ALL_MACHINES = \ |
| cpu-mt.lo \ |
| cpu-msp430.lo \ |
| cpu-or32.lo \ |
| + cpu-nios2.lo \ |
| cpu-ns32k.lo \ |
| cpu-openrisc.lo \ |
| cpu-pdp11.lo \ |
| @@ -391,6 +392,7 @@ ALL_MACHINES_CFILES = \ |
| cpu-mt.c \ |
| cpu-msp430.c \ |
| cpu-or32.c \ |
| + cpu-nios2.c \ |
| cpu-ns32k.c \ |
| cpu-openrisc.c \ |
| cpu-pdp11.c \ |
| @@ -502,6 +504,7 @@ BFD32_BACKENDS = \ |
| elf32-mips.lo \ |
| elf32-mt.lo \ |
| elf32-msp430.lo \ |
| + elf32-nios2.lo \ |
| elf32-openrisc.lo \ |
| elf32-or32.lo \ |
| elf32-pj.lo \ |
| @@ -678,6 +681,7 @@ BFD32_BACKENDS_CFILES = \ |
| elf32-mips.c \ |
| elf32-mt.c \ |
| elf32-msp430.c \ |
| + elf32-nios2.c \ |
| elf32-openrisc.c \ |
| elf32-or32.c \ |
| elf32-pj.c \ |
| @@ -1626,6 +1630,7 @@ cpu-m10300.lo: cpu-m10300.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h |
| cpu-maxq.lo: cpu-maxq.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h |
| cpu-mcore.lo: cpu-mcore.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h |
| cpu-mips.lo: cpu-mips.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h |
| +cpu-nios2.lo: cpu-nios2.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h |
| cpu-mmix.lo: cpu-mmix.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h |
| cpu-mt.lo: cpu-mt.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h |
| cpu-msp430.lo: cpu-msp430.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h |
| @@ -1989,6 +1994,10 @@ elf32-msp430.lo: elf32-msp430.c $(INCDIR)/filenames.h \ |
| $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ |
| $(INCDIR)/bfdlink.h $(INCDIR)/elf/msp430.h $(INCDIR)/elf/reloc-macros.h \ |
| elf32-target.h |
| +elf32-nios2.lo: elf32-nios2.c $(INCDIR)/filenames.h $(INCDIR)/bfdlink.h \ |
| + genlink.h elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \ |
| + $(INCDIR)/elf/external.h $(INCDIR)/elf/nios2.h \ |
| + $(INCDIR)/elf/reloc-macros.h elf32-target.h |
| elf32-openrisc.lo: elf32-openrisc.c $(INCDIR)/filenames.h \ |
| $(INCDIR)/hashtab.h elf-bfd.h $(INCDIR)/elf/common.h \ |
| $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h \ |
| diff --git a/bfd/archures.c b/bfd/archures.c |
| index 5029cb0..ece60b4 100644 |
| --- a/bfd/archures.c |
| +++ b/bfd/archures.c |
| @@ -381,6 +381,8 @@ DESCRIPTION |
| . bfd_arch_maxq, {* Dallas MAXQ 10/20 *} |
| .#define bfd_mach_maxq10 10 |
| .#define bfd_mach_maxq20 20 |
| +. bfd_arch_nios2, |
| +.#define bfd_mach_nios2 1 |
| . bfd_arch_z80, |
| .#define bfd_mach_z80strict 1 {* No undocumented opcodes. *} |
| .#define bfd_mach_z80 3 {* With ixl, ixh, iyl, and iyh. *} |
| @@ -462,6 +464,7 @@ extern const bfd_arch_info_type bfd_mn10300_arch; |
| extern const bfd_arch_info_type bfd_msp430_arch; |
| extern const bfd_arch_info_type bfd_mt_arch; |
| extern const bfd_arch_info_type bfd_ns32k_arch; |
| +extern const bfd_arch_info_type bfd_nios2_arch; |
| extern const bfd_arch_info_type bfd_openrisc_arch; |
| extern const bfd_arch_info_type bfd_or32_arch; |
| extern const bfd_arch_info_type bfd_pdp11_arch; |
| @@ -530,6 +533,7 @@ static const bfd_arch_info_type * const bfd_archures_list[] = |
| &bfd_mn10300_arch, |
| &bfd_mt_arch, |
| &bfd_msp430_arch, |
| + &bfd_nios2_arch, |
| &bfd_ns32k_arch, |
| &bfd_openrisc_arch, |
| &bfd_or32_arch, |
| diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h |
| index 8f2af8b..f5c51d6 100644 |
| --- a/bfd/bfd-in2.h |
| +++ b/bfd/bfd-in2.h |
| @@ -2010,6 +2010,8 @@ enum bfd_architecture |
| bfd_arch_maxq, /* Dallas MAXQ 10/20 */ |
| #define bfd_mach_maxq10 10 |
| #define bfd_mach_maxq20 20 |
| + bfd_arch_nios2, |
| +#define bfd_mach_nios2 1 |
| bfd_arch_z80, |
| #define bfd_mach_z80strict 1 /* No undocumented opcodes. */ |
| #define bfd_mach_z80 3 /* With ixl, ixh, iyl, and iyh. */ |
| @@ -4271,6 +4273,23 @@ internally by the linker after analysis of a |
| BFD_RELOC_XTENSA_ASM_EXPAND. */ |
| BFD_RELOC_XTENSA_ASM_SIMPLIFY, |
| |
| +/* Relocations used by the Altera New Jersey core */ |
| + BFD_RELOC_NIOS2_S16, |
| + BFD_RELOC_NIOS2_U16, |
| + BFD_RELOC_NIOS2_CALL26, |
| + BFD_RELOC_NIOS2_IMM5, |
| + BFD_RELOC_NIOS2_CACHE_OPX, |
| + BFD_RELOC_NIOS2_IMM6, |
| + BFD_RELOC_NIOS2_IMM8, |
| + BFD_RELOC_NIOS2_HI16, |
| + BFD_RELOC_NIOS2_LO16, |
| + BFD_RELOC_NIOS2_HIADJ16, |
| + BFD_RELOC_NIOS2_GPREL, |
| + BFD_RELOC_NIOS2_UJMP, |
| + BFD_RELOC_NIOS2_CJMP, |
| + BFD_RELOC_NIOS2_CALLR, |
| + BFD_RELOC_NIOS2_ALIGN, |
| + |
| /* 8 bit signed offset in (ix+d) or (iy+d). */ |
| BFD_RELOC_Z80_DISP8, |
| |
| diff --git a/bfd/config.bfd b/bfd/config.bfd |
| old mode 100755 |
| new mode 100644 |
| index 9b81db7..fa86103 |
| --- a/bfd/config.bfd |
| +++ b/bfd/config.bfd |
| @@ -88,6 +88,7 @@ m68*) targ_archs=bfd_m68k_arch ;; |
| m88*) targ_archs=bfd_m88k_arch ;; |
| maxq*) targ_archs=bfd_maxq_arch ;; |
| mips*) targ_archs=bfd_mips_arch ;; |
| +nios2*) targ_archs=bfd_nios2_arch ;; |
| or32*) targ_archs=bfd_or32_arch ;; |
| pdp11*) targ_archs=bfd_pdp11_arch ;; |
| pj*) targ_archs="bfd_pj_arch bfd_i386_arch";; |
| @@ -985,6 +986,21 @@ case "${targ}" in |
| targ_underscore=yes |
| ;; |
| |
| + nios2eb-*-*) |
| + targ_defvec=bfd_elf32_bignios2_vec |
| + targ_selvecs=bfd_elf32_littlenios2_vec |
| + ;; |
| + |
| + nios2el-*-*) |
| + targ_defvec=bfd_elf32_littlenios2_vec |
| + targ_selvecs=bfd_elf32_bignios2_vec |
| + ;; |
| + |
| + nios2-*-*) |
| + targ_defvec=bfd_elf32_littlenios2_vec |
| + targ_selvecs=bfd_elf32_bignios2_vec |
| + ;; |
| + |
| openrisc-*-elf) |
| targ_defvec=bfd_elf32_openrisc_vec |
| ;; |
| diff --git a/bfd/configure b/bfd/configure |
| index bc138ff..a64fef5 100755 |
| --- a/bfd/configure |
| +++ b/bfd/configure |
| @@ -10846,6 +10846,8 @@ do |
| bfd_elf32_littlemips_vec) tb="$tb elf32-mips.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo" ;; |
| bfd_elf32_littlemips_vxworks_vec) |
| tb="$tb elf32-mips.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo" ;; |
| + bfd_elf32_littlenios2_vec) tb="$tb elf32-nios2.lo elf32.lo $elf" ;; |
| + bfd_elf32_bignios2_vec) tb="$tb elf32-nios2.lo elf32.lo $elf" ;; |
| bfd_elf32_m32c_vec) tb="$tb elf32-m32c.lo elf32.lo $elf" ;; |
| bfd_elf32_m32r_vec) tb="$tb elf32-m32r.lo elf32.lo $elf" ;; |
| bfd_elf32_m32rle_vec) tb="$tb elf32-m32r.lo elf32.lo $elf" ;; |
| diff --git a/bfd/configure.in b/bfd/configure.in |
| index fa0d50f..eb1e5f6 100644 |
| --- a/bfd/configure.in |
| +++ b/bfd/configure.in |
| @@ -655,6 +655,8 @@ do |
| bfd_elf32_nlittlemips_vec) tb="$tb elfn32-mips.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo"; target_size=64 ;; |
| bfd_elf32_ntradbigmips_vec) tb="$tb elfn32-mips.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo"; target_size=64 ;; |
| bfd_elf32_ntradlittlemips_vec) tb="$tb elfn32-mips.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo"; target_size=64 ;; |
| + bfd_elf32_littlenios2_vec) tb="$tb elf32-nios2.lo elf32.lo $elf" ;; |
| + bfd_elf32_bignios2_vec) tb="$tb elf32-nios2.lo elf32.lo $elf" ;; |
| bfd_elf32_openrisc_vec) tb="$tb elf32-openrisc.lo elf32.lo $elf" ;; |
| bfd_elf32_or32_big_vec) tb="$tb elf32-or32.lo elf32.lo $elf" ;; |
| bfd_elf32_pj_vec) tb="$tb elf32-pj.lo elf32.lo $elf";; |
| diff --git a/bfd/cpu-nios2.c b/bfd/cpu-nios2.c |
| new file mode 100644 |
| index 0000000..c8f39c9 |
| --- /dev/null |
| +++ b/bfd/cpu-nios2.c |
| @@ -0,0 +1,70 @@ |
| +/* bfd back-end for Altera Nios II support |
| + |
| + Copyright (C) 2003 |
| + by Nigel Gray (ngray@altera.com). |
| + |
| +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" |
| + |
| +static const bfd_arch_info_type *nios2_compatible |
| + (const bfd_arch_info_type *, const bfd_arch_info_type *); |
| + |
| +/* The default routine tests bits_per_word, which is wrong on mips as |
| + mips word size doesn't correlate with reloc size. */ |
| + |
| +static const bfd_arch_info_type * |
| +nios2_compatible (const bfd_arch_info_type *a, const bfd_arch_info_type *b) |
| +{ |
| + if (a->arch != b->arch) |
| + return NULL; |
| + |
| + /* Machine compatibility is checked in |
| + _bfd_mips_elf_merge_private_bfd_data. */ |
| + |
| + return a; |
| +} |
| + |
| +#define N(BITS_WORD, BITS_ADDR, NUMBER, PRINT, DEFAULT, NEXT) \ |
| + { \ |
| + BITS_WORD, /* bits in a word */ \ |
| + BITS_ADDR, /* bits in an address */ \ |
| + 8, /* 8 bits in a byte */ \ |
| + bfd_arch_nios2, \ |
| + NUMBER, \ |
| + "nios2", \ |
| + PRINT, \ |
| + 3, \ |
| + DEFAULT, \ |
| + nios2_compatible, \ |
| + bfd_default_scan, \ |
| + NEXT, \ |
| + } |
| + |
| +#define NN(index) (&arch_info_struct[(index) + 1]) |
| + |
| +static const bfd_arch_info_type arch_info_struct[] = |
| +{ |
| + N (32, 32, bfd_mach_nios2, "nios2", FALSE, 0), |
| +}; |
| + |
| +/* There is only one architecture - but we give the default a machine number of 0 |
| + so the linker can distinguish it */ |
| +const bfd_arch_info_type bfd_nios2_arch = |
| +N (32, 32, 0, "nios2", TRUE, &arch_info_struct[0]); |
| diff --git a/bfd/elf32-nios2.c b/bfd/elf32-nios2.c |
| new file mode 100644 |
| index 0000000..f9ba1a0 |
| --- /dev/null |
| +++ b/bfd/elf32-nios2.c |
| @@ -0,0 +1,2193 @@ |
| +/* New Jersey-specific support for 32-bit ELF |
| + |
| + Copyright (C) 2003 |
| + by Nigel Gray (ngray@altera.com). |
| + |
| + |
| +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. */ |
| + |
| +/* This file handles Altera New Jersey ELF targets */ |
| + |
| +#include "bfd.h" |
| +#include "sysdep.h" |
| +#include "libbfd.h" |
| +#include "bfdlink.h" |
| +#include "genlink.h" |
| +#include "elf-bfd.h" |
| +#include "elf/nios2.h" |
| +#include "opcode/nios2.h" |
| + |
| +/* use RELA relocations*/ |
| +#ifndef USE_RELA |
| +#define USE_RELA |
| +#endif |
| + |
| +#ifdef USE_REL |
| +#undef USE_REL |
| +#endif |
| + |
| +/* Function prototypes */ |
| + |
| +static reloc_howto_type *nios2_elf32_bfd_reloc_type_lookup |
| + (bfd *, bfd_reloc_code_real_type); |
| + |
| +static bfd_boolean nios2_elf32_relax_section |
| + (bfd *, asection *, struct bfd_link_info *, bfd_boolean *); |
| + |
| +static bfd_boolean nios2_elf32_relax_delete_bytes |
| + (bfd *, asection *, bfd_vma, int); |
| + |
| +static reloc_howto_type *nios2_elf32_rtype_to_howto |
| + (unsigned int r_type, bfd_boolean rela_p); |
| + |
| +static void nios2_elf32_info_to_howto |
| + (bfd * abfd, arelent * cache_ptr, Elf_Internal_Rela * dst); |
| + |
| +static bfd_boolean nios2_elf32_relocate_section |
| + (bfd * output_bfd, 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); |
| + |
| +static reloc_howto_type *lookup_howto (unsigned int rtype); |
| + |
| +static bfd_reloc_status_type nios2_elf_final_gp |
| + (bfd *, asymbol *, bfd_boolean, char **, bfd_vma *, |
| + struct bfd_link_info *); |
| + |
| +static bfd_boolean nios2_elf_assign_gp |
| + (bfd *, bfd_vma *, struct bfd_link_info *); |
| + |
| +static bfd_reloc_status_type nios2_elf32_ignore_reloc |
| + (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); |
| + |
| +static bfd_reloc_status_type nios2_elf32_hi16_relocate |
| + (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); |
| + |
| +static bfd_reloc_status_type nios2_elf32_lo16_relocate |
| + (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); |
| + |
| +static bfd_reloc_status_type nios2_elf32_hiadj16_relocate |
| + (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); |
| + |
| +static bfd_reloc_status_type nios2_elf32_pcrel16_relocate |
| + (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); |
| + |
| +static bfd_reloc_status_type nios2_elf32_call26_relocate |
| + (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); |
| + |
| +static bfd_reloc_status_type nios2_elf32_gprel_relocate |
| + (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); |
| + |
| +static bfd_reloc_status_type nios2_elf32_ujmp_relocate |
| + (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); |
| + |
| +static bfd_reloc_status_type nios2_elf32_cjmp_relocate |
| + (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); |
| + |
| +static bfd_reloc_status_type nios2_elf32_callr_relocate |
| + (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); |
| + |
| +static bfd_reloc_status_type nios2_elf32_do_hi16_relocate |
| + (bfd *, reloc_howto_type *, asection *, |
| + bfd_byte *, bfd_vma, bfd_vma, bfd_vma); |
| + |
| +static bfd_reloc_status_type nios2_elf32_do_lo16_relocate |
| + (bfd *, reloc_howto_type *, asection *, |
| + bfd_byte *, bfd_vma, bfd_vma, bfd_vma); |
| + |
| +static bfd_reloc_status_type nios2_elf32_do_hiadj16_relocate |
| + (bfd *, reloc_howto_type *, asection *, |
| + bfd_byte *, bfd_vma, bfd_vma, bfd_vma); |
| + |
| +static bfd_reloc_status_type nios2_elf32_do_pcrel16_relocate |
| + (bfd *, reloc_howto_type *, asection *, |
| + bfd_byte *, bfd_vma, bfd_vma, bfd_vma); |
| + |
| +static bfd_reloc_status_type nios2_elf32_do_call26_relocate |
| + (bfd *, reloc_howto_type *, asection *, |
| + bfd_byte *, bfd_vma, bfd_vma, bfd_vma); |
| + |
| +static bfd_reloc_status_type nios2_elf32_do_gprel_relocate |
| + (bfd *, reloc_howto_type *, asection *, |
| + bfd_byte *, bfd_vma, bfd_vma, bfd_vma); |
| + |
| +static bfd_reloc_status_type nios2_elf32_do_ujmp_relocate |
| + (bfd *, reloc_howto_type *, asection *, |
| + bfd_byte *, bfd_vma, bfd_vma, bfd_vma); |
| + |
| +static bfd_reloc_status_type nios2_elf32_do_cjmp_relocate |
| + (bfd *, reloc_howto_type *, asection *, |
| + bfd_byte *, bfd_vma, bfd_vma, bfd_vma); |
| + |
| +static bfd_reloc_status_type nios2_elf32_do_callr_relocate |
| + (bfd *, reloc_howto_type *, asection *, |
| + bfd_byte *, bfd_vma, bfd_vma, bfd_vma); |
| + |
| + |
| +static void nios2_elf32_post_process_headers |
| + (bfd *, struct bfd_link_info *); |
| + |
| +static bfd_boolean nios2_elf32_section_from_shdr |
| + (bfd *, Elf_Internal_Shdr *, const char *name, int shindex); |
| + |
| +static bfd_boolean nios2_elf32_section_flags |
| + (flagword *, const Elf_Internal_Shdr *); |
| + |
| +static bfd_boolean nios2_elf32_fake_sections |
| + (bfd *, Elf_Internal_Shdr *, asection *); |
| + |
| + |
| + |
| +static bfd_boolean nios2_elf32_check_relocs |
| + (bfd *, struct bfd_link_info *, asection *, |
| + const Elf_Internal_Rela *); |
| + |
| +static asection *nios2_elf32_gc_mark_hook (asection * sec, |
| + struct bfd_link_info * |
| + info, |
| + Elf_Internal_Rela * rel, |
| + struct elf_link_hash_entry |
| + * h, |
| + Elf_Internal_Sym * sym); |
| + |
| + |
| +/* target vector */ |
| +extern const bfd_target bfd_elf32_littlenios2_vec; |
| +extern const bfd_target bfd_elf32_bignios2_vec; |
| + |
| +/* The relocation table used for SHT_REL sections. */ |
| + |
| +static reloc_howto_type elf_nios2_howto_table_rel[] = { |
| + /* No relocation. */ |
| + HOWTO (R_NIOS2_NONE, /* type */ |
| + 0, /* rightshift */ |
| + 0, /* size (0 = byte, 1 = short, 2 = long) */ |
| + 0, /* bitsize */ |
| + FALSE, /* pc_relative */ |
| + 0, /* bitpos */ |
| + complain_overflow_dont, /* complain_on_overflow */ |
| + bfd_elf_generic_reloc, /* special_function */ |
| + "R_NIOS2_NONE", /* name */ |
| + FALSE, /* partial_inplace */ |
| + 0, /* src_mask */ |
| + 0, /* dst_mask */ |
| + FALSE), /* pcrel_offset */ |
| + |
| + /* 16-bit signed immediate relocation */ |
| + HOWTO (R_NIOS2_S16, /* type */ |
| + 0, /* rightshift */ |
| + 2, /* size (0 = byte, 1 = short, 2 = long) */ |
| + 16, /* bitsize */ |
| + FALSE, /* pc_relative */ |
| + 6, /* bitpos */ |
| + complain_overflow_signed, /* complain on overflow */ |
| + bfd_elf_generic_reloc, /* special function */ |
| + "R_NIOS2_S16", /* name */ |
| + FALSE, /* partial_inplace */ |
| + 0x003fffc0, /* src_mask */ |
| + 0x003fffc0, /* dest_mask */ |
| + FALSE), /* pcrel_offset */ |
| + |
| + /* 16-bit unsigned immediate relocation */ |
| + HOWTO (R_NIOS2_U16, /* type */ |
| + 0, /* rightshift */ |
| + 2, /* size (0 = byte, 1 = short, 2 = long) */ |
| + 16, /* bitsize */ |
| + FALSE, /* pc_relative */ |
| + 6, /* bitpos */ |
| + complain_overflow_unsigned, /* complain on overflow */ |
| + bfd_elf_generic_reloc, /* special function */ |
| + "R_NIOS2_U16", /* name */ |
| + FALSE, /* partial_inplace */ |
| + 0x003fffc0, /* src_mask */ |
| + 0x003fffc0, /* dest_mask */ |
| + FALSE), /* pcrel_offset */ |
| + |
| + HOWTO (R_NIOS2_PCREL16, /* type */ |
| + 0, /* rightshift */ |
| + 2, /* size (0 = byte, 1 = short, 2 = long) */ |
| + 16, /* bitsize */ |
| + TRUE, /* pc_relative */ |
| + 6, /* bitpos */ |
| + complain_overflow_signed, /* complain on overflow */ |
| + nios2_elf32_pcrel16_relocate, /* special function */ |
| + "R_NIOS2_PCREL16", /* name */ |
| + FALSE, /* partial_inplace */ |
| + 0x003fffc0, /* src_mask */ |
| + 0x003fffc0, /* dest_mask */ |
| + TRUE), /* pcrel_offset */ |
| + |
| + HOWTO (R_NIOS2_CALL26, /* type */ |
| + 2, /* rightshift */ |
| + 2, /* size (0 = byte, 1 = short, 2 = long) */ |
| + 26, /* bitsize */ |
| + FALSE, /* pc_relative */ |
| + 6, /* bitpos */ |
| + complain_overflow_dont, /* complain on overflow */ |
| + nios2_elf32_call26_relocate, /* special function */ |
| + "R_NIOS2_CALL26", /* name */ |
| + FALSE, /* partial_inplace */ |
| + 0xffffffc0, /* src_mask */ |
| + 0xffffffc0, /* dst_mask */ |
| + FALSE), /* pcrel_offset */ |
| + |
| + HOWTO (R_NIOS2_IMM5, |
| + 0, |
| + 2, |
| + 5, |
| + FALSE, |
| + 6, |
| + complain_overflow_bitfield, |
| + bfd_elf_generic_reloc, |
| + "R_NIOS2_IMM5", |
| + FALSE, |
| + 0x000007c0, |
| + 0x000007c0, |
| + FALSE), |
| + |
| + HOWTO (R_NIOS2_CACHE_OPX, |
| + 0, |
| + 2, |
| + 5, |
| + FALSE, |
| + 22, |
| + complain_overflow_bitfield, |
| + bfd_elf_generic_reloc, |
| + "R_NIOS2_CACHE_OPX", |
| + FALSE, |
| + 0x07c00000, |
| + 0x07c00000, |
| + FALSE), |
| + |
| + HOWTO (R_NIOS2_IMM6, |
| + 0, |
| + 2, |
| + 6, |
| + FALSE, |
| + 6, |
| + complain_overflow_bitfield, |
| + bfd_elf_generic_reloc, |
| + "R_NIOS2_IMM6", |
| + FALSE, |
| + 0x00000fc0, |
| + 0x00000fc0, |
| + FALSE), |
| + |
| + HOWTO (R_NIOS2_IMM8, |
| + 0, |
| + 2, |
| + 8, |
| + FALSE, |
| + 6, |
| + complain_overflow_bitfield, |
| + bfd_elf_generic_reloc, |
| + "R_NIOS2_IMM8", |
| + FALSE, |
| + 0x00003fc0, |
| + 0x00003fc0, |
| + FALSE), |
| + |
| + HOWTO (R_NIOS2_HI16, |
| + 0, |
| + 2, |
| + 32, |
| + FALSE, |
| + 6, |
| + complain_overflow_dont, |
| + nios2_elf32_hi16_relocate, |
| + "R_NIOS2_HI16", |
| + FALSE, |
| + 0x003fffc0, |
| + 0x003fffc0, |
| + FALSE), |
| + |
| + HOWTO (R_NIOS2_LO16, |
| + 0, |
| + 2, |
| + 32, |
| + FALSE, |
| + 6, |
| + complain_overflow_dont, |
| + nios2_elf32_lo16_relocate, |
| + "R_NIOS2_LO16", |
| + FALSE, |
| + 0x003fffc0, |
| + 0x003fffc0, |
| + FALSE), |
| + |
| + HOWTO (R_NIOS2_HIADJ16, |
| + 0, |
| + 2, |
| + 32, |
| + FALSE, |
| + 6, |
| + complain_overflow_dont, |
| + nios2_elf32_hiadj16_relocate, |
| + "R_NIOS2_HIADJ16", |
| + FALSE, |
| + 0x003fffc0, |
| + 0x003fffc0, |
| + FALSE), |
| + |
| + HOWTO (R_NIOS2_BFD_RELOC_32, |
| + 0, |
| + 2, /* long */ |
| + 32, |
| + FALSE, |
| + 0, |
| + complain_overflow_dont, |
| + bfd_elf_generic_reloc, |
| + "R_NIOS2_BFD_RELOC32", |
| + FALSE, |
| + 0xffffffff, |
| + 0xffffffff, |
| + FALSE), |
| + |
| + HOWTO (R_NIOS2_BFD_RELOC_16, |
| + 0, |
| + 1, /* short */ |
| + 16, |
| + FALSE, |
| + 0, |
| + complain_overflow_bitfield, |
| + bfd_elf_generic_reloc, |
| + "R_NIOS2_BFD_RELOC16", |
| + FALSE, |
| + 0x0000ffff, |
| + 0x0000ffff, |
| + FALSE), |
| + |
| + HOWTO (R_NIOS2_BFD_RELOC_8, |
| + 0, |
| + 0, /* byte */ |
| + 8, |
| + FALSE, |
| + 0, |
| + complain_overflow_bitfield, |
| + bfd_elf_generic_reloc, |
| + "R_NIOS2_BFD_RELOC8", |
| + FALSE, |
| + 0x000000ff, |
| + 0x000000ff, |
| + FALSE), |
| + |
| + HOWTO (R_NIOS2_GPREL, |
| + 0, |
| + 2, |
| + 32, |
| + FALSE, |
| + 6, |
| + complain_overflow_dont, |
| + nios2_elf32_gprel_relocate, |
| + "R_NIOS2_GPREL", |
| + FALSE, |
| + 0x003fffc0, |
| + 0x003fffc0, |
| + FALSE), |
| + |
| + HOWTO (R_NIOS2_GNU_VTINHERIT, |
| + 0, |
| + 2, /* short */ |
| + 0, |
| + FALSE, |
| + 0, |
| + complain_overflow_dont, |
| + NULL, |
| + "R_NIOS2_GNU_VTINHERIT", |
| + FALSE, |
| + 0, |
| + 0, |
| + FALSE), |
| + |
| + HOWTO (R_NIOS2_GNU_VTENTRY, |
| + 0, |
| + 2, /* byte */ |
| + 0, |
| + FALSE, |
| + 0, |
| + complain_overflow_dont, |
| + _bfd_elf_rel_vtable_reloc_fn, |
| + "R_NIOS2_GNU_VTENTRY", |
| + FALSE, |
| + 0, |
| + 0, |
| + FALSE), |
| + |
| + HOWTO (R_NIOS2_UJMP, |
| + 0, |
| + 2, |
| + 32, |
| + FALSE, |
| + 6, |
| + complain_overflow_dont, |
| + nios2_elf32_ujmp_relocate, |
| + "R_NIOS2_UJMP", |
| + FALSE, |
| + 0x003fffc0, |
| + 0x003fffc0, |
| + FALSE), |
| + |
| + HOWTO (R_NIOS2_CJMP, |
| + 0, |
| + 2, |
| + 32, |
| + FALSE, |
| + 6, |
| + complain_overflow_dont, |
| + nios2_elf32_cjmp_relocate, |
| + "R_NIOS2_CJMP", |
| + FALSE, |
| + 0x003fffc0, |
| + 0x003fffc0, |
| + FALSE), |
| + |
| + HOWTO (R_NIOS2_CALLR, |
| + 0, |
| + 2, |
| + 32, |
| + FALSE, |
| + 6, |
| + complain_overflow_dont, |
| + nios2_elf32_callr_relocate, |
| + "R_NIOS2_CALLR", |
| + FALSE, |
| + 0x003fffc0, |
| + 0x003fffc0, |
| + FALSE), |
| + |
| + HOWTO (R_NIOS2_ALIGN, |
| + 0, |
| + 2, |
| + 0, |
| + FALSE, |
| + 0, |
| + complain_overflow_dont, |
| + nios2_elf32_ignore_reloc, |
| + "R_NIOS2_ALIGN", |
| + FALSE, |
| + 0, |
| + 0, |
| + TRUE), |
| + |
| +/* add other relocations here */ |
| +}; |
| + |
| +static unsigned char elf_code_to_howto_index[R_NIOS2_ILLEGAL + 1]; |
| + |
| +static reloc_howto_type * |
| +lookup_howto (unsigned int rtype) |
| +{ |
| + static int initialized = 0; |
| + int i; |
| + int howto_tbl_size = (int) (sizeof (elf_nios2_howto_table_rel) |
| + / sizeof (elf_nios2_howto_table_rel[0])); |
| + |
| + if (!initialized) |
| + { |
| + initialized = 1; |
| + memset (elf_code_to_howto_index, 0xff, |
| + sizeof (elf_code_to_howto_index)); |
| + for (i = 0; i < howto_tbl_size; i++) |
| + elf_code_to_howto_index[elf_nios2_howto_table_rel[i].type] = i; |
| + } |
| + |
| + BFD_ASSERT (rtype <= R_NIOS2_ILLEGAL); |
| + i = elf_code_to_howto_index[rtype]; |
| + if (i >= howto_tbl_size) |
| + return 0; |
| + return elf_nios2_howto_table_rel + i; |
| +} |
| + |
| +/* |
| + map for converting BFD reloc types to New Jersey |
| + reloc types |
| + */ |
| +struct elf_reloc_map |
| +{ |
| + bfd_reloc_code_real_type bfd_val; |
| + enum elf_nios2_reloc_type elf_val; |
| +}; |
| + |
| +static const struct elf_reloc_map nios2_reloc_map[] = { |
| + {BFD_RELOC_NIOS2_S16, R_NIOS2_S16}, |
| + {BFD_RELOC_NIOS2_U16, R_NIOS2_U16}, |
| + {BFD_RELOC_16_PCREL, R_NIOS2_PCREL16}, |
| + {BFD_RELOC_NIOS2_CALL26, R_NIOS2_CALL26}, |
| + {BFD_RELOC_NIOS2_IMM5, R_NIOS2_IMM5}, |
| + {BFD_RELOC_NIOS2_CACHE_OPX, R_NIOS2_CACHE_OPX}, |
| + {BFD_RELOC_NIOS2_IMM6, R_NIOS2_IMM6}, |
| + {BFD_RELOC_NIOS2_IMM8, R_NIOS2_IMM8}, |
| + {BFD_RELOC_NIOS2_HI16, R_NIOS2_HI16}, |
| + {BFD_RELOC_NIOS2_LO16, R_NIOS2_LO16}, |
| + {BFD_RELOC_NIOS2_HIADJ16, R_NIOS2_HIADJ16}, |
| + {BFD_RELOC_32, R_NIOS2_BFD_RELOC_32}, |
| + {BFD_RELOC_16, R_NIOS2_BFD_RELOC_16}, |
| + {BFD_RELOC_8, R_NIOS2_BFD_RELOC_8}, |
| + {BFD_RELOC_NIOS2_GPREL, R_NIOS2_GPREL}, |
| + {BFD_RELOC_VTABLE_INHERIT, R_NIOS2_GNU_VTINHERIT}, |
| + {BFD_RELOC_VTABLE_ENTRY, R_NIOS2_GNU_VTENTRY}, |
| + {BFD_RELOC_NIOS2_UJMP, R_NIOS2_UJMP}, |
| + {BFD_RELOC_NIOS2_CJMP, R_NIOS2_CJMP}, |
| + {BFD_RELOC_NIOS2_CALLR, R_NIOS2_CALLR}, |
| + {BFD_RELOC_NIOS2_ALIGN, R_NIOS2_ALIGN}, |
| +}; |
| + |
| +/* Given a BFD reloc type, return a howto structure. */ |
| + |
| +static reloc_howto_type * |
| +nios2_elf32_bfd_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED, |
| + bfd_reloc_code_real_type code) |
| +{ |
| + int i; |
| + for (i = 0; |
| + i < (int) (sizeof (nios2_reloc_map) / sizeof (struct elf_reloc_map)); |
| + ++i) |
| + { |
| + if (nios2_reloc_map[i].bfd_val == code) |
| + return &elf_nios2_howto_table_rel[(int) nios2_reloc_map[i].elf_val]; |
| + } |
| + |
| + return NULL; |
| +} |
| + |
| +/* Helper function for nios2_elf32_info_to_howto */ |
| + |
| +static reloc_howto_type * |
| +nios2_elf32_rtype_to_howto (unsigned int r_type, |
| + bfd_boolean rela_p ATTRIBUTE_UNUSED) |
| +{ |
| + BFD_ASSERT (r_type < R_NIOS2_ILLEGAL); |
| + return &elf_nios2_howto_table_rel[r_type]; |
| +} |
| + |
| +/* Given a ELF32 relocation, fill in a arelent structure */ |
| + |
| +static void |
| +nios2_elf32_info_to_howto (bfd * abfd ATTRIBUTE_UNUSED, arelent * cache_ptr, |
| + Elf_Internal_Rela * dst) |
| +{ |
| + unsigned int r_type; |
| + |
| + r_type = ELF32_R_TYPE (dst->r_info); |
| + cache_ptr->howto = nios2_elf32_rtype_to_howto (r_type, FALSE); |
| + |
| + // FIXME - do we need to do anything else here??? |
| +} |
| + |
| +/* The assembler has output long jmp/call sequences for all calls |
| + * and pc-relative branches that it cannot guarantee are within |
| + * range, so the linker must attempt to "relax" these sequences to |
| + * short branches and calls if it can. Since we only relax in one |
| + * direction - long to short - we don't need to see whether each |
| + * relaxation invalidates any others |
| + * |
| + * |
| + **/ |
| +static bfd_boolean |
| +nios2_elf32_relax_section (bfd * abfd, |
| + asection * sec, |
| + struct bfd_link_info *link_info, bfd_boolean * again) |
| +{ |
| + Elf_Internal_Shdr *symtab_hdr; |
| + Elf_Internal_Rela *internal_relocs; |
| + Elf_Internal_Rela *irel, *irelend; |
| + bfd_byte *contents = NULL; |
| + Elf_Internal_Sym *isymbuf = NULL; |
| + |
| + /* Assume nothing changes. */ |
| + *again = FALSE; |
| + |
| + /* We don't have to do anything for a relocatable link, if |
| + this section does not have relocs, or if this is not a |
| + code section. */ |
| + if (link_info->relocatable |
| + || (sec->flags & SEC_RELOC) == 0 |
| + || sec->reloc_count == 0 || (sec->flags & SEC_CODE) == 0) |
| + return TRUE; |
| + |
| + /* If this is the first time we have been called for this section, |
| + initialize the cooked size. */ |
| + if (sec->size == 0) |
| + sec->size = sec->rawsize; |
| + |
| + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; |
| + |
| + /* Get a copy of the native relocations. */ |
| + internal_relocs = (_bfd_elf_link_read_relocs |
| + (abfd, sec, (void *) NULL, (Elf_Internal_Rela *) NULL, |
| + link_info->keep_memory)); |
| + if (internal_relocs == NULL) |
| + goto error_return; |
| + |
| + /* Walk through them looking for relaxing opportunities. */ |
| + irelend = internal_relocs + sec->reloc_count; |
| + for (irel = internal_relocs; irel < irelend; irel++) |
| + { |
| + bfd_vma symval; |
| + |
| + /* If this isn't something that can be relaxed, then ignore |
| + this reloc. */ |
| + if (ELF32_R_TYPE (irel->r_info) != (int) R_NIOS2_UJMP |
| + && ELF32_R_TYPE (irel->r_info) != (int) R_NIOS2_CJMP |
| + && ELF32_R_TYPE (irel->r_info) != (int) R_NIOS2_CALLR) |
| + { |
| + continue; |
| + } |
| + |
| + /* Get the section contents if we haven't done so already. */ |
| + if (contents == NULL) |
| + { |
| + /* Get cached copy if it exists. */ |
| + if (elf_section_data (sec)->this_hdr.contents != NULL) |
| + contents = elf_section_data (sec)->this_hdr.contents; |
| + else |
| + { |
| + /* Go get them off disk. */ |
| + contents = (bfd_byte *) bfd_malloc (sec->rawsize); |
| + if (contents == NULL) |
| + goto error_return; |
| + |
| + if (!bfd_get_section_contents (abfd, sec, contents, |
| + (file_ptr) 0, sec->rawsize)) |
| + goto error_return; |
| + } |
| + } |
| + |
| + /* Read this BFD's local symbols if we haven't done so already. */ |
| + if (isymbuf == NULL && symtab_hdr->sh_info != 0) |
| + { |
| + isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; |
| + if (isymbuf == NULL) |
| + isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, |
| + symtab_hdr->sh_info, 0, |
| + NULL, NULL, NULL); |
| + if (isymbuf == NULL) |
| + goto error_return; |
| + } |
| + |
| + /* Get the value of the symbol referred to by the reloc. */ |
| + if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) |
| + { |
| + /* A local symbol. */ |
| + Elf_Internal_Sym *isym; |
| + asection *sym_sec; |
| + |
| + isym = isymbuf + ELF32_R_SYM (irel->r_info); |
| + if (isym->st_shndx == SHN_UNDEF) |
| + sym_sec = bfd_und_section_ptr; |
| + else if (isym->st_shndx == SHN_ABS) |
| + sym_sec = bfd_abs_section_ptr; |
| + else if (isym->st_shndx == SHN_COMMON) |
| + sym_sec = bfd_com_section_ptr; |
| + else |
| + sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx); |
| + symval = (isym->st_value |
| + + sym_sec->output_section->vma + sym_sec->output_offset); |
| + } |
| + else |
| + { |
| + unsigned long indx; |
| + struct elf_link_hash_entry *h; |
| + |
| + /* An external symbol. */ |
| + indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; |
| + h = elf_sym_hashes (abfd)[indx]; |
| + BFD_ASSERT (h != NULL); |
| + if (h->root.type != bfd_link_hash_defined |
| + && h->root.type != bfd_link_hash_defweak) |
| + { |
| + /* This appears to be a reference to an undefined |
| + symbol. Just ignore it--it will be caught by the |
| + regular reloc processing. */ |
| + continue; |
| + } |
| + |
| + symval = (h->root.u.def.value |
| + + h->root.u.def.section->output_section->vma |
| + + h->root.u.def.section->output_offset); |
| + } |
| + |
| + /* For simplicity of coding, we are going to modify the section |
| + contents, the section relocs, and the BFD symbol table. We |
| + must tell the rest of the code not to free up this |
| + information. It would be possible to instead create a table |
| + of changes which have to be made, as is done in coff-mips.c; |
| + that would be more work, but would require less memory when |
| + the linker is run. */ |
| + |
| + /* try to turn : |
| + * movhi at, %hi(symbol) |
| + * movui at, %lo(symbol) |
| + * callr at |
| + * into: |
| + * call symbol |
| + */ |
| + if (ELF32_R_TYPE (irel->r_info) == (int) R_NIOS2_CALLR) |
| + { |
| + bfd_vma targ_addr = symval + irel->r_addend; |
| + bfd_vma curr_addr = (sec->output_section->vma + sec->output_offset); |
| + bfd_vma targ_page, curr_page; |
| + targ_page = targ_addr & 0xf0000000; |
| + curr_page = curr_addr & 0xf0000000; |
| + |
| + if (targ_page == curr_page) |
| + { |
| + /* change the opcode to a call */ |
| + bfd_put_32 (abfd, OP_MATCH_CALL, contents + irel->r_offset); |
| + /* Note that we've changed the relocs, section contents, etc. */ |
| + elf_section_data (sec)->relocs = internal_relocs; |
| + elf_section_data (sec)->this_hdr.contents = contents; |
| + symtab_hdr->contents = (unsigned char *) isymbuf; |
| + |
| + /* Fix the relocation's type. */ |
| + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), |
| + R_NIOS2_CALL26); |
| + |
| + /* delete the next two instructions */ |
| + if (!nios2_elf32_relax_delete_bytes (abfd, sec, |
| + irel->r_offset + 4, 8)) |
| + goto error_return; |
| + |
| + /* NG FIXME - I'm putting this in for now, but I don't think we need it */ |
| + *again = TRUE; |
| + } |
| + } |
| + |
| + /* try to turn : |
| + * movhi at, %hi(symbol) |
| + * movui at, %lo(symbol) |
| + * jmp at |
| + * into: |
| + * br symbol |
| + */ |
| + if (ELF32_R_TYPE (irel->r_info) == (int) R_NIOS2_UJMP) |
| + { |
| + bfd_vma pcrel_offset; |
| + Elf_Internal_Rela *irelalign = NULL; |
| + Elf_Internal_Rela *irela = elf_section_data (sec)->relocs; |
| + Elf_Internal_Rela *irelend = irel + sec->reloc_count; |
| + |
| + for (; irela < irelend; irela++) |
| + { |
| + if (ELF32_R_TYPE (irela->r_info) == (int) R_NIOS2_ALIGN |
| + && irela->r_offset > irel->r_offset + 4 |
| + && 8 < (1 << irela->r_addend)) |
| + { |
| + irelalign = irela; |
| + break; |
| + } |
| + } |
| + |
| + /* calculate the pcrelative offset from current location */ |
| + pcrel_offset = symval; |
| + pcrel_offset -= (sec->output_section->vma + sec->output_offset); |
| + pcrel_offset += irel->r_addend; |
| + |
| + /* we need to compute the pcrel_offset from the next instruction */ |
| + pcrel_offset -= (irel->r_offset + 4); |
| + |
| + /* does this value fit in 16 bits */ |
| + if ((irelalign == NULL && (long) pcrel_offset <= 0x8004 |
| + && (long) pcrel_offset >= -0x8000) || (irelalign != NULL |
| + && (long) pcrel_offset |
| + <= 0x7ffc |
| + && (long) pcrel_offset |
| + >= -0x8000)) |
| + { |
| + /* change the opcode to an unconditional branch */ |
| + bfd_put_32 (abfd, OP_MATCH_BR, contents + irel->r_offset); |
| + /* Note that we've changed the relocs, section contents, etc. */ |
| + elf_section_data (sec)->relocs = internal_relocs; |
| + elf_section_data (sec)->this_hdr.contents = contents; |
| + symtab_hdr->contents = (unsigned char *) isymbuf; |
| + |
| + /* Fix the relocation's type. */ |
| + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), |
| + R_NIOS2_PCREL16); |
| + |
| + /* delete the next two instructions */ |
| + if (!nios2_elf32_relax_delete_bytes (abfd, sec, |
| + irel->r_offset + 4, 8)) |
| + goto error_return; |
| + |
| + /* NG FIXME - I'm putting this in for now, but I don't think we need it */ |
| + *again = TRUE; |
| + } |
| + } |
| + |
| + /* try to turn : |
| + * b{cond} a, b skip |
| + * movhi at, %hi(symbol) |
| + * movui at, %lo(symbol) |
| + * jmp at |
| + * skip: |
| + * ... |
| + * into: |
| + * br{opp_cond} a, b, symbol |
| + */ |
| + if (ELF32_R_TYPE (irel->r_info) == (int) R_NIOS2_CJMP) |
| + { |
| + bfd_vma pcrel_offset; |
| + Elf_Internal_Rela *irelalign = NULL; |
| + Elf_Internal_Rela *irela = elf_section_data (sec)->relocs; |
| + Elf_Internal_Rela *irelend = irel + sec->reloc_count; |
| + |
| + for (; irela < irelend; irela++) |
| + { |
| + if (ELF32_R_TYPE (irela->r_info) == (int) R_NIOS2_ALIGN |
| + && irela->r_offset > irel->r_offset + 4 |
| + && 8 < (1 << irela->r_addend)) |
| + { |
| + irelalign = irela; |
| + break; |
| + } |
| + } |
| + |
| + /* calculate the pcrelative offset from current location */ |
| + pcrel_offset = symval; |
| + pcrel_offset -= (sec->output_section->vma + sec->output_offset); |
| + pcrel_offset += irel->r_addend; |
| + |
| + /* we need to compute the pcrel_offset from this instruction |
| + * ie the movhi */ |
| + pcrel_offset -= (irel->r_offset); |
| + |
| + /* does this value fit in 16 bits */ |
| + if ((irelalign == NULL && (long) pcrel_offset <= 0x8008 |
| + && (long) pcrel_offset >= -0x8000) || (irelalign != NULL |
| + && (long) pcrel_offset |
| + <= 0x7ffc |
| + && (long) pcrel_offset |
| + >= -0x8000)) |
| + { |
| + unsigned long opcode, op_a, op_b; |
| + /* get the conditional branch opcode */ |
| + opcode = bfd_get_32 (abfd, contents + irel->r_offset - 4); |
| + /* reverse the condition */ |
| + switch (opcode & OP_MASK_OP) |
| + { |
| + case OP_MATCH_BEQ: |
| + opcode = (opcode & ~OP_MASK_OP) | OP_MATCH_BNE; |
| + break; |
| + case OP_MATCH_BNE: |
| + opcode = (opcode & ~OP_MASK_OP) | OP_MATCH_BEQ; |
| + break; |
| + case OP_MATCH_BGE: |
| + case OP_MATCH_BGEU: |
| + case OP_MATCH_BLT: |
| + case OP_MATCH_BLTU: |
| + /* swap the operands */ |
| + op_a = (opcode & OP_MASK_RRT) << 5; |
| + op_b = (opcode & OP_MASK_RRS) >> 5; |
| + opcode = |
| + (opcode & ~(OP_MASK_RRS | OP_MASK_RRT)) | op_a | op_b; |
| + break; |
| + default: |
| + fprintf (stderr, |
| + "relaxation error - expecting conditional branch, aborting\n"); |
| + abort (); |
| + break; |
| + } |
| + |
| + /* we must set the branch target to zero so that the skip over the jmp doesn't get |
| + * added to the jmp */ |
| + opcode = opcode & (~OP_MASK_IMM16); |
| + |
| + /* change the opcode to the reversed conditional branch */ |
| + bfd_put_32 (abfd, opcode, contents + irel->r_offset - 4); |
| + /* Note that we've changed the relocs, section contents, etc. */ |
| + elf_section_data (sec)->relocs = internal_relocs; |
| + elf_section_data (sec)->this_hdr.contents = contents; |
| + symtab_hdr->contents = (unsigned char *) isymbuf; |
| + |
| + /* Fix the relocation's type. */ |
| + irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), |
| + R_NIOS2_PCREL16); |
| + |
| + /* this relocation's offset has also been reduced by 4 bytes */ |
| + irel->r_offset -= 4; |
| + |
| + /* delete the next three instructions */ |
| + if (!nios2_elf32_relax_delete_bytes (abfd, sec, |
| + irel->r_offset + 4, 12)) |
| + goto error_return; |
| + |
| + /* NG FIXME - I'm putting this in for now, but I don't think we need it */ |
| + *again = TRUE; |
| + } |
| + } |
| + |
| + /* otherwise, leave alone */ |
| + } |
| + |
| + if (isymbuf != NULL && symtab_hdr->contents != (unsigned char *) isymbuf) |
| + { |
| + if (!link_info->keep_memory) |
| + free (isymbuf); |
| + else |
| + { |
| + /* Cache the symbols for elf_link_input_bfd. */ |
| + symtab_hdr->contents = (unsigned char *) isymbuf; |
| + } |
| + } |
| + |
| + if (contents != NULL |
| + && elf_section_data (sec)->this_hdr.contents != contents) |
| + { |
| + if (!link_info->keep_memory) |
| + free (contents); |
| + else |
| + { |
| + /* Cache the section contents for elf_link_input_bfd. */ |
| + elf_section_data (sec)->this_hdr.contents = contents; |
| + } |
| + } |
| + |
| + if (internal_relocs != NULL |
| + && elf_section_data (sec)->relocs != internal_relocs) |
| + free (internal_relocs); |
| + |
| + |
| + return TRUE; |
| + |
| +error_return: |
| + if (isymbuf != NULL && symtab_hdr->contents != (unsigned char *) isymbuf) |
| + free (isymbuf); |
| + if (contents != NULL |
| + && elf_section_data (sec)->this_hdr.contents != contents) |
| + free (contents); |
| + if (internal_relocs != NULL |
| + && elf_section_data (sec)->relocs != internal_relocs) |
| + free (internal_relocs); |
| + |
| + return FALSE; |
| +} |
| + |
| +/* Delete some bytes from a section while relaxing. |
| + * Copied from mn10200 port */ |
| + |
| +static bfd_boolean |
| +nios2_elf32_relax_delete_bytes (bfd * abfd, |
| + asection * sec, bfd_vma addr, int count) |
| +{ |
| + Elf_Internal_Shdr *symtab_hdr; |
| + unsigned int sec_shndx; |
| + bfd_byte *contents; |
| + Elf_Internal_Rela *irel, *irelend; |
| + Elf_Internal_Rela *irelalign; |
| + bfd_vma toaddr; |
| + Elf_Internal_Sym *isym; |
| + Elf_Internal_Sym *isymend; |
| + struct elf_link_hash_entry **sym_hashes; |
| + struct elf_link_hash_entry **end_hashes; |
| + unsigned int symcount; |
| + asection *asec; |
| + |
| + sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec); |
| + |
| + contents = elf_section_data (sec)->this_hdr.contents; |
| + |
| + /* The deletion must stop at the next ALIGN reloc for an aligment |
| + power larger than the number of bytes we are deleting. */ |
| + |
| + irelalign = NULL; |
| + /* +1 because we need to readjust symbols at end of section */ |
| + toaddr = sec->size + 1; |
| + |
| + irel = elf_section_data (sec)->relocs; |
| + irelend = irel + sec->reloc_count; |
| + |
| + for (; irel < irelend; irel++) |
| + { |
| + if (ELF32_R_TYPE (irel->r_info) == (int) R_NIOS2_ALIGN |
| + && irel->r_offset > addr && count < (1 << irel->r_addend)) |
| + { |
| + irelalign = irel; |
| + /* +1 because we need to readjust symbols at end of section */ |
| + toaddr = irel->r_offset + 1; |
| + break; |
| + } |
| + } |
| + |
| + |
| + /* Actually delete the bytes. */ |
| + memmove (contents + addr, contents + addr + count, |
| + (size_t) ((toaddr - 1) - addr - count)); |
| + |
| + if (irelalign == NULL) |
| + sec->size -= count; |
| + else |
| + { |
| + int i; |
| + |
| +#define NOP_OPCODE (0x0001883a) |
| + |
| + BFD_ASSERT ((count & 3) == 0); |
| + for (i = 0; i < count; i += 4) |
| + bfd_put_32 (abfd, (bfd_vma) NOP_OPCODE, |
| + contents + (toaddr - 1) - count + i); |
| + } |
| + |
| + /* get the symbol table */ |
| + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; |
| + isym = (Elf_Internal_Sym *) symtab_hdr->contents; |
| + |
| + /* Adjust all the reloc offsets in this section. */ |
| + for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++) |
| + { |
| + /* Get the new reloc address. */ |
| + if ((irel->r_offset > addr && irel->r_offset < toaddr)) |
| + irel->r_offset -= count; |
| + } |
| + |
| + /* Adjust relocations against targets in this section whose positions |
| + * have moved as a result of the relaxation */ |
| + |
| + for (asec = abfd->sections; asec; asec = asec->next) |
| + { |
| + irelend = elf_section_data (asec)->relocs + asec->reloc_count; |
| + for (irel = elf_section_data (asec)->relocs; irel < irelend; irel++) |
| + { |
| + Elf_Internal_Sym *sym; |
| + /* if the symbol which this reloc is against doesn't change |
| + * we need to change the reloc addend */ |
| + |
| + sym = isym + ELF32_R_SYM (irel->r_info); |
| + if (sym->st_shndx == sec_shndx |
| + && !(sym->st_value > addr && sym->st_value < toaddr) |
| + && sym->st_value + irel->r_addend > addr |
| + && sym->st_value + irel->r_addend < toaddr) |
| + { |
| + irel->r_addend -= count; |
| + } |
| + |
| + } |
| + } |
| + |
| + /* Adjust the local symbols defined in this section. */ |
| + for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++) |
| + { |
| + if (isym->st_shndx == sec_shndx |
| + && isym->st_value > addr && isym->st_value < toaddr) |
| + isym->st_value -= count; |
| + |
| + |
| + } |
| + |
| + /* Now adjust the global symbols defined in this section. */ |
| + symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym) |
| + - symtab_hdr->sh_info); |
| + sym_hashes = elf_sym_hashes (abfd); |
| + end_hashes = sym_hashes + symcount; |
| + for (; sym_hashes < end_hashes; sym_hashes++) |
| + { |
| + struct elf_link_hash_entry *sym_hash = *sym_hashes; |
| + if ((sym_hash->root.type == bfd_link_hash_defined |
| + || sym_hash->root.type == bfd_link_hash_defweak) |
| + && sym_hash->root.u.def.section == sec |
| + && sym_hash->root.u.def.value > addr |
| + && sym_hash->root.u.def.value < toaddr) |
| + { |
| + sym_hash->root.u.def.value -= count; |
| + } |
| + } |
| + |
| + return TRUE; |
| +} |
| + |
| +struct bfd_link_info *nios2_link_info = NULL; |
| + |
| +/* |
| +void |
| +_bfd_set_link_info (info) |
| + struct bfd_link_info *info; |
| +{ |
| + nios2_link_info = info; |
| +} |
| +*/ |
| + |
| +bfd_boolean linker_force_make_executable = FALSE; |
| + |
| +/* |
| +void |
| +_bfd_set_force_make_executable (force) |
| + bfd_boolean force; |
| +{ |
| + linker_force_make_executable = force; |
| +} |
| +*/ |
| + |
| +/* Set the GP value for OUTPUT_BFD. Returns FALSE if this is a |
| + dangerous relocation. */ |
| + |
| +static bfd_boolean |
| +nios2_elf_assign_gp (bfd *output_bfd, bfd_vma *pgp, struct bfd_link_info *info) |
| +{ |
| + |
| + bfd_boolean gp_found; |
| + struct bfd_hash_entry *h; |
| + struct bfd_link_hash_entry *lh; |
| + |
| + /* If we've already figured out what GP will be, just return it. */ |
| + *pgp = _bfd_get_gp_value (output_bfd); |
| + if (*pgp) |
| + return TRUE; |
| + |
| + h = bfd_hash_lookup (&info->hash->table, "_gp", FALSE, FALSE); |
| + lh = (struct bfd_link_hash_entry *) h; |
| +lookup: |
| + if (lh) |
| + { |
| + switch (lh->type) |
| + { |
| + case bfd_link_hash_undefined: |
| + case bfd_link_hash_undefweak: |
| + case bfd_link_hash_common: |
| + gp_found = FALSE; |
| + break; |
| + case bfd_link_hash_defined: |
| + case bfd_link_hash_defweak: |
| + gp_found = TRUE; |
| + *pgp = lh->u.def.value; |
| + break; |
| + case bfd_link_hash_indirect: |
| + case bfd_link_hash_warning: |
| + lh = lh->u.i.link; |
| + /* @@FIXME ignoring warning for now */ |
| + goto lookup; |
| + case bfd_link_hash_new: |
| + default: |
| + abort (); |
| + } |
| + } |
| + else |
| + gp_found = FALSE; |
| + |
| + if (!gp_found) |
| + { |
| + /* Only get the error once. */ |
| + *pgp = 4; |
| + _bfd_set_gp_value (output_bfd, *pgp); |
| + return FALSE; |
| + } |
| + |
| + _bfd_set_gp_value (output_bfd, *pgp); |
| + |
| + return TRUE; |
| +} |
| + |
| +/* We have to figure out the gp value, so that we can adjust the |
| + symbol value correctly. We look up the symbol _gp in the output |
| + BFD. If we can't find it, we're stuck. We cache it in the ELF |
| + target data. We don't need to adjust the symbol value for an |
| + external symbol if we are producing relocatable output. */ |
| + |
| +static bfd_reloc_status_type |
| +nios2_elf_final_gp (bfd *output_bfd, asymbol *symbol, bfd_boolean relocatable, |
| + char **error_message, bfd_vma *pgp, struct bfd_link_info *info) |
| +{ |
| + if (bfd_is_und_section (symbol->section) && !relocatable) |
| + { |
| + *pgp = 0; |
| + return bfd_reloc_undefined; |
| + } |
| + |
| + *pgp = _bfd_get_gp_value (output_bfd); |
| + if (*pgp == 0 && (!relocatable || (symbol->flags & BSF_SECTION_SYM) != 0)) |
| + { |
| + /* if this is called without link_info, then |
| + we cannot be doing a final link */ |
| + if (info == NULL) |
| + relocatable = TRUE; |
| + |
| + if (relocatable) |
| + { |
| + /* Make up a value. */ |
| + *pgp = symbol->section->output_section->vma + 0x4000; |
| + _bfd_set_gp_value (output_bfd, *pgp); |
| + } |
| + else if (!nios2_elf_assign_gp (output_bfd, pgp, info)) |
| + { |
| + *error_message = |
| + (char *) |
| + _("global pointer relative relocation when _gp not defined"); |
| + return bfd_reloc_dangerous; |
| + } |
| + } |
| + |
| + return bfd_reloc_ok; |
| +} |
| + |
| + |
| +/* Relocations that require special handling */ |
| + |
| +/* This is for relocations used only when relaxing to ensure |
| + * changes in size of section don't screw up .align */ |
| +static bfd_reloc_status_type |
| +nios2_elf32_ignore_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc_entry, |
| + asymbol *symbol ATTRIBUTE_UNUSED, void *data ATTRIBUTE_UNUSED, |
| + asection *input_section, bfd *output_bfd, char **error_message ATTRIBUTE_UNUSED) |
| +{ |
| + if (output_bfd != NULL) |
| + reloc_entry->address += input_section->output_offset; |
| + return bfd_reloc_ok; |
| +} |
| + |
| +static bfd_reloc_status_type |
| +nios2_elf32_hi16_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol, void *data, |
| + asection *input_section, bfd *output_bfd, char **error_message ATTRIBUTE_UNUSED) |
| +{ |
| + /* This part is from bfd_elf_generic_reloc. */ |
| + if (output_bfd != (bfd *) NULL |
| + && (symbol->flags & BSF_SECTION_SYM) == 0 |
| + && (!reloc_entry->howto->partial_inplace || reloc_entry->addend == 0)) |
| + { |
| + reloc_entry->address += input_section->output_offset; |
| + return bfd_reloc_ok; |
| + } |
| + |
| + if (output_bfd != NULL) |
| + /* FIXME: See bfd_perform_relocation. Is this right? */ |
| + return bfd_reloc_ok; |
| + |
| + return nios2_elf32_do_hi16_relocate (abfd, reloc_entry->howto, |
| + input_section, |
| + data, reloc_entry->address, |
| + (symbol->value |
| + + symbol->section->output_section->vma |
| + + symbol->section->output_offset), |
| + reloc_entry->addend); |
| +} |
| + |
| +static bfd_reloc_status_type |
| +nios2_elf32_lo16_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol, |
| + void *data, asection *input_section, bfd *output_bfd, char **error_message ATTRIBUTE_UNUSED) |
| +{ |
| +/* This part is from bfd_elf_generic_reloc. */ |
| + if (output_bfd != (bfd *) NULL |
| + && (symbol->flags & BSF_SECTION_SYM) == 0 |
| + && (!reloc_entry->howto->partial_inplace || reloc_entry->addend == 0)) |
| + { |
| + reloc_entry->address += input_section->output_offset; |
| + return bfd_reloc_ok; |
| + } |
| + |
| + if (output_bfd != NULL) |
| + /* FIXME: See bfd_perform_relocation. Is this right? */ |
| + return bfd_reloc_ok; |
| + |
| + return nios2_elf32_do_lo16_relocate (abfd, reloc_entry->howto, |
| + input_section, |
| + data, reloc_entry->address, |
| + (symbol->value |
| + + symbol->section->output_section->vma |
| + + symbol->section->output_offset), |
| + reloc_entry->addend); |
| +} |
| + |
| +static bfd_reloc_status_type |
| +nios2_elf32_hiadj16_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol, |
| + void *data, asection *input_section, bfd *output_bfd, |
| + char **error_message ATTRIBUTE_UNUSED) |
| +{ |
| +/* This part is from bfd_elf_generic_reloc. */ |
| + if (output_bfd != (bfd *) NULL |
| + && (symbol->flags & BSF_SECTION_SYM) == 0 |
| + && (!reloc_entry->howto->partial_inplace || reloc_entry->addend == 0)) |
| + { |
| + reloc_entry->address += input_section->output_offset; |
| + return bfd_reloc_ok; |
| + } |
| + |
| + if (output_bfd != NULL) |
| + /* FIXME: See bfd_perform_relocation. Is this right? */ |
| + return bfd_reloc_ok; |
| + |
| + return nios2_elf32_do_hiadj16_relocate (abfd, reloc_entry->howto, |
| + input_section, |
| + data, reloc_entry->address, |
| + (symbol->value |
| + + |
| + symbol->section->output_section-> |
| + vma + |
| + symbol->section->output_offset), |
| + reloc_entry->addend); |
| +} |
| + |
| +static bfd_reloc_status_type |
| +nios2_elf32_pcrel16_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol, |
| + void *data, asection *input_section, bfd *output_bfd, |
| + char **error_message ATTRIBUTE_UNUSED) |
| +{ |
| +/* This part is from bfd_elf_generic_reloc. */ |
| + if (output_bfd != (bfd *) NULL |
| + && (symbol->flags & BSF_SECTION_SYM) == 0 |
| + && (!reloc_entry->howto->partial_inplace || reloc_entry->addend == 0)) |
| + { |
| + reloc_entry->address += input_section->output_offset; |
| + return bfd_reloc_ok; |
| + } |
| + |
| + if (output_bfd != NULL) |
| + /* FIXME: See bfd_perform_relocation. Is this right? */ |
| + return bfd_reloc_ok; |
| + |
| + return nios2_elf32_do_pcrel16_relocate (abfd, reloc_entry->howto, |
| + input_section, |
| + data, reloc_entry->address, |
| + (symbol->value |
| + + |
| + symbol->section->output_section-> |
| + vma + |
| + symbol->section->output_offset), |
| + reloc_entry->addend); |
| +} |
| + |
| +static bfd_reloc_status_type |
| +nios2_elf32_call26_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol, |
| + void *data, asection *input_section, bfd *output_bfd, char **error_message ATTRIBUTE_UNUSED) |
| +{ |
| +/* This part is from bfd_elf_generic_reloc. */ |
| + if (output_bfd != (bfd *) NULL |
| + && (symbol->flags & BSF_SECTION_SYM) == 0 |
| + && (!reloc_entry->howto->partial_inplace || reloc_entry->addend == 0)) |
| + { |
| + reloc_entry->address += input_section->output_offset; |
| + return bfd_reloc_ok; |
| + } |
| + |
| + if (output_bfd != NULL) |
| + /* FIXME: See bfd_perform_relocation. Is this right? */ |
| + return bfd_reloc_ok; |
| + |
| + return nios2_elf32_do_call26_relocate (abfd, reloc_entry->howto, |
| + input_section, |
| + data, reloc_entry->address, |
| + (symbol->value |
| + + |
| + symbol->section->output_section-> |
| + vma + |
| + symbol->section->output_offset), |
| + reloc_entry->addend); |
| +} |
| + |
| +static bfd_reloc_status_type |
| +nios2_elf32_gprel_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol, |
| + void *data, asection *input_section, bfd *output_bfd, char **msg) |
| +{ |
| + bfd_vma relocation; |
| + bfd_vma gp; |
| + bfd_reloc_status_type r; |
| + |
| + |
| +/* This part is from bfd_elf_generic_reloc. */ |
| + if (output_bfd != (bfd *) NULL |
| + && (symbol->flags & BSF_SECTION_SYM) == 0 |
| + && (!reloc_entry->howto->partial_inplace || reloc_entry->addend == 0)) |
| + { |
| + reloc_entry->address += input_section->output_offset; |
| + return bfd_reloc_ok; |
| + } |
| + |
| + if (output_bfd != NULL) |
| + /* FIXME: See bfd_perform_relocation. Is this right? */ |
| + return bfd_reloc_ok; |
| + |
| + relocation = symbol->value |
| + + symbol->section->output_section->vma + symbol->section->output_offset; |
| + |
| + if ((r = |
| + nios2_elf_final_gp (abfd, symbol, FALSE, msg, &gp, |
| + nios2_link_info)) == bfd_reloc_ok) |
| + { |
| + relocation = relocation + reloc_entry->addend - gp; |
| + reloc_entry->addend = 0; |
| + if ((signed) relocation < -32768 || (signed) relocation > 32767) |
| + { |
| + *msg = _("global pointer relative address out of range"); |
| + r = bfd_reloc_outofrange; |
| + } |
| + else |
| + { |
| + r = nios2_elf32_do_gprel_relocate (abfd, reloc_entry->howto, |
| + input_section, |
| + data, reloc_entry->address, |
| + relocation, reloc_entry->addend); |
| + } |
| + } |
| + |
| + return r; |
| +} |
| + |
| +static bfd_reloc_status_type |
| +nios2_elf32_ujmp_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol, |
| + void *data, asection *input_section, bfd *output_bfd, char **msg ATTRIBUTE_UNUSED) |
| +{ |
| + /* This part is from bfd_elf_generic_reloc. */ |
| + if (output_bfd != (bfd *) NULL |
| + && (symbol->flags & BSF_SECTION_SYM) == 0 |
| + && (!reloc_entry->howto->partial_inplace || reloc_entry->addend == 0)) |
| + { |
| + reloc_entry->address += input_section->output_offset; |
| + return bfd_reloc_ok; |
| + } |
| + |
| + if (output_bfd != NULL) |
| + /* FIXME: See bfd_perform_relocation. Is this right? */ |
| + return bfd_reloc_ok; |
| + |
| + return nios2_elf32_do_ujmp_relocate (abfd, reloc_entry->howto, |
| + input_section, |
| + data, reloc_entry->address, |
| + (symbol->value |
| + + symbol->section->output_section->vma |
| + + symbol->section->output_offset), |
| + reloc_entry->addend); |
| +} |
| + |
| +static bfd_reloc_status_type |
| +nios2_elf32_cjmp_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol, |
| + void *data, asection *input_section, bfd *output_bfd, char **msg ATTRIBUTE_UNUSED) |
| +{ |
| + /* This part is from bfd_elf_generic_reloc. */ |
| + if (output_bfd != (bfd *) NULL |
| + && (symbol->flags & BSF_SECTION_SYM) == 0 |
| + && (!reloc_entry->howto->partial_inplace || reloc_entry->addend == 0)) |
| + { |
| + reloc_entry->address += input_section->output_offset; |
| + return bfd_reloc_ok; |
| + } |
| + |
| + if (output_bfd != NULL) |
| + /* FIXME: See bfd_perform_relocation. Is this right? */ |
| + return bfd_reloc_ok; |
| + |
| + return nios2_elf32_do_cjmp_relocate (abfd, reloc_entry->howto, |
| + input_section, |
| + data, reloc_entry->address, |
| + (symbol->value |
| + + symbol->section->output_section->vma |
| + + symbol->section->output_offset), |
| + reloc_entry->addend); |
| +} |
| + |
| +static bfd_reloc_status_type |
| +nios2_elf32_callr_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol, |
| + void *data, asection *input_section, bfd *output_bfd, char **msg ATTRIBUTE_UNUSED) |
| +{ |
| + /* This part is from bfd_elf_generic_reloc. */ |
| + if (output_bfd != (bfd *) NULL |
| + && (symbol->flags & BSF_SECTION_SYM) == 0 |
| + && (!reloc_entry->howto->partial_inplace || reloc_entry->addend == 0)) |
| + { |
| + reloc_entry->address += input_section->output_offset; |
| + return bfd_reloc_ok; |
| + } |
| + |
| + if (output_bfd != NULL) |
| + /* FIXME: See bfd_perform_relocation. Is this right? */ |
| + return bfd_reloc_ok; |
| + |
| + |
| + return nios2_elf32_do_callr_relocate (abfd, reloc_entry->howto, |
| + input_section, |
| + data, reloc_entry->address, |
| + (symbol->value |
| + + |
| + symbol->section->output_section-> |
| + vma + |
| + symbol->section->output_offset), |
| + reloc_entry->addend); |
| +} |
| + |
| +/* Do the relocations which require special handling */ |
| + |
| +static bfd_reloc_status_type |
| +nios2_elf32_do_hi16_relocate (bfd *abfd, reloc_howto_type *howto, |
| + asection *input_section ATTRIBUTE_UNUSED, bfd_byte *data, |
| + bfd_vma offset, bfd_vma symbol_value, bfd_vma addend) |
| +{ |
| + symbol_value = symbol_value + addend; |
| + addend = 0; |
| + symbol_value = (symbol_value >> 16) & 0xffff; |
| + return _bfd_final_link_relocate (howto, abfd, input_section, |
| + data, offset, symbol_value, addend); |
| +} |
| + |
| + |
| +static bfd_reloc_status_type |
| +nios2_elf32_do_lo16_relocate (bfd *abfd, reloc_howto_type *howto, |
| + asection *input_section ATTRIBUTE_UNUSED, bfd_byte *data, |
| + bfd_vma offset, bfd_vma symbol_value, bfd_vma addend) |
| +{ |
| + symbol_value = symbol_value + addend; |
| + addend = 0; |
| + symbol_value = symbol_value & 0xffff; |
| + return _bfd_final_link_relocate (howto, abfd, input_section, |
| + data, offset, symbol_value, addend); |
| +} |
| + |
| +static bfd_reloc_status_type |
| +nios2_elf32_do_hiadj16_relocate (bfd *abfd, reloc_howto_type *howto, |
| + asection *input_section ATTRIBUTE_UNUSED, bfd_byte *data, bfd_vma offset, |
| + bfd_vma symbol_value, bfd_vma addend) |
| +{ |
| + symbol_value = symbol_value + addend; |
| + addend = 0; |
| + symbol_value = |
| + ((symbol_value >> 16) & 0xffff) + ((symbol_value >> 15) & 0x01); |
| + return _bfd_final_link_relocate (howto, abfd, input_section, data, offset, |
| + symbol_value, addend); |
| +} |
| + |
| +static bfd_reloc_status_type |
| +nios2_elf32_do_pcrel16_relocate (bfd *abfd, reloc_howto_type *howto, |
| + asection *input_section ATTRIBUTE_UNUSED, bfd_byte *data, |
| + bfd_vma offset, bfd_vma symbol_value, bfd_vma addend) |
| +{ |
| + // NIOS2 pc relative relocations are relative to the next 32-bit instruction so we need |
| + // to subtract 4 before doing a final_link_relocate |
| + symbol_value = symbol_value + addend - 4; |
| + addend = 0; |
| + return _bfd_final_link_relocate (howto, abfd, input_section, |
| + data, offset, symbol_value, addend); |
| +} |
| + |
| +static bfd_reloc_status_type |
| +nios2_elf32_do_call26_relocate (bfd *abfd, reloc_howto_type *howto, |
| + asection *input_section ATTRIBUTE_UNUSED, bfd_byte *data, |
| + bfd_vma offset, bfd_vma symbol_value, bfd_vma addend) |
| +{ |
| + /* check that the relocation is in the same page as the current address */ |
| + if (((symbol_value + addend) & 0xf0000000) |
| + != ((input_section->output_section->vma + offset) & 0xf0000000)) |
| + return bfd_reloc_overflow; |
| + |
| + return _bfd_final_link_relocate (howto, abfd, input_section, |
| + data, offset, symbol_value, addend); |
| +} |
| + |
| + |
| +static bfd_reloc_status_type |
| +nios2_elf32_do_gprel_relocate (bfd *abfd, reloc_howto_type *howto, |
| + asection *input_section ATTRIBUTE_UNUSED, bfd_byte *data, |
| + bfd_vma offset, bfd_vma symbol_value, bfd_vma addend) |
| +{ |
| + // because we need the output_bfd, the special handling is done |
| + // in nios2_elf32_relocate_section or in nios2_elf32_gprel_relocate |
| + return _bfd_final_link_relocate (howto, abfd, input_section, |
| + data, offset, symbol_value, addend); |
| +} |
| + |
| +static bfd_reloc_status_type |
| +nios2_elf32_do_ujmp_relocate (bfd *abfd, reloc_howto_type *howto, |
| + asection *input_section ATTRIBUTE_UNUSED, bfd_byte *data, |
| + bfd_vma offset, bfd_vma symbol_value, bfd_vma addend) |
| +{ |
| + bfd_vma symbol_lo16, symbol_hi16; |
| + bfd_reloc_status_type r; |
| + symbol_value = symbol_value + addend; |
| + addend = 0; |
| + symbol_hi16 = (symbol_value >> 16) & 0xffff; |
| + symbol_lo16 = symbol_value & 0xffff; |
| + |
| + r = _bfd_final_link_relocate (howto, abfd, input_section, |
| + data, offset, symbol_hi16, addend); |
| + |
| + if (r == bfd_reloc_ok) |
| + return _bfd_final_link_relocate (howto, abfd, input_section, |
| + data, offset + 4, symbol_lo16, addend); |
| + |
| + return r; |
| +} |
| + |
| +static bfd_reloc_status_type |
| +nios2_elf32_do_cjmp_relocate (bfd *abfd, reloc_howto_type *howto, |
| + asection *input_section ATTRIBUTE_UNUSED, bfd_byte *data, |
| + bfd_vma offset, bfd_vma symbol_value, bfd_vma addend) |
| +{ |
| + bfd_vma symbol_lo16, symbol_hi16; |
| + bfd_reloc_status_type r; |
| + symbol_value = symbol_value + addend; |
| + addend = 0; |
| + symbol_hi16 = (symbol_value >> 16) & 0xffff; |
| + symbol_lo16 = symbol_value & 0xffff; |
| + |
| + r = _bfd_final_link_relocate (howto, abfd, input_section, |
| + data, offset, symbol_hi16, addend); |
| + |
| + if (r == bfd_reloc_ok) |
| + return _bfd_final_link_relocate (howto, abfd, input_section, |
| + data, offset + 4, symbol_lo16, addend); |
| + |
| + return r; |
| +} |
| + |
| +static bfd_reloc_status_type |
| +nios2_elf32_do_callr_relocate (bfd *abfd, reloc_howto_type *howto, |
| + asection *input_section ATTRIBUTE_UNUSED, bfd_byte *data, |
| + bfd_vma offset, bfd_vma symbol_value, bfd_vma addend) |
| +{ |
| + bfd_vma symbol_lo16, symbol_hi16; |
| + bfd_reloc_status_type r; |
| + symbol_value = symbol_value + addend; |
| + addend = 0; |
| + symbol_hi16 = (symbol_value >> 16) & 0xffff; |
| + symbol_lo16 = symbol_value & 0xffff; |
| + |
| + r = _bfd_final_link_relocate (howto, abfd, input_section, |
| + data, offset, symbol_hi16, addend); |
| + |
| + if (r == bfd_reloc_ok) |
| + return _bfd_final_link_relocate (howto, abfd, input_section, |
| + data, offset + 4, symbol_lo16, addend); |
| + |
| + return r; |
| +} |
| + |
| +/* |
| + The function nios2_elf32_relocate_section is used by the linker |
| + to perform relocations |
| +*/ |
| +static bfd_boolean |
| +nios2_elf32_relocate_section (bfd * output_bfd, |
| + 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; |
| + |
| +// size_t psymalloc = 0; |
| +// _bfd_generic_link_output_symbols(output_bfd, input_bfd, info, &psymalloc); |
| + 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_vma gp; |
| + bfd_reloc_status_type r = bfd_reloc_ok; |
| + const char *name = NULL; |
| + int r_type; |
| + const char *msg; |
| + |
| + msg = (const char *) NULL; |
| + |
| + r_type = ELF32_R_TYPE (rel->r_info); |
| + |
| + r_symndx = ELF32_R_SYM (rel->r_info); |
| + |
| + if (info->relocatable) |
| + { |
| + /* This is a relocatable 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 = lookup_howto ((unsigned) 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); |
| + |
| + // this ensures that relocations against duplicated symbols |
| + // in merged sections that have been removed are fixed up against |
| + // the remaining symbol and not the one that has been removed |
| + if ((sec->flags & SEC_MERGE) |
| + && ELF_ST_TYPE (sym->st_info) == STT_SECTION) |
| + { |
| + rel->r_addend = |
| + _bfd_elf_rel_local_sym (output_bfd, sym, &sec, rel->r_addend); |
| + rel->r_addend -= relocation; |
| + rel->r_addend += sec->output_section->vma + sec->output_offset; |
| + } |
| + |
| + 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; |
| + } |
| + } |
| + |
| + if (howto != NULL) |
| + { |
| + switch (howto->type) |
| + { |
| + case R_NIOS2_HI16: |
| + r = |
| + nios2_elf32_do_hi16_relocate (input_bfd, howto, input_section, |
| + contents, rel->r_offset, |
| + relocation, rel->r_addend); |
| + break; |
| + case R_NIOS2_LO16: |
| + r = |
| + nios2_elf32_do_lo16_relocate (input_bfd, howto, input_section, |
| + contents, rel->r_offset, |
| + relocation, rel->r_addend); |
| + break; |
| + case R_NIOS2_HIADJ16: |
| + r = |
| + nios2_elf32_do_hiadj16_relocate (input_bfd, howto, |
| + input_section, contents, |
| + rel->r_offset, relocation, |
| + rel->r_addend); |
| + break; |
| + case R_NIOS2_PCREL16: |
| + r = |
| + nios2_elf32_do_pcrel16_relocate (input_bfd, howto, |
| + input_section, contents, |
| + rel->r_offset, relocation, |
| + rel->r_addend); |
| + break; |
| + case R_NIOS2_GPREL: |
| + // turns an absolute address into a gp-relative address |
| + if (!nios2_elf_assign_gp (output_bfd, &gp, info)) |
| + { |
| + msg = |
| + _ |
| + ("global pointer relative relocation when _gp not defined"); |
| + r = bfd_reloc_dangerous; |
| + } |
| + else |
| + { |
| + relocation = relocation + rel->r_addend - gp; |
| + rel->r_addend = 0; |
| + if ((signed) relocation < -32768 |
| + || (signed) relocation > 32767) |
| + { |
| + msg = _("global pointer relative address out of range"); |
| + r = bfd_reloc_outofrange; |
| + } |
| + else |
| + { |
| + r = |
| + _bfd_final_link_relocate (howto, input_bfd, |
| + input_section, contents, |
| + rel->r_offset, relocation, |
| + rel->r_addend); |
| + } |
| + } |
| + |
| + break; |
| + case R_NIOS2_UJMP: |
| + r = |
| + nios2_elf32_do_ujmp_relocate (input_bfd, howto, input_section, |
| + contents, rel->r_offset, |
| + relocation, rel->r_addend); |
| + break; |
| + case R_NIOS2_CJMP: |
| + r = |
| + nios2_elf32_do_cjmp_relocate (input_bfd, howto, input_section, |
| + contents, rel->r_offset, |
| + relocation, rel->r_addend); |
| + break; |
| + case R_NIOS2_CALLR: |
| + r = |
| + nios2_elf32_do_callr_relocate (input_bfd, howto, |
| + input_section, contents, |
| + rel->r_offset, relocation, |
| + rel->r_addend); |
| + break; |
| + case R_NIOS2_CALL26: |
| + r = |
| + nios2_elf32_do_call26_relocate (input_bfd, howto, |
| + input_section, contents, |
| + rel->r_offset, relocation, |
| + rel->r_addend); |
| + break; |
| + case R_NIOS2_ALIGN: |
| + r = bfd_reloc_ok; |
| + /* comment - for symmetry this would be |
| + r = nios2_elf32_do_ignore_reloc (input_bfd, howto, input_section, |
| + contents, rel->r_offset, |
| + relocation, rel->r_addend); |
| + but do_ignore_reloc would do no more than return bfd_reloc_ok */ |
| + break; |
| + default: |
| + r = _bfd_final_link_relocate (howto, input_bfd, input_section, |
| + contents, rel->r_offset, |
| + relocation, rel->r_addend); |
| + break; |
| + } |
| + } |
| + else |
| + { |
| + r = bfd_reloc_notsupported; |
| + } |
| + |
| + if (r != bfd_reloc_ok) |
| + { |
| + if (h != NULL) |
| + name = h->root.root.string; |
| + else |
| + { |
| + name = (bfd_elf_string_from_elf_section |
| + (input_bfd, symtab_hdr->sh_link, sym->st_name)); |
| + if (name == NULL || *name == '\0') |
| + name = bfd_section_name (input_bfd, sec); |
| + } |
| + |
| + switch (r) |
| + { |
| + case bfd_reloc_overflow: |
| + r = info->callbacks->reloc_overflow |
| + (info, (h ? &h->root : NULL), 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: |
| + if (msg == NULL) |
| + msg = _("relocation out of range"); |
| + break; |
| + |
| + case bfd_reloc_notsupported: |
| + if (msg == NULL) |
| + msg = _("unsupported relocation"); |
| + break; |
| + |
| + case bfd_reloc_dangerous: |
| + if (msg == NULL) |
| + msg = _("dangerous relocation"); |
| + break; |
| + |
| + default: |
| + if (msg == NULL) |
| + msg = _("unknown error"); |
| + break; |
| + } |
| + |
| + if (msg) |
| + { |
| + r = info->callbacks->warning |
| + (info, msg, name, input_bfd, input_section, rel->r_offset); |
| + return linker_force_make_executable; |
| + } |
| + } |
| + } |
| + return TRUE; |
| +} |
| + |
| + |
| + |
| +/* Handle an NIOS2 specific section when reading an object file. This |
| + is called when elfcode.h finds a section with an unknown type. |
| + FIXME: We need to handle the SHF_NIOS2_GPREL flag */ |
| + |
| +static bfd_boolean |
| +nios2_elf32_section_from_shdr (bfd *abfd, |
| + Elf_Internal_Shdr *hdr, const char *name, int shindex) |
| +{ |
| + asection *newsect; |
| + |
| + /* NG - I'm keeping this code commented out at the moment |
| + in case we add a .mdebug section */ |
| + |
| + /* |
| + switch (hdr->sh_type) |
| + { |
| + case SHT_NIOS2_DEBUG: |
| + if (strcmp (name, ".mdebug") != 0) |
| + return FALSE; |
| + break; |
| + default: |
| + return FALSE; |
| + } |
| + */ |
| + |
| + if (!_bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex)) |
| + return FALSE; |
| + |
| + newsect = hdr->bfd_section; |
| + |
| + /* ditto */ |
| + /* |
| + if (hdr->sh_type == SHT_NIOS2_DEBUG) |
| + { |
| + if (! bfd_set_section_flags (abfd, newsect, |
| + (bfd_get_section_flags (abfd, newsect) |
| + | SEC_DEBUGGING))) |
| + return FALSE; |
| + } |
| + */ |
| + return TRUE; |
| +} |
| + |
| +/* Convert NIOS2 specific section flags to bfd internal section flags. */ |
| + |
| +static bfd_boolean |
| +nios2_elf32_section_flags (flagword *flags, const Elf_Internal_Shdr *hdr) |
| +{ |
| + if (hdr->sh_flags & SHF_NIOS2_GPREL) |
| + *flags |= SEC_SMALL_DATA; |
| + |
| + return TRUE; |
| +} |
| + |
| +/* Set the correct type for an NIOS2 ELF section. We do this by the |
| + section name, which is a hack, but ought to work. */ |
| + |
| +static bfd_boolean |
| +nios2_elf32_fake_sections (bfd *abfd ATTRIBUTE_UNUSED, |
| + Elf_Internal_Shdr *hdr, asection *sec) |
| +{ |
| + register const char *name; |
| + |
| + name = bfd_get_section_name (abfd, sec); |
| + |
| + if (strcmp (name, ".mdebug") == 0) |
| + { |
| + /* we don't yet have an .mdebug section, but I'm leaving this here |
| + in case we ever do |
| + hdr->sh_type = SHT_NIOS2_DEBUG; |
| + |
| + if ((abfd->flags & DYNAMIC) != 0 ) |
| + hdr->sh_entsize = 0; |
| + else |
| + hdr->sh_entsize = 1; |
| + */ |
| + } |
| + else if ((sec->flags & SEC_SMALL_DATA) |
| + || strcmp (name, ".sdata") == 0 |
| + || strcmp (name, ".sbss") == 0 |
| + || strcmp (name, ".lit4") == 0 || strcmp (name, ".lit8") == 0) |
| + hdr->sh_flags |= SHF_NIOS2_GPREL; |
| + |
| + 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 bfd_boolean |
| +nios2_elf32_check_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->relocatable) |
| + 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]; |
| + |
| + switch (ELF32_R_TYPE (rel->r_info)) |
| + { |
| + /* This relocation describes the C++ object vtable hierarchy. |
| + Reconstruct it for later use during GC. */ |
| + case R_NIOS2_GNU_VTINHERIT: |
| + if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset)) |
| + return FALSE; |
| + break; |
| + |
| + /* This relocation describes which C++ vtable entries are actually |
| + used. Record for later use during GC. */ |
| + case R_NIOS2_GNU_VTENTRY: |
| + if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) |
| + return FALSE; |
| + break; |
| + } |
| + } |
| + |
| + return TRUE; |
| +} |
| + |
| + |
| +/* Return the section that should be marked against GC for a given |
| + relocation. */ |
| + |
| +asection * |
| +nios2_elf32_gc_mark_hook (asection *sec, |
| + 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)) |
| + { |
| + case R_NIOS2_GNU_VTINHERIT: |
| + case R_NIOS2_GNU_VTENTRY: |
| + break; |
| + |
| + 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 |
| + return bfd_section_from_elf_index (sec->owner, sym->st_shndx); |
| + |
| + return NULL; |
| +} |
| + |
| +/* |
| + NG ??? I'm marking the sections as standalone ie. I'm linking for |
| + standalone embedded applications, not for UNIX System V or any other |
| + OS/ABI - this may need to change when we deal with embedded PIC or |
| + dynamic linking |
| +*/ |
| + |
| +static void |
| +nios2_elf32_post_process_headers (bfd *abfd, |
| + struct bfd_link_info *link_info ATTRIBUTE_UNUSED) |
| +{ |
| + Elf_Internal_Ehdr *i_ehdrp; /* Elf file header, internal form */ |
| + |
| + i_ehdrp = elf_elfheader (abfd); |
| + i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_STANDALONE; |
| +} |
| + |
| +#define ELF_ARCH bfd_arch_nios2 |
| +#define ELF_MACHINE_CODE EM_ALTERA_NIOS2 |
| + |
| +/* for now we just make this 1, as we have no MMU in New Jersey */ |
| + |
| +#define ELF_MAXPAGESIZE 1 |
| + |
| +/* relocation table lookup macros */ |
| + |
| +#define bfd_elf32_bfd_reloc_type_lookup nios2_elf32_bfd_reloc_type_lookup |
| + |
| +/* JUMP_TABLE_LINK macros */ |
| + |
| +#define bfd_elf32_bfd_relax_section nios2_elf32_relax_section |
| + |
| +/* elf_info_to_howto (using RELA relocations) */ |
| + |
| +#define elf_info_to_howto nios2_elf32_info_to_howto |
| + |
| +/* elf backend functions */ |
| + |
| +#define elf_backend_can_gc_sections 1 |
| + |
| +#define elf_backend_relocate_section nios2_elf32_relocate_section |
| +#define elf_backend_section_from_shdr nios2_elf32_section_from_shdr |
| +#define elf_backend_section_flags nios2_elf32_section_flags |
| +#define elf_backend_fake_sections nios2_elf32_fake_sections |
| +#define elf_backend_post_process_headers nios2_elf32_post_process_headers |
| +#define elf_backend_check_relocs nios2_elf32_check_relocs |
| + |
| +#define elf_backend_gc_mark_hook nios2_elf32_gc_mark_hook |
| + |
| + |
| + |
| +/* Support for SGI-ish mips targets. */ |
| +#define TARGET_LITTLE_SYM bfd_elf32_littlenios2_vec |
| +#define TARGET_LITTLE_NAME "elf32-littlenios2" |
| +#define TARGET_BIG_SYM bfd_elf32_bignios2_vec |
| +#define TARGET_BIG_NAME "elf32-bignios2" |
| + |
| +#include "elf32-target.h" |
| diff --git a/bfd/reloc.c b/bfd/reloc.c |
| index 1b8c8d7..c66a23d 100644 |
| --- a/bfd/reloc.c |
| +++ b/bfd/reloc.c |
| @@ -4733,6 +4733,39 @@ ENUMDOC |
| msp430 specific relocation codes |
| |
| ENUM |
| + BFD_RELOC_NIOS2_S16 |
| +ENUMX |
| + BFD_RELOC_NIOS2_U16 |
| +ENUMX |
| + BFD_RELOC_NIOS2_CALL26 |
| +ENUMX |
| + BFD_RELOC_NIOS2_IMM5 |
| +ENUMX |
| + BFD_RELOC_NIOS2_CACHE_OPX |
| +ENUMX |
| + BFD_RELOC_NIOS2_IMM6 |
| +ENUMX |
| + BFD_RELOC_NIOS2_IMM8 |
| +ENUMX |
| + BFD_RELOC_NIOS2_HI16 |
| +ENUMX |
| + BFD_RELOC_NIOS2_LO16 |
| +ENUMX |
| + BFD_RELOC_NIOS2_HIADJ16 |
| +ENUMX |
| + BFD_RELOC_NIOS2_GPREL |
| +ENUMX |
| + BFD_RELOC_NIOS2_UJMP |
| +ENUMX |
| + BFD_RELOC_NIOS2_CJMP |
| +ENUMX |
| + BFD_RELOC_NIOS2_CALLR |
| +ENUMX |
| + BFD_RELOC_NIOS2_ALIGN |
| +ENUMDOC |
| + Relocations used by the Altera Nios II core |
| + |
| +ENUM |
| BFD_RELOC_IQ2000_OFFSET_16 |
| ENUMX |
| BFD_RELOC_IQ2000_OFFSET_21 |
| diff --git a/bfd/targets.c b/bfd/targets.c |
| index 71e3337..d5f6d60 100644 |
| --- a/bfd/targets.c |
| +++ b/bfd/targets.c |
| @@ -619,6 +619,8 @@ extern const bfd_target bfd_elf32_ntradbigmips_vec; |
| extern const bfd_target bfd_elf32_ntradlittlemips_vec; |
| extern const bfd_target bfd_elf32_openrisc_vec; |
| extern const bfd_target bfd_elf32_or32_big_vec; |
| +extern const bfd_target bfd_elf32_littlenios2_vec; |
| +extern const bfd_target bfd_elf32_bignios2_vec; |
| extern const bfd_target bfd_elf32_pj_vec; |
| extern const bfd_target bfd_elf32_pjl_vec; |
| extern const bfd_target bfd_elf32_powerpc_vec; |
| @@ -819,6 +821,8 @@ extern const bfd_target sco5_core_vec; |
| extern const bfd_target trad_core_vec; |
| |
| extern const bfd_target bfd_elf32_am33lin_vec; |
| +extern const bfd_target bfd_elf32_littlenios2_vec; |
| +extern const bfd_target bfd_elf32_bignios2_vec; |
| static const bfd_target * const _bfd_target_vector[] = |
| { |
| #ifdef SELECT_VECS |
| @@ -923,6 +927,8 @@ static const bfd_target * const _bfd_target_vector[] = |
| &bfd_elf32_littlearm_vxworks_vec, |
| &bfd_elf32_littlemips_vec, |
| &bfd_elf32_littlemips_vxworks_vec, |
| + &bfd_elf32_littlenios2_vec, |
| + &bfd_elf32_bignios2_vec, |
| &bfd_elf32_m32c_vec, |
| &bfd_elf32_m32r_vec, |
| &bfd_elf32_m32rle_vec, |
| diff --git a/config.sub b/config.sub |
| index fab0aa3..462e7c6 100755 |
| --- a/config.sub |
| +++ b/config.sub |
| @@ -270,7 +270,7 @@ case $basic_machine in |
| | mn10200 | mn10300 \ |
| | mt \ |
| | msp430 \ |
| - | nios | nios2 \ |
| + | nios2 | nios2eb | nios2el \ |
| | ns16k | ns32k \ |
| | or32 \ |
| | pdp10 | pdp11 | pj | pjl \ |
| diff --git a/configure.in b/configure.in |
| index a4befda..f2e34c7 100644 |
| --- a/configure.in |
| +++ b/configure.in |
| @@ -740,6 +740,9 @@ case "${target}" in |
| mips*-*-*) |
| noconfigdirs="$noconfigdirs gprof ${libgcj}" |
| ;; |
| + nios2*-*-*) |
| + noconfigdirs="$noconfigdirs ld" |
| + ;; |
| romp-*-*) |
| noconfigdirs="$noconfigdirs bfd binutils ld gas opcodes target-libgloss ${libgcj}" |
| ;; |
| diff --git a/gdb/Makefile.in b/gdb/Makefile.in |
| index 14fd58b..eac9489 100644 |
| --- a/gdb/Makefile.in |
| +++ b/gdb/Makefile.in |
| @@ -593,6 +593,7 @@ libiberty_h = $(INCLUDE_DIR)/libiberty.h |
| libbfd_h = $(BFD_SRC)/libbfd.h |
| remote_sim_h = $(INCLUDE_DIR)/gdb/remote-sim.h |
| demangle_h = $(INCLUDE_DIR)/demangle.h |
| +nios2_h = $(INCLUDE_DIR)/opcode/nios2.h |
| obstack_h = $(INCLUDE_DIR)/obstack.h |
| opcode_m68hc11_h = $(INCLUDE_DIR)/opcode/m68hc11.h |
| readline_h = $(READLINE_SRC)/readline.h |
| @@ -2399,6 +2400,7 @@ ms1-tdep.o: ms1-tdep.c $(defs_h) $(frame_h) $(frame_unwind_h) $(frame_base_h) \ |
| $(trad_frame_h) $(inferior_h) $(dwarf2_frame_h) $(infcall_h) \ |
| $(gdb_assert_h) |
| nbsd-tdep.o: nbsd-tdep.c $(defs_h) $(gdb_string_h) $(solib_svr4_h) |
| +nios2-tdep.o: nios2-tdep.c $(defs_h) $(symtab_h) $(frame_h) $(nios2_h) |
| nlmread.o: nlmread.c $(defs_h) $(bfd_h) $(symtab_h) $(symfile_h) \ |
| $(objfiles_h) $(buildsym_h) $(stabsread_h) $(block_h) |
| nto-procfs.o: nto-procfs.c $(defs_h) $(gdb_dirent_h) $(exceptions_h) \ |
| diff --git a/gdb/config/nios2/nios2.mt b/gdb/config/nios2/nios2.mt |
| new file mode 100644 |
| index 0000000..63413b4 |
| --- /dev/null |
| +++ b/gdb/config/nios2/nios2.mt |
| @@ -0,0 +1,4 @@ |
| +# Target: Altera New Jersey Processor machine (NIOS2) |
| +TDEPFILES= nios2-tdep.o |
| + |
| + |
| diff --git a/gdb/config/nios2/tm-nios2.h b/gdb/config/nios2/tm-nios2.h |
| new file mode 100644 |
| index 0000000..2962b6b |
| --- /dev/null |
| +++ b/gdb/config/nios2/tm-nios2.h |
| @@ -0,0 +1,28 @@ |
| +/* Definitions to target GDB to New Jersey targets. |
| + Copyright 1986, 1987, 1988, 1989, 1991, 1993, 1994, |
| + 1995, 1996, 1997, 1998, 1999, 2000, 2003 |
| + by Peter Brookes (pbrookes@altera.com) |
| + |
| + This file is part of GDB. |
| + |
| + 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 TM_NIOS2_H |
| +#define TM_NIOS2_H |
| + |
| +#define GDB_MULTI_ARCH 1 |
| + |
| +#endif /* TM_NIOS2_H */ |
| diff --git a/gdb/configure.tgt b/gdb/configure.tgt |
| index dd2e719..7222f59 100644 |
| --- a/gdb/configure.tgt |
| +++ b/gdb/configure.tgt |
| @@ -20,6 +20,7 @@ m68hc11*|m6811*) gdb_target_cpu=m68hc11 ;; |
| m68*) gdb_target_cpu=m68k ;; |
| m88*) gdb_target_cpu=m88k ;; |
| mips*) gdb_target_cpu=mips ;; |
| +nios2*) gdb_target_cpu=nios2 ;; |
| powerpc*) gdb_target_cpu=powerpc ;; |
| sparc*) gdb_target_cpu=sparc ;; |
| thumb*) gdb_target_cpu=arm ;; |
| @@ -155,6 +156,8 @@ mn10300-*-*) gdb_target=mn10300 ;; |
| |
| mt-*-*) gdb_target=mt ;; |
| |
| +nios2*-*-*) gdb_target=nios2 ;; |
| + |
| powerpc-*-netbsd* | powerpc-*-knetbsd*-gnu) |
| gdb_target=nbsd ;; |
| powerpc-*-openbsd*) gdb_target=obsd ;; |
| diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in |
| index 9748c95..b3fb5f8 100644 |
| --- a/gdb/gdbserver/Makefile.in |
| +++ b/gdb/gdbserver/Makefile.in |
| @@ -280,6 +280,7 @@ linux-ia64-low.o: linux-ia64-low.c $(linux_low_h) $(server_h) |
| linux-m32r-low.o: linux-m32r-low.c $(linux_low_h) $(server_h) |
| linux-mips-low.o: linux-mips-low.c $(linux_low_h) $(server_h) \ |
| $(gdb_proc_service_h) |
| +linux-nios2-low.o: linux-nios2-low.c $(linux_low_h) $(server_h) |
| linux-ppc-low.o: linux-ppc-low.c $(linux_low_h) $(server_h) |
| linux-ppc64-low.o: linux-ppc64-low.c $(linux_low_h) $(server_h) |
| linux-s390-low.o: linux-s390-low.c $(linux_low_h) $(server_h) |
| @@ -318,6 +319,9 @@ reg-m68k.c : $(srcdir)/../regformats/reg-m68k.dat $(regdat_sh) |
| reg-mips.o : reg-mips.c $(regdef_h) |
| reg-mips.c : $(srcdir)/../regformats/reg-mips.dat $(regdat_sh) |
| sh $(regdat_sh) $(srcdir)/../regformats/reg-mips.dat reg-mips.c |
| +reg-nios2.o : reg-nios2.c $(regdef_h) |
| +reg-nios2.c : $(srcdir)/../regformats/reg-nios2.dat $(regdat_sh) |
| + sh $(regdat_sh) $(srcdir)/../regformats/reg-nios2.dat reg-nios2.c |
| reg-ppc.o : reg-ppc.c $(regdef_h) |
| reg-ppc.c : $(srcdir)/../regformats/reg-ppc.dat $(regdat_sh) |
| sh $(regdat_sh) $(srcdir)/../regformats/reg-ppc.dat reg-ppc.c |
| diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv |
| index 5a4792c..fdc847c 100644 |
| --- a/gdb/gdbserver/configure.srv |
| +++ b/gdb/gdbserver/configure.srv |
| @@ -72,6 +72,10 @@ case "${target}" in |
| srv_linux_usrregs=yes |
| srv_linux_thread_db=yes |
| ;; |
| + nios2-*-linux*) srv_regobj=reg-nios2.o |
| + srv_tgtobj="linux-low.o linux-nios2-low.o" |
| + srv_linux_usrregs=yes |
| + ;; |
| powerpc64-*-linux*) srv_regobj=reg-ppc64.o |
| srv_tgtobj="linux-low.o linux-ppc64-low.o" |
| srv_linux_usrregs=yes |
| diff --git a/gdb/gdbserver/linux-nios2-low.c b/gdb/gdbserver/linux-nios2-low.c |
| new file mode 100644 |
| index 0000000..1fab749 |
| --- /dev/null |
| +++ b/gdb/gdbserver/linux-nios2-low.c |
| @@ -0,0 +1,89 @@ |
| +/* GNU/Linux/Nios2 specific low level interface for the remote server for GDB */ |
| + |
| +#include "server.h" |
| +#include "linux-low.h" |
| + |
| +#ifdef HAVE_SYS_REG_H |
| +#include <sys/reg.h> |
| +#endif |
| + |
| +#include <asm/ptrace.h> |
| + |
| +static int nios2_regmap[] = |
| +{ |
| + -1, PTR_R1 * 4, PTR_R2 * 4, PTR_R3 * 4, |
| + PTR_R4 * 4, PTR_R5 * 4, PTR_R6 * 4, PTR_R7 * 4, |
| + PTR_R8 * 4, PTR_R9 * 4, PTR_R10 * 4, PTR_R11 * 4, |
| + PTR_R12 * 4, PTR_R13 * 4, PTR_R14 * 4, PTR_R15 * 4, /* reg 15 */ |
| + PTR_R16 * 4, PTR_R17 * 4, PTR_R18 * 4, PTR_R19 * 4, |
| + PTR_R20 * 4, PTR_R21 * 4, PTR_R22 * 4, PTR_R23 * 4, |
| + -1, -1, PTR_GP * 4, PTR_SP * 4, |
| + PTR_FP * 4, -1, -1, PTR_RA * 4, /* reg 31 */ |
| + PTR_PC * 4, -1, -1, -1, |
| + -1, -1, -1, -1, |
| + -1, -1, -1, -1 |
| +}; |
| + |
| +#define nios2_num_regs (sizeof(nios2_regmap) / sizeof(nios2_regmap[0])) |
| + |
| +static int |
| +nios2_cannot_store_register (int regno) |
| +{ |
| + return (regno >= 33); |
| +} |
| + |
| +static int |
| +nios2_cannot_fetch_register (int regno) |
| +{ |
| + return (regno >= 33); |
| +} |
| + |
| +static CORE_ADDR |
| +nios2_get_pc () |
| +{ |
| + unsigned long pc; |
| + collect_register_by_name ("pc", &pc); |
| + return pc; |
| +} |
| + |
| +static void |
| +nios2_set_pc (CORE_ADDR pc) |
| +{ |
| + unsigned long newpc = pc; |
| + supply_register_by_name ("pc", &newpc); |
| +} |
| + |
| +#if 0 |
| +static const unsigned long nios2_breakpoint = 0x003da03a; |
| +#else |
| +static const unsigned long nios2_breakpoint = 0x003b687a; /* Trap instr. w/imm=0x01 */ |
| +#endif |
| +#define nios2_breakpoint_len 4 |
| + |
| +static int |
| +nios2_breakpoint_at (CORE_ADDR where) |
| +{ |
| + unsigned long insn; |
| + |
| + (*the_target->read_memory) (where, (char *) &insn, nios2_breakpoint_len); |
| + if (insn == nios2_breakpoint) |
| + return 1; |
| + |
| + /* If necessary, recognize more trap instructions here. GDB only uses the |
| + one. */ |
| + return 0; |
| +} |
| + |
| +struct linux_target_ops the_low_target = { |
| + nios2_num_regs, |
| + nios2_regmap, |
| + nios2_cannot_fetch_register, |
| + nios2_cannot_store_register, |
| + nios2_get_pc, |
| + nios2_set_pc, |
| + (const char *) &nios2_breakpoint, |
| + nios2_breakpoint_len, |
| + NULL, |
| + 0, |
| + nios2_breakpoint_at, |
| +}; |
| diff --git a/gdb/nios2-tdep.c b/gdb/nios2-tdep.c |
| new file mode 100644 |
| index 0000000..e0712dd |
| --- /dev/null |
| +++ b/gdb/nios2-tdep.c |
| @@ -0,0 +1,1610 @@ |
| +/* Target-machine dependent code for Nios2, for GDB. |
| + Copyright (C) 2003-2005 |
| + by Peter Brookes (pbrookes@altera.com) |
| + and Andrew Draper (adraper@altera.com) |
| + |
| + This file is part of GDB. |
| + |
| + 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 "defs.h" |
| +#include "frame.h" |
| +#include "frame-unwind.h" |
| +#include "frame-base.h" |
| +#include "trad-frame.h" |
| +#include "dwarf2-frame.h" |
| +#include "symtab.h" |
| +#include "inferior.h" |
| +#include "gdbtypes.h" |
| +#include "gdbcore.h" |
| +#include "gdbcmd.h" |
| +#include "target.h" |
| +#include "dis-asm.h" |
| +#include "regcache.h" |
| +#include "value.h" |
| +#include "symfile.h" |
| +#include "arch-utils.h" |
| +#include "floatformat.h" |
| +#include "gdb_assert.h" |
| + |
| +/* To get entry_point_address. */ |
| +#include "objfiles.h" |
| + |
| +/* Nios II ISA specific encodings and macros */ |
| +#include "opcode/nios2.h" |
| + |
| +/* Macros */ |
| + |
| +#define Z_REGNUM 0 /* Zero */ |
| +#define R2_REGNUM 2 /* used for return value */ |
| +#define R3_REGNUM 3 /* used for return value */ |
| +/* used for hidden zero argument to store ptr to struct return value */ |
| +#define R4_REGNUM 4 |
| +#define R7_REGNUM 7 |
| +#define GP_REGNUM 26 /* Global Pointer */ |
| +#undef SP_REGNUM |
| +#define SP_REGNUM 27 /* Stack Pointer */ |
| +#undef FP_REGNUM |
| +#define FP_REGNUM 28 /* Frame Pointer */ |
| +#define EA_REGNUM 29 /* Exception address */ |
| +#define BA_REGNUM 30 /* Breakpoint return address */ |
| +#define RA_REGNUM 31 /* Return address */ |
| +#undef PC_REGNUM |
| +#define PC_REGNUM 32 |
| +#define STATUS_REGNUM 33 /* Ctrl registers */ |
| +#define ESTATUS_REGNUM 34 |
| +#define BSTATUS_REGNUM 35 |
| +#define IENABLE_REGNUM 36 |
| +#define IPENDING_REGNUM 37 |
| +#define CPUID_REGNUM 38 |
| +#define PTEADDR_REGNUM 41 |
| +#define TLBACC_REGNUM 42 |
| +#define TLBMISC_REGNUM 43 |
| +#define FIRST_ARGREG R4_REGNUM |
| +#define LAST_ARGREG R7_REGNUM |
| +/* Number of all registers */ |
| +#define NIOS2_NUM_REGS (44) |
| +/* The maximum register number displayed to the user, */ |
| +/* as a result of typing "info reg" at the gdb prompt */ |
| +#define NIOS2_MAX_REG_DISPLAYED_REGNUM (38) |
| + |
| +#define NIOS2_OPCODE_SIZE 4 |
| + |
| +/* Structures */ |
| +struct register_info |
| +{ |
| + int size; |
| + char *name; |
| + struct type **type; |
| +}; |
| + |
| +/* The current value in the register is the value in r[base] at the start of |
| + * the function + offset ; unless base < 0 in which case it's unknown. |
| + */ |
| +typedef struct |
| +{ |
| + int reg; |
| + unsigned int offset; |
| + |
| +} REG_VALUE; |
| + |
| + |
| +typedef struct |
| +{ |
| + int basereg; |
| + CORE_ADDR addr; |
| + |
| +} REG_SAVED; |
| + |
| +struct nios2_unwind_cache |
| +{ |
| + /* The frame's base, optionally used by the high-level debug info. */ |
| + CORE_ADDR base; |
| + |
| + /* The previous frame's inner most stack address. Used as this |
| + frame ID's stack_addr. */ |
| + CORE_ADDR cfa; |
| + |
| + /* The address of the first instruction in this function */ |
| + CORE_ADDR pc; |
| + |
| + /* Which register holds the return address for the frame. */ |
| + int return_regnum; |
| + |
| + /* Table indicating what changes have been made to each register */ |
| + REG_VALUE reg_value[NIOS2_NUM_REGS]; |
| + |
| + /* Table indicating where each register has been saved. */ |
| + REG_SAVED reg_saved[NIOS2_NUM_REGS]; |
| +}; |
| + |
| + |
| +/* Function prototypes */ |
| +CORE_ADDR nios2_saved_pc_after_call (struct frame_info *fi); |
| + |
| +/* nios2_register_info_table[i] is the number of bytes of storage in |
| + GDB's register array occupied by register i. */ |
| +static struct register_info nios2_register_info_table[] = { |
| + /* 0 */ {4, "zero", &builtin_type_uint32}, |
| + /* 1 */ {4, "at", &builtin_type_uint32}, |
| + /* 2 */ {4, "r2", &builtin_type_uint32}, |
| + /* 3 */ {4, "r3", &builtin_type_uint32}, |
| + /* 4 */ {4, "r4", &builtin_type_uint32}, |
| + /* 5 */ {4, "r5", &builtin_type_uint32}, |
| + /* 6 */ {4, "r6", &builtin_type_uint32}, |
| + /* 7 */ {4, "r7", &builtin_type_uint32}, |
| + /* 8 */ {4, "r8", &builtin_type_uint32}, |
| + /* 9 */ {4, "r9", &builtin_type_uint32}, |
| + /* 10 */ {4, "r10", &builtin_type_uint32}, |
| + /* 11 */ {4, "r11", &builtin_type_uint32}, |
| + /* 12 */ {4, "r12", &builtin_type_uint32}, |
| + /* 13 */ {4, "r13", &builtin_type_uint32}, |
| + /* 14 */ {4, "r14", &builtin_type_uint32}, |
| + /* 15 */ {4, "r15", &builtin_type_uint32}, |
| + /* 16 */ {4, "r16", &builtin_type_uint32}, |
| + /* 17 */ {4, "r17", &builtin_type_uint32}, |
| + /* 18 */ {4, "r18", &builtin_type_uint32}, |
| + /* 19 */ {4, "r19", &builtin_type_uint32}, |
| + /* 20 */ {4, "r20", &builtin_type_uint32}, |
| + /* 21 */ {4, "r21", &builtin_type_uint32}, |
| + /* 22 */ {4, "r22", &builtin_type_uint32}, |
| + /* 23 */ {4, "r23", &builtin_type_uint32}, |
| + /* 24 */ {4, "et", &builtin_type_uint32}, |
| + /* 25 */ {4, "bt", &builtin_type_uint32}, |
| + /* 26 */ {4, "gp", &builtin_type_uint32}, |
| + /* 27 */ {4, "sp", &builtin_type_uint32}, |
| + /* 28 */ {4, "fp", &builtin_type_uint32}, |
| + /* 29 */ {4, "ea", &builtin_type_uint32}, |
| + /* 30 */ {4, "ba", &builtin_type_uint32}, |
| + /* 31 */ {4, "ra", &builtin_type_uint32}, |
| + /* 32 */ {4, "pc", &builtin_type_uint32}, |
| + /* 33 */ {4, "status", &builtin_type_uint32}, |
| + /* 34 */ {4, "estatus", &builtin_type_uint32}, |
| + /* 35 */ {4, "bstatus", &builtin_type_uint32}, |
| + /* 36 */ {4, "ienable", &builtin_type_uint32}, |
| + /* 37 */ {4, "ipending", &builtin_type_uint32}, |
| + /* 38 */ {4, "cpuid", &builtin_type_uint32}, |
| + /* 39 */ {4, "ctl6", &builtin_type_uint32}, |
| + /* 40 */ {4, "ctl7", &builtin_type_uint32}, |
| + /* 41 */ {4, "pteaddr", &builtin_type_uint32}, |
| + /* 42 */ {4, "tlbacc", &builtin_type_uint32}, |
| + /* 43 */ {4, "tlbmisc", &builtin_type_uint32} |
| +}; |
| + |
| +/* This array is a mapping from Dwarf-2 register |
| + numbering to GDB's */ |
| +static int nios2_dwarf2gdb_regno_map[] = { |
| + 0, 1, 2, 3, |
| + 4, 5, 6, 7, |
| + 8, 9, 10, 11, |
| + 12, 13, 14, 15, |
| + 16, 17, 18, 19, |
| + 20, 21, 22, 23, |
| + 24, 25, |
| + GP_REGNUM, /* 26 */ |
| + SP_REGNUM, /* 27 */ |
| + FP_REGNUM, /* 28 */ |
| + EA_REGNUM, /* 29 */ |
| + BA_REGNUM, /* 30 */ |
| + RA_REGNUM, /* 31 */ |
| + PC_REGNUM, /* 32 */ |
| + STATUS_REGNUM, /* 33 */ |
| + ESTATUS_REGNUM, /* 34 */ |
| + BSTATUS_REGNUM, /* 35 */ |
| + IENABLE_REGNUM, /* 36 */ |
| + IPENDING_REGNUM, /* 37 */ |
| + 38, 39, 40, 41, 42, 43 |
| +}; |
| + |
| +/* Dwarf-2 <-> GDB register numbers mapping. */ |
| +int |
| +nios2_dwarf_reg_to_regnum (int dw_reg) |
| +{ |
| + if (dw_reg < 0 || dw_reg > NIOS2_NUM_REGS) |
| + { |
| + warning ("Dwarf-2 uses unmapped register #%d\n", dw_reg); |
| + return dw_reg; |
| + } |
| + |
| + return nios2_dwarf2gdb_regno_map[dw_reg]; |
| +} |
| + |
| +/* Same as read_memory_u6signed_integer, but don't report an error if |
| + can't read. */ |
| +int |
| +nios2_read_memory_unsigned_integer (CORE_ADDR memaddr, int len, ULONGEST *ret) |
| +{ |
| + char buf[sizeof (ULONGEST)]; |
| + int error; |
| + |
| + error = target_read_memory (memaddr, buf, len); |
| + if (error != 0) |
| + return 0; |
| + else |
| + { |
| + *ret = extract_unsigned_integer (buf, len); |
| + return 1; |
| + } |
| +} |
| + |
| +/* Find the name for the specified NIOS2 regno */ |
| +static const char * |
| +nios2_register_name (int regno) |
| +{ |
| + /* Don't display any registers after NIOS2_MAX_REG_DISPLAYED_REGNUM */ |
| + if (regno < 0) |
| + return NULL; |
| + else if (regno > NIOS2_MAX_REG_DISPLAYED_REGNUM) |
| + return NULL; |
| + return nios2_register_info_table[regno].name; |
| +} |
| + |
| +/* Returns the default type for register N. */ |
| +static struct type * |
| +nios2_register_type (struct gdbarch *gdbarch, int regno) |
| +{ |
| +/* FIXME Do we need some checks on regno ? */ |
| + return *nios2_register_info_table[regno].type; |
| +} |
| + |
| +/* nios2_register_byte_table[i] is the offset into the register file of the |
| + start of register number i. We initialize this from |
| + nios2_register_info_table. */ |
| +int nios2_register_byte_table[NIOS2_NUM_REGS]; |
| + |
| +/* Index within `registers' of the first byte of the space for register REGNO. */ |
| +int |
| +nios2_register_byte (int regno) |
| +{ |
| + return nios2_register_byte_table[regno]; |
| +} |
| + |
| +/* Number of bytes of storage in the actual machine representation for |
| + register 'regno'. */ |
| +static int |
| +nios2_register_raw_size (int regno) |
| +{ |
| + return nios2_register_info_table[regno].size; |
| +} |
| + |
| +/* Number of bytes of storage in the program's representation for |
| + register 'regno'. */ |
| +static int |
| +nios2_register_virtual_size (int regno) |
| +{ |
| + return nios2_register_info_table[regno].size; |
| +} |
| + |
| +/* Return the GDB type object for the "standard" data type |
| + of data in register 'regno'. */ |
| +static struct type * |
| +nios2_register_virtual_type (int regno) |
| +{ |
| + return *nios2_register_info_table[regno].type; |
| +} |
| + |
| +/* Does this register need conversion betwen raw and virtual formats */ |
| +int |
| +nios2_register_convertible (int regno) |
| +{ |
| + if (nios2_register_raw_size (regno) == nios2_register_virtual_size (regno)) |
| + return 0; |
| + else |
| + return 1; |
| +} |
| + |
| + |
| + |
| +/* Given a return value in `regcache' with a type `valtype', |
| + extract and copy its value into `valbuf'. */ |
| +/* FIXME: check this function*/ |
| +void |
| +nios2_extract_return_value (struct type *valtype, struct regcache *regcache, void *valbuf) |
| +{ |
| +#ifdef PORTINGTO61 |
| + int len = TYPE_LENGTH (valtype); |
| + |
| + /* pointer types are returned in register r2, |
| + up to 16-bit types in r2 |
| + up to 32-bit types in r2,r3 */ |
| + if (len <= nios2_register_raw_size (R2_REGNUM)) |
| + memcpy (valbuf, regbuf + REGISTER_BYTE (R2_REGNUM), len); |
| + else if (len <= (nios2_register_raw_size (R2_REGNUM) |
| + + nios2_register_raw_size (R3_REGNUM))) |
| + memcpy (valbuf, regbuf + REGISTER_BYTE (R2_REGNUM), len); |
| + else |
| + { |
| + /* Can I get the returned value here ? */ |
| + memset(valbuf, 0, len); |
| + } |
| +#endif |
| +} |
| + |
| +/* Write into appropriate registers a function return value |
| + of type TYPE, given in virtual format. */ |
| +/* FIXME: check if required */ |
| +void |
| +nios2_store_return_value (struct type *valtype, void *valbuf) |
| +{ |
| +#ifdef PORTINGTO61 |
| + int len = TYPE_LENGTH (valtype); |
| + |
| + /* return values of up to 8 bytes are returned in $r2 $r3 */ |
| + |
| + if (len <= nios2_register_raw_size (R2_REGNUM)) |
| + write_register_bytes (REGISTER_BYTE (R2_REGNUM), |
| + valbuf, |
| + len); |
| + else if (len <= (nios2_register_raw_size (R2_REGNUM) |
| + + nios2_register_raw_size (R3_REGNUM))) |
| + write_register_bytes (REGISTER_BYTE (R2_REGNUM), |
| + valbuf, |
| + len); |
| +#endif |
| +} |
| + |
| +#ifdef PORTINGTO61 |
| + |
| +/* Setup the function arguments for calling a function in the inferior. */ |
| +static CORE_ADDR |
| +nios2_push_arguments (int nargs, struct value **args, CORE_ADDR sp, |
| + int struct_return, CORE_ADDR struct_addr) |
| +{ |
| + int argreg; |
| + int argnum; |
| + struct stack_arg |
| + { |
| + int len; |
| + char *val; |
| + } *stack_args; |
| + int nstack_args = 0; |
| + |
| + stack_args = (struct stack_arg *) alloca (nargs * sizeof (struct stack_arg)); |
| + |
| + /* The lowest register number containing arguments */ |
| + argreg = FIRST_ARGREG; |
| + |
| + /* Align the stack. It will be needed |
| + if we call a function which has argument overflow. */ |
| + sp &= ~3; |
| + |
| + /* If this function returns a struct which does not fit in the |
| + return registers, we must pass a buffer to the function |
| + which it can use to save the return value. */ |
| + if (struct_return) |
| + write_register (R2_REGNUM, struct_addr); |
| + |
| + /* FIXME: what about unions? */ |
| + for (argnum = 0; argnum < nargs; argnum++) |
| + { |
| + char *val = (char *) VALUE_CONTENTS (args[argnum]); |
| + int len = TYPE_LENGTH (VALUE_TYPE (args[argnum])); |
| + struct type *type = VALUE_TYPE (args[argnum]); |
| + int olen; |
| + |
| + if ((argreg <= LAST_ARGREG && len <= (LAST_ARGREG - argreg + 1) * DEPRECATED_REGISTER_SIZE) |
| + || (TYPE_CODE (type) == TYPE_CODE_STRUCT)) |
| + { |
| + /* Something that will fit entirely into registers or go on the stack. */ |
| + while (len > 0 && argreg <= LAST_ARGREG) |
| + { write_register (argreg, extract_unsigned_integer (val, DEPRECATED_REGISTER_SIZE)); |
| + |
| + argreg++; |
| + val += DEPRECATED_REGISTER_SIZE; |
| + len -= DEPRECATED_REGISTER_SIZE; |
| + } |
| + |
| + /* Any remainder for the stack is noted below... */ |
| + } |
| + else if (TYPE_CODE (VALUE_TYPE (args[argnum])) != TYPE_CODE_STRUCT |
| + && len > DEPRECATED_REGISTER_SIZE) |
| + { |
| + /* All subsequent args go onto the stack. */ |
| + argnum = LAST_ARGREG + 1; |
| + } |
| + |
| + if (len > 0) |
| + { |
| + /* Note that this must be saved onto the stack */ |
| + stack_args[nstack_args].val = val; |
| + stack_args[nstack_args].len = len; |
| + nstack_args++; |
| + } |
| + } |
| + |
| + /* We're done with registers and stack allocation. Now do the actual |
| + stack pushes. */ |
| + while (nstack_args--) |
| + { |
| + sp -= stack_args[nstack_args].len; |
| + write_memory (sp, stack_args[nstack_args].val, stack_args[nstack_args].len); |
| + } |
| + |
| + /* Return adjusted stack pointer. */ |
| + return sp; |
| +} |
| + |
| +/* Function: push_return_address (pc) |
| + Set up the return address for the inferior function call.*/ |
| +/* FIXME: Check if required */ |
| +static CORE_ADDR |
| +nios2_push_return_address (CORE_ADDR pc, CORE_ADDR sp) |
| +{ |
| + write_register (RA_REGNUM, CALL_DUMMY_ADDRESS ()); |
| + return sp; |
| +} |
| + |
| +/* Extract from an array regcache containing the (raw) register state |
| + the address in which a function should return its structure value, |
| + as a CORE_ADDR (or an expression that can be used as one). */ |
| +/* FIXME: Check if required */ |
| + |
| +static CORE_ADDR |
| +nios2_extract_struct_value_address (char *regbuf) |
| +{ |
| + return (extract_address ((regbuf) + REGISTER_BYTE (R4_REGNUM), |
| + REGISTER_RAW_SIZE (R4_REGNUM))); |
| +} |
| + |
| +/* Store the address of the place in which to copy the structure the |
| + subroutine will return. This is called from call_function. */ |
| + |
| +/* FIXME: Check if required */ |
| +static void |
| +nios2_store_struct_return (CORE_ADDR addr, CORE_ADDR sp) |
| +{ |
| + write_register (R4_REGNUM, (addr)); |
| +} |
| +#endif |
| + |
| + |
| +/* This function analyzes the function prologue and tries to work |
| + out where registers are saved and how long the prologue is. |
| + The prologue will consist of the following parts: |
| + 1) Optional profiling instrumentation. The old version uses six |
| + instructions. We step over this if there is an exact match. |
| + nextpc r8 |
| + mov r9, ra |
| + movhi r10, %hiadj(.LP2) |
| + addi r10, r10, %lo(.LP2) |
| + call mcount |
| + mov ra, r9 |
| + The new version uses two or three instructions (the last of |
| + these might get merged in with the STW which saves RA to the |
| + stack). We interpret these. |
| + mov r8, ra |
| + call mcount |
| + mov ra, r8 |
| + |
| + 2) Optional interrupt entry decision. Again, we step over |
| + this if there is an exact match. |
| + rdctl et,estatus |
| + andi et,et,1 |
| + beq et,zero, <software_exception> |
| + rdctl et,ipending |
| + beq et,zero, <software_exception> |
| + |
| + 3) A stack adjustment or stack which, which will be one of: |
| + addi sp, sp, -constant |
| + or: |
| + movi r8, constant |
| + sub sp, sp, r8 |
| + or |
| + movhi r8, constant |
| + addi r8, r8, constant |
| + sub sp, sp, r8 |
| + or |
| + movhi rx, %hiadj(newstack) |
| + addhi rx, rx, %lo(newstack) |
| + stw sp, constant(rx) |
| + mov sp, rx |
| + |
| + 4) An optional stack check, which can take either of these forms: |
| + bgeu sp, rx, +8 |
| + break 3 |
| + or |
| + bltu sp, rx, .Lstack_overflow |
| + ... |
| + .Lstack_overflow: |
| + break 3 |
| + |
| + 5) Saving any registers which need to be saved. These will |
| + normally just be stored onto the stack: |
| + stw rx, constant(sp) |
| + but in the large frame case will use r8 as an offset back |
| + to the cfa: |
| + add r8, r8, sp |
| + stw rx, -constant(r8) |
| + |
| + Saving control registers looks slightly different: |
| + rdctl rx, ctlN |
| + stw rx, constant(sp) |
| + |
| + 6) An optional FP setup, either if the user has requested a |
| + frame pointer or if the function calls alloca. |
| + This is always: |
| + mov fp, sp |
| + |
| + The prologue instructions may be interleaved, and the register |
| + saves and FP setup can occur in either order. |
| + |
| + To cope with all this variability we decode all the instructions |
| + from the start of the prologue until we hit a branch, call or |
| + return. For each of the instructions mentioned in 3, 4 and 5 we |
| + handle the limited cases of stores to the stack and operations |
| + on constant values. |
| + */ |
| + |
| +typedef struct |
| +{ |
| + unsigned int insn; |
| + unsigned int mask; |
| +} wild_insn; |
| + |
| +static const wild_insn profiler_insn[] = |
| +{ |
| + { 0x0010e03a, 0x00000000 }, // nextpc r8 |
| + { 0xf813883a, 0x00000000 }, // mov r9,ra |
| + { 0x02800034, 0x003FFFC0 }, // movhi r10,257 |
| + { 0x52800004, 0x003FFFC0 }, // addi r10,r10,-31992 |
| + { 0x00000000, 0xFFFFFFC0 }, // call <mcount> |
| + { 0x483f883a, 0x00000000 } // mov ra,r9 |
| +}; |
| + |
| +static const wild_insn irqentry_insn[] = |
| +{ |
| + { 0x0031307a, 0x00000000 }, // rdctl et,estatus |
| + { 0xc600004c, 0x00000000 }, // andi et,et,1 |
| + { 0xc0000026, 0x003FFFC0 }, // beq et,zero, <software_exception> |
| + { 0x0031313a, 0x00000000 }, // rdctl et,ipending |
| + { 0xc0000026, 0x003FFFC0 } // beq et,zero, <software_exception> |
| +}; |
| + |
| +static void |
| +nios2_setup_default(struct nios2_unwind_cache *cache) |
| +{ |
| + int i; |
| + |
| + for (i = 0; i < NIOS2_NUM_REGS; i++) |
| + { |
| + /* All registers start off holding their previous values */ |
| + cache->reg_value[i].reg = i; |
| + cache->reg_value[i].offset = 0; |
| + |
| + /* All registers start off not saved */ |
| + cache->reg_saved[i].basereg = -1; |
| + cache->reg_saved[i].addr = 0; |
| + } |
| +} |
| + |
| +static int |
| +nios2_match_sequence(CORE_ADDR start_pc, const wild_insn * sequence, int count) |
| +{ |
| + CORE_ADDR pc = start_pc; |
| + int i; |
| + unsigned int insn; |
| + |
| + for (i = 0 ; i < count ; i++) |
| + { |
| + insn = read_memory_unsigned_integer (pc, NIOS2_OPCODE_SIZE); |
| + if ((insn & ~sequence[i].mask) != sequence[i].insn) |
| + return 0; |
| + |
| + pc += NIOS2_OPCODE_SIZE; |
| + } |
| + |
| + return 1; |
| +} |
| + |
| + |
| +CORE_ADDR |
| +nios2_analyze_prologue (const CORE_ADDR start_pc, const CORE_ADDR current_pc, |
| + struct nios2_unwind_cache *cache, struct frame_info *next_frame) |
| +{ |
| + /* Maximum lines of prologue to check */ |
| + /* Note that this number should not be too large, else we can potentially */ |
| + /* end up iterating through unmapped memory */ |
| + CORE_ADDR limit_pc = start_pc + 200; |
| + int regno; |
| + |
| + /* Does the frame set up the FP register? */ |
| + int base_reg = 0; |
| + |
| + REG_VALUE * value = cache->reg_value; |
| + REG_VALUE temp_value[NIOS2_NUM_REGS]; |
| + |
| + int i; |
| + |
| + /* Save the starting PC so we can correct the pc after running */ |
| + /* through the prolog, using symbol info */ |
| + CORE_ADDR pc = start_pc; |
| + |
| + /* Is this an exception handler? */ |
| + int exception_handler = 0; |
| + |
| + /* What was the original value of SP (or fake original value for |
| + * functions which switch stacks? |
| + */ |
| + CORE_ADDR frame_high; |
| + |
| + /* Is this the end of the prologue? */ |
| + int within_prologue = 1; |
| + |
| + CORE_ADDR prologue_end; |
| + |
| + /* Is this the innermost function? */ |
| + int innermost = (frame_relative_level(next_frame) < 0); |
| + |
| +#ifdef DEBUG_PRINT |
| + fprintf_unfiltered (gdb_stdlog, |
| + "{ nios2_analyze_prologue start=0x%s, current=0x%s ", |
| + paddr_nz (start_pc), paddr_nz (current_pc)); |
| +#endif |
| + |
| + /* Set up the default values of the registers. */ |
| + nios2_setup_default(cache); |
| + |
| + /* If the first few instructions are the profile entry then skip over them. */ |
| + /* Newer versions of the compiler use more efficient profiling code. */ |
| + if (nios2_match_sequence(pc, profiler_insn, sizeof(profiler_insn)/sizeof(profiler_insn[0]))) |
| + pc += sizeof(profiler_insn)/sizeof(profiler_insn[0]) * NIOS2_OPCODE_SIZE; |
| + |
| + /* If the first few are an interrupt entry then skip over them too */ |
| + if (nios2_match_sequence(pc, irqentry_insn, sizeof(irqentry_insn)/sizeof(irqentry_insn[0]))) |
| + { |
| + pc += sizeof(irqentry_insn)/sizeof(irqentry_insn[0]) * NIOS2_OPCODE_SIZE; |
| + exception_handler = 1; |
| + } |
| + |
| + prologue_end = start_pc; |
| + |
| + /* Find the prologue instructions. */ |
| + /* Fortunately we're in 32bit paradise */ |
| + while (pc < limit_pc && within_prologue) |
| + { |
| + /* Present instruction. */ |
| + unsigned int insn; |
| + |
| + int prologue_insn = 0; |
| + |
| + if (pc == current_pc) |
| + { |
| + /* |
| + * When we reach the current PC we must save the current register |
| + * state (for the backtrace) but keep analysing because there might |
| + * be more to find out (eg. is this an exception handler). |
| + */ |
| + memcpy(temp_value, value, sizeof(temp_value)); |
| + value = temp_value; |
| +#ifdef DEBUG_PRINT |
| + fprintf_unfiltered (gdb_stdlog, "*"); |
| +#endif |
| + } |
| + |
| + insn = read_memory_unsigned_integer (pc, NIOS2_OPCODE_SIZE); |
| + pc += NIOS2_OPCODE_SIZE; |
| + |
| +#ifdef DEBUG_PRINT |
| + fprintf_unfiltered (gdb_stdlog, "[%08X]", insn); |
| +#endif |
| + |
| + /* The following instructions can appear in the prologue */ |
| + |
| + if ((insn & 0x0001FFFF) == 0x0001883A) |
| + { |
| + /* ADD rc, ra, rb (also used for MOV) */ |
| + |
| + int ra = GET_IW_A(insn); |
| + int rb = GET_IW_B(insn); |
| + int rc = GET_IW_C(insn); |
| + |
| + if (rc == SP_REGNUM && rb == 0 && value[ra].reg == cache->reg_saved[SP_REGNUM].basereg) |
| + { |
| + /* If the previous value of SP is available somewhere near the new |
| + * stack pointer value then this is a stack switch. |
| + */ |
| + |
| + /* If any registers were saved on the stack before then we can't backtrace |
| + * into them now. |
| + */ |
| + for (i = 0 ; i < NIOS2_NUM_REGS ; i++) |
| + { |
| + if (cache->reg_saved[i].basereg == SP_REGNUM) |
| + cache->reg_saved[i].basereg = -1; |
| + if (value[i].reg == SP_REGNUM) |
| + value[i].reg = -1; |
| + } |
| + |
| + /* Create a fake "high water mark" 4 bytes above where SP was stored |
| + * and fake up the registers to be consistent with that. |
| + */ |
| + value[SP_REGNUM].reg = SP_REGNUM; |
| + value[SP_REGNUM].offset = value[ra].offset - cache->reg_saved[SP_REGNUM].addr - 4; |
| + |
| + cache->reg_saved[SP_REGNUM].basereg = SP_REGNUM; |
| + cache->reg_saved[SP_REGNUM].addr = -4; |
| + } |
| + |
| + else if (rc != 0) |
| + { |
| + if (value[rb].reg == 0) |
| + value[rc].reg = value[ra].reg; |
| + else if (value[ra].reg == 0) |
| + value[rc].reg = value[rb].reg; |
| + else |
| + value[rc].reg = -1; |
| + |
| + value[rc].offset = value[ra].offset + value[rb].offset; |
| + } |
| + prologue_insn = 1; |
| + } |
| + |
| + else if ((insn & 0x0001FFFF) == 0x0001983A) |
| + { |
| + /* SUB rc, ra, rb */ |
| + |
| + int ra = GET_IW_A(insn); |
| + int rb = GET_IW_B(insn); |
| + int rc = GET_IW_C(insn); |
| + |
| + if (rc != 0) |
| + { |
| + if (value[rb].reg == 0) |
| + value[rc].reg = value[ra].reg; |
| + else |
| + value[rc].reg = -1; |
| + |
| + value[rc].offset = value[ra].offset - value[rb].offset; |
| + } |
| + } |
| + |
| + else if ((insn & 0x0000003F) == 0x00000004) |
| + { |
| + /* ADDI rb, ra, immed (also used for MOVI) */ |
| + short immed = GET_IW_IMM16(insn); |
| + int ra = GET_IW_A(insn); |
| + int rb = GET_IW_B(insn); |
| + |
| + if (rb == SP_REGNUM) |
| + { |
| + /* The first stack adjustment is part of the prologue. Any subsequent |
| + stack adjustments are either down to alloca or the epilogue so stop |
| + analysing when we hit them. */ |
| + if (value[rb].offset != 0 || value[ra].reg != SP_REGNUM) |
| + break; |
| + } |
| + |
| + if (rb != 0) |
| + { |
| + value[rb].reg = value[ra].reg; |
| + value[rb].offset = value[ra].offset + immed; |
| + } |
| + |
| + prologue_insn = 1; |
| + } |
| + |
| + else if ((insn & 0x0000003F) == 0x00000034) |
| + { |
| + /* ORHI rb, ra, immed (also used for MOVHI) */ |
| + unsigned int immed = GET_IW_IMM16(insn); |
| + int ra = GET_IW_A(insn); |
| + int rb = GET_IW_B(insn); |
| + |
| + if (rb != 0) |
| + { |
| + value[rb].reg = (value[ra].reg == 0) ? 0 : -1; |
| + value[rb].offset = value[ra].offset | (immed << 16); |
| + } |
| + } |
| + |
| + else if (((insn & IW_OP_MASK) == OP_STW || (insn & IW_OP_MASK) == OP_STWIO)) |
| + { |
| + /* STW rb, immediate(ra) */ |
| + |
| + short immed16 = GET_IW_IMM16(insn); |
| + int ra = GET_IW_A(insn); |
| + int rb = GET_IW_B(insn); |
| + |
| + /* Are we storing the original value of a register? For exception handlers |
| + * the value of EA-4 (return address from interrupts etc) is sometimes stored. |
| + */ |
| + int orig = value[rb].reg; |
| + if (orig > 0 && (value[rb].offset == 0 || (orig == EA_REGNUM && value[rb].offset == -4))) |
| + { |
| + /* We are most interested in stores to the stack, but will also take note |
| + * of stores to other places as they might be useful later. |
| + */ |
| + if ((value[ra].reg == SP_REGNUM && cache->reg_saved[orig].basereg != SP_REGNUM) || |
| + cache->reg_saved[orig].basereg == -1) |
| + { |
| + if (pc < current_pc) |
| + { |
| + /* Save off callee saved registers */ |
| + cache->reg_saved[orig].basereg = value[ra].reg; |
| + cache->reg_saved[orig].addr = value[ra].offset + GET_IW_IMM16(insn); |
| + } |
| + |
| + prologue_insn = 1; |
| + |
| + if (orig == EA_REGNUM || orig == ESTATUS_REGNUM) |
| + exception_handler = 1; |
| + } |
| + } |
| + } |
| + |
| + else if ((insn & 0xFFC1F83F) == 0x0001303A) |
| + { |
| + /* RDCTL rC, ctlN */ |
| + int rc = GET_IW_C(insn); |
| + int n = GET_IW_CONTROL_REGNUM(insn); |
| + |
| + if (rc != 0) |
| + { |
| + value[rc].reg = STATUS_REGNUM + n; |
| + value[rc].offset = 0; |
| + } |
| + |
| + prologue_insn = 1; |
| + } |
| + |
| + else if ((insn & 0x0000003F) == 0 && |
| + value[8].reg == RA_REGNUM && value[8].offset == 0 && |
| + value[SP_REGNUM].reg == SP_REGNUM && value[SP_REGNUM].offset == 0) |
| + { |
| + /* A CALL instruction. This is treated as a call to mcount if ra |
| + * has been stored into r8 beforehand and if it's before the stack adjust. |
| + * mcount corrupts r2-r3, r9-r15 & ra |
| + */ |
| + for (i = 2 ; i <= 3 ; i++) |
| + value[i].reg = -1; |
| + for (i = 9 ; i <= 15 ; i++) |
| + value[i].reg = -1; |
| + value[RA_REGNUM].reg = -1; |
| + |
| + prologue_insn = 1; |
| + } |
| + |
| + else if ((insn & 0xF83FFFFF) == 0xD800012E) |
| + { |
| + /* BGEU sp, rx, +8 |
| + * BREAK 3 |
| + * This instruction sequence is used in stack checking - we can ignore it |
| + */ |
| + unsigned int next_insn = read_memory_unsigned_integer(pc, NIOS2_OPCODE_SIZE); |
| + |
| + if (next_insn != 0x003DA0FA) |
| + within_prologue = 0; |
| + else |
| + pc += NIOS2_OPCODE_SIZE; |
| + } |
| + |
| + else if ((insn & 0xF800003F) == 0xD8000036) |
| + { |
| + /* BLTU sp, rx, .Lstackoverflow |
| + * If the location branched to holds a BREAK 3 instruction then this is |
| + * also stack overflow detection. We can ignore it. |
| + */ |
| + CORE_ADDR target_pc = pc + ((insn & 0x3FFFC0) >> 6); |
| + unsigned int target_insn = read_memory_unsigned_integer(target_pc, NIOS2_OPCODE_SIZE); |
| + |
| + if (target_insn != 0x003DA0FA) |
| + within_prologue = 0; |
| + } |
| + |
| + /* Any other instructions are allowed to be moved up into the prologue. If we |
| + reach a branch, call or return then the prologue is considered over */ |
| + /* We also consider a second stack adjustment as terminating the prologue (see |
| + above) */ |
| + |
| + else |
| + { |
| + switch (GET_IW_OP(insn)) |
| + { |
| + case OP_BEQ: |
| + case OP_BGE: |
| + case OP_BGEU: |
| + case OP_BLT: |
| + case OP_BLTU: |
| + case OP_BNE: |
| + case OP_BR: |
| + case OP_CALL: |
| + within_prologue = 0; |
| + break; |
| + case OP_OPX: |
| + if (GET_IW_OPX(insn) == OPX_RET || |
| + GET_IW_OPX(insn) == OPX_ERET || |
| + GET_IW_OPX(insn) == OPX_BRET || |
| + GET_IW_OPX(insn) == OPX_CALLR || |
| + GET_IW_OPX(insn) == OPX_JMP) |
| + { |
| + within_prologue = 0; |
| + } |
| + default: |
| + break; |
| + } |
| + } |
| + |
| + if (prologue_insn) |
| + prologue_end = pc; |
| + } |
| + |
| + /* Are we within the function epilogue? If so then we should go back to the |
| + original register values */ |
| + if (innermost && current_pc > start_pc) |
| + { |
| + /* First check whether the previous instruction was a stack |
| + adjustment. */ |
| + unsigned int insn = read_memory_unsigned_integer (current_pc - NIOS2_OPCODE_SIZE, NIOS2_OPCODE_SIZE); |
| + |
| + if ((insn & 0xFFC0003C) == 0xDEC00004 || /* ADDI sp, sp, */ |
| + (insn & 0xFFC1FFFF) == 0xDEC1883A || /* ADD sp, sp, */ |
| + (insn & 0xFFC0003F) == 0xDEC00017) /* LDW sp, constant(sp) */ |
| + { |
| + /* Then check if it's followed by a return or a tail call */ |
| + insn = read_memory_unsigned_integer (current_pc, NIOS2_OPCODE_SIZE); |
| + |
| + if (insn == 0xF800283A || /* RET */ |
| + insn == 0xE800083A || /* ERET */ |
| + (insn & 0x07FFFFFF) == 0x0000683A || /* JMP */ |
| + (insn & 0xFFC0003F) == 6) /* BR */ |
| + { |
| + /* Go back to default value of the registers */ |
| + nios2_setup_default(cache); |
| + } |
| + } |
| + } |
| + |
| + /* Exception handlers use a different return address register. */ |
| + if (exception_handler) |
| + cache->return_regnum = EA_REGNUM; |
| + |
| +#ifdef DEBUG_PRINT |
| + fprintf_unfiltered (gdb_stdlog, "\n-> retreg=%d, ", cache->return_regnum); |
| +#endif |
| + |
| + if (cache->reg_value[FP_REGNUM].reg == SP_REGNUM) |
| + { |
| + /* If the FP now holds an offset from the CFA then this is a normal |
| + frame which uses the frame pointer. */ |
| + base_reg = FP_REGNUM; |
| + } |
| + else if (cache->reg_value[SP_REGNUM].reg == SP_REGNUM) |
| + { |
| + /* FP doesn't hold an offset from the CFA. If SP still holds an |
| + offset from the CFA then we might be in a function which omits |
| + the frame pointer, or we might be partway through the prologue. |
| + In both cases we can find the CFA using SP. */ |
| + base_reg = SP_REGNUM; |
| + } |
| + else |
| + { |
| + /* Somehow the stack pointer has been corrupted. We can't return. */ |
| +#ifdef DEBUG_PRINT |
| + fprintf_unfiltered (gdb_stdlog, "<can't reach cfa> }\n"); |
| +#endif |
| + return 0; |
| + } |
| + |
| + if (cache->reg_value[base_reg].offset == 0 || |
| + cache->reg_saved[RA_REGNUM].basereg != SP_REGNUM || |
| + cache->reg_saved[cache->return_regnum].basereg != SP_REGNUM) |
| + { |
| + /* |
| + * If the frame didn't adjust the stack, didn't save RA or didn't save |
| + * EA in an exception handler then it must either be a leaf function |
| + * (doesn't call any other functions) or it can't return. If it has |
| + * called another function then it can't be a leaf, so set base == 0 |
| + * to indicate that we can't backtrace past it. |
| + */ |
| + |
| + if (!innermost) |
| + { |
| + /* If it isn't the innermost function then it can't be a leaf, unless |
| + * it was interrupted. Check whether RA for this frame is the same |
| + * as PC. If so then it probably wan't interrupted. |
| + */ |
| + char buf[8]; |
| + CORE_ADDR ra; |
| + |
| + frame_unwind_register (next_frame, RA_REGNUM, buf); |
| + ra = extract_typed_address (buf, builtin_type_void_func_ptr); |
| + |
| + if (ra == current_pc) |
| + { |
| +#ifdef DEBUG_PRINT |
| + fprintf_unfiltered (gdb_stdlog, "<noreturn ADJUST 0x%s, r31@r%d+?>, r%d@r%d+?> }\n", |
| + paddr_nz(cache->reg_value[base_reg].offset), |
| + cache->reg_saved[RA_REGNUM].basereg, |
| + cache->return_regnum, cache->reg_saved[cache->return_regnum].basereg); |
| +#endif |
| + return 0; |
| + } |
| + } |
| + } |
| + |
| + /* Get the value of whichever register we are using for the base. */ |
| + cache->base = frame_unwind_register_unsigned (next_frame, base_reg); |
| + |
| + /* What was the value of SP at the start of this function (or just |
| + * after the stack switch). |
| + */ |
| + frame_high = cache->base - cache->reg_value[base_reg].offset; |
| + |
| + /* Adjust all the saved registers such that they contain addresses |
| + instead of offsets. */ |
| + for (i = 0; i < NIOS2_NUM_REGS; i++) |
| + if (cache->reg_saved[i].basereg == SP_REGNUM) |
| + { |
| + cache->reg_saved[i].basereg = Z_REGNUM; |
| + cache->reg_saved[i].addr += frame_high; |
| + } |
| + |
| + for (i = 0; i < NIOS2_NUM_REGS; i++) |
| + if (cache->reg_saved[i].basereg == GP_REGNUM) |
| + { |
| + CORE_ADDR gp = frame_unwind_register_unsigned (next_frame, GP_REGNUM); |
| + |
| + for ( ; i < NIOS2_NUM_REGS; i++) |
| + if (cache->reg_saved[i].basereg == GP_REGNUM) |
| + { |
| + cache->reg_saved[i].basereg = Z_REGNUM; |
| + cache->reg_saved[i].addr += gp; |
| + } |
| + } |
| + |
| + /* Work out what the value of SP was on the first instruction of this |
| + * function. If we didn't switch stacks then this can be trivially |
| + * computed from the base address. |
| + */ |
| + if (cache->reg_saved[SP_REGNUM].basereg == Z_REGNUM) |
| + { |
| + cache->cfa = read_memory_unsigned_integer(cache->reg_saved[SP_REGNUM].addr, 4); |
| + } |
| + else |
| + cache->cfa = frame_high; |
| + |
| + /* Exception handlers restore ESTATUS into STATUS. */ |
| + if (exception_handler) |
| + { |
| + cache->reg_saved[STATUS_REGNUM] = cache->reg_saved[ESTATUS_REGNUM]; |
| + cache->reg_saved[ESTATUS_REGNUM].basereg = -1; |
| + } |
| + |
| +#ifdef DEBUG_PRINT |
| + fprintf_unfiltered (gdb_stdlog, "cfa=0x%s }\n", paddr_nz(cache->cfa)); |
| +#endif |
| + |
| + return prologue_end; |
| +} |
| + |
| +struct frame_info * |
| +setup_arbitrary_frame (int argc, CORE_ADDR *argv) |
| +{ |
| + if (argc != 2) |
| + error ("Nios II frame specifications require two arguments: sp and pc"); |
| + |
| + return create_new_frame (argv[0], argv[1]); |
| +} |
| + |
| +#ifdef PORTINGTO61 |
| +/* Should be handled by unwind informations. */ |
| +/* However, doing this manually until we can find */ |
| +/* use the CFA information to examine the stack */ |
| +void |
| +nios2_frame_init_saved_regs (struct frame_info *fi) |
| +{ |
| + CORE_ADDR ip; |
| + |
| + /* Examine the entire prologue. */ |
| + register int frameless_p = 0; |
| + |
| + /* Has this frame's registers already been initialized? */ |
| + if (fi->saved_regs) |
| + return; |
| + |
| + frame_saved_regs_zalloc (fi); |
| + |
| + ip = get_pc_function_start (fi->pc); |
| + nios2_examine (ip, fi, frameless_p); |
| +} |
| +#endif |
| + |
| + |
| +/* Given a PC value corresponding to the start of a function, return the PC |
| + of the first instruction after the function prologue. */ |
| + |
| +CORE_ADDR |
| +nios2_skip_prologue (CORE_ADDR start_pc) |
| +{ |
| + CORE_ADDR func_addr, func_end; |
| + struct symtab_and_line sal; |
| + CORE_ADDR pc_after_prologue; |
| + |
| + /* If we have line debugging information, then the end of the prologue |
| + should the first assembly instruction of the first source line. */ |
| + if (find_pc_partial_function (start_pc, NULL, &func_addr, &func_end)) |
| + { |
| + sal = find_pc_line (func_addr, 0); |
| + if (sal.end > 0 && sal.end < func_end) |
| + return sal.end; |
| + } |
| + |
| + return start_pc; |
| +} |
| + |
| +/* nios2_software_single_step() is called just before we want to resume |
| + the inferior, if we want to single-step it but there is no hardware |
| + or kernel single-step support (NIOS2 on GNU/Linux for example). We find |
| + the target of the coming instruction and breakpoint it. |
| + |
| + single_step is also called just after the inferior stops. If we had |
| + set up a simulated single-step, we undo our damage. */ |
| + |
| +void |
| +nios2_software_single_step (enum target_signal sig, int insert_breakpoints_p) |
| +{ |
| + int ii; |
| + unsigned int insn; |
| + CORE_ADDR pc; |
| + CORE_ADDR breaks[2]; |
| + int imme; |
| + |
| + if (insert_breakpoints_p) |
| + { |
| + pc = read_pc (); |
| + breaks[0] = pc + 4; |
| + breaks[1] = -1; |
| + insn = read_memory_unsigned_integer (pc, 4); |
| + |
| + /* Calculate the destination of a branch/jump */ |
| + switch (GET_IW_OP(insn)) |
| + { |
| + /* I-type branch */ |
| + case OP_BEQ: |
| + case OP_BGE: |
| + case OP_BGEU: |
| + case OP_BLT: |
| + case OP_BLTU: |
| + case OP_BNE: |
| + imme = (short) GET_IW_IMM16(insn); |
| + breaks[1] = pc + 4 + imme; |
| + break; |
| + case OP_BR: |
| + imme = (short) GET_IW_IMM16(insn); |
| + breaks[0] = pc + 4 + imme; |
| + break; |
| + /* J-type branch */ |
| + case OP_CALL: |
| + case OP_JMPI: |
| + imme = GET_IW_IMM26(insn); |
| + breaks[0] = (pc & 0xf0000000) | (imme * 4); |
| + break; |
| + /* R-type branch */ |
| + case OP_OPX: |
| + switch (GET_IW_OPX(insn)) |
| + { |
| + case OPX_CALLR: |
| + case OPX_JMP: |
| + case OPX_RET: |
| + imme = read_register (GET_IW_A(insn)); |
| + breaks[0] = imme; |
| + break; |
| + } |
| + break; |
| + } |
| + |
| + /* Don't put two breakpoints on the same address. */ |
| + if (breaks[1] == breaks[0]) |
| + breaks[1] = -1; |
| + |
| + for (ii = 0; ii < 2; ++ii) |
| + { |
| + /* ignore invalid breakpoint. */ |
| + if (breaks[ii] == -1) |
| + continue; |
| + insert_single_step_breakpoint (breaks[ii]); |
| + } |
| + } |
| + else |
| + remove_single_step_breakpoints (); |
| + |
| +} |
| + |
| +const unsigned char* |
| +nios2_breakpoint_from_pc (CORE_ADDR *bp_addr, int *bp_size) |
| +{ |
| + /* break encoding: 31->27 26->22 21->17 16->11 10->6 5->0 */ |
| + /* 00000 00000 0x1e 0x34 00000 0x3a */ |
| + /* 00000 00000 11110 110100 00000 111010 */ |
| + /* In bytes: 00000000 00111101 10100000 00111010 */ |
| + /* 0x0 0x3d 0xa0 0x3a */ |
| +#if 0 |
| + static unsigned char breakpoint[] = {0x3a, 0xa0, 0x3d, 0x0}; |
| +#else |
| + static unsigned char breakpoint[] = {0x7a, 0x68, 0x3b, 0x0}; /* Trap instr. w/imm=0x01 */ |
| +#endif |
| + *bp_size = 4; |
| + return breakpoint; |
| +} |
| + |
| + |
| +int |
| +gdb_print_insn_nios2 (bfd_vma memaddr, disassemble_info *info) |
| +{ |
| + if (info->endian == BFD_ENDIAN_BIG) |
| + { |
| + return print_insn_big_nios2 (memaddr, info); |
| + } |
| + else |
| + { |
| + return print_insn_little_nios2 (memaddr, info); |
| + } |
| +} |
| + |
| + |
| + |
| +/* Adjust the address downward (direction of stack growth) so that it |
| + is correctly aligned for a new stack frame. */ |
| + |
| +/* ??? Big endian issues here? */ |
| + |
| +static CORE_ADDR |
| +nios2_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr) |
| +{ |
| + return align_down (addr, 4); |
| +} |
| + |
| + |
| + |
| +/* We don't convert anything at the moment */ |
| +static int |
| +nios2_convert_register_p (int regnum, struct type *type) |
| +{ |
| + return 0; |
| +} |
| + |
| +static void |
| +nios2_register_to_value (struct frame_info *frame, int regnum, |
| + struct type *type, void *to) |
| +{ |
| + get_frame_register (frame, regnum + 0, (char *) to + 0); |
| + get_frame_register (frame, regnum + 0, (char *) to + 0); |
| +} |
| + |
| +static void |
| +nios2_value_to_register (struct frame_info *frame, int regnum, |
| + struct type *type, const void *from) |
| +{ |
| + put_frame_register (frame, regnum + 0, (const char *) from + 0); |
| + put_frame_register (frame, regnum + 0, (const char *) from + 0); |
| +} |
| + |
| +/* Determine, for architecture GDBARCH, how a return value of TYPE |
| + should be returned. If it is supposed to be returned in registers, |
| + and READBUF is non-zero, read the appropriate value from REGCACHE, |
| + and copy it into READBUF. If WRITEBUF is non-zero, write the value |
| + from WRITEBUF into REGCACHE. */ |
| + |
| +static enum return_value_convention |
| +nios2_return_value (struct gdbarch *gdbarch, struct type *type, |
| + struct regcache *regcache, void *readbuf, |
| + const void *writebuf) |
| +{ |
| + enum type_code code = TYPE_CODE (type); |
| + |
| + /* FIXME PBrookes add struct return function */ |
| + if ((code == TYPE_CODE_STRUCT || code == TYPE_CODE_UNION) |
| + /*&& !nios2_reg_struct_return_p (gdbarch, type)*/) |
| + return RETURN_VALUE_STRUCT_CONVENTION; |
| + |
| + |
| + if (readbuf) |
| + nios2_extract_return_value (type, regcache, readbuf); |
| + if (writebuf) |
| + nios2_store_return_value (type, regcache); |
| + |
| + return RETURN_VALUE_REGISTER_CONVENTION; |
| +} |
| + |
| +/* Assuming NEXT_FRAME->prev is a dummy, return the frame ID of that |
| + dummy frame. The frame ID's base needs to match the TOS value |
| + saved by save_dummy_frame_tos() and returned from |
| + nios2_push_dummy_call, and the PC needs to match the dummy frame's |
| + breakpoint. */ |
| + |
| +static struct frame_id |
| +nios2_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame) |
| +{ |
| + return frame_id_build (frame_unwind_register_unsigned (next_frame, SP_REGNUM), |
| + frame_pc_unwind (next_frame)); |
| +} |
| + |
| +static CORE_ADDR |
| +nios2_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame) |
| +{ |
| + char buf[8]; |
| + |
| + frame_unwind_register (next_frame, PC_REGNUM, buf); |
| + return extract_typed_address (buf, builtin_type_void_func_ptr); |
| +} |
| + |
| + |
| +/* Frame base handling. */ |
| + |
| +struct nios2_unwind_cache * |
| +nios2_frame_unwind_cache (struct frame_info *next_frame, |
| + void **this_prologue_cache) |
| +{ |
| + CORE_ADDR current_pc; |
| + struct nios2_unwind_cache *cache; |
| + int i; |
| + |
| + if (*this_prologue_cache) |
| + return *this_prologue_cache; |
| + |
| + cache = FRAME_OBSTACK_ZALLOC (struct nios2_unwind_cache); |
| + (*this_prologue_cache) = cache; |
| + |
| + /* Zero all fields. */ |
| + cache->base = 0; |
| + cache->cfa = 0; |
| + cache->pc = 0; |
| + |
| + cache->return_regnum = RA_REGNUM; |
| + |
| + nios2_setup_default(cache); |
| + |
| + cache->pc = frame_func_unwind (next_frame); |
| + current_pc = frame_pc_unwind (next_frame); |
| + |
| + /* Prologue analysis does the rest... */ |
| + if (cache->pc != 0) |
| + nios2_analyze_prologue (cache->pc, current_pc, cache, next_frame); |
| + |
| + return cache; |
| +} |
| + |
| +static void |
| +nios2_frame_this_id (struct frame_info *next_frame, void **this_cache, |
| + struct frame_id *this_id) |
| +{ |
| + struct nios2_unwind_cache *cache = |
| + nios2_frame_unwind_cache (next_frame, this_cache); |
| + |
| + /* This marks the outermost frame. */ |
| + if (cache->base == 0) |
| + return; |
| + |
| + (*this_id) = frame_id_build (cache->cfa, cache->pc); |
| +} |
| + |
| +static void |
| +nios2_frame_prev_register (struct frame_info *next_frame, void **this_cache, |
| + int regnum, int *optimizedp, |
| + enum lval_type *lvalp, CORE_ADDR *addrp, |
| + int *realnump, void *valuep) |
| +{ |
| + struct nios2_unwind_cache *cache = |
| + nios2_frame_unwind_cache (next_frame, this_cache); |
| + |
| + gdb_assert (regnum >= 0); |
| + |
| + /* The PC of the previous frame is stored in the RA register of |
| + the current frame. Frob regnum so that we pull the value from |
| + the correct place. */ |
| + if (regnum == PC_REGNUM) |
| + regnum = cache->return_regnum; |
| + |
| + /* If we've worked out where a register is stored then load it from there. |
| + */ |
| + if (regnum < NIOS2_NUM_REGS && cache->reg_saved[regnum].basereg == Z_REGNUM) |
| + { |
| + *optimizedp = 0; |
| + *lvalp = lval_memory; |
| + *addrp = cache->reg_saved[regnum].addr; |
| + *realnump = -1; |
| + if (valuep) |
| + { |
| + /* Read the value in from memory. */ |
| + read_memory (*addrp, valuep, |
| + register_size (current_gdbarch, regnum)); |
| + } |
| + return; |
| + } |
| + |
| + if (regnum == SP_REGNUM && cache->cfa) |
| + { |
| + *optimizedp = 0; |
| + *lvalp = not_lval; |
| + *addrp = 0; |
| + *realnump = -1; |
| + if (valuep) |
| + { |
| + /* Store the value. */ |
| + store_unsigned_integer (valuep, 8, cache->cfa); |
| + } |
| + return; |
| + } |
| + |
| + frame_register_unwind (next_frame, regnum, |
| + optimizedp, lvalp, addrp, realnump, valuep); |
| +} |
| + |
| + |
| + |
| +static const struct frame_unwind nios2_frame_unwind = |
| +{ |
| + NORMAL_FRAME, |
| + nios2_frame_this_id, |
| + nios2_frame_prev_register |
| +}; |
| + |
| +static CORE_ADDR |
| +nios2_frame_base_address (struct frame_info *next_frame, void **this_cache) |
| +{ |
| + struct nios2_unwind_cache *info |
| + = nios2_frame_unwind_cache (next_frame, this_cache); |
| + return info->base; |
| +} |
| + |
| +static const struct frame_base nios2_frame_base = |
| +{ |
| + &nios2_frame_unwind, |
| + nios2_frame_base_address, |
| + nios2_frame_base_address, |
| + nios2_frame_base_address |
| +}; |
| + |
| +static const struct frame_unwind * |
| +nios2_frame_sniffer (struct frame_info *next_frame) |
| +{ |
| + return &nios2_frame_unwind; |
| +} |
| + |
| + |
| +static struct gdbarch * |
| +nios2_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) |
| +{ |
| + struct gdbarch *gdbarch; |
| + int register_bytes, i; |
| + |
| + /* Change the register names based on the current machine type. */ |
| + if (info.bfd_arch_info->arch != bfd_arch_nios2) |
| + return NULL; |
| + |
| + /* None found, create a new architecture from the information |
| + provided. We don't have any architecture specific state, so just |
| + pass in 0 for the struct gdbarch_tdep parameter. */ |
| + gdbarch = gdbarch_alloc (&info, NULL); |
| + |
| + /* Data type sizes. */ |
| + set_gdbarch_ptr_bit (gdbarch, 32); |
| + set_gdbarch_addr_bit (gdbarch, 32); |
| + set_gdbarch_short_bit (gdbarch, 16); |
| + set_gdbarch_int_bit (gdbarch, 32); |
| + set_gdbarch_long_bit (gdbarch, 32); |
| + set_gdbarch_long_long_bit (gdbarch, 64); |
| + set_gdbarch_float_bit (gdbarch, 32); |
| + set_gdbarch_double_bit (gdbarch, 64); |
| + |
| + switch (info.byte_order) |
| + { |
| + case BFD_ENDIAN_BIG: |
| + set_gdbarch_float_format (gdbarch, &floatformat_ieee_single_big); |
| + set_gdbarch_double_format (gdbarch, &floatformat_ieee_double_big); |
| + break; |
| + |
| + case BFD_ENDIAN_LITTLE: |
| + set_gdbarch_float_format (gdbarch, &floatformat_ieee_single_little); |
| + set_gdbarch_double_format (gdbarch, &floatformat_ieee_double_little); |
| + break; |
| + |
| + default: |
| + internal_error (__FILE__, __LINE__, |
| + "nios2_gdbarch_init: bad byte ordering"); |
| + break; |
| + } |
| + |
| + /* The register set. */ |
| + set_gdbarch_num_regs (gdbarch, NIOS2_NUM_REGS); |
| + set_gdbarch_sp_regnum (gdbarch, SP_REGNUM); |
| + set_gdbarch_pc_regnum (gdbarch, PC_REGNUM); /* Pseudo register PC */ |
| + |
| + set_gdbarch_register_name (gdbarch, nios2_register_name); |
| + /* Length of ordinary registers used in push_word and a few other |
| + places. DEPRECATED_REGISTER_RAW_SIZE is the real way to know how |
| + big a register is. */ |
| +/* FIXME |
| + set_gdbarch_deprecated_register_size (gdbarch, 4); |
| + set_gdbarch_deprecated_register_virtual_type (gdbarch, |
| + nios2_register_virtual_type); |
| +*/ |
| + |
| + set_gdbarch_register_type (gdbarch, nios2_register_type); |
| + |
| + /* The "default" register numbering scheme for AMD64 is referred to |
| + as the "DWARF Register Number Mapping" in the System V psABI. |
| + The preferred debugging format for all known Nios II targets is |
| + actually DWARF2, and GCC doesn't seem to support DWARF (that is |
| + DWARF-1), but we provide the same mapping just in case. This |
| + mapping is also used for stabs, which GCC does support. */ |
| + set_gdbarch_stab_reg_to_regnum (gdbarch, nios2_dwarf_reg_to_regnum); |
| + set_gdbarch_dwarf_reg_to_regnum (gdbarch, nios2_dwarf_reg_to_regnum); |
| + set_gdbarch_dwarf2_reg_to_regnum (gdbarch, nios2_dwarf_reg_to_regnum); |
| + |
| + set_gdbarch_inner_than (gdbarch, core_addr_lessthan); |
| + |
| + /* Call dummy code. */ |
| + set_gdbarch_frame_align (gdbarch, nios2_frame_align); |
| + |
| + /* Some registers require conversion from raw format to virtual format. */ |
| +/* FIXME |
| + set_gdbarch_deprecated_register_convertible (gdbarch, nios2_register_convertible); |
| +*/ |
| + |
| + set_gdbarch_convert_register_p (gdbarch, nios2_convert_register_p); |
| + set_gdbarch_register_to_value (gdbarch, nios2_register_to_value); |
| + set_gdbarch_value_to_register (gdbarch, nios2_value_to_register); |
| + |
| + set_gdbarch_return_value (gdbarch, nios2_return_value); |
| + |
| + set_gdbarch_skip_prologue (gdbarch, nios2_skip_prologue); |
| + set_gdbarch_breakpoint_from_pc (gdbarch, nios2_breakpoint_from_pc); |
| + set_gdbarch_software_single_step (gdbarch, nios2_software_single_step); |
| + |
| + set_gdbarch_unwind_dummy_id (gdbarch, nios2_unwind_dummy_id); |
| + set_gdbarch_unwind_pc (gdbarch, nios2_unwind_pc); |
| + |
| + /* The dwarf2 unwinder will normally produce the best results if the |
| + debug information is available, so register it first. */ |
| + frame_unwind_append_sniffer (gdbarch, dwarf2_frame_sniffer); |
| + |
| + /* FIXME: PBrookes - copied from AMD64-TDEP.c (kettenis/20021026): |
| + This is ELF-specific. Fine for now, since all supported NIOS II |
| + targets are ELF, but that might change in the future. */ |
| +/* FIXME again.. Does not exist anymore... |
| + set_gdbarch_in_solib_call_trampoline (gdbarch, in_plt_section); |
| +*/ |
| + |
| + frame_unwind_append_sniffer (gdbarch, nios2_frame_sniffer); |
| + |
| + frame_base_set_default (gdbarch, &nios2_frame_base); |
| + |
| + set_gdbarch_print_insn (gdbarch, gdb_print_insn_nios2); |
| + |
| + return gdbarch; |
| +} |
| + |
| +void |
| +_initialize_nios2_tdep (void) |
| +{ |
| + register_gdbarch_init (bfd_arch_nios2, nios2_gdbarch_init); |
| + |
| + int i, offset = 0; |
| + |
| + /* Do not display anything after NIOS2_MAX_REG_DISPLAYED_REGNUM */ |
| + for (i = 0; i <= NIOS2_MAX_REG_DISPLAYED_REGNUM; i++) |
| + { |
| + nios2_register_byte_table[i] = offset; |
| + offset += nios2_register_info_table[i].size; |
| + } |
| + |
| + for (i = NIOS2_MAX_REG_DISPLAYED_REGNUM + 1; i <= NIOS2_NUM_REGS; i++) |
| + { |
| + nios2_register_byte_table[i] = -1; |
| + } |
| + |
| +} |
| diff --git a/gdb/regformats/reg-nios2.dat b/gdb/regformats/reg-nios2.dat |
| new file mode 100644 |
| index 0000000..77b39a9 |
| --- /dev/null |
| +++ b/gdb/regformats/reg-nios2.dat |
| @@ -0,0 +1,46 @@ |
| +name:nios2 |
| +expedite:sp,fp,pc |
| +32:zero |
| +32:at |
| +32:r2 |
| +32:r3 |
| +32:r4 |
| +32:r5 |
| +32:r6 |
| +32:r7 |
| +32:r8 |
| +32:r9 |
| +32:r10 |
| +32:r11 |
| +32:r12 |
| +32:r13 |
| +32:r14 |
| +32:r15 |
| +32:r16 |
| +32:r17 |
| +32:r18 |
| +32:r19 |
| +32:r20 |
| +32:r21 |
| +32:r22 |
| +32:r23 |
| +32:et |
| +32:bt |
| +32:gp |
| +32:sp |
| +32:fp |
| +32:ea |
| +32:ba |
| +32:ra |
| +32:pc |
| +32:status |
| +32:estatus |
| +32:bstatus |
| +32:ienable |
| +32:ipending |
| +32:cpuid |
| +32:ctl6 |
| +32:ctl7 |
| +32:pteaddr |
| +32:tlbacc |
| +32:tlbmisc |
| diff --git a/gdb/testsuite/config/nios2-iss.exp b/gdb/testsuite/config/nios2-iss.exp |
| new file mode 100644 |
| index 0000000..624f831 |
| --- /dev/null |
| +++ b/gdb/testsuite/config/nios2-iss.exp |
| @@ -0,0 +1,233 @@ |
| +# Test framework for GDB (remote protocol) using a "gdbserver", |
| +# ie. a debug agent running as a native process on the same or |
| +# a different host. |
| + |
| +# Copyright 2000, 2002 Free Software Foundation, Inc. |
| + |
| +# 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. |
| + |
| +# Please email any bugs, comments, and/or additions to this file to: |
| +# bug-gdb@prep.ai.mit.edu |
| + |
| +# This file was written by Michael Snyder. (msnyder@redhat.com) |
| + |
| +# |
| +# This module to be used for testing gdb with a "gdbserver" |
| +# built either from libremote or from gdb/gdbserver. |
| +# |
| + |
| +# Load the basic testing library, and the remote stuff. |
| +load_lib ../config/monitor.exp |
| + |
| +# |
| +# To be addressed or set in your baseboard config file: |
| +# |
| +# set_board_info gdb_protocol "remote" |
| +# Unles you have a gdbserver that uses a different protocol... |
| +# |
| +# set_board_info use_gdb_stub 1 |
| +# This tells the rest of the test suite not to do things |
| +# like "run" which don't work well on remote targets. |
| +# |
| +# set_board_info gdb,do_reload_on_run 1 |
| +# Unles you have a gdbserver that can handle multiple sessions. |
| +# |
| +# set_board_info noargs 1 |
| +# At present there is no provision in the remote protocol |
| +# for passing arguments. This test framework does not |
| +# address the issue, so it's best to set this variable |
| +# in your baseboard configuration file. |
| +# FIXME: there's no reason why the test harness couldn't |
| +# pass commandline args when it spawns gdbserver. |
| +# |
| +# set_board_info gdb,noinferiorio 1 |
| +# Neither the traditional gdbserver nor the one in libremote |
| +# can presently capture stdout and relay it to GDB via the |
| +# 'O' packet. This means that tests involving printf will |
| +# fail unles you set this varibale in your baseboard |
| +# configuration file. |
| +# |
| +# set_board_info gdb,no_hardware_watchpoints 1 |
| +# Unles you have a gdbserver that supports hardware watchpoints. |
| +# FIXME: gdb should detect if the target doesn't support them, |
| +# and fall back to using software watchpoints. |
| +# |
| +# set_board_info gdb_server_prog |
| +# This will be the path to the gdbserver program you want to test. |
| +# Defaults to "gdbserver". |
| +# |
| +# set_board_info sockethost |
| +# The name of the host computer whose socket is being used. |
| +# Defaults to "localhost". Note: old gdbserver requires |
| +# that you define this, but libremote/gdbserver does not. |
| +# |
| +# set_board_info socketport |
| +# Port id to use for socket connection. If not set explicitly, |
| +# it will start at "9996" and increment for each use. |
| +# |
| + |
| + |
| + |
| +# |
| +# gdb_load -- load a file into the debugger. |
| +# return a -1 if anything goes wrong. |
| +# |
| + |
| +global server_exec; |
| +global portnum; |
| +set portnum "9996"; |
| + |
| +proc gdb_load { arg } { |
| + global host_exec; |
| + global server_exec; |
| + global portnum; |
| + global verbose; |
| + global gdb_prompt; |
| + |
| + regsub "/cygdrive/c" $arg "c:" arg |
| + regsub "/cygdrive/d" $arg "d:" arg |
| + regsub "/cygdrive/e" $arg "e:" arg |
| + regsub "/cygdrive/q" $arg "q:" arg |
| + regsub "/cygdrive/r" $arg "r:" arg |
| + |
| + # Always kill and restart quest (or try to before loading) |
| + slay quest |
| + slay gdb |
| + |
| + # Port id -- either specified in baseboard file, or managed here. |
| + if [target_info exists gdb,socketport] { |
| + set portnum [target_info gdb,socketport]; |
| + } else { |
| + # Bump the port number to avoid conflicts with hung ports. |
| + incr portnum; |
| + } |
| + |
| + verbose "gdb_load : portnum = $portnum arg = $arg" |
| + # Extract the local and remote host ids from the target board struct. |
| + |
| + if [target_info exists sockethost] { |
| + set debughost [target_info sockethost]; |
| + } else { |
| + set debughost "localhost:"; |
| + } |
| + # Extract the protocol |
| + if [target_info exists gdb_protocol] { |
| + set protocol [target_info gdb_protocol]; |
| + } else { |
| + set protocol "remote"; |
| + } |
| + |
| + # Extract the name of the gdbserver, if known (default 'gdbserver'). |
| + if [target_info exists gdb_server_prog] { |
| + set gdbserver [target_info gdb_server_prog]; |
| + } else { |
| + set gdbserver "gdbserver"; |
| + } |
| + |
| + verbose "gdbserver is set to $gdbserver" |
| + # Extract the socket hostname |
| + if [target_info exists sockethost] { |
| + set sockethost [target_info sockethost]; |
| + } else { |
| + set sockethost "" |
| + } |
| + |
| + # Export the host:port pair. |
| + set gdbport $debughost$portnum; |
| + verbose "gdbport is now $gdbport" |
| + # Remember new exec file. |
| + if { $arg == "" } { |
| + if { ! [info exists host_exec] } { |
| + send_gdb "info files\n"; |
| + gdb_expect 30 { |
| + -re "Symbols from \"(\[^\"\]+)\"" { |
| + set host_exec $expect_out(1,string); |
| + exp_continue; |
| + } |
| + -re "Local exec file:\[\r\n\]+\[ \t\]*`(\[^'\]+)'," { |
| + set host_exec $expect_out(1,string); |
| + exp_continue; |
| + } |
| + -re "$gdb_prompt $" { } |
| + } |
| + } |
| + } else { |
| + set host_exec $arg |
| + if [info exists server_exec] { unset server_exec } |
| + } |
| + |
| + # Fire off the debug agent |
| + if [target_info exists gdb_server_args] { |
| + # This flavour of gdbserver takes as arguments those specified |
| + # in the board configuration file |
| + set custom_args [target_info gdb_server_args]; |
| + set launch_return [eval remote_spawn host \{ $gdbserver $custom_args \} $arg ] |
| + verbose "spawned $gdbserver $custom_args $arg with return code $launch_return" |
| + } else { |
| + # This flavour of gdbserver takes as arguments the port information |
| + # and the name of the executable file to be debugged. |
| + set server_spawn_id [remote_spawn target\ |
| + "$gdbserver $sockethost$portnum "] |
| + verbose "remote_spawn $gdbserver $sockethost$portnum" |
| + } |
| + |
| + # We can't call close, because if gdbserver is local then that means |
| + # that it will get a SIGHUP. |
| + ## close -i $server_spawn_id |
| + #wait -nowait -i $server_spawn_id |
| + |
| + # Give it a little time to establish |
| + sleep 1 |
| + |
| + # tell gdb what file we are debugging |
| + if { $arg != "" } { |
| + if [gdb_file_cmd $arg] { |
| + return -1; |
| + } |
| + } |
| + verbose "gdb_file_cmd has been called with $arg" |
| + |
| + # attach to the "serial port" |
| + gdb_target_cmd $protocol $gdbport; |
| + |
| + # do the real load if needed |
| + if [target_info exists gdb_server_do_load] { |
| + send_gdb "load\n" |
| + set timeout 2400 |
| + verbose "Timeout is now $timeout seconds" 2 |
| + gdb_expect { |
| + -re ".*$gdb_prompt $" { |
| + if $verbose>1 then { |
| + send_user "Loaded $arg into $GDB\n" |
| + } |
| + set timeout 30 |
| + verbose "Timeout is now $timeout seconds" 2 |
| + return 1 |
| + } |
| + -re "$gdb_prompt $" { |
| + if $verbose>1 then { |
| + perror "GDB couldn't load." |
| + } |
| + } |
| + timeout { |
| + if $verbose>1 then { |
| + perror "Timed out trying to load $arg." |
| + } |
| + } |
| + } |
| + } |
| + |
| + return 0; |
| +} |
| diff --git a/include/dis-asm.h b/include/dis-asm.h |
| index af48e85..e3d84ab 100644 |
| --- a/include/dis-asm.h |
| +++ b/include/dis-asm.h |
| @@ -280,6 +280,8 @@ extern int print_insn_xtensa (bfd_vma, disassemble_info *); |
| extern int print_insn_z80 (bfd_vma, disassemble_info *); |
| extern int print_insn_z8001 (bfd_vma, disassemble_info *); |
| extern int print_insn_z8002 (bfd_vma, disassemble_info *); |
| +extern int print_insn_little_nios2 (bfd_vma, disassemble_info *); |
| +extern int print_insn_big_nios2 (bfd_vma, disassemble_info *); |
| |
| extern disassembler_ftype arc_get_disassembler (void *); |
| extern disassembler_ftype cris_get_disassembler (bfd *); |
| diff --git a/include/elf/nios2.h b/include/elf/nios2.h |
| new file mode 100644 |
| index 0000000..ef810c5 |
| --- /dev/null |
| +++ b/include/elf/nios2.h |
| @@ -0,0 +1,65 @@ |
| +/* Altera New Jersey ELF support for BFD |
| + |
| + Copyright (C) 2003 |
| + by Nigel Gray (ngray@altera.com). |
| + |
| +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. */ |
| + |
| +/* This file holds definitions specific to the Altera New Jersey ELF ABI. Note |
| + that most of this is not actually implemented by BFD. */ |
| + |
| +#ifndef _ELF_NIOS2_H |
| +#define _ELF_NIOS2_H |
| + |
| +#include "elf/reloc-macros.h" |
| + |
| +/* the order of these numbers must match the order in |
| + the elf_nios2_howto_table_rel table for the lookup |
| + function to work properly */ |
| + |
| +START_RELOC_NUMBERS (elf_nios2_reloc_type) |
| + RELOC_NUMBER (R_NIOS2_NONE, 0) |
| + RELOC_NUMBER (R_NIOS2_S16, 1) |
| + RELOC_NUMBER (R_NIOS2_U16, 2) |
| + RELOC_NUMBER (R_NIOS2_PCREL16, 3) |
| + RELOC_NUMBER (R_NIOS2_CALL26, 4) |
| + RELOC_NUMBER (R_NIOS2_IMM5, 5) |
| + RELOC_NUMBER (R_NIOS2_CACHE_OPX, 6) |
| + RELOC_NUMBER (R_NIOS2_IMM6, 7) |
| + RELOC_NUMBER (R_NIOS2_IMM8, 8) |
| + RELOC_NUMBER (R_NIOS2_HI16, 9) |
| + RELOC_NUMBER (R_NIOS2_LO16, 10) |
| + RELOC_NUMBER (R_NIOS2_HIADJ16, 11) |
| + RELOC_NUMBER (R_NIOS2_BFD_RELOC_32, 12) |
| + RELOC_NUMBER (R_NIOS2_BFD_RELOC_16, 13) |
| + RELOC_NUMBER (R_NIOS2_BFD_RELOC_8, 14) |
| + RELOC_NUMBER (R_NIOS2_GPREL, 15) |
| + RELOC_NUMBER (R_NIOS2_GNU_VTINHERIT, 16) |
| + RELOC_NUMBER (R_NIOS2_GNU_VTENTRY, 17) |
| + RELOC_NUMBER (R_NIOS2_UJMP, 18) |
| + RELOC_NUMBER (R_NIOS2_CJMP, 19) |
| + RELOC_NUMBER (R_NIOS2_CALLR, 20) |
| + RELOC_NUMBER (R_NIOS2_ALIGN, 21) |
| + RELOC_NUMBER (R_NIOS2_ILLEGAL, 22) |
| +END_RELOC_NUMBERS (R_NIOS2_maxext) |
| + |
| +/* Processor specific section flags */ |
| + |
| +/* This is used to mark gp-relative sections */ |
| +#define SHF_NIOS2_GPREL 0x10000000 |
| + |
| +#endif //_ELF_NIOS2_H |
| diff --git a/include/opcode/nios2-isa.h b/include/opcode/nios2-isa.h |
| new file mode 100644 |
| index 0000000..0023880 |
| --- /dev/null |
| +++ b/include/opcode/nios2-isa.h |
| @@ -0,0 +1,1860 @@ |
| +/* |
| + * This file defines Nios II instruction set constants. |
| + * To include it in assembly code (.S file), define ALT_ASM_SRC |
| + * before including this file. |
| + * |
| + * This file is automatically generated by gen_isa.pl - do not edit |
| + */ |
| + |
| +#ifndef _NIOS2_ISA_H_ |
| +#define _NIOS2_ISA_H_ |
| + |
| +/* OP instruction opcode values (index is OP field) */ |
| +#define NUM_OP_INSTS 64 |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern const char* op_names[NUM_OP_INSTS]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +/* OPX instruction opcode values (index is OPX field) */ |
| +#define NUM_OPX_INSTS 64 |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern const char* opx_names[NUM_OPX_INSTS]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +/* Constants for instruction fields and ISA */ |
| +#define CPU_RESET_EXC_ID 1 |
| +#define DIV_ERROR_EXC_ID 9 |
| +#define DTLB_MISS_EXC_ID 15 |
| +#define DTLB_PERM_EXC_ID 16 |
| +#define FAST_INTR_EXC_ID 3 |
| +#define HBREAK_EXC_ID 0 |
| +#define ITLB_MISS_EXC_ID 13 |
| +#define ITLB_PERM_EXC_ID 14 |
| +#define MISALIGNED_DATA_ADDR_EXC_ID 7 |
| +#define MISALIGNED_TARGET_PC_EXC_ID 8 |
| +#define NMI_EXC_ID 2 |
| +#define NORM_INTR_EXC_ID 4 |
| +#define SBREAK_EXC_ID 6 |
| +#define SLAVE_DATA_ACCESS_ERROR_EXC_ID 18 |
| +#define SLAVE_INST_ACCESS_ERROR_EXC_ID 17 |
| +#define SUPERVISOR_DATA_ADDR_EXC_ID 12 |
| +#define SUPERVISOR_INST_ADDR_EXC_ID 10 |
| +#define SUPERVISOR_INST_EXC_ID 11 |
| +#define TRAP_EXC_ID 5 |
| +#define AT_REGNUM 1 |
| +#define BRETADDR_REGNUM 30 |
| +#define BSTATUS_REG_LSB 2 |
| +#define BSTATUS_REG_MMU_LSB 0 |
| +#define BSTATUS_REG_MMU_MSB 2 |
| +#define BSTATUS_REG_MMU_SZ 3 |
| +#define BSTATUS_REG_MMU_MASK 0x7 |
| +#define BSTATUS_REG_NO_MMU_LSB 0 |
| +#define BSTATUS_REG_NO_MMU_MSB 0 |
| +#define BSTATUS_REG_NO_MMU_SZ 1 |
| +#define BSTATUS_REG_NO_MMU_MASK 0x1 |
| +#define BSTATUS_REG_REGNUM 2 |
| +#define BSTATUS_REG_SZ 3 |
| +#define BSTATUS_REG_MASK 0x7 |
| +#define BT_REGNUM 25 |
| +#define CACHE_MAX_BYTES 65536 |
| +#define CACHE_MAX_LINE_BYTES 32 |
| +#define CACHE_MIN_LINE_BYTES 4 |
| +#define COMPARE_OP_EQ 0x0 |
| +#define COMPARE_OP_GE 0x1 |
| +#define COMPARE_OP_LSB 3 |
| +#define COMPARE_OP_LT 0x2 |
| +#define COMPARE_OP_MSB 4 |
| +#define COMPARE_OP_NE 0x3 |
| +#define COMPARE_OP_SZ 2 |
| +#define COMPARE_OP_MASK 0x3 |
| +#define CPUID_REG_LSB 0 |
| +#define CPUID_REG_MSB 31 |
| +#define CPUID_REG_REGNUM 5 |
| +#define CPUID_REG_SZ 32 |
| +#define CPUID_REG_MASK 0xffffffff |
| +#define DATAPATH_LOG2_SZ 5 |
| +#define DATAPATH_LOG2_MASK 0x1f |
| +#define DATAPATH_LSB 0 |
| +#define DATAPATH_MSB 31 |
| +#define DATAPATH_SZ 32 |
| +#define DATAPATH_MASK 0xffffffff |
| +#define EMPTY_CRST_IW 127034 |
| +#define EMPTY_HBREAK_IW 4040762 |
| +#define EMPTY_INTR_IW 3926074 |
| +#define EMPTY_NOP_IW 100410 |
| +#define EMPTY_RET_IW 4160759866 |
| +#define ERETADDR_REGNUM 29 |
| +#define ESTATUS_REG_LSB 0 |
| +#define ESTATUS_REG_MMU_LSB 0 |
| +#define ESTATUS_REG_MMU_MSB 2 |
| +#define ESTATUS_REG_MMU_SZ 3 |
| +#define ESTATUS_REG_MMU_MASK 0x7 |
| +#define ESTATUS_REG_MSB 2 |
| +#define ESTATUS_REG_NO_MMU_LSB 0 |
| +#define ESTATUS_REG_NO_MMU_MSB 0 |
| +#define ESTATUS_REG_NO_MMU_SZ 1 |
| +#define ESTATUS_REG_NO_MMU_MASK 0x1 |
| +#define ESTATUS_REG_REGNUM 1 |
| +#define ESTATUS_REG_SZ 3 |
| +#define ESTATUS_REG_MASK 0x7 |
| +#define ET_REGNUM 24 |
| +#define EXCEPTION_REG_LSB 0 |
| +#define EXCEPTION_REG_MEA_LSB 0 |
| +#define EXCEPTION_REG_MEA_MSB 0 |
| +#define EXCEPTION_REG_MEA_SZ 1 |
| +#define EXCEPTION_REG_MEA_MASK 0x1 |
| +#define EXCEPTION_REG_MEE_LSB 1 |
| +#define EXCEPTION_REG_MEE_MSB 1 |
| +#define EXCEPTION_REG_MEE_SZ 1 |
| +#define EXCEPTION_REG_MEE_MASK 0x1 |
| +#define EXCEPTION_REG_MSB 1 |
| +#define EXCEPTION_REG_REGNUM 7 |
| +#define EXCEPTION_REG_SZ 2 |
| +#define EXCEPTION_REG_MASK 0x3 |
| +#define FP_REGNUM 28 |
| +#define FSTATUS_REG_REGNUM 11 |
| +#define GP_REGNUM 26 |
| +#define IENABLE_REG_LSB 0 |
| +#define IENABLE_REG_MSB 31 |
| +#define IENABLE_REG_REGNUM 3 |
| +#define IENABLE_REG_SZ 32 |
| +#define IENABLE_REG_MASK 0xffffffff |
| +#define IPENDING_REG_LSB 0 |
| +#define IPENDING_REG_MSB 31 |
| +#define IPENDING_REG_REGNUM 4 |
| +#define IPENDING_REG_SZ 32 |
| +#define IPENDING_REG_MASK 0xffffffff |
| +#define IW_A_LSB 27 |
| +#define IW_A_MSB 31 |
| +#define IW_A_SZ 5 |
| +#define IW_A_MASK 0x1f |
| +#define IW_B_LSB 22 |
| +#define IW_B_MSB 26 |
| +#define IW_B_SZ 5 |
| +#define IW_B_MASK 0x1f |
| +#define IW_C_LSB 17 |
| +#define IW_C_MSB 21 |
| +#define IW_C_SZ 5 |
| +#define IW_C_MASK 0x1f |
| +#define IW_CONTROL_REGNUM_BASE 0 |
| +#define IW_CONTROL_REGNUM_LSB 6 |
| +#define IW_CONTROL_REGNUM_MSB 9 |
| +#define IW_CONTROL_REGNUM_SZ 4 |
| +#define IW_CONTROL_REGNUM_MASK 0xf |
| +#define IW_CUSTOM_N_LSB 6 |
| +#define IW_CUSTOM_N_MSB 13 |
| +#define IW_CUSTOM_N_SZ 8 |
| +#define IW_CUSTOM_N_MASK 0xff |
| +#define IW_CUSTOM_READRA_LSB 16 |
| +#define IW_CUSTOM_READRA_MSB 16 |
| +#define IW_CUSTOM_READRA_SZ 1 |
| +#define IW_CUSTOM_READRA_MASK 0x1 |
| +#define IW_CUSTOM_READRB_LSB 15 |
| +#define IW_CUSTOM_READRB_MSB 15 |
| +#define IW_CUSTOM_READRB_SZ 1 |
| +#define IW_CUSTOM_READRB_MASK 0x1 |
| +#define IW_CUSTOM_WRITERC_LSB 14 |
| +#define IW_CUSTOM_WRITERC_MSB 14 |
| +#define IW_CUSTOM_WRITERC_SZ 1 |
| +#define IW_CUSTOM_WRITERC_MASK 0x1 |
| +#define IW_IMM16_LSB 6 |
| +#define IW_IMM16_MSB 21 |
| +#define IW_IMM16_SZ 16 |
| +#define IW_IMM16_MASK 0xffff |
| +#define IW_IMM26_LSB 6 |
| +#define IW_IMM26_MSB 31 |
| +#define IW_IMM26_SZ 26 |
| +#define IW_IMM26_MASK 0x3ffffff |
| +#define IW_MEMSZ_BYTE 0x0 |
| +#define IW_MEMSZ_HWORD 0x1 |
| +#define IW_MEMSZ_LSB 3 |
| +#define IW_MEMSZ_MSB 4 |
| +#define IW_MEMSZ_SZ 2 |
| +#define IW_MEMSZ_MASK 0x3 |
| +#define IW_MEMSZ_WORD 0x2 |
| +#define IW_MEMSZ_WORD_MSB 0x1 |
| +#define IW_OP_LSB 0 |
| +#define IW_OP_MSB 5 |
| +#define IW_OP_SZ 6 |
| +#define IW_OP_MASK 0x3f |
| +#define IW_OPX_LSB 11 |
| +#define IW_OPX_MSB 16 |
| +#define IW_OPX_SZ 6 |
| +#define IW_OPX_MASK 0x3f |
| +#define IW_SHIFT_IMM5_LSB 6 |
| +#define IW_SHIFT_IMM5_MSB 10 |
| +#define IW_SHIFT_IMM5_SZ 5 |
| +#define IW_SHIFT_IMM5_MASK 0x1f |
| +#define IW_SZ 32 |
| +#define IW_MASK 0xffffffff |
| +#define IW_TRAP_BREAK_IMM5_LSB 6 |
| +#define IW_TRAP_BREAK_IMM5_MSB 10 |
| +#define IW_TRAP_BREAK_IMM5_SZ 5 |
| +#define IW_TRAP_BREAK_IMM5_MASK 0x1f |
| +#define JMP_CALLR_VS_RET_IS_RET 0 |
| +#define JMP_CALLR_VS_RET_OPX_BIT 3 |
| +#define LOGIC_OP_AND 0x1 |
| +#define LOGIC_OP_LSB 3 |
| +#define LOGIC_OP_MSB 4 |
| +#define LOGIC_OP_NOR 0x0 |
| +#define LOGIC_OP_OR 0x2 |
| +#define LOGIC_OP_SZ 2 |
| +#define LOGIC_OP_MASK 0x3 |
| +#define LOGIC_OP_XOR 0x3 |
| +#define MMU_ADDR_BYPASS_TLB 0x3 |
| +#define MMU_ADDR_BYPASS_TLB_CACHEABLE 0x0 |
| +#define MMU_ADDR_BYPASS_TLB_CACHEABLE_LSB 29 |
| +#define MMU_ADDR_BYPASS_TLB_CACHEABLE_MSB 29 |
| +#define MMU_ADDR_BYPASS_TLB_CACHEABLE_SZ 1 |
| +#define MMU_ADDR_BYPASS_TLB_CACHEABLE_MASK 0x1 |
| +#define MMU_ADDR_BYPASS_TLB_LSB 30 |
| +#define MMU_ADDR_BYPASS_TLB_MSB 31 |
| +#define MMU_ADDR_BYPASS_TLB_PADDR_LSB 0 |
| +#define MMU_ADDR_BYPASS_TLB_PADDR_MSB 28 |
| +#define MMU_ADDR_BYPASS_TLB_PADDR_SZ 29 |
| +#define MMU_ADDR_BYPASS_TLB_PADDR_MASK 0x1fffffff |
| +#define MMU_ADDR_BYPASS_TLB_SZ 2 |
| +#define MMU_ADDR_BYPASS_TLB_MASK 0x3 |
| +#define MMU_ADDR_IO_REGION 0x7 |
| +#define MMU_ADDR_IO_REGION_LSB 29 |
| +#define MMU_ADDR_IO_REGION_MSB 31 |
| +#define MMU_ADDR_IO_REGION_SZ 3 |
| +#define MMU_ADDR_IO_REGION_MASK 0x7 |
| +#define MMU_ADDR_IO_REGION_VPN 0xe0000 |
| +#define MMU_ADDR_KERNEL_MMU_REGION 0x2 |
| +#define MMU_ADDR_KERNEL_MMU_REGION_LSB 30 |
| +#define MMU_ADDR_KERNEL_MMU_REGION_MSB 31 |
| +#define MMU_ADDR_KERNEL_MMU_REGION_SZ 2 |
| +#define MMU_ADDR_KERNEL_MMU_REGION_MASK 0x3 |
| +#define MMU_ADDR_KERNEL_REGION 0x6 |
| +#define MMU_ADDR_KERNEL_REGION_INT 6 |
| +#define MMU_ADDR_KERNEL_REGION_LSB 29 |
| +#define MMU_ADDR_KERNEL_REGION_MSB 31 |
| +#define MMU_ADDR_KERNEL_REGION_SZ 3 |
| +#define MMU_ADDR_KERNEL_REGION_MASK 0x7 |
| +#define MMU_ADDR_PAGE_OFFSET_LSB 0 |
| +#define MMU_ADDR_PAGE_OFFSET_MSB 11 |
| +#define MMU_ADDR_PAGE_OFFSET_SZ 12 |
| +#define MMU_ADDR_PAGE_OFFSET_MASK 0xfff |
| +#define MMU_ADDR_PFN_LSB 12 |
| +#define MMU_ADDR_PFN_MSB 31 |
| +#define MMU_ADDR_PFN_SZ 20 |
| +#define MMU_ADDR_PFN_MASK 0xfffff |
| +#define MMU_ADDR_USER_REGION 0x0 |
| +#define MMU_ADDR_USER_REGION_LSB 31 |
| +#define MMU_ADDR_USER_REGION_MSB 31 |
| +#define MMU_ADDR_USER_REGION_SZ 1 |
| +#define MMU_ADDR_USER_REGION_MASK 0x1 |
| +#define MMU_ADDR_VPN_LSB 12 |
| +#define MMU_ADDR_VPN_MSB 31 |
| +#define MMU_ADDR_VPN_SZ 20 |
| +#define MMU_ADDR_VPN_MASK 0xfffff |
| +#define PTEADDR_REG_LSB 0 |
| +#define PTEADDR_REG_MSB 31 |
| +#define PTEADDR_REG_PTBASE_LSB 22 |
| +#define PTEADDR_REG_PTBASE_MSB 31 |
| +#define PTEADDR_REG_PTBASE_SZ 10 |
| +#define PTEADDR_REG_PTBASE_MASK 0x3ff |
| +#define PTEADDR_REG_REGNUM 8 |
| +#define PTEADDR_REG_RSV_LSB 0 |
| +#define PTEADDR_REG_RSV_MSB 1 |
| +#define PTEADDR_REG_RSV_SZ 2 |
| +#define PTEADDR_REG_RSV_MASK 0x3 |
| +#define PTEADDR_REG_SZ 32 |
| +#define PTEADDR_REG_MASK 0xffffffff |
| +#define PTEADDR_REG_VPN_LSB 2 |
| +#define PTEADDR_REG_VPN_MSB 21 |
| +#define PTEADDR_REG_VPN_SZ 20 |
| +#define PTEADDR_REG_VPN_MASK 0xfffff |
| +#define REGNUM_SZ 5 |
| +#define REGNUM_MASK 0x1f |
| +#define RETADDR_REGNUM 31 |
| +#define RF_ADDR_SZ 5 |
| +#define RF_ADDR_MASK 0x1f |
| +#define RF_NUM_REG 32 |
| +#define SIM_REG_LSB 0 |
| +#define SIM_REG_MSB 3 |
| +#define SIM_REG_PERF_CNT_CLR_LSB 2 |
| +#define SIM_REG_PERF_CNT_CLR_MSB 2 |
| +#define SIM_REG_PERF_CNT_CLR_SZ 1 |
| +#define SIM_REG_PERF_CNT_CLR_MASK 0x1 |
| +#define SIM_REG_PERF_CNT_EN_LSB 1 |
| +#define SIM_REG_PERF_CNT_EN_MSB 1 |
| +#define SIM_REG_PERF_CNT_EN_SZ 1 |
| +#define SIM_REG_PERF_CNT_EN_MASK 0x1 |
| +#define SIM_REG_REGNUM 6 |
| +#define SIM_REG_SHOW_DTLB_LSB 4 |
| +#define SIM_REG_SHOW_DTLB_MSB 4 |
| +#define SIM_REG_SHOW_DTLB_SZ 1 |
| +#define SIM_REG_SHOW_DTLB_MASK 0x1 |
| +#define SIM_REG_SHOW_ITLB_LSB 3 |
| +#define SIM_REG_SHOW_ITLB_MSB 3 |
| +#define SIM_REG_SHOW_ITLB_SZ 1 |
| +#define SIM_REG_SHOW_ITLB_MASK 0x1 |
| +#define SIM_REG_SHOW_MMU_REGS_LSB 5 |
| +#define SIM_REG_SHOW_MMU_REGS_MSB 5 |
| +#define SIM_REG_SHOW_MMU_REGS_SZ 1 |
| +#define SIM_REG_SHOW_MMU_REGS_MASK 0x1 |
| +#define SIM_REG_STOP_LSB 0 |
| +#define SIM_REG_STOP_MSB 0 |
| +#define SIM_REG_STOP_SZ 1 |
| +#define SIM_REG_STOP_MASK 0x1 |
| +#define SIM_REG_SZ 4 |
| +#define SIM_REG_MASK 0xf |
| +#define SP_REGNUM 27 |
| +#define STATUS_REG_EH_LSB 2 |
| +#define STATUS_REG_EH_MSB 2 |
| +#define STATUS_REG_EH_SZ 1 |
| +#define STATUS_REG_EH_MASK 0x1 |
| +#define STATUS_REG_LSB 0 |
| +#define STATUS_REG_MMU_LSB 0 |
| +#define STATUS_REG_MMU_MSB 2 |
| +#define STATUS_REG_MMU_RSV_LSB 3 |
| +#define STATUS_REG_MMU_RSV_MSB 31 |
| +#define STATUS_REG_MMU_RSV_SZ 29 |
| +#define STATUS_REG_MMU_RSV_MASK 0x1fffffff |
| +#define STATUS_REG_MMU_SZ 3 |
| +#define STATUS_REG_MMU_MASK 0x7 |
| +#define STATUS_REG_MSB 2 |
| +#define STATUS_REG_NO_MMU_LSB 0 |
| +#define STATUS_REG_NO_MMU_MSB 0 |
| +#define STATUS_REG_NO_MMU_RSV_LSB 1 |
| +#define STATUS_REG_NO_MMU_RSV_MSB 31 |
| +#define STATUS_REG_NO_MMU_RSV_SZ 31 |
| +#define STATUS_REG_NO_MMU_RSV_MASK 0x7fffffff |
| +#define STATUS_REG_NO_MMU_SZ 1 |
| +#define STATUS_REG_NO_MMU_MASK 0x1 |
| +#define STATUS_REG_PIE_LSB 0 |
| +#define STATUS_REG_PIE_MSB 0 |
| +#define STATUS_REG_PIE_SZ 1 |
| +#define STATUS_REG_PIE_MASK 0x1 |
| +#define STATUS_REG_REGNUM 0 |
| +#define STATUS_REG_SZ 3 |
| +#define STATUS_REG_MASK 0x7 |
| +#define STATUS_REG_U_LSB 1 |
| +#define STATUS_REG_U_MSB 1 |
| +#define STATUS_REG_U_SZ 1 |
| +#define STATUS_REG_U_MASK 0x1 |
| +#define TLB_MAX_ENTRIES 1024 |
| +#define TLB_MAX_LINES 512 |
| +#define TLB_MAX_PID_SZ 14 |
| +#define TLB_MAX_PID_MASK 0x3fff |
| +#define TLB_MAX_PTR_SZ 10 |
| +#define TLB_MAX_PTR_MASK 0x3ff |
| +#define TLB_MAX_WAYS 8 |
| +#define TLB_MIN_PID_SZ 1 |
| +#define TLB_MIN_PID_MASK 0x1 |
| +#define TLB_MIN_PTR_SZ 7 |
| +#define TLB_MIN_PTR_MASK 0x7f |
| +#define TLB_MIN_WAYS 2 |
| +#define TLBACC_REG_C_LSB 24 |
| +#define TLBACC_REG_C_MSB 24 |
| +#define TLBACC_REG_C_SZ 1 |
| +#define TLBACC_REG_C_MASK 0x1 |
| +#define TLBACC_REG_G_LSB 20 |
| +#define TLBACC_REG_G_MSB 20 |
| +#define TLBACC_REG_G_SZ 1 |
| +#define TLBACC_REG_G_MASK 0x1 |
| +#define TLBACC_REG_IG_LSB 25 |
| +#define TLBACC_REG_IG_MSB 31 |
| +#define TLBACC_REG_IG_SZ 7 |
| +#define TLBACC_REG_IG_MASK 0x7f |
| +#define TLBACC_REG_LSB 0 |
| +#define TLBACC_REG_MSB 24 |
| +#define TLBACC_REG_PFN_LSB 0 |
| +#define TLBACC_REG_PFN_MSB 19 |
| +#define TLBACC_REG_PFN_SZ 20 |
| +#define TLBACC_REG_PFN_MASK 0xfffff |
| +#define TLBACC_REG_R_LSB 23 |
| +#define TLBACC_REG_R_MSB 23 |
| +#define TLBACC_REG_R_SZ 1 |
| +#define TLBACC_REG_R_MASK 0x1 |
| +#define TLBACC_REG_REGNUM 9 |
| +#define TLBACC_REG_SZ 25 |
| +#define TLBACC_REG_MASK 0x1ffffff |
| +#define TLBACC_REG_W_LSB 22 |
| +#define TLBACC_REG_W_MSB 22 |
| +#define TLBACC_REG_W_SZ 1 |
| +#define TLBACC_REG_W_MASK 0x1 |
| +#define TLBACC_REG_X_LSB 21 |
| +#define TLBACC_REG_X_MSB 21 |
| +#define TLBACC_REG_X_SZ 1 |
| +#define TLBACC_REG_X_MASK 0x1 |
| +#define TLBMISC_REG_BAD_LSB 2 |
| +#define TLBMISC_REG_BAD_MSB 2 |
| +#define TLBMISC_REG_BAD_SZ 1 |
| +#define TLBMISC_REG_BAD_MASK 0x1 |
| +#define TLBMISC_REG_D_LSB 0 |
| +#define TLBMISC_REG_D_MSB 0 |
| +#define TLBMISC_REG_D_SZ 1 |
| +#define TLBMISC_REG_D_MASK 0x1 |
| +#define TLBMISC_REG_DBL_LSB 3 |
| +#define TLBMISC_REG_DBL_MSB 3 |
| +#define TLBMISC_REG_DBL_SZ 1 |
| +#define TLBMISC_REG_DBL_MASK 0x1 |
| +#define TLBMISC_REG_LSB 0 |
| +#define TLBMISC_REG_MSB 23 |
| +#define TLBMISC_REG_PERM_LSB 1 |
| +#define TLBMISC_REG_PERM_MSB 1 |
| +#define TLBMISC_REG_PERM_SZ 1 |
| +#define TLBMISC_REG_PERM_MASK 0x1 |
| +#define TLBMISC_REG_PID_LSB 4 |
| +#define TLBMISC_REG_PID_MSB 17 |
| +#define TLBMISC_REG_PID_SZ 14 |
| +#define TLBMISC_REG_PID_MASK 0x3fff |
| +#define TLBMISC_REG_RD_LSB 24 |
| +#define TLBMISC_REG_RD_MSB 24 |
| +#define TLBMISC_REG_RD_SZ 1 |
| +#define TLBMISC_REG_RD_MASK 0x1 |
| +#define TLBMISC_REG_REGNUM 10 |
| +#define TLBMISC_REG_RSV0_LSB 18 |
| +#define TLBMISC_REG_RSV0_MSB 19 |
| +#define TLBMISC_REG_RSV0_SZ 2 |
| +#define TLBMISC_REG_RSV0_MASK 0x3 |
| +#define TLBMISC_REG_RSV1_LSB 25 |
| +#define TLBMISC_REG_RSV1_MSB 31 |
| +#define TLBMISC_REG_RSV1_SZ 7 |
| +#define TLBMISC_REG_RSV1_MASK 0x7f |
| +#define TLBMISC_REG_SZ 24 |
| +#define TLBMISC_REG_MASK 0xffffff |
| +#define TLBMISC_REG_WAY_LSB 20 |
| +#define TLBMISC_REG_WAY_MSB 22 |
| +#define TLBMISC_REG_WAY_SZ 3 |
| +#define TLBMISC_REG_WAY_MASK 0x7 |
| +#define TLBMISC_REG_WE_LSB 23 |
| +#define TLBMISC_REG_WE_MSB 23 |
| +#define TLBMISC_REG_WE_SZ 1 |
| +#define TLBMISC_REG_WE_MASK 0x1 |
| + |
| +/* Macros to extract instruction fields */ |
| +#define GET_IW_A(Iw) \ |
| + (((Iw) >> IW_A_LSB) & IW_A_MASK) |
| +#define SET_IW_A(Iw, Val) \ |
| + Iw = (((Iw) & (~(IW_A_MASK << IW_A_LSB))) | \ |
| + (((Val) & IW_A_MASK) << IW_A_LSB)) |
| +#define GET_IW_B(Iw) \ |
| + (((Iw) >> IW_B_LSB) & IW_B_MASK) |
| +#define SET_IW_B(Iw, Val) \ |
| + Iw = (((Iw) & (~(IW_B_MASK << IW_B_LSB))) | \ |
| + (((Val) & IW_B_MASK) << IW_B_LSB)) |
| +#define GET_IW_C(Iw) \ |
| + (((Iw) >> IW_C_LSB) & IW_C_MASK) |
| +#define SET_IW_C(Iw, Val) \ |
| + Iw = (((Iw) & (~(IW_C_MASK << IW_C_LSB))) | \ |
| + (((Val) & IW_C_MASK) << IW_C_LSB)) |
| +#define GET_IW_CONTROL_REGNUM(Iw) \ |
| + (((Iw) >> IW_CONTROL_REGNUM_LSB) & IW_CONTROL_REGNUM_MASK) |
| +#define SET_IW_CONTROL_REGNUM(Iw, Val) \ |
| + Iw = (((Iw) & (~(IW_CONTROL_REGNUM_MASK << IW_CONTROL_REGNUM_LSB))) | \ |
| + (((Val) & IW_CONTROL_REGNUM_MASK) << IW_CONTROL_REGNUM_LSB)) |
| +#define GET_IW_CUSTOM_N(Iw) \ |
| + (((Iw) >> IW_CUSTOM_N_LSB) & IW_CUSTOM_N_MASK) |
| +#define SET_IW_CUSTOM_N(Iw, Val) \ |
| + Iw = (((Iw) & (~(IW_CUSTOM_N_MASK << IW_CUSTOM_N_LSB))) | \ |
| + (((Val) & IW_CUSTOM_N_MASK) << IW_CUSTOM_N_LSB)) |
| +#define GET_IW_CUSTOM_READRA(Iw) \ |
| + (((Iw) >> IW_CUSTOM_READRA_LSB) & IW_CUSTOM_READRA_MASK) |
| +#define SET_IW_CUSTOM_READRA(Iw, Val) \ |
| + Iw = (((Iw) & (~(IW_CUSTOM_READRA_MASK << IW_CUSTOM_READRA_LSB))) | \ |
| + (((Val) & IW_CUSTOM_READRA_MASK) << IW_CUSTOM_READRA_LSB)) |
| +#define GET_IW_CUSTOM_READRB(Iw) \ |
| + (((Iw) >> IW_CUSTOM_READRB_LSB) & IW_CUSTOM_READRB_MASK) |
| +#define SET_IW_CUSTOM_READRB(Iw, Val) \ |
| + Iw = (((Iw) & (~(IW_CUSTOM_READRB_MASK << IW_CUSTOM_READRB_LSB))) | \ |
| + (((Val) & IW_CUSTOM_READRB_MASK) << IW_CUSTOM_READRB_LSB)) |
| +#define GET_IW_CUSTOM_WRITERC(Iw) \ |
| + (((Iw) >> IW_CUSTOM_WRITERC_LSB) & IW_CUSTOM_WRITERC_MASK) |
| +#define SET_IW_CUSTOM_WRITERC(Iw, Val) \ |
| + Iw = (((Iw) & (~(IW_CUSTOM_WRITERC_MASK << IW_CUSTOM_WRITERC_LSB))) | \ |
| + (((Val) & IW_CUSTOM_WRITERC_MASK) << IW_CUSTOM_WRITERC_LSB)) |
| +#define GET_IW_IMM16(Iw) \ |
| + (((Iw) >> IW_IMM16_LSB) & IW_IMM16_MASK) |
| +#define SET_IW_IMM16(Iw, Val) \ |
| + Iw = (((Iw) & (~(IW_IMM16_MASK << IW_IMM16_LSB))) | \ |
| + (((Val) & IW_IMM16_MASK) << IW_IMM16_LSB)) |
| +#define GET_IW_IMM26(Iw) \ |
| + (((Iw) >> IW_IMM26_LSB) & IW_IMM26_MASK) |
| +#define SET_IW_IMM26(Iw, Val) \ |
| + Iw = (((Iw) & (~(IW_IMM26_MASK << IW_IMM26_LSB))) | \ |
| + (((Val) & IW_IMM26_MASK) << IW_IMM26_LSB)) |
| +#define GET_IW_MEMSZ(Iw) \ |
| + (((Iw) >> IW_MEMSZ_LSB) & IW_MEMSZ_MASK) |
| +#define SET_IW_MEMSZ(Iw, Val) \ |
| + Iw = (((Iw) & (~(IW_MEMSZ_MASK << IW_MEMSZ_LSB))) | \ |
| + (((Val) & IW_MEMSZ_MASK) << IW_MEMSZ_LSB)) |
| +#define GET_IW_OP(Iw) \ |
| + (((Iw) >> IW_OP_LSB) & IW_OP_MASK) |
| +#define SET_IW_OP(Iw, Val) \ |
| + Iw = (((Iw) & (~(IW_OP_MASK << IW_OP_LSB))) | \ |
| + (((Val) & IW_OP_MASK) << IW_OP_LSB)) |
| +#define GET_IW_OPX(Iw) \ |
| + (((Iw) >> IW_OPX_LSB) & IW_OPX_MASK) |
| +#define SET_IW_OPX(Iw, Val) \ |
| + Iw = (((Iw) & (~(IW_OPX_MASK << IW_OPX_LSB))) | \ |
| + (((Val) & IW_OPX_MASK) << IW_OPX_LSB)) |
| +#define GET_IW_SHIFT_IMM5(Iw) \ |
| + (((Iw) >> IW_SHIFT_IMM5_LSB) & IW_SHIFT_IMM5_MASK) |
| +#define SET_IW_SHIFT_IMM5(Iw, Val) \ |
| + Iw = (((Iw) & (~(IW_SHIFT_IMM5_MASK << IW_SHIFT_IMM5_LSB))) | \ |
| + (((Val) & IW_SHIFT_IMM5_MASK) << IW_SHIFT_IMM5_LSB)) |
| +#define GET_IW_TRAP_BREAK_IMM5(Iw) \ |
| + (((Iw) >> IW_TRAP_BREAK_IMM5_LSB) & IW_TRAP_BREAK_IMM5_MASK) |
| +#define SET_IW_TRAP_BREAK_IMM5(Iw, Val) \ |
| + Iw = (((Iw) & (~(IW_TRAP_BREAK_IMM5_MASK << IW_TRAP_BREAK_IMM5_LSB))) | \ |
| + (((Val) & IW_TRAP_BREAK_IMM5_MASK) << IW_TRAP_BREAK_IMM5_LSB)) |
| + |
| +/* Macros to extract control register fields */ |
| +#define GET_BSTATUS_REG_MMU(Reg) \ |
| + (((Reg) >> BSTATUS_REG_MMU_LSB) & BSTATUS_REG_MMU_MASK) |
| +#define SET_BSTATUS_REG_MMU(Reg, Val) \ |
| + Reg = (((Reg) & (~(BSTATUS_REG_MMU_MASK << BSTATUS_REG_MMU_LSB))) | \ |
| + (((Val) & BSTATUS_REG_MMU_MASK) << BSTATUS_REG_MMU_LSB)) |
| +#define GET_BSTATUS_REG_NO_MMU(Reg) \ |
| + (((Reg) >> BSTATUS_REG_NO_MMU_LSB) & BSTATUS_REG_NO_MMU_MASK) |
| +#define SET_BSTATUS_REG_NO_MMU(Reg, Val) \ |
| + Reg = (((Reg) & (~(BSTATUS_REG_NO_MMU_MASK << BSTATUS_REG_NO_MMU_LSB))) | \ |
| + (((Val) & BSTATUS_REG_NO_MMU_MASK) << BSTATUS_REG_NO_MMU_LSB)) |
| +#define GET_ESTATUS_REG_MMU(Reg) \ |
| + (((Reg) >> ESTATUS_REG_MMU_LSB) & ESTATUS_REG_MMU_MASK) |
| +#define SET_ESTATUS_REG_MMU(Reg, Val) \ |
| + Reg = (((Reg) & (~(ESTATUS_REG_MMU_MASK << ESTATUS_REG_MMU_LSB))) | \ |
| + (((Val) & ESTATUS_REG_MMU_MASK) << ESTATUS_REG_MMU_LSB)) |
| +#define GET_ESTATUS_REG_NO_MMU(Reg) \ |
| + (((Reg) >> ESTATUS_REG_NO_MMU_LSB) & ESTATUS_REG_NO_MMU_MASK) |
| +#define SET_ESTATUS_REG_NO_MMU(Reg, Val) \ |
| + Reg = (((Reg) & (~(ESTATUS_REG_NO_MMU_MASK << ESTATUS_REG_NO_MMU_LSB))) | \ |
| + (((Val) & ESTATUS_REG_NO_MMU_MASK) << ESTATUS_REG_NO_MMU_LSB)) |
| +#define GET_EXCEPTION_REG_MEA(Reg) \ |
| + (((Reg) >> EXCEPTION_REG_MEA_LSB) & EXCEPTION_REG_MEA_MASK) |
| +#define SET_EXCEPTION_REG_MEA(Reg, Val) \ |
| + Reg = (((Reg) & (~(EXCEPTION_REG_MEA_MASK << EXCEPTION_REG_MEA_LSB))) | \ |
| + (((Val) & EXCEPTION_REG_MEA_MASK) << EXCEPTION_REG_MEA_LSB)) |
| +#define GET_EXCEPTION_REG_MEE(Reg) \ |
| + (((Reg) >> EXCEPTION_REG_MEE_LSB) & EXCEPTION_REG_MEE_MASK) |
| +#define SET_EXCEPTION_REG_MEE(Reg, Val) \ |
| + Reg = (((Reg) & (~(EXCEPTION_REG_MEE_MASK << EXCEPTION_REG_MEE_LSB))) | \ |
| + (((Val) & EXCEPTION_REG_MEE_MASK) << EXCEPTION_REG_MEE_LSB)) |
| +#define GET_PTEADDR_REG_PTBASE(Reg) \ |
| + (((Reg) >> PTEADDR_REG_PTBASE_LSB) & PTEADDR_REG_PTBASE_MASK) |
| +#define SET_PTEADDR_REG_PTBASE(Reg, Val) \ |
| + Reg = (((Reg) & (~(PTEADDR_REG_PTBASE_MASK << PTEADDR_REG_PTBASE_LSB))) | \ |
| + (((Val) & PTEADDR_REG_PTBASE_MASK) << PTEADDR_REG_PTBASE_LSB)) |
| +#define GET_PTEADDR_REG_RSV(Reg) \ |
| + (((Reg) >> PTEADDR_REG_RSV_LSB) & PTEADDR_REG_RSV_MASK) |
| +#define SET_PTEADDR_REG_RSV(Reg, Val) \ |
| + Reg = (((Reg) & (~(PTEADDR_REG_RSV_MASK << PTEADDR_REG_RSV_LSB))) | \ |
| + (((Val) & PTEADDR_REG_RSV_MASK) << PTEADDR_REG_RSV_LSB)) |
| +#define GET_PTEADDR_REG_VPN(Reg) \ |
| + (((Reg) >> PTEADDR_REG_VPN_LSB) & PTEADDR_REG_VPN_MASK) |
| +#define SET_PTEADDR_REG_VPN(Reg, Val) \ |
| + Reg = (((Reg) & (~(PTEADDR_REG_VPN_MASK << PTEADDR_REG_VPN_LSB))) | \ |
| + (((Val) & PTEADDR_REG_VPN_MASK) << PTEADDR_REG_VPN_LSB)) |
| +#define GET_SIM_REG_PERF_CNT_CLR(Reg) \ |
| + (((Reg) >> SIM_REG_PERF_CNT_CLR_LSB) & SIM_REG_PERF_CNT_CLR_MASK) |
| +#define SET_SIM_REG_PERF_CNT_CLR(Reg, Val) \ |
| + Reg = (((Reg) & (~(SIM_REG_PERF_CNT_CLR_MASK << SIM_REG_PERF_CNT_CLR_LSB))) | \ |
| + (((Val) & SIM_REG_PERF_CNT_CLR_MASK) << SIM_REG_PERF_CNT_CLR_LSB)) |
| +#define GET_SIM_REG_PERF_CNT_EN(Reg) \ |
| + (((Reg) >> SIM_REG_PERF_CNT_EN_LSB) & SIM_REG_PERF_CNT_EN_MASK) |
| +#define SET_SIM_REG_PERF_CNT_EN(Reg, Val) \ |
| + Reg = (((Reg) & (~(SIM_REG_PERF_CNT_EN_MASK << SIM_REG_PERF_CNT_EN_LSB))) | \ |
| + (((Val) & SIM_REG_PERF_CNT_EN_MASK) << SIM_REG_PERF_CNT_EN_LSB)) |
| +#define GET_SIM_REG_SHOW_DTLB(Reg) \ |
| + (((Reg) >> SIM_REG_SHOW_DTLB_LSB) & SIM_REG_SHOW_DTLB_MASK) |
| +#define SET_SIM_REG_SHOW_DTLB(Reg, Val) \ |
| + Reg = (((Reg) & (~(SIM_REG_SHOW_DTLB_MASK << SIM_REG_SHOW_DTLB_LSB))) | \ |
| + (((Val) & SIM_REG_SHOW_DTLB_MASK) << SIM_REG_SHOW_DTLB_LSB)) |
| +#define GET_SIM_REG_SHOW_ITLB(Reg) \ |
| + (((Reg) >> SIM_REG_SHOW_ITLB_LSB) & SIM_REG_SHOW_ITLB_MASK) |
| +#define SET_SIM_REG_SHOW_ITLB(Reg, Val) \ |
| + Reg = (((Reg) & (~(SIM_REG_SHOW_ITLB_MASK << SIM_REG_SHOW_ITLB_LSB))) | \ |
| + (((Val) & SIM_REG_SHOW_ITLB_MASK) << SIM_REG_SHOW_ITLB_LSB)) |
| +#define GET_SIM_REG_SHOW_MMU_REGS(Reg) \ |
| + (((Reg) >> SIM_REG_SHOW_MMU_REGS_LSB) & SIM_REG_SHOW_MMU_REGS_MASK) |
| +#define SET_SIM_REG_SHOW_MMU_REGS(Reg, Val) \ |
| + Reg = (((Reg) & (~(SIM_REG_SHOW_MMU_REGS_MASK << SIM_REG_SHOW_MMU_REGS_LSB))) | \ |
| + (((Val) & SIM_REG_SHOW_MMU_REGS_MASK) << SIM_REG_SHOW_MMU_REGS_LSB)) |
| +#define GET_SIM_REG_STOP(Reg) \ |
| + (((Reg) >> SIM_REG_STOP_LSB) & SIM_REG_STOP_MASK) |
| +#define SET_SIM_REG_STOP(Reg, Val) \ |
| + Reg = (((Reg) & (~(SIM_REG_STOP_MASK << SIM_REG_STOP_LSB))) | \ |
| + (((Val) & SIM_REG_STOP_MASK) << SIM_REG_STOP_LSB)) |
| +#define GET_STATUS_REG_EH(Reg) \ |
| + (((Reg) >> STATUS_REG_EH_LSB) & STATUS_REG_EH_MASK) |
| +#define SET_STATUS_REG_EH(Reg, Val) \ |
| + Reg = (((Reg) & (~(STATUS_REG_EH_MASK << STATUS_REG_EH_LSB))) | \ |
| + (((Val) & STATUS_REG_EH_MASK) << STATUS_REG_EH_LSB)) |
| +#define GET_STATUS_REG_MMU(Reg) \ |
| + (((Reg) >> STATUS_REG_MMU_LSB) & STATUS_REG_MMU_MASK) |
| +#define SET_STATUS_REG_MMU(Reg, Val) \ |
| + Reg = (((Reg) & (~(STATUS_REG_MMU_MASK << STATUS_REG_MMU_LSB))) | \ |
| + (((Val) & STATUS_REG_MMU_MASK) << STATUS_REG_MMU_LSB)) |
| +#define GET_STATUS_REG_MMU_RSV(Reg) \ |
| + (((Reg) >> STATUS_REG_MMU_RSV_LSB) & STATUS_REG_MMU_RSV_MASK) |
| +#define SET_STATUS_REG_MMU_RSV(Reg, Val) \ |
| + Reg = (((Reg) & (~(STATUS_REG_MMU_RSV_MASK << STATUS_REG_MMU_RSV_LSB))) | \ |
| + (((Val) & STATUS_REG_MMU_RSV_MASK) << STATUS_REG_MMU_RSV_LSB)) |
| +#define GET_STATUS_REG_NO_MMU(Reg) \ |
| + (((Reg) >> STATUS_REG_NO_MMU_LSB) & STATUS_REG_NO_MMU_MASK) |
| +#define SET_STATUS_REG_NO_MMU(Reg, Val) \ |
| + Reg = (((Reg) & (~(STATUS_REG_NO_MMU_MASK << STATUS_REG_NO_MMU_LSB))) | \ |
| + (((Val) & STATUS_REG_NO_MMU_MASK) << STATUS_REG_NO_MMU_LSB)) |
| +#define GET_STATUS_REG_NO_MMU_RSV(Reg) \ |
| + (((Reg) >> STATUS_REG_NO_MMU_RSV_LSB) & STATUS_REG_NO_MMU_RSV_MASK) |
| +#define SET_STATUS_REG_NO_MMU_RSV(Reg, Val) \ |
| + Reg = (((Reg) & (~(STATUS_REG_NO_MMU_RSV_MASK << STATUS_REG_NO_MMU_RSV_LSB))) | \ |
| + (((Val) & STATUS_REG_NO_MMU_RSV_MASK) << STATUS_REG_NO_MMU_RSV_LSB)) |
| +#define GET_STATUS_REG_PIE(Reg) \ |
| + (((Reg) >> STATUS_REG_PIE_LSB) & STATUS_REG_PIE_MASK) |
| +#define SET_STATUS_REG_PIE(Reg, Val) \ |
| + Reg = (((Reg) & (~(STATUS_REG_PIE_MASK << STATUS_REG_PIE_LSB))) | \ |
| + (((Val) & STATUS_REG_PIE_MASK) << STATUS_REG_PIE_LSB)) |
| +#define GET_STATUS_REG_U(Reg) \ |
| + (((Reg) >> STATUS_REG_U_LSB) & STATUS_REG_U_MASK) |
| +#define SET_STATUS_REG_U(Reg, Val) \ |
| + Reg = (((Reg) & (~(STATUS_REG_U_MASK << STATUS_REG_U_LSB))) | \ |
| + (((Val) & STATUS_REG_U_MASK) << STATUS_REG_U_LSB)) |
| +#define GET_TLBACC_REG_C(Reg) \ |
| + (((Reg) >> TLBACC_REG_C_LSB) & TLBACC_REG_C_MASK) |
| +#define SET_TLBACC_REG_C(Reg, Val) \ |
| + Reg = (((Reg) & (~(TLBACC_REG_C_MASK << TLBACC_REG_C_LSB))) | \ |
| + (((Val) & TLBACC_REG_C_MASK) << TLBACC_REG_C_LSB)) |
| +#define GET_TLBACC_REG_G(Reg) \ |
| + (((Reg) >> TLBACC_REG_G_LSB) & TLBACC_REG_G_MASK) |
| +#define SET_TLBACC_REG_G(Reg, Val) \ |
| + Reg = (((Reg) & (~(TLBACC_REG_G_MASK << TLBACC_REG_G_LSB))) | \ |
| + (((Val) & TLBACC_REG_G_MASK) << TLBACC_REG_G_LSB)) |
| +#define GET_TLBACC_REG_IG(Reg) \ |
| + (((Reg) >> TLBACC_REG_IG_LSB) & TLBACC_REG_IG_MASK) |
| +#define SET_TLBACC_REG_IG(Reg, Val) \ |
| + Reg = (((Reg) & (~(TLBACC_REG_IG_MASK << TLBACC_REG_IG_LSB))) | \ |
| + (((Val) & TLBACC_REG_IG_MASK) << TLBACC_REG_IG_LSB)) |
| +#define GET_TLBACC_REG_PFN(Reg) \ |
| + (((Reg) >> TLBACC_REG_PFN_LSB) & TLBACC_REG_PFN_MASK) |
| +#define SET_TLBACC_REG_PFN(Reg, Val) \ |
| + Reg = (((Reg) & (~(TLBACC_REG_PFN_MASK << TLBACC_REG_PFN_LSB))) | \ |
| + (((Val) & TLBACC_REG_PFN_MASK) << TLBACC_REG_PFN_LSB)) |
| +#define GET_TLBACC_REG_R(Reg) \ |
| + (((Reg) >> TLBACC_REG_R_LSB) & TLBACC_REG_R_MASK) |
| +#define SET_TLBACC_REG_R(Reg, Val) \ |
| + Reg = (((Reg) & (~(TLBACC_REG_R_MASK << TLBACC_REG_R_LSB))) | \ |
| + (((Val) & TLBACC_REG_R_MASK) << TLBACC_REG_R_LSB)) |
| +#define GET_TLBACC_REG_W(Reg) \ |
| + (((Reg) >> TLBACC_REG_W_LSB) & TLBACC_REG_W_MASK) |
| +#define SET_TLBACC_REG_W(Reg, Val) \ |
| + Reg = (((Reg) & (~(TLBACC_REG_W_MASK << TLBACC_REG_W_LSB))) | \ |
| + (((Val) & TLBACC_REG_W_MASK) << TLBACC_REG_W_LSB)) |
| +#define GET_TLBACC_REG_X(Reg) \ |
| + (((Reg) >> TLBACC_REG_X_LSB) & TLBACC_REG_X_MASK) |
| +#define SET_TLBACC_REG_X(Reg, Val) \ |
| + Reg = (((Reg) & (~(TLBACC_REG_X_MASK << TLBACC_REG_X_LSB))) | \ |
| + (((Val) & TLBACC_REG_X_MASK) << TLBACC_REG_X_LSB)) |
| +#define GET_TLBMISC_REG_BAD(Reg) \ |
| + (((Reg) >> TLBMISC_REG_BAD_LSB) & TLBMISC_REG_BAD_MASK) |
| +#define SET_TLBMISC_REG_BAD(Reg, Val) \ |
| + Reg = (((Reg) & (~(TLBMISC_REG_BAD_MASK << TLBMISC_REG_BAD_LSB))) | \ |
| + (((Val) & TLBMISC_REG_BAD_MASK) << TLBMISC_REG_BAD_LSB)) |
| +#define GET_TLBMISC_REG_D(Reg) \ |
| + (((Reg) >> TLBMISC_REG_D_LSB) & TLBMISC_REG_D_MASK) |
| +#define SET_TLBMISC_REG_D(Reg, Val) \ |
| + Reg = (((Reg) & (~(TLBMISC_REG_D_MASK << TLBMISC_REG_D_LSB))) | \ |
| + (((Val) & TLBMISC_REG_D_MASK) << TLBMISC_REG_D_LSB)) |
| +#define GET_TLBMISC_REG_DBL(Reg) \ |
| + (((Reg) >> TLBMISC_REG_DBL_LSB) & TLBMISC_REG_DBL_MASK) |
| +#define SET_TLBMISC_REG_DBL(Reg, Val) \ |
| + Reg = (((Reg) & (~(TLBMISC_REG_DBL_MASK << TLBMISC_REG_DBL_LSB))) | \ |
| + (((Val) & TLBMISC_REG_DBL_MASK) << TLBMISC_REG_DBL_LSB)) |
| +#define GET_TLBMISC_REG_PERM(Reg) \ |
| + (((Reg) >> TLBMISC_REG_PERM_LSB) & TLBMISC_REG_PERM_MASK) |
| +#define SET_TLBMISC_REG_PERM(Reg, Val) \ |
| + Reg = (((Reg) & (~(TLBMISC_REG_PERM_MASK << TLBMISC_REG_PERM_LSB))) | \ |
| + (((Val) & TLBMISC_REG_PERM_MASK) << TLBMISC_REG_PERM_LSB)) |
| +#define GET_TLBMISC_REG_PID(Reg) \ |
| + (((Reg) >> TLBMISC_REG_PID_LSB) & TLBMISC_REG_PID_MASK) |
| +#define SET_TLBMISC_REG_PID(Reg, Val) \ |
| + Reg = (((Reg) & (~(TLBMISC_REG_PID_MASK << TLBMISC_REG_PID_LSB))) | \ |
| + (((Val) & TLBMISC_REG_PID_MASK) << TLBMISC_REG_PID_LSB)) |
| +#define GET_TLBMISC_REG_RD(Reg) \ |
| + (((Reg) >> TLBMISC_REG_RD_LSB) & TLBMISC_REG_RD_MASK) |
| +#define SET_TLBMISC_REG_RD(Reg, Val) \ |
| + Reg = (((Reg) & (~(TLBMISC_REG_RD_MASK << TLBMISC_REG_RD_LSB))) | \ |
| + (((Val) & TLBMISC_REG_RD_MASK) << TLBMISC_REG_RD_LSB)) |
| +#define GET_TLBMISC_REG_RSV0(Reg) \ |
| + (((Reg) >> TLBMISC_REG_RSV0_LSB) & TLBMISC_REG_RSV0_MASK) |
| +#define SET_TLBMISC_REG_RSV0(Reg, Val) \ |
| + Reg = (((Reg) & (~(TLBMISC_REG_RSV0_MASK << TLBMISC_REG_RSV0_LSB))) | \ |
| + (((Val) & TLBMISC_REG_RSV0_MASK) << TLBMISC_REG_RSV0_LSB)) |
| +#define GET_TLBMISC_REG_RSV1(Reg) \ |
| + (((Reg) >> TLBMISC_REG_RSV1_LSB) & TLBMISC_REG_RSV1_MASK) |
| +#define SET_TLBMISC_REG_RSV1(Reg, Val) \ |
| + Reg = (((Reg) & (~(TLBMISC_REG_RSV1_MASK << TLBMISC_REG_RSV1_LSB))) | \ |
| + (((Val) & TLBMISC_REG_RSV1_MASK) << TLBMISC_REG_RSV1_LSB)) |
| +#define GET_TLBMISC_REG_WAY(Reg) \ |
| + (((Reg) >> TLBMISC_REG_WAY_LSB) & TLBMISC_REG_WAY_MASK) |
| +#define SET_TLBMISC_REG_WAY(Reg, Val) \ |
| + Reg = (((Reg) & (~(TLBMISC_REG_WAY_MASK << TLBMISC_REG_WAY_LSB))) | \ |
| + (((Val) & TLBMISC_REG_WAY_MASK) << TLBMISC_REG_WAY_LSB)) |
| +#define GET_TLBMISC_REG_WE(Reg) \ |
| + (((Reg) >> TLBMISC_REG_WE_LSB) & TLBMISC_REG_WE_MASK) |
| +#define SET_TLBMISC_REG_WE(Reg, Val) \ |
| + Reg = (((Reg) & (~(TLBMISC_REG_WE_MASK << TLBMISC_REG_WE_LSB))) | \ |
| + (((Val) & TLBMISC_REG_WE_MASK) << TLBMISC_REG_WE_LSB)) |
| + |
| +/* Macros to extract MMU fields */ |
| +#define GET_MMU_ADDR_BYPASS_TLB_CACHEABLE(Addr) \ |
| + (((Addr) >> MMU_ADDR_BYPASS_TLB_CACHEABLE_LSB) & MMU_ADDR_BYPASS_TLB_CACHEABLE_MASK) |
| +#define SET_MMU_ADDR_BYPASS_TLB_CACHEABLE(Addr, Val) \ |
| + Addr = (((Addr) & (~(MMU_ADDR_BYPASS_TLB_CACHEABLE_MASK << MMU_ADDR_BYPASS_TLB_CACHEABLE_LSB))) | \ |
| + (((Val) & MMU_ADDR_BYPASS_TLB_CACHEABLE_MASK) << MMU_ADDR_BYPASS_TLB_CACHEABLE_LSB)) |
| +#define GET_MMU_ADDR_BYPASS_TLB(Addr) \ |
| + (((Addr) >> MMU_ADDR_BYPASS_TLB_LSB) & MMU_ADDR_BYPASS_TLB_MASK) |
| +#define SET_MMU_ADDR_BYPASS_TLB(Addr, Val) \ |
| + Addr = (((Addr) & (~(MMU_ADDR_BYPASS_TLB_MASK << MMU_ADDR_BYPASS_TLB_LSB))) | \ |
| + (((Val) & MMU_ADDR_BYPASS_TLB_MASK) << MMU_ADDR_BYPASS_TLB_LSB)) |
| +#define GET_MMU_ADDR_BYPASS_TLB_PADDR(Addr) \ |
| + (((Addr) >> MMU_ADDR_BYPASS_TLB_PADDR_LSB) & MMU_ADDR_BYPASS_TLB_PADDR_MASK) |
| +#define SET_MMU_ADDR_BYPASS_TLB_PADDR(Addr, Val) \ |
| + Addr = (((Addr) & (~(MMU_ADDR_BYPASS_TLB_PADDR_MASK << MMU_ADDR_BYPASS_TLB_PADDR_LSB))) | \ |
| + (((Val) & MMU_ADDR_BYPASS_TLB_PADDR_MASK) << MMU_ADDR_BYPASS_TLB_PADDR_LSB)) |
| +#define GET_MMU_ADDR_IO_REGION(Addr) \ |
| + (((Addr) >> MMU_ADDR_IO_REGION_LSB) & MMU_ADDR_IO_REGION_MASK) |
| +#define SET_MMU_ADDR_IO_REGION(Addr, Val) \ |
| + Addr = (((Addr) & (~(MMU_ADDR_IO_REGION_MASK << MMU_ADDR_IO_REGION_LSB))) | \ |
| + (((Val) & MMU_ADDR_IO_REGION_MASK) << MMU_ADDR_IO_REGION_LSB)) |
| +#define GET_MMU_ADDR_KERNEL_MMU_REGION(Addr) \ |
| + (((Addr) >> MMU_ADDR_KERNEL_MMU_REGION_LSB) & MMU_ADDR_KERNEL_MMU_REGION_MASK) |
| +#define SET_MMU_ADDR_KERNEL_MMU_REGION(Addr, Val) \ |
| + Addr = (((Addr) & (~(MMU_ADDR_KERNEL_MMU_REGION_MASK << MMU_ADDR_KERNEL_MMU_REGION_LSB))) | \ |
| + (((Val) & MMU_ADDR_KERNEL_MMU_REGION_MASK) << MMU_ADDR_KERNEL_MMU_REGION_LSB)) |
| +#define GET_MMU_ADDR_KERNEL_REGION(Addr) \ |
| + (((Addr) >> MMU_ADDR_KERNEL_REGION_LSB) & MMU_ADDR_KERNEL_REGION_MASK) |
| +#define SET_MMU_ADDR_KERNEL_REGION(Addr, Val) \ |
| + Addr = (((Addr) & (~(MMU_ADDR_KERNEL_REGION_MASK << MMU_ADDR_KERNEL_REGION_LSB))) | \ |
| + (((Val) & MMU_ADDR_KERNEL_REGION_MASK) << MMU_ADDR_KERNEL_REGION_LSB)) |
| +#define GET_MMU_ADDR_PAGE_OFFSET(Addr) \ |
| + (((Addr) >> MMU_ADDR_PAGE_OFFSET_LSB) & MMU_ADDR_PAGE_OFFSET_MASK) |
| +#define SET_MMU_ADDR_PAGE_OFFSET(Addr, Val) \ |
| + Addr = (((Addr) & (~(MMU_ADDR_PAGE_OFFSET_MASK << MMU_ADDR_PAGE_OFFSET_LSB))) | \ |
| + (((Val) & MMU_ADDR_PAGE_OFFSET_MASK) << MMU_ADDR_PAGE_OFFSET_LSB)) |
| +#define GET_MMU_ADDR_PFN(Addr) \ |
| + (((Addr) >> MMU_ADDR_PFN_LSB) & MMU_ADDR_PFN_MASK) |
| +#define SET_MMU_ADDR_PFN(Addr, Val) \ |
| + Addr = (((Addr) & (~(MMU_ADDR_PFN_MASK << MMU_ADDR_PFN_LSB))) | \ |
| + (((Val) & MMU_ADDR_PFN_MASK) << MMU_ADDR_PFN_LSB)) |
| +#define GET_MMU_ADDR_USER_REGION(Addr) \ |
| + (((Addr) >> MMU_ADDR_USER_REGION_LSB) & MMU_ADDR_USER_REGION_MASK) |
| +#define SET_MMU_ADDR_USER_REGION(Addr, Val) \ |
| + Addr = (((Addr) & (~(MMU_ADDR_USER_REGION_MASK << MMU_ADDR_USER_REGION_LSB))) | \ |
| + (((Val) & MMU_ADDR_USER_REGION_MASK) << MMU_ADDR_USER_REGION_LSB)) |
| +#define GET_MMU_ADDR_VPN(Addr) \ |
| + (((Addr) >> MMU_ADDR_VPN_LSB) & MMU_ADDR_VPN_MASK) |
| +#define SET_MMU_ADDR_VPN(Addr, Val) \ |
| + Addr = (((Addr) & (~(MMU_ADDR_VPN_MASK << MMU_ADDR_VPN_LSB))) | \ |
| + (((Val) & MMU_ADDR_VPN_MASK) << MMU_ADDR_VPN_LSB)) |
| + |
| +/* OP instruction values */ |
| +#define OP_ADDI 4 |
| +#define OP_ANDHI 44 |
| +#define OP_ANDI 12 |
| +#define OP_BEQ 38 |
| +#define OP_BGE 14 |
| +#define OP_BGEU 46 |
| +#define OP_BLT 22 |
| +#define OP_BLTU 54 |
| +#define OP_BNE 30 |
| +#define OP_BR 6 |
| +#define OP_CALL 0 |
| +#define OP_CMPEQI 32 |
| +#define OP_CMPGEI 8 |
| +#define OP_CMPGEUI 40 |
| +#define OP_CMPLTI 16 |
| +#define OP_CMPLTUI 48 |
| +#define OP_CMPNEI 24 |
| +#define OP_CUSTOM 50 |
| +#define OP_FLUSHD 59 |
| +#define OP_FLUSHDA 27 |
| +#define OP_INITD 51 |
| +#define OP_JMPI 1 |
| +#define OP_LDB 7 |
| +#define OP_LDBIO 39 |
| +#define OP_LDBU 3 |
| +#define OP_LDBUIO 35 |
| +#define OP_LDH 15 |
| +#define OP_LDHIO 47 |
| +#define OP_LDHU 11 |
| +#define OP_LDHUIO 43 |
| +#define OP_LDW 23 |
| +#define OP_LDWIO 55 |
| +#define OP_MULI 36 |
| +#define OP_OPX 58 |
| +#define OP_ORHI 52 |
| +#define OP_ORI 20 |
| +#define OP_STB 5 |
| +#define OP_STBIO 37 |
| +#define OP_STH 13 |
| +#define OP_STHIO 45 |
| +#define OP_STW 21 |
| +#define OP_STWIO 53 |
| +#define OP_XORHI 60 |
| +#define OP_XORI 28 |
| + |
| +/* OPX instruction values */ |
| +#define OPX_ADD 49 |
| +#define OPX_AND 14 |
| +#define OPX_BREAK 52 |
| +#define OPX_BRET 9 |
| +#define OPX_CALLR 29 |
| +#define OPX_CMPEQ 32 |
| +#define OPX_CMPGE 8 |
| +#define OPX_CMPGEU 40 |
| +#define OPX_CMPLT 16 |
| +#define OPX_CMPLTU 48 |
| +#define OPX_CMPNE 24 |
| +#define OPX_CRST 62 |
| +#define OPX_DIV 37 |
| +#define OPX_DIVU 36 |
| +#define OPX_ERET 1 |
| +#define OPX_FLUSHI 12 |
| +#define OPX_FLUSHP 4 |
| +#define OPX_HBREAK 53 |
| +#define OPX_INITI 41 |
| +#define OPX_INTR 61 |
| +#define OPX_JMP 13 |
| +#define OPX_MUL 39 |
| +#define OPX_MULXSS 31 |
| +#define OPX_MULXSU 23 |
| +#define OPX_MULXUU 7 |
| +#define OPX_NEXTPC 28 |
| +#define OPX_NOR 6 |
| +#define OPX_OR 22 |
| +#define OPX_RDCTL 38 |
| +#define OPX_RET 5 |
| +#define OPX_ROL 3 |
| +#define OPX_ROLI 2 |
| +#define OPX_ROR 11 |
| +#define OPX_SLL 19 |
| +#define OPX_SLLI 18 |
| +#define OPX_SRA 59 |
| +#define OPX_SRAI 58 |
| +#define OPX_SRL 27 |
| +#define OPX_SRLI 26 |
| +#define OPX_SUB 57 |
| +#define OPX_SYNC 54 |
| +#define OPX_TRAP 45 |
| +#define OPX_WRCTL 46 |
| +#define OPX_XOR 30 |
| + |
| +/* Macros to detect sub-opcode instructions */ |
| +#define IS_OPX_INST(Iw) (GET_IW_OP(Iw) == OP_OPX) |
| +#define IS_CUSTOM_INST(Iw) (GET_IW_OP(Iw) == OP_CUSTOM) |
| + |
| +/* Instruction property macros */ |
| +#define IW_PROP_RESERVED_OP(Iw) (0) |
| + |
| +#define IW_PROP_RESERVED_OPX(Iw) (0) |
| + |
| +#define IW_PROP_RESERVED(Iw) (0) |
| + |
| +#define IW_PROP_SUPERVISOR_ONLY(Iw) ( \ |
| + (op_prop_supervisor_only[GET_IW_OP(Iw)] || \ |
| + (IS_OPX_INST(Iw) && opx_prop_supervisor_only[GET_IW_OPX(Iw)]))) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char op_prop_supervisor_only[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char opx_prop_supervisor_only[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_INITI_FLUSHI(Iw) ( \ |
| + ( \ |
| + ((GET_IW_OPX((Iw)) == OPX_INITI) && IS_OPX_INST(Iw)) || \ |
| + ((GET_IW_OPX((Iw)) == OPX_FLUSHI) && IS_OPX_INST(Iw)) \ |
| + ) \ |
| + \ |
| +) |
| + |
| +#define IW_PROP_FLUSH_PIPE(Iw) ( \ |
| + (IS_OPX_INST(Iw) && opx_prop_flush_pipe[GET_IW_OPX(Iw)])) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char opx_prop_flush_pipe[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_JMP_INDIRECT_NON_TRAP(Iw) ( \ |
| + (IS_OPX_INST(Iw) && opx_prop_jmp_indirect_non_trap[GET_IW_OPX(Iw)])) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char opx_prop_jmp_indirect_non_trap[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_JMP_INDIRECT(Iw) ( \ |
| + (IS_OPX_INST(Iw) && opx_prop_jmp_indirect[GET_IW_OPX(Iw)])) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char opx_prop_jmp_indirect[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_JMP_DIRECT(Iw) ( \ |
| + ( \ |
| + ((GET_IW_OP((Iw)) == OP_CALL)) || \ |
| + ((GET_IW_OP((Iw)) == OP_JMPI)) \ |
| + ) \ |
| + \ |
| +) |
| + |
| +#define IW_PROP_MUL_LSW(Iw) ( \ |
| + ( \ |
| + ((GET_IW_OP((Iw)) == OP_MULI)) || \ |
| + ((GET_IW_OPX((Iw)) == OPX_MUL) && IS_OPX_INST(Iw)) \ |
| + ) \ |
| + \ |
| +) |
| + |
| +#define IW_PROP_MULX(Iw) ( \ |
| + (IS_OPX_INST(Iw) && opx_prop_mulx[GET_IW_OPX(Iw)])) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char opx_prop_mulx[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_MUL(Iw) ( \ |
| + (op_prop_mul[GET_IW_OP(Iw)] || \ |
| + (IS_OPX_INST(Iw) && opx_prop_mul[GET_IW_OPX(Iw)]))) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char op_prop_mul[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char opx_prop_mul[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_DIV_UNSIGNED(Iw) ( \ |
| + ( \ |
| + ((GET_IW_OPX((Iw)) == OPX_DIVU) && IS_OPX_INST(Iw)) \ |
| + ) \ |
| + \ |
| +) |
| + |
| +#define IW_PROP_DIV_SIGNED(Iw) ( \ |
| + ( \ |
| + ((GET_IW_OPX((Iw)) == OPX_DIV) && IS_OPX_INST(Iw)) \ |
| + ) \ |
| + \ |
| +) |
| + |
| +#define IW_PROP_DIV(Iw) ( \ |
| + ( \ |
| + ((GET_IW_OPX((Iw)) == OPX_DIVU) && IS_OPX_INST(Iw)) || \ |
| + ((GET_IW_OPX((Iw)) == OPX_DIV) && IS_OPX_INST(Iw)) \ |
| + ) \ |
| + \ |
| +) |
| + |
| +#define IW_PROP_UNIMPLEMENTED(Iw) (0) |
| + |
| +#define IW_PROP_IMPLICIT_DST_RETADDR(Iw) ( \ |
| + ( \ |
| + ((GET_IW_OP((Iw)) == OP_CALL)) \ |
| + ) \ |
| + \ |
| +) |
| + |
| +#define IW_PROP_IMPLICIT_DST_ERETADDR(Iw) (0) |
| + |
| +#define IW_PROP_EXCEPTION(Iw) ( \ |
| + ( \ |
| + ((GET_IW_OPX((Iw)) == OPX_TRAP) && IS_OPX_INST(Iw)) || \ |
| + ((GET_IW_OPX((Iw)) == OPX_INTR) && IS_OPX_INST(Iw)) \ |
| + ) \ |
| + \ |
| +) |
| + |
| +#define IW_PROP_BREAK(Iw) ( \ |
| + ( \ |
| + ((GET_IW_OPX((Iw)) == OPX_BREAK) && IS_OPX_INST(Iw)) || \ |
| + ((GET_IW_OPX((Iw)) == OPX_HBREAK) && IS_OPX_INST(Iw)) \ |
| + ) \ |
| + \ |
| +) |
| + |
| +#define IW_PROP_CRST(Iw) ( \ |
| + ( \ |
| + ((GET_IW_OPX((Iw)) == OPX_CRST) && IS_OPX_INST(Iw)) \ |
| + ) \ |
| + \ |
| +) |
| + |
| +#define IW_PROP_WR_CTL_REG(Iw) ( \ |
| + (IS_OPX_INST(Iw) && opx_prop_wr_ctl_reg[GET_IW_OPX(Iw)])) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char opx_prop_wr_ctl_reg[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_UNCOND_CTI_NON_BR(Iw) ( \ |
| + (op_prop_uncond_cti_non_br[GET_IW_OP(Iw)] || \ |
| + (IS_OPX_INST(Iw) && opx_prop_uncond_cti_non_br[GET_IW_OPX(Iw)]))) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char op_prop_uncond_cti_non_br[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char opx_prop_uncond_cti_non_br[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_RETADDR(Iw) ( \ |
| + (op_prop_retaddr[GET_IW_OP(Iw)] || \ |
| + (IS_OPX_INST(Iw) && opx_prop_retaddr[GET_IW_OPX(Iw)]))) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char op_prop_retaddr[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char opx_prop_retaddr[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_SHIFT_LEFT(Iw) ( \ |
| + ( \ |
| + ((GET_IW_OPX((Iw)) == OPX_SLLI) && IS_OPX_INST(Iw)) || \ |
| + ((GET_IW_OPX((Iw)) == OPX_SLL) && IS_OPX_INST(Iw)) \ |
| + ) \ |
| + \ |
| +) |
| + |
| +#define IW_PROP_SHIFT_LOGICAL(Iw) ( \ |
| + (IS_OPX_INST(Iw) && opx_prop_shift_logical[GET_IW_OPX(Iw)])) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char opx_prop_shift_logical[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_ROT_LEFT(Iw) ( \ |
| + ( \ |
| + ((GET_IW_OPX((Iw)) == OPX_ROLI) && IS_OPX_INST(Iw)) || \ |
| + ((GET_IW_OPX((Iw)) == OPX_ROL) && IS_OPX_INST(Iw)) \ |
| + ) \ |
| + \ |
| +) |
| + |
| +#define IW_PROP_SHIFT_ROT_LEFT(Iw) ( \ |
| + (IS_OPX_INST(Iw) && opx_prop_shift_rot_left[GET_IW_OPX(Iw)])) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char opx_prop_shift_rot_left[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_SHIFT_RIGHT_LOGICAL(Iw) ( \ |
| + ( \ |
| + ((GET_IW_OPX((Iw)) == OPX_SRLI) && IS_OPX_INST(Iw)) || \ |
| + ((GET_IW_OPX((Iw)) == OPX_SRL) && IS_OPX_INST(Iw)) \ |
| + ) \ |
| + \ |
| +) |
| + |
| +#define IW_PROP_SHIFT_RIGHT_ARITH(Iw) ( \ |
| + ( \ |
| + ((GET_IW_OPX((Iw)) == OPX_SRAI) && IS_OPX_INST(Iw)) || \ |
| + ((GET_IW_OPX((Iw)) == OPX_SRA) && IS_OPX_INST(Iw)) \ |
| + ) \ |
| + \ |
| +) |
| + |
| +#define IW_PROP_SHIFT_RIGHT(Iw) ( \ |
| + (IS_OPX_INST(Iw) && opx_prop_shift_right[GET_IW_OPX(Iw)])) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char opx_prop_shift_right[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_ROT_RIGHT(Iw) ( \ |
| + ( \ |
| + ((GET_IW_OPX((Iw)) == OPX_ROR) && IS_OPX_INST(Iw)) \ |
| + ) \ |
| + \ |
| +) |
| + |
| +#define IW_PROP_SHIFT_ROT_RIGHT(Iw) ( \ |
| + (IS_OPX_INST(Iw) && opx_prop_shift_rot_right[GET_IW_OPX(Iw)])) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char opx_prop_shift_rot_right[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_SHIFT_ROT(Iw) ( \ |
| + (IS_OPX_INST(Iw) && opx_prop_shift_rot[GET_IW_OPX(Iw)])) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char opx_prop_shift_rot[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_SHIFT_ROT_IMM(Iw) ( \ |
| + (IS_OPX_INST(Iw) && opx_prop_shift_rot_imm[GET_IW_OPX(Iw)])) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char opx_prop_shift_rot_imm[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_ROTATE(Iw) ( \ |
| + (IS_OPX_INST(Iw) && opx_prop_rotate[GET_IW_OPX(Iw)])) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char opx_prop_rotate[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_LOGIC_REG(Iw) ( \ |
| + (IS_OPX_INST(Iw) && opx_prop_logic_reg[GET_IW_OPX(Iw)])) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char opx_prop_logic_reg[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_LOGIC_HI_IMM16(Iw) ( \ |
| + (op_prop_logic_hi_imm16[GET_IW_OP(Iw)])) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char op_prop_logic_hi_imm16[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_LOGIC_LO_IMM16(Iw) ( \ |
| + (op_prop_logic_lo_imm16[GET_IW_OP(Iw)])) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char op_prop_logic_lo_imm16[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_LOGIC_IMM16(Iw) ( \ |
| + (op_prop_logic_imm16[GET_IW_OP(Iw)])) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char op_prop_logic_imm16[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_LOGIC(Iw) ( \ |
| + (op_prop_logic[GET_IW_OP(Iw)] || \ |
| + (IS_OPX_INST(Iw) && opx_prop_logic[GET_IW_OPX(Iw)]))) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char op_prop_logic[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char opx_prop_logic[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_UNSIGNED_LO_IMM16(Iw) ( \ |
| + (op_prop_unsigned_lo_imm16[GET_IW_OP(Iw)] || \ |
| + (IS_OPX_INST(Iw) && opx_prop_unsigned_lo_imm16[GET_IW_OPX(Iw)]))) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char op_prop_unsigned_lo_imm16[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char opx_prop_unsigned_lo_imm16[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_ARITH_IMM16(Iw) ( \ |
| + ( \ |
| + ((GET_IW_OP((Iw)) == OP_ADDI)) || \ |
| + ((GET_IW_OP((Iw)) == OP_MULI)) \ |
| + ) \ |
| + \ |
| +) |
| + |
| +#define IW_PROP_CMP_IMM16(Iw) ( \ |
| + (op_prop_cmp_imm16[GET_IW_OP(Iw)])) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char op_prop_cmp_imm16[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_JMPI(Iw) ( \ |
| + ( \ |
| + ((GET_IW_OP((Iw)) == OP_JMPI)) \ |
| + ) \ |
| + \ |
| +) |
| + |
| +#define IW_PROP_CMP_IMM16_WITH_CALL_JMPI(Iw) ( \ |
| + (op_prop_cmp_imm16_with_call_jmpi[GET_IW_OP(Iw)])) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char op_prop_cmp_imm16_with_call_jmpi[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_CMP_REG(Iw) ( \ |
| + (IS_OPX_INST(Iw) && opx_prop_cmp_reg[GET_IW_OPX(Iw)])) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char opx_prop_cmp_reg[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_SRC_IMM5(Iw) ( \ |
| + (IS_OPX_INST(Iw) && opx_prop_src_imm5[GET_IW_OPX(Iw)])) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char opx_prop_src_imm5[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_CMP_WITH_LT(Iw) ( \ |
| + (op_prop_cmp_with_lt[GET_IW_OP(Iw)] || \ |
| + (IS_OPX_INST(Iw) && opx_prop_cmp_with_lt[GET_IW_OPX(Iw)]))) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char op_prop_cmp_with_lt[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char opx_prop_cmp_with_lt[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_CMP_WITH_EQ(Iw) ( \ |
| + (op_prop_cmp_with_eq[GET_IW_OP(Iw)] || \ |
| + (IS_OPX_INST(Iw) && opx_prop_cmp_with_eq[GET_IW_OPX(Iw)]))) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char op_prop_cmp_with_eq[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char opx_prop_cmp_with_eq[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_CMP_WITH_GE(Iw) ( \ |
| + (op_prop_cmp_with_ge[GET_IW_OP(Iw)] || \ |
| + (IS_OPX_INST(Iw) && opx_prop_cmp_with_ge[GET_IW_OPX(Iw)]))) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char op_prop_cmp_with_ge[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char opx_prop_cmp_with_ge[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_CMP_WITH_NE(Iw) ( \ |
| + ( \ |
| + ((GET_IW_OP((Iw)) == OP_CMPNEI)) || \ |
| + ((GET_IW_OPX((Iw)) == OPX_CMPNE) && IS_OPX_INST(Iw)) \ |
| + ) \ |
| + \ |
| +) |
| + |
| +#define IW_PROP_CMP_ALU_SIGNED(Iw) ( \ |
| + (op_prop_cmp_alu_signed[GET_IW_OP(Iw)] || \ |
| + (IS_OPX_INST(Iw) && opx_prop_cmp_alu_signed[GET_IW_OPX(Iw)]))) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char op_prop_cmp_alu_signed[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char opx_prop_cmp_alu_signed[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_CMP(Iw) ( \ |
| + (op_prop_cmp[GET_IW_OP(Iw)] || \ |
| + (IS_OPX_INST(Iw) && opx_prop_cmp[GET_IW_OPX(Iw)]))) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char op_prop_cmp[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char opx_prop_cmp[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_BR_WITH_LT(Iw) ( \ |
| + ( \ |
| + ((GET_IW_OP((Iw)) == OP_BLT)) || \ |
| + ((GET_IW_OP((Iw)) == OP_BLTU)) \ |
| + ) \ |
| + \ |
| +) |
| + |
| +#define IW_PROP_BR_WITH_GE(Iw) ( \ |
| + ( \ |
| + ((GET_IW_OP((Iw)) == OP_BGE)) || \ |
| + ((GET_IW_OP((Iw)) == OP_BGEU)) \ |
| + ) \ |
| + \ |
| +) |
| + |
| +#define IW_PROP_BR_WITH_EQ(Iw) ( \ |
| + (op_prop_br_with_eq[GET_IW_OP(Iw)])) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char op_prop_br_with_eq[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_BR_WITH_NE(Iw) ( \ |
| + ( \ |
| + ((GET_IW_OP((Iw)) == OP_BNE)) \ |
| + ) \ |
| + \ |
| +) |
| + |
| +#define IW_PROP_BR_ALU_SIGNED(Iw) ( \ |
| + ( \ |
| + ((GET_IW_OP((Iw)) == OP_BGE)) || \ |
| + ((GET_IW_OP((Iw)) == OP_BLT)) \ |
| + ) \ |
| + \ |
| +) |
| + |
| +#define IW_PROP_BR_COND(Iw) ( \ |
| + (op_prop_br_cond[GET_IW_OP(Iw)])) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char op_prop_br_cond[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_BR_UNCOND(Iw) ( \ |
| + ( \ |
| + ((GET_IW_OP((Iw)) == OP_BR)) \ |
| + ) \ |
| + \ |
| +) |
| + |
| +#define IW_PROP_BR(Iw) ( \ |
| + (op_prop_br[GET_IW_OP(Iw)])) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char op_prop_br[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_ALU_SUB(Iw) ( \ |
| + (op_prop_alu_sub[GET_IW_OP(Iw)] || \ |
| + (IS_OPX_INST(Iw) && opx_prop_alu_sub[GET_IW_OPX(Iw)]))) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char op_prop_alu_sub[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char opx_prop_alu_sub[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_FORCE_XOR(Iw) ( \ |
| + (op_prop_force_xor[GET_IW_OP(Iw)] || \ |
| + (IS_OPX_INST(Iw) && opx_prop_force_xor[GET_IW_OPX(Iw)]))) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char op_prop_force_xor[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char opx_prop_force_xor[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_LOAD8(Iw) ( \ |
| + (op_prop_load8[GET_IW_OP(Iw)])) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char op_prop_load8[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_LOAD16(Iw) ( \ |
| + (op_prop_load16[GET_IW_OP(Iw)])) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char op_prop_load16[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_LOAD32(Iw) ( \ |
| + ( \ |
| + ((GET_IW_OP((Iw)) == OP_LDW)) || \ |
| + ((GET_IW_OP((Iw)) == OP_LDWIO)) \ |
| + ) \ |
| + \ |
| +) |
| + |
| +#define IW_PROP_LOAD_SIGNED(Iw) ( \ |
| + (op_prop_load_signed[GET_IW_OP(Iw)])) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char op_prop_load_signed[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_LOAD_UNSIGNED(Iw) ( \ |
| + (op_prop_load_unsigned[GET_IW_OP(Iw)])) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char op_prop_load_unsigned[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_LOAD(Iw) ( \ |
| + (op_prop_load[GET_IW_OP(Iw)])) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char op_prop_load[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_LOAD_INITD_FLUSHD_FLUSHDA(Iw) ( \ |
| + (op_prop_load_initd_flushd_flushda[GET_IW_OP(Iw)])) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char op_prop_load_initd_flushd_flushda[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_LOAD_NON_IO(Iw) ( \ |
| + (op_prop_load_non_io[GET_IW_OP(Iw)])) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char op_prop_load_non_io[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_STORE8(Iw) ( \ |
| + ( \ |
| + ((GET_IW_OP((Iw)) == OP_STB)) || \ |
| + ((GET_IW_OP((Iw)) == OP_STBIO)) \ |
| + ) \ |
| + \ |
| +) |
| + |
| +#define IW_PROP_STORE16(Iw) ( \ |
| + ( \ |
| + ((GET_IW_OP((Iw)) == OP_STH)) || \ |
| + ((GET_IW_OP((Iw)) == OP_STHIO)) \ |
| + ) \ |
| + \ |
| +) |
| + |
| +#define IW_PROP_STORE32(Iw) ( \ |
| + ( \ |
| + ((GET_IW_OP((Iw)) == OP_STW)) || \ |
| + ((GET_IW_OP((Iw)) == OP_STWIO)) \ |
| + ) \ |
| + \ |
| +) |
| + |
| +#define IW_PROP_STORE(Iw) ( \ |
| + (op_prop_store[GET_IW_OP(Iw)])) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char op_prop_store[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_STORE_NON_IO(Iw) ( \ |
| + (op_prop_store_non_io[GET_IW_OP(Iw)])) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char op_prop_store_non_io[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_MEM(Iw) ( \ |
| + (op_prop_mem[GET_IW_OP(Iw)])) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char op_prop_mem[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_INITD(Iw) ( \ |
| + ( \ |
| + ((GET_IW_OP((Iw)) == OP_INITD)) \ |
| + ) \ |
| + \ |
| +) |
| + |
| +#define IW_PROP_FLUSHD(Iw) ( \ |
| + ( \ |
| + ((GET_IW_OP((Iw)) == OP_FLUSHD)) \ |
| + ) \ |
| + \ |
| +) |
| + |
| +#define IW_PROP_INITD_FLUSHD(Iw) ( \ |
| + ( \ |
| + ((GET_IW_OP((Iw)) == OP_INITD)) || \ |
| + ((GET_IW_OP((Iw)) == OP_FLUSHD)) \ |
| + ) \ |
| + \ |
| +) |
| + |
| +#define IW_PROP_FLUSHDA(Iw) ( \ |
| + ( \ |
| + ((GET_IW_OP((Iw)) == OP_FLUSHDA)) \ |
| + ) \ |
| + \ |
| +) |
| + |
| +#define IW_PROP_FLUSHD_FLUSHDA(Iw) ( \ |
| + ( \ |
| + ((GET_IW_OP((Iw)) == OP_FLUSHD)) || \ |
| + ((GET_IW_OP((Iw)) == OP_FLUSHDA)) \ |
| + ) \ |
| + \ |
| +) |
| + |
| +#define IW_PROP_INITD_FLUSHD_FLUSHDA(Iw) ( \ |
| + (op_prop_initd_flushd_flushda[GET_IW_OP(Iw)])) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char op_prop_initd_flushd_flushda[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_LOAD_IO(Iw) ( \ |
| + (op_prop_load_io[GET_IW_OP(Iw)])) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char op_prop_load_io[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_STORE_IO(Iw) ( \ |
| + (op_prop_store_io[GET_IW_OP(Iw)])) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char op_prop_store_io[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_MEM_IO(Iw) ( \ |
| + (op_prop_mem_io[GET_IW_OP(Iw)])) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char op_prop_mem_io[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_ARITH(Iw) ( \ |
| + (op_prop_arith[GET_IW_OP(Iw)] || \ |
| + (IS_OPX_INST(Iw) && opx_prop_arith[GET_IW_OPX(Iw)]))) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char op_prop_arith[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char opx_prop_arith[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_A_NOT_SRC(Iw) ( \ |
| + ( \ |
| + ((GET_IW_OP((Iw)) == OP_CALL)) || \ |
| + ((GET_IW_OP((Iw)) == OP_JMPI)) \ |
| + ) \ |
| + || (IS_CUSTOM_INST(Iw) && !GET_IW_CUSTOM_READRA(Iw)) \ |
| +) |
| + |
| +#define IW_PROP_B_NOT_SRC(Iw) ( \ |
| + (op_prop_b_not_src[GET_IW_OP(Iw)]) \ |
| + || (IS_CUSTOM_INST(Iw) && !GET_IW_CUSTOM_READRB(Iw))) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char op_prop_b_not_src[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_IGNORE_DST(Iw) ( \ |
| + (op_prop_ignore_dst[GET_IW_OP(Iw)]) \ |
| + || (IS_CUSTOM_INST(Iw) && !GET_IW_CUSTOM_WRITERC(Iw))) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char op_prop_ignore_dst[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_SRC2_CHOOSE_IMM(Iw) ( \ |
| + (op_prop_src2_choose_imm[GET_IW_OP(Iw)] || \ |
| + (IS_OPX_INST(Iw) && opx_prop_src2_choose_imm[GET_IW_OPX(Iw)]))) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char op_prop_src2_choose_imm[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char opx_prop_src2_choose_imm[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_WRCTL_INST(Iw) ( \ |
| + ( \ |
| + ((GET_IW_OPX((Iw)) == OPX_WRCTL) && IS_OPX_INST(Iw)) \ |
| + ) \ |
| + \ |
| +) |
| + |
| +#define IW_PROP_RDCTL_INST(Iw) ( \ |
| + ( \ |
| + ((GET_IW_OPX((Iw)) == OPX_RDCTL) && IS_OPX_INST(Iw)) \ |
| + ) \ |
| + \ |
| +) |
| + |
| +#define IW_PROP_MUL_SRC1_SIGNED(Iw) ( \ |
| + ( \ |
| + ((GET_IW_OPX((Iw)) == OPX_MULXSS) && IS_OPX_INST(Iw)) || \ |
| + ((GET_IW_OPX((Iw)) == OPX_MULXSU) && IS_OPX_INST(Iw)) \ |
| + ) \ |
| + \ |
| +) |
| + |
| +#define IW_PROP_MUL_SRC2_SIGNED(Iw) ( \ |
| + ( \ |
| + ((GET_IW_OPX((Iw)) == OPX_MULXSS) && IS_OPX_INST(Iw)) \ |
| + ) \ |
| + \ |
| +) |
| + |
| +#define IW_PROP_MUL_SHIFT_SRC1_SIGNED(Iw) ( \ |
| + (IS_OPX_INST(Iw) && opx_prop_mul_shift_src1_signed[GET_IW_OPX(Iw)])) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char opx_prop_mul_shift_src1_signed[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_MUL_SHIFT_SRC2_SIGNED(Iw) ( \ |
| + ( \ |
| + ((GET_IW_OPX((Iw)) == OPX_MULXSS) && IS_OPX_INST(Iw)) \ |
| + ) \ |
| + \ |
| +) |
| + |
| +#define IW_PROP_DONT_DISPLAY_DST_REG(Iw) ( \ |
| + (op_prop_dont_display_dst_reg[GET_IW_OP(Iw)] || \ |
| + (IS_OPX_INST(Iw) && opx_prop_dont_display_dst_reg[GET_IW_OPX(Iw)]))) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char op_prop_dont_display_dst_reg[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char opx_prop_dont_display_dst_reg[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_DONT_DISPLAY_SRC1_REG(Iw) ( \ |
| + (op_prop_dont_display_src1_reg[GET_IW_OP(Iw)] || \ |
| + (IS_OPX_INST(Iw) && opx_prop_dont_display_src1_reg[GET_IW_OPX(Iw)]))) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char op_prop_dont_display_src1_reg[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char opx_prop_dont_display_src1_reg[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_DONT_DISPLAY_SRC2_REG(Iw) ( \ |
| + (op_prop_dont_display_src2_reg[GET_IW_OP(Iw)] || \ |
| + (IS_OPX_INST(Iw) && opx_prop_dont_display_src2_reg[GET_IW_OPX(Iw)]))) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char op_prop_dont_display_src2_reg[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char opx_prop_dont_display_src2_reg[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_SRC1_NO_X(Iw) ( \ |
| + (op_prop_src1_no_x[GET_IW_OP(Iw)] || \ |
| + (IS_OPX_INST(Iw) && opx_prop_src1_no_x[GET_IW_OPX(Iw)]))) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char op_prop_src1_no_x[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char opx_prop_src1_no_x[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#define IW_PROP_SRC2_NO_X(Iw) ( \ |
| + (op_prop_src2_no_x[GET_IW_OP(Iw)] || \ |
| + (IS_OPX_INST(Iw) && opx_prop_src2_no_x[GET_IW_OPX(Iw)]))) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char op_prop_src2_no_x[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern unsigned char opx_prop_src2_no_x[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +/* Instruction types */ |
| +#define INST_TYPE_OP 0 |
| +#define INST_TYPE_OPX 1 |
| + |
| +/* Canonical instruction codes independent of encoding */ |
| +#define CALL_INST_CODE 0 |
| +#define JMPI_INST_CODE 1 |
| +#define LDBU_INST_CODE 2 |
| +#define ADDI_INST_CODE 3 |
| +#define STB_INST_CODE 4 |
| +#define BR_INST_CODE 5 |
| +#define LDB_INST_CODE 6 |
| +#define CMPGEI_INST_CODE 7 |
| +#define LDHU_INST_CODE 8 |
| +#define ANDI_INST_CODE 9 |
| +#define STH_INST_CODE 10 |
| +#define BGE_INST_CODE 11 |
| +#define LDH_INST_CODE 12 |
| +#define CMPLTI_INST_CODE 13 |
| +#define ORI_INST_CODE 14 |
| +#define STW_INST_CODE 15 |
| +#define BLT_INST_CODE 16 |
| +#define LDW_INST_CODE 17 |
| +#define CMPNEI_INST_CODE 18 |
| +#define FLUSHDA_INST_CODE 19 |
| +#define XORI_INST_CODE 20 |
| +#define BNE_INST_CODE 21 |
| +#define CMPEQI_INST_CODE 22 |
| +#define LDBUIO_INST_CODE 23 |
| +#define MULI_INST_CODE 24 |
| +#define STBIO_INST_CODE 25 |
| +#define BEQ_INST_CODE 26 |
| +#define LDBIO_INST_CODE 27 |
| +#define CMPGEUI_INST_CODE 28 |
| +#define LDHUIO_INST_CODE 29 |
| +#define ANDHI_INST_CODE 30 |
| +#define STHIO_INST_CODE 31 |
| +#define BGEU_INST_CODE 32 |
| +#define LDHIO_INST_CODE 33 |
| +#define CMPLTUI_INST_CODE 34 |
| +#define CUSTOM_INST_CODE 35 |
| +#define INITD_INST_CODE 36 |
| +#define ORHI_INST_CODE 37 |
| +#define STWIO_INST_CODE 38 |
| +#define BLTU_INST_CODE 39 |
| +#define LDWIO_INST_CODE 40 |
| +#define FLUSHD_INST_CODE 41 |
| +#define XORHI_INST_CODE 42 |
| +#define ERET_INST_CODE 43 |
| +#define ROLI_INST_CODE 44 |
| +#define ROL_INST_CODE 45 |
| +#define FLUSHP_INST_CODE 46 |
| +#define RET_INST_CODE 47 |
| +#define NOR_INST_CODE 48 |
| +#define MULXUU_INST_CODE 49 |
| +#define CMPGE_INST_CODE 50 |
| +#define BRET_INST_CODE 51 |
| +#define ROR_INST_CODE 52 |
| +#define FLUSHI_INST_CODE 53 |
| +#define JMP_INST_CODE 54 |
| +#define AND_INST_CODE 55 |
| +#define CMPLT_INST_CODE 56 |
| +#define SLLI_INST_CODE 57 |
| +#define SLL_INST_CODE 58 |
| +#define OR_INST_CODE 59 |
| +#define MULXSU_INST_CODE 60 |
| +#define CMPNE_INST_CODE 61 |
| +#define SRLI_INST_CODE 62 |
| +#define SRL_INST_CODE 63 |
| +#define NEXTPC_INST_CODE 64 |
| +#define CALLR_INST_CODE 65 |
| +#define XOR_INST_CODE 66 |
| +#define MULXSS_INST_CODE 67 |
| +#define CMPEQ_INST_CODE 68 |
| +#define DIVU_INST_CODE 69 |
| +#define DIV_INST_CODE 70 |
| +#define RDCTL_INST_CODE 71 |
| +#define MUL_INST_CODE 72 |
| +#define CMPGEU_INST_CODE 73 |
| +#define INITI_INST_CODE 74 |
| +#define TRAP_INST_CODE 75 |
| +#define WRCTL_INST_CODE 76 |
| +#define CMPLTU_INST_CODE 77 |
| +#define ADD_INST_CODE 78 |
| +#define BREAK_INST_CODE 79 |
| +#define HBREAK_INST_CODE 80 |
| +#define SYNC_INST_CODE 81 |
| +#define SUB_INST_CODE 82 |
| +#define SRAI_INST_CODE 83 |
| +#define SRA_INST_CODE 84 |
| +#define INTR_INST_CODE 85 |
| +#define CRST_INST_CODE 86 |
| +#define RSV_INST_CODE 87 |
| +#define NUM_NIOS2_INST_CODES 88 |
| + |
| +#ifndef ALT_ASM_SRC |
| +/* Instruction information entry */ |
| +typedef struct { |
| + const char* name; /* Assembly-language instruction name */ |
| + int instType; /* INST_TYPE_OP or INST_TYPE_OPX */ |
| + unsigned opcode; /* Value of instruction word OP/OPX field */ |
| +} Nios2InstInfo; |
| + |
| +extern Nios2InstInfo nios2InstInfo[NUM_NIOS2_INST_CODES]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +/* Returns the instruction code given the 32-bit instruction word */ |
| +#define GET_INST_CODE(Iw) \ |
| + (IS_OPX_INST(Iw) ? opxToInstCode[GET_IW_OPX(Iw)] : opToInstCode[GET_IW_OP(Iw)]) |
| + |
| +#ifndef ALT_ASM_SRC |
| +extern int opToInstCode[64]; |
| +extern int opxToInstCode[64]; |
| +#endif /* ALT_ASM_SRC */ |
| + |
| +/* |
| + * MMU Memory Region Macros |
| + */ |
| +#define USER_REGION_MIN_VADDR 0x00000000 |
| +#define USER_REGION_MAX_VADDR 0x7fffffff |
| +#define KERNEL_MMU_REGION_MIN_VADDR 0x80000000 |
| +#define KERNEL_MMU_REGION_MAX_VADDR 0xbfffffff |
| +#define KERNEL_REGION_MIN_VADDR 0xc0000000 |
| +#define KERNEL_REGION_MAX_VADDR 0xdfffffff |
| +#define IO_REGION_MIN_VADDR 0xe0000000 |
| +#define IO_REGION_MAX_VADDR 0xffffffff |
| + |
| +#define MMU_PAGE_SIZE (0x1 << (MMU_ADDR_PAGE_OFFSET_SZ)) |
| + |
| +#define isMmuUserRegion(Vaddr) \ |
| + (GET_MMU_ADDR_USER_REGION(Vaddr) == MMU_ADDR_USER_REGION) |
| +#define isMmuKernelMmuRegion(Vaddr) \ |
| + (GET_MMU_ADDR_KERNEL_MMU_REGION(Vaddr) == MMU_ADDR_KERNEL_MMU_REGION) |
| +#define isMmuKernelRegion(Vaddr) \ |
| + (GET_MMU_ADDR_KERNEL_REGION(Vaddr) == MMU_ADDR_KERNEL_REGION) |
| +#define isMmuIORegion(Vaddr) \ |
| + (GET_MMU_ADDR_IO_REGION(Vaddr) == MMU_ADDR_IO_REGION) |
| + |
| +/* Does this virtual address bypass the TLB? */ |
| +#define vaddrBypassTlb(Vaddr) \ |
| + (GET_MMU_ADDR_BYPASS_TLB(Vaddr) == MMU_ADDR_BYPASS_TLB) |
| + |
| +/* If TLB is bypassed, is the address cacheable or uncachable. */ |
| +#define vaddrBypassTlbCacheable(Vaddr) \ |
| + (GET_MMU_ADDR_BYPASS_TLB_CACHEABLE(Vaddr) == MMU_ADDR_BYPASS_TLB_CACHEABLE) |
| + |
| +/* |
| + * Compute physical address for regions that bypass the TLB. |
| + * Just need to clear some top bits. |
| + */ |
| +#define bypassTlbVaddrToPaddr(Vaddr) \ |
| + ((Vaddr) & (MMU_ADDR_BYPASS_TLB_PADDR_MASK << MMU_ADDR_BYPASS_TLB_PADDR_LSB)) |
| + |
| +/* |
| + * Will the physical address fit in the Kernel/IO region virtual address space? |
| + */ |
| +#define fitsInKernelRegion(Paddr) \ |
| + (GET_MMU_ADDR_KERNEL_REGION(Paddr) == 0) |
| +#define fitsInIORegion(Paddr) \ |
| + (GET_MMU_ADDR_IO_REGION(Paddr) == 0) |
| + |
| +/* Convert a physical address to a Kernel/IO region virtual address. */ |
| +#define paddrToKernelRegionVaddr(Paddr) \ |
| + ((Paddr) | (MMU_ADDR_KERNEL_REGION << MMU_ADDR_KERNEL_REGION_LSB)) |
| +#define paddrToIORegionVaddr(Paddr) \ |
| + ((Paddr) | (MMU_ADDR_IO_REGION << MMU_ADDR_IO_REGION_LSB)) |
| + |
| +/* |
| + * Convert a virtual address to a Kernel/IO region virtual address. |
| + * Uses bypassTlbVaddrToPaddr to clear top bits. |
| + */ |
| +#define vaddrToKernelRegionVaddr(Vaddr) \ |
| + paddrToKernelRegionVaddr(bypassTlbVaddrToPaddr(Vaddr)) |
| +#define vaddrToIORegionVaddr(Vaddr) \ |
| + paddrToIORegionVaddr(bypassTlbVaddrToPaddr(Vaddr)) |
| + |
| +/* Convert between VPN/PFN and virtual/physical addresses. */ |
| +#define vpnToVaddr(Vpn) ((Vpn) << MMU_ADDR_VPN_LSB) |
| +#define pfnToPaddr(Pfn) ((Pfn) << MMU_ADDR_PFN_LSB) |
| +#define vaddrToVpn(Vaddr) GET_MMU_ADDR_VPN(Vaddr) |
| +#define paddrToPfn(Paddr) GET_MMU_ADDR_PFN(Paddr) |
| + |
| +/* Bitwise OR with a KERNEL region address to make it an IO region address */ |
| +#define KERNEL_TO_IO_REGION 0x20000000 |
| + |
| +#endif /* _NIOS2_ISA_H_ */ |
| diff --git a/include/opcode/nios2.h b/include/opcode/nios2.h |
| new file mode 100644 |
| index 0000000..992bb80 |
| --- /dev/null |
| +++ b/include/opcode/nios2.h |
| @@ -0,0 +1,361 @@ |
| +/* nios2.h. Altera New Jersey opcode list for GAS, the GNU assembler. |
| + |
| + Copyright (C) 2003 |
| + by Nigel Gray (ngray@altera.com). |
| + |
| +This file is part of GDB, GAS, and the GNU binutils. |
| + |
| +GDB, GAS, and the GNU binutils are free software; you can redistribute |
| +them and/or modify them under the terms of the GNU General Public |
| +License as published by the Free Software Foundation; either version |
| +1, or (at your option) any later version. |
| + |
| +GDB, GAS, and the GNU binutils are distributed in the hope that they |
| +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 file; see the file COPYING. If not, write to the Free |
| +Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ |
| + |
| +#ifndef _NIOS2_H_ |
| +#define _NIOS2_H_ |
| + |
| + |
| +/**************************************************************************** |
| + * This file contains structures, bit masks and shift counts used |
| + * by the GNU toolchain to define the New Jersey instruction set and |
| + * access various opcode fields. |
| + ****************************************************************************/ |
| + |
| +enum overflow_type |
| +{ |
| + call_target_overflow = 0, |
| + branch_target_overflow, |
| + address_offset_overflow, |
| + signed_immed16_overflow, |
| + unsigned_immed16_overflow, |
| + unsigned_immed5_overflow, |
| + custom_opcode_overflow, |
| + no_overflow |
| +}; |
| + |
| +/*--------------------------------------------------------------------------- |
| + This structure holds information for a particular instruction |
| + ---------------------------------------------------------------------------*/ |
| + |
| +/* match When assembling, this |
| + opcode is modified by the arguments to produce the actual opcode |
| + that is used. If pinfo is INSN_MACRO, then this is 0. */ |
| + |
| +/* mask If pinfo is not INSN_MACRO, then this is a bit mask for the |
| + relevant portions of the opcode when disassembling. If the |
| + actual opcode anded with the match field equals the opcode field, |
| + then we have found the correct instruction. If pinfo is |
| + INSN_MACRO, then this field is the macro identifier. */ |
| + |
| +/* For a macro, this is INSN_MACRO. Otherwise, it is a collection |
| + of bits describing the instruction, notably any relevant hazard |
| + information. */ |
| + |
| +struct nios2_opcode |
| +{ |
| + const char *name; /* The name of the instruction. */ |
| + const char *args; /* A string describing the arguments for this instruction. */ |
| + const char *args_test; /* Like args, but with an extra argument for the expected opcode */ |
| + unsigned long num_args; /* the number of arguments the instruction takes */ |
| + unsigned long match; /* The basic opcode for the instruction. */ |
| + unsigned long mask; /* mask for the opcode field of the instruction */ |
| + unsigned long pinfo; /* is this a real instruction or instruction macro */ |
| + enum overflow_type overflow_msg; /* msg template used to generate informative message when fixup overflows */ |
| +}; |
| + |
| +/* This value is used in the nios2_opcode.pinfo field to indicate that the instruction |
| + is a macro or pseudo-op. This requires special treatment by the assembler, and is |
| + used by the disassembler to determine whether to check for a nop */ |
| +#define NIOS2_INSN_MACRO 0x80000000 |
| +#define NIOS2_INSN_MACRO_MOV 0x80000001 |
| +#define NIOS2_INSN_MACRO_MOVI 0x80000002 |
| +#define NIOS2_INSN_MACRO_MOVIA 0x80000004 |
| + |
| +#define NIOS2_INSN_RELAXABLE 0x40000000 |
| +#define NIOS2_INSN_UBRANCH 0x00000010 |
| +#define NIOS2_INSN_CBRANCH 0x00000020 |
| +#define NIOS2_INSN_CALL 0x00000040 |
| + |
| +#define NIOS2_INSN_ADDI 0x00000080 |
| +#define NIOS2_INSN_ANDI 0x00000100 |
| +#define NIOS2_INSN_ORI 0x00000200 |
| +#define NIOS2_INSN_XORI 0x00000400 |
| + |
| + |
| + |
| +/* Associates a register name ($6) with a 5-bit index (eg 6) */ |
| +struct nios2_reg |
| +{ |
| + const char *name; |
| + const int index; |
| +}; |
| + |
| + |
| +/* ------------------------------------------------------------------------- |
| + Bitfield masks for New Jersey instructions |
| + -------------------------------------------------------------------------*/ |
| + |
| +/* These are bit masks and shift counts to use to access the various |
| + fields of an instruction. */ |
| + |
| +/* Macros for getting and setting an instruction field */ |
| +#define GET_INSN_FIELD(X, i) ((i) & OP_MASK_##X) >> OP_SH_##X |
| +#define SET_INSN_FIELD(X, i, j) (i) = ((i) &~ (OP_MASK_##X)) | ((j) << OP_SH_##X) |
| + |
| + |
| +/* |
| + We include the auto-generated file nios2-isa.h and define the mask |
| + and shifts below in terms of those in nios2-isa.h. This ensures |
| + that the binutils and hardware are always in sync |
| +*/ |
| + |
| +#include "nios2-isa.h" |
| + |
| +#define OP_MASK_OP (IW_OP_MASK << IW_OP_LSB) |
| +#define OP_SH_OP IW_OP_LSB |
| + |
| + |
| +/* Masks and shifts for I-type instructions */ |
| + |
| +#define OP_MASK_IOP (IW_OP_MASK << IW_OP_LSB) |
| +#define OP_SH_IOP IW_OP_LSB |
| + |
| +#define OP_MASK_IMM16 (IW_IMM16_MASK << IW_IMM16_LSB) |
| +#define OP_SH_IMM16 IW_IMM16_LSB |
| + |
| +#define OP_MASK_IRD (IW_B_MASK << IW_B_LSB) // the same as T for I-type |
| +#define OP_SH_IRD IW_B_LSB |
| + |
| +#define OP_MASK_IRT (IW_B_MASK << IW_B_LSB) |
| +#define OP_SH_IRT IW_B_LSB |
| + |
| +#define OP_MASK_IRS (IW_A_MASK << IW_A_LSB) |
| +#define OP_SH_IRS IW_A_LSB |
| + |
| +/* Masks and shifts for R-type instructions */ |
| + |
| +#define OP_MASK_ROP (IW_OP_MASK << IW_OP_LSB) |
| +#define OP_SH_ROP IW_OP_LSB |
| + |
| +#define OP_MASK_ROPX (IW_OPX_MASK << IW_OPX_LSB) |
| +#define OP_SH_ROPX IW_OPX_LSB |
| + |
| +#define OP_MASK_RRD (IW_C_MASK << IW_C_LSB) |
| +#define OP_SH_RRD IW_C_LSB |
| + |
| +#define OP_MASK_RRT (IW_B_MASK << IW_B_LSB) |
| +#define OP_SH_RRT IW_B_LSB |
| + |
| +#define OP_MASK_RRS (IW_A_MASK << IW_A_LSB) |
| +#define OP_SH_RRS IW_A_LSB |
| + |
| +/* Masks and shifts for J-type instructions */ |
| + |
| +#define OP_MASK_JOP (IW_OP_MASK << IW_OP_LSB) |
| +#define OP_SH_JOP IW_OP_LSB |
| + |
| +#define OP_MASK_IMM26 (IW_IMM26_MASK << IW_IMM26_LSB) |
| +#define OP_SH_IMM26 IW_IMM26_LSB |
| + |
| +/* Masks and shifts for CTL instructions */ |
| + |
| +#define OP_MASK_RCTL 0x000007c0 |
| +#define OP_SH_RCTL 6 |
| + |
| +/* break instruction imm5 field */ |
| +#define OP_MASK_TRAP_IMM5 0x000007c0 |
| +#define OP_SH_TRAP_IMM5 6 |
| + |
| +/* instruction imm5 field */ |
| +#define OP_MASK_IMM5 (IW_SHIFT_IMM5_MASK << IW_SHIFT_IMM5_LSB) |
| +#define OP_SH_IMM5 IW_SHIFT_IMM5_LSB |
| + |
| +/* cache operation fields (type j,i(s)) */ |
| +#define OP_MASK_CACHE_OPX (IW_B_MASK << IW_B_LSB) |
| +#define OP_SH_CACHE_OPX IW_B_LSB |
| +#define OP_MASK_CACHE_RRS (IW_A_MASK << IW_A_LSB) |
| +#define OP_SH_CACHE_RRS IW_A_LSB |
| + |
| +/* custom instruction masks */ |
| +#define OP_MASK_CUSTOM_A 0x00010000 |
| +#define OP_SH_CUSTOM_A 16 |
| + |
| +#define OP_MASK_CUSTOM_B 0x00008000 |
| +#define OP_SH_CUSTOM_B 15 |
| + |
| +#define OP_MASK_CUSTOM_C 0x00004000 |
| +#define OP_SH_CUSTOM_C 14 |
| + |
| +#define OP_MASK_CUSTOM_N 0x00003fc0 |
| +#define OP_SH_CUSTOM_N 6 |
| +#define OP_MAX_CUSTOM_N 255 |
| + |
| +/* |
| + The following macros define the opcode matches for each |
| + instruction |
| + code & OP_MASK_INST == OP_MATCH_INST |
| + */ |
| + |
| +/* OP instruction matches */ |
| +#define OP_MATCH_ADDI OP_ADDI |
| +#define OP_MATCH_ANDHI OP_ANDHI |
| +#define OP_MATCH_ANDI OP_ANDI |
| +#define OP_MATCH_BEQ OP_BEQ |
| +#define OP_MATCH_BGE OP_BGE |
| +#define OP_MATCH_BGEU OP_BGEU |
| +#define OP_MATCH_BLT OP_BLT |
| +#define OP_MATCH_BLTU OP_BLTU |
| +#define OP_MATCH_BNE OP_BNE |
| +#define OP_MATCH_BR OP_BR |
| +#define OP_MATCH_FLUSHD OP_FLUSHD |
| +#define OP_MATCH_FLUSHDA OP_FLUSHDA |
| +#define OP_MATCH_INITD OP_INITD |
| +#define OP_MATCH_CALL OP_CALL |
| +#define OP_MATCH_CMPEQI OP_CMPEQI |
| +#define OP_MATCH_CMPGEI OP_CMPGEI |
| +#define OP_MATCH_CMPGEUI OP_CMPGEUI |
| +#define OP_MATCH_CMPLTI OP_CMPLTI |
| +#define OP_MATCH_CMPLTUI OP_CMPLTUI |
| +#define OP_MATCH_CMPNEI OP_CMPNEI |
| +#define OP_MATCH_JMPI OP_JMPI |
| +#define OP_MATCH_LDB OP_LDB |
| +#define OP_MATCH_LDBIO OP_LDBIO |
| +#define OP_MATCH_LDBU OP_LDBU |
| +#define OP_MATCH_LDBUIO OP_LDBUIO |
| +#define OP_MATCH_LDH OP_LDH |
| +#define OP_MATCH_LDHIO OP_LDHIO |
| +#define OP_MATCH_LDHU OP_LDHU |
| +#define OP_MATCH_LDHUIO OP_LDHUIO |
| +#define OP_MATCH_LDW OP_LDW |
| +#define OP_MATCH_LDWIO OP_LDWIO |
| +#define OP_MATCH_MULI OP_MULI |
| +#define OP_MATCH_OPX OP_OPX |
| +#define OP_MATCH_ORHI OP_ORHI |
| +#define OP_MATCH_ORI OP_ORI |
| +#define OP_MATCH_STB OP_STB |
| +#define OP_MATCH_STBIO OP_STBIO |
| +#define OP_MATCH_STH OP_STH |
| +#define OP_MATCH_STHIO OP_STHIO |
| +#define OP_MATCH_STW OP_STW |
| +#define OP_MATCH_STWIO OP_STWIO |
| +#define OP_MATCH_CUSTOM OP_CUSTOM |
| +#define OP_MATCH_XORHI OP_XORHI |
| +#define OP_MATCH_XORI OP_XORI |
| +#define OP_MATCH_OPX OP_OPX |
| + |
| + |
| + |
| +/* OPX instruction values */ |
| +#define OP_MATCH_ADD ((OPX_ADD << IW_OPX_LSB) | (OP_OPX)) |
| +#define OP_MATCH_AND ((OPX_AND << IW_OPX_LSB) | (OP_OPX)) |
| +#define OP_MATCH_BREAK ((0x1e << 17) | (OPX_BREAK << IW_OPX_LSB) | (OP_OPX)) |
| +#define OP_MATCH_BRET ((0xf0000000) | (OPX_BRET << IW_OPX_LSB) | (OP_OPX)) |
| +#define OP_MATCH_CALLR ((0x1f << 17) | (OPX_CALLR << IW_OPX_LSB) | (OP_OPX)) |
| +#define OP_MATCH_CMPEQ ((OPX_CMPEQ << IW_OPX_LSB) | (OP_OPX)) |
| +#define OP_MATCH_CMPGE ((OPX_CMPGE << IW_OPX_LSB) | (OP_OPX)) |
| +#define OP_MATCH_CMPGEU ((OPX_CMPGEU << IW_OPX_LSB) | (OP_OPX)) |
| +#define OP_MATCH_CMPLT ((OPX_CMPLT << IW_OPX_LSB) | (OP_OPX)) |
| +#define OP_MATCH_CMPLTU ((OPX_CMPLTU << IW_OPX_LSB) | (OP_OPX)) |
| +#define OP_MATCH_CMPNE ((OPX_CMPNE << IW_OPX_LSB) | (OP_OPX)) |
| +#define OP_MATCH_DIV ((OPX_DIV << IW_OPX_LSB) | (OP_OPX)) |
| +#define OP_MATCH_DIVU ((OPX_DIVU << IW_OPX_LSB) | (OP_OPX)) |
| +#define OP_MATCH_JMP ((OPX_JMP << IW_OPX_LSB) | (OP_OPX)) |
| +#define OP_MATCH_MUL ((OPX_MUL << IW_OPX_LSB) | (OP_OPX)) |
| +#define OP_MATCH_MULXSS ((OPX_MULXSS << IW_OPX_LSB) | (OP_OPX)) |
| +#define OP_MATCH_MULXSU ((OPX_MULXSU << IW_OPX_LSB) | (OP_OPX)) |
| +#define OP_MATCH_MULXUU ((OPX_MULXUU << IW_OPX_LSB) | (OP_OPX)) |
| +#define OP_MATCH_NEXTPC ((OPX_NEXTPC << IW_OPX_LSB) | (OP_OPX)) |
| +#define OP_MATCH_NOR ((OPX_NOR << IW_OPX_LSB) | (OP_OPX)) |
| +#define OP_MATCH_OR ((OPX_OR << IW_OPX_LSB) | (OP_OPX)) |
| +#define OP_MATCH_RDCTL ((OPX_RDCTL << IW_OPX_LSB) | (OP_OPX)) |
| +#define OP_MATCH_RET ((0xf8000000) | (OPX_RET << IW_OPX_LSB) | (OP_OPX)) |
| +#define OP_MATCH_ROL ((OPX_ROL << IW_OPX_LSB) | (OP_OPX)) |
| +#define OP_MATCH_ROLI ((OPX_ROLI << IW_OPX_LSB) | (OP_OPX)) |
| +#define OP_MATCH_ROR ((OPX_ROR << IW_OPX_LSB) | (OP_OPX)) |
| +#define OP_MATCH_SLL ((OPX_SLL << IW_OPX_LSB) | (OP_OPX)) |
| +#define OP_MATCH_SLLI ((OPX_SLLI << IW_OPX_LSB) | (OP_OPX)) |
| +#define OP_MATCH_SRA ((OPX_SRA << IW_OPX_LSB) | (OP_OPX)) |
| +#define OP_MATCH_SRAI ((OPX_SRAI << IW_OPX_LSB) | (OP_OPX)) |
| +#define OP_MATCH_SRL ((OPX_SRL << IW_OPX_LSB) | (OP_OPX)) |
| +#define OP_MATCH_SRLI ((OPX_SRLI << IW_OPX_LSB) | (OP_OPX)) |
| +#define OP_MATCH_SUB ((OPX_SUB << IW_OPX_LSB) | (OP_OPX)) |
| +#define OP_MATCH_SYNC ((OPX_SYNC << IW_OPX_LSB) | (OP_OPX)) |
| +#define OP_MATCH_TRAP ((0x1d << 17) | (OPX_TRAP << IW_OPX_LSB) | (OP_OPX)) |
| +#define OP_MATCH_ERET ((0xe8000000) | (OPX_ERET << IW_OPX_LSB) | (OP_OPX)) |
| +#define OP_MATCH_WRCTL ((OPX_WRCTL << IW_OPX_LSB) | (OP_OPX)) |
| +#define OP_MATCH_XOR ((OPX_XOR << IW_OPX_LSB) | (OP_OPX)) |
| +#define OP_MATCH_FLUSHI ((OPX_FLUSHI << IW_OPX_LSB) | (OP_OPX)) |
| +#define OP_MATCH_FLUSHP ((OPX_FLUSHP << IW_OPX_LSB) | (OP_OPX)) |
| +#define OP_MATCH_INITI ((OPX_INITI << IW_OPX_LSB) | (OP_OPX)) |
| + |
| +/* |
| + Some unusual op masks |
| +*/ |
| +#define OP_MASK_BREAK ((OP_MASK_RRS | OP_MASK_RRT | OP_MASK_RRD | OP_MASK_ROPX | OP_MASK_OP) & 0xfffff03f) |
| +#define OP_MASK_CALLR ((OP_MASK_RRT | OP_MASK_RRD | OP_MASK_ROPX | OP_MASK_OP)) |
| +#define OP_MASK_JMP ((OP_MASK_RRT | OP_MASK_RRD | OP_MASK_ROPX | OP_MASK_OP)) |
| +#define OP_MASK_SYNC ((OP_MASK_RRT | OP_MASK_RRD | OP_MASK_ROPX | OP_MASK_OP)) |
| +#define OP_MASK_TRAP ((OP_MASK_RRS | OP_MASK_RRT | OP_MASK_RRD | OP_MASK_ROPX | OP_MASK_OP) & 0xfffff83f) |
| +#define OP_MASK_WRCTL ((OP_MASK_RRT | OP_MASK_RRD | OP_MASK_ROPX | OP_MASK_OP)) /*& 0xfffff83f */ |
| +#define OP_MASK_NEXTPC ((OP_MASK_RRS | OP_MASK_RRT | OP_MASK_ROPX | OP_MASK_OP)) |
| +#define OP_MASK_FLUSHI ((OP_MASK_RRT | OP_MASK_RRD | OP_MASK_ROPX | OP_MASK_OP)) |
| +#define OP_MASK_INITI ((OP_MASK_RRT | OP_MASK_RRD | OP_MASK_ROPX | OP_MASK_OP)) |
| + |
| +#define OP_MASK_ROLI ((OP_MASK_RRT | OP_MASK_ROPX | OP_MASK_OP)) |
| +#define OP_MASK_SLLI ((OP_MASK_RRT | OP_MASK_ROPX | OP_MASK_OP)) |
| +#define OP_MASK_SRAI ((OP_MASK_RRT | OP_MASK_ROPX | OP_MASK_OP)) |
| +#define OP_MASK_SRLI ((OP_MASK_RRT | OP_MASK_ROPX | OP_MASK_OP)) |
| +#define OP_MASK_RDCTL ((OP_MASK_RRS | OP_MASK_RRT | OP_MASK_ROPX | OP_MASK_OP)) /*& 0xfffff83f */ |
| + |
| +#ifndef OP_MASK |
| +#define OP_MASK 0xffffffff |
| +#endif |
| + |
| +/* These are the data structures we use to hold the instruction information */ |
| + |
| +extern const struct nios2_opcode nios2_builtin_opcodes[]; |
| +extern const int bfd_nios2_num_builtin_opcodes; |
| +extern struct nios2_opcode *nios2_opcodes; |
| +extern int bfd_nios2_num_opcodes; |
| + |
| +/* These are the data structures used to hold the operand parsing information */ |
| +//extern const struct nios2_arg_parser nios2_arg_parsers[]; |
| +//extern struct nios2_arg_parser* nios2_arg_parsers; |
| +//extern const int nios2_num_builtin_arg_parsers; |
| +//extern int nios2_num_arg_parsers; |
| + |
| +/* These are the data structures used to hold the register information */ |
| +extern const struct nios2_reg nios2_builtin_regs[]; |
| +extern struct nios2_reg *nios2_regs; |
| +extern const int nios2_num_builtin_regs; |
| +extern int nios2_num_regs; |
| + |
| +/* Machine-independent macro for number of opcodes */ |
| + |
| +#define NUMOPCODES bfd_nios2_num_opcodes |
| +#define NUMREGISTERS nios2_num_regs; |
| + |
| +/* these are used in disassembly to get the correct register names */ |
| +#define NUMREGNAMES 32 |
| +#define NUMCTLREGNAMES 32 |
| +#define CTLREGBASE 42 |
| +#define COPROCREGBASE 83 |
| +#define NUMCOPROCREGNAMES 32 |
| + |
| + |
| +/* this is made extern so that the assembler can use it to find out |
| + what instruction caused an error */ |
| +extern const struct nios2_opcode *nios2_find_opcode_hash (unsigned long); |
| + |
| +/* overflow message strings used in the assembler */ |
| +extern char *overflow_msgs[]; |
| + |
| +#endif // _NIOS2_H |
| diff --git a/opcodes/Makefile.am b/opcodes/Makefile.am |
| index ebd252f..a7ca06b 100644 |
| --- a/opcodes/Makefile.am |
| +++ b/opcodes/Makefile.am |
| @@ -146,6 +146,13 @@ CFILES = \ |
| mt-dis.c \ |
| mt-ibld.c \ |
| mt-opc.c \ |
| + nios2-opc.c \ |
| + nios2-dis.c \ |
| + ms1-asm.c \ |
| + ms1-desc.c \ |
| + ms1-dis.c \ |
| + ms1-ibld.c \ |
| + ms1-opc.c \ |
| ns32k-dis.c \ |
| openrisc-asm.c \ |
| openrisc-desc.c \ |
| @@ -281,6 +288,8 @@ ALL_MACHINES = \ |
| mt-dis.lo \ |
| mt-ibld.lo \ |
| mt-opc.lo \ |
| + nios2-opc.lo \ |
| + nios2-dis.lo \ |
| ns32k-dis.lo \ |
| openrisc-asm.lo \ |
| openrisc-desc.lo \ |
| @@ -980,6 +989,13 @@ mt-opc.lo: mt-opc.c sysdep.h config.h $(INCDIR)/ansidecl.h \ |
| mt-desc.h $(INCDIR)/opcode/cgen-bitset.h $(INCDIR)/opcode/cgen.h \ |
| $(INCDIR)/symcat.h $(INCDIR)/opcode/cgen-bitset.h mt-opc.h \ |
| $(INCDIR)/libiberty.h $(INCDIR)/ansidecl.h $(INCDIR)/safe-ctype.h |
| +nios2-opc.lo: nios2-opc.c sysdep.h config.h $(INCDIR)/ansidecl.h \ |
| + $(INCDIR)/opcode/nios2.h |
| +nios2-dis.lo: nios2-dis.c sysdep.h config.h $(INCDIR)/ansidecl.h \ |
| + $(INCDIR)/dis-asm.h $(BFD_H) $(INCDIR)/symcat.h $(INCDIR)/opcode/nios2.h \ |
| + opintl.h $(BFDDIR)/elf-bfd.h $(INCDIR)/elf/common.h \ |
| + $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h \ |
| + $(INCDIR)/elf/nios2.h $(INCDIR)/elf/reloc-macros.h |
| ns32k-dis.lo: ns32k-dis.c $(BFD_H) $(INCDIR)/ansidecl.h \ |
| $(INCDIR)/symcat.h sysdep.h config.h $(INCDIR)/ansidecl.h \ |
| $(INCDIR)/dis-asm.h $(BFD_H) $(INCDIR)/opcode/ns32k.h \ |
| diff --git a/opcodes/Makefile.in b/opcodes/Makefile.in |
| index 85003e6..9e3baae 100644 |
| --- a/opcodes/Makefile.in |
| +++ b/opcodes/Makefile.in |
| @@ -360,6 +360,8 @@ CFILES = \ |
| mt-dis.c \ |
| mt-ibld.c \ |
| mt-opc.c \ |
| + nios2-opc.c \ |
| + nios2-dis.c \ |
| ns32k-dis.c \ |
| openrisc-asm.c \ |
| openrisc-desc.c \ |
| @@ -495,6 +497,8 @@ ALL_MACHINES = \ |
| mt-dis.lo \ |
| mt-ibld.lo \ |
| mt-opc.lo \ |
| + nios2-opc.lo \ |
| + nios2-dis.lo \ |
| ns32k-dis.lo \ |
| openrisc-asm.lo \ |
| openrisc-desc.lo \ |
| @@ -1517,6 +1521,13 @@ mt-opc.lo: mt-opc.c sysdep.h config.h $(INCDIR)/ansidecl.h \ |
| mt-desc.h $(INCDIR)/opcode/cgen-bitset.h $(INCDIR)/opcode/cgen.h \ |
| $(INCDIR)/symcat.h $(INCDIR)/opcode/cgen-bitset.h mt-opc.h \ |
| $(INCDIR)/libiberty.h $(INCDIR)/ansidecl.h $(INCDIR)/safe-ctype.h |
| +nios2-opc.lo: nios2-opc.c sysdep.h config.h $(INCDIR)/ansidecl.h \ |
| + $(INCDIR)/opcode/nios2.h |
| +nios2-dis.lo: nios2-dis.c sysdep.h config.h $(INCDIR)/ansidecl.h \ |
| + $(INCDIR)/dis-asm.h $(BFD_H) $(INCDIR)/symcat.h $(INCDIR)/opcode/nios2.h \ |
| + opintl.h $(BFDDIR)/elf-bfd.h $(INCDIR)/elf/common.h \ |
| + $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h \ |
| + $(INCDIR)/elf/nios2.h $(INCDIR)/elf/reloc-macros.h |
| ns32k-dis.lo: ns32k-dis.c $(BFD_H) $(INCDIR)/ansidecl.h \ |
| $(INCDIR)/symcat.h sysdep.h config.h $(INCDIR)/ansidecl.h \ |
| $(INCDIR)/dis-asm.h $(BFD_H) $(INCDIR)/opcode/ns32k.h \ |
| diff --git a/opcodes/configure b/opcodes/configure |
| index 8e3e27e..a28cc46 100755 |
| --- a/opcodes/configure |
| +++ b/opcodes/configure |
| @@ -6561,6 +6561,7 @@ if test x${all_targets} = xfalse ; then |
| bfd_mn10300_arch) ta="$ta m10300-dis.lo m10300-opc.lo" ;; |
| bfd_mt_arch) ta="$ta mt-asm.lo mt-desc.lo mt-dis.lo mt-ibld.lo mt-opc.lo" using_cgen=yes ;; |
| bfd_msp430_arch) ta="$ta msp430-dis.lo" ;; |
| + bfd_nios2_arch) ta="$ta nios2-opc.lo nios2-dis.lo" ;; |
| bfd_ns32k_arch) ta="$ta ns32k-dis.lo" ;; |
| bfd_openrisc_arch) ta="$ta openrisc-asm.lo openrisc-desc.lo openrisc-dis.lo openrisc-ibld.lo openrisc-opc.lo" using_cgen=yes ;; |
| bfd_or32_arch) ta="$ta or32-dis.lo or32-opc.lo" using_cgen=yes ;; |
| diff --git a/opcodes/configure.in b/opcodes/configure.in |
| index d937784..c9df814 100644 |
| --- a/opcodes/configure.in |
| +++ b/opcodes/configure.in |
| @@ -190,6 +190,7 @@ if test x${all_targets} = xfalse ; then |
| bfd_mn10300_arch) ta="$ta m10300-dis.lo m10300-opc.lo" ;; |
| bfd_mt_arch) ta="$ta mt-asm.lo mt-desc.lo mt-dis.lo mt-ibld.lo mt-opc.lo" using_cgen=yes ;; |
| bfd_msp430_arch) ta="$ta msp430-dis.lo" ;; |
| + bfd_nios2_arch) ta="$ta nios2-opc.lo nios2-dis.lo" ;; |
| bfd_ns32k_arch) ta="$ta ns32k-dis.lo" ;; |
| bfd_openrisc_arch) ta="$ta openrisc-asm.lo openrisc-desc.lo openrisc-dis.lo openrisc-ibld.lo openrisc-opc.lo" using_cgen=yes ;; |
| bfd_or32_arch) ta="$ta or32-dis.lo or32-opc.lo" using_cgen=yes ;; |
| diff --git a/opcodes/disassemble.c b/opcodes/disassemble.c |
| index ca28f56..dfacbb9 100644 |
| --- a/opcodes/disassemble.c |
| +++ b/opcodes/disassemble.c |
| @@ -80,6 +80,7 @@ |
| #define ARCH_xtensa |
| #define ARCH_z80 |
| #define ARCH_z8k |
| +#define ARCH_nios2 |
| #define INCLUDE_SHMEDIA |
| #endif |
| |
| @@ -424,6 +425,14 @@ disassembler (abfd) |
| disassemble = print_insn_iq2000; |
| break; |
| #endif |
| +#ifdef ARCH_nios2 |
| + case bfd_arch_nios2: |
| + if (bfd_big_endian (abfd)) |
| + disassemble = print_insn_big_nios2; |
| + else |
| + disassemble = print_insn_little_nios2; |
| + break; |
| +#endif |
| #ifdef ARCH_m32c |
| case bfd_arch_m32c: |
| disassemble = print_insn_m32c; |
| diff --git a/opcodes/nios2-dis.c b/opcodes/nios2-dis.c |
| new file mode 100644 |
| index 0000000..ac9eb0d |
| --- /dev/null |
| +++ b/opcodes/nios2-dis.c |
| @@ -0,0 +1,462 @@ |
| +/* nios2-dis.c -- Altera New Jersey disassemble routines. |
| + |
| + Copyright (C) 2003 |
| + by Nigel Gray (ngray@altera.com). |
| + |
| +This file is part of GDB, GAS, and the GNU binutils. |
| + |
| +GDB, GAS, and the GNU binutils are free software; you can redistribute |
| +them and/or modify them under the terms of the GNU General Public |
| +License as published by the Free Software Foundation; either version |
| +1, or (at your option) any later version. |
| + |
| +GDB, GAS, and the GNU binutils are distributed in the hope that they |
| +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 file; see the file COPYING. If not, write to the Free |
| +Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ |
| + |
| +#include <stdlib.h> |
| +#include <assert.h> |
| +#include <string.h> |
| +#include "dis-asm.h" |
| +#include "opcode/nios2.h" |
| + |
| +/* No symbol table is available when this code runs out in an embedded |
| + system as when it is used for disassembler support in a monitor. */ |
| + |
| +#if !defined(EMBEDDED_ENV) |
| +#define SYMTAB_AVAILABLE 1 |
| +#include "elf-bfd.h" |
| +#include "elf/nios2.h" |
| +#endif |
| + |
| +/* length of New Jersey instruction in bytes */ |
| +#define INSNLEN 4 |
| + |
| +/* helper function prototypes */ |
| +static int nios2_disassemble (bfd_vma, unsigned long, disassemble_info *); |
| +static void nios2_init_opcode_hash (void); |
| + |
| + |
| +static int nios2_print_insn_arg (const char *argptr, unsigned long opcode, |
| + bfd_vma address, disassemble_info * info); |
| + |
| + |
| +/* print_insn_nios2 is the main disassemble function for New Jersey. |
| + The function diassembler(abfd) (source in disassemble.c) returns a |
| + pointer to this either print_insn_big_nios2 or |
| + print_insn_little_nios2, which in turn call this function, when the |
| + bfd machine type is New Jersey. print_insn_nios2 reads the |
| + instruction word at the address given, and prints the disassembled |
| + instruction on the stream info->stream using info->fprintf_func. */ |
| + |
| +static int |
| +print_insn_nios2 (bfd_vma address, disassemble_info * info, |
| + enum bfd_endian endianness) |
| +{ |
| + /* buffer into which the instruction bytes are written */ |
| + bfd_byte buffer[INSNLEN]; |
| + /* used to indicate return status from function calls */ |
| + int status; |
| + |
| + assert (info != NULL); |
| + |
| + status = (*info->read_memory_func) (address, buffer, INSNLEN, info); |
| + if (status == 0) |
| + { |
| + unsigned long insn; |
| + if (endianness == BFD_ENDIAN_BIG) |
| + insn = (unsigned long) bfd_getb32 (buffer); |
| + else |
| + insn = (unsigned long) bfd_getl32 (buffer); |
| + status = nios2_disassemble (address, insn, info); |
| + } |
| + else |
| + { |
| + (*info->memory_error_func) (status, address, info); |
| + status = -1; |
| + } |
| + return status; |
| +} |
| + |
| +int |
| +print_insn_big_nios2 (bfd_vma address, disassemble_info * info) |
| +{ |
| + return print_insn_nios2 (address, info, BFD_ENDIAN_BIG); |
| +} |
| + |
| +int |
| +print_insn_little_nios2 (bfd_vma address, disassemble_info * info) |
| +{ |
| + return print_insn_nios2 (address, info, BFD_ENDIAN_LITTLE); |
| +} |
| + |
| +/* Data structures used by the opcode hash table */ |
| + |
| +typedef struct _nios2_opcode_hash |
| +{ |
| + const struct nios2_opcode *opcode; |
| + struct _nios2_opcode_hash *next; |
| +} nios2_opcode_hash; |
| + |
| +static bfd_boolean nios2_hash_init = 0; |
| +static nios2_opcode_hash *nios2_hash[(OP_MASK_OP) + 1]; |
| + |
| +/* separate hash table for pseudo-ops */ |
| +static nios2_opcode_hash *nios2_ps_hash[(OP_MASK_OP) + 1]; |
| + |
| +/* Function to initialize the opcode hash table */ |
| + |
| +void |
| +nios2_init_opcode_hash () |
| +{ |
| + unsigned int i; |
| + register const struct nios2_opcode *op; |
| + nios2_opcode_hash *tmp_hash; |
| + |
| + for (i = 0; i <= OP_MASK_OP; ++i) |
| + { |
| + nios2_hash[0] = NULL; |
| + } |
| + for (i = 0; i <= OP_MASK_OP; i++) |
| + { |
| + for (op = nios2_opcodes; op < &nios2_opcodes[NUMOPCODES]; op++) |
| + { |
| + if ((op->pinfo & NIOS2_INSN_MACRO) == NIOS2_INSN_MACRO) |
| + { |
| + if (i == ((op->match >> OP_SH_OP) & OP_MASK_OP) && |
| + (op-> |
| + pinfo & (NIOS2_INSN_MACRO_MOV | NIOS2_INSN_MACRO_MOVI) & |
| + 0x7fffffff) != 0) |
| + { |
| + tmp_hash = nios2_ps_hash[i]; |
| + if (tmp_hash == NULL) |
| + { |
| + tmp_hash = |
| + (nios2_opcode_hash *) |
| + malloc (sizeof (nios2_opcode_hash)); |
| + nios2_ps_hash[i] = tmp_hash; |
| + } |
| + else |
| + { |
| + while (tmp_hash->next != NULL) |
| + tmp_hash = tmp_hash->next; |
| + tmp_hash->next = |
| + (nios2_opcode_hash *) |
| + malloc (sizeof (nios2_opcode_hash)); |
| + tmp_hash = tmp_hash->next; |
| + } |
| + if (tmp_hash == NULL) |
| + { |
| + fprintf (stderr, |
| + "error allocating memory...broken disassembler\n"); |
| + abort (); |
| + } |
| + tmp_hash->opcode = op; |
| + tmp_hash->next = NULL; |
| + } |
| + } |
| + else if (i == ((op->match >> OP_SH_OP) & OP_MASK_OP)) |
| + { |
| + tmp_hash = nios2_hash[i]; |
| + if (tmp_hash == NULL) |
| + { |
| + tmp_hash = |
| + (nios2_opcode_hash *) malloc (sizeof (nios2_opcode_hash)); |
| + nios2_hash[i] = tmp_hash; |
| + } |
| + else |
| + { |
| + while (tmp_hash->next != NULL) |
| + tmp_hash = tmp_hash->next; |
| + tmp_hash->next = |
| + (nios2_opcode_hash *) malloc (sizeof (nios2_opcode_hash)); |
| + tmp_hash = tmp_hash->next; |
| + } |
| + if (tmp_hash == NULL) |
| + { |
| + fprintf (stderr, |
| + "error allocating memory...broken disassembler\n"); |
| + abort (); |
| + } |
| + tmp_hash->opcode = op; |
| + tmp_hash->next = NULL; |
| + } |
| + } |
| + } |
| + nios2_hash_init = 1; |
| +#ifdef DEBUG_HASHTABLE |
| + for (i = 0; i <= OP_MASK_OP; ++i) |
| + { |
| + printf ("index: 0x%02X ops: ", i); |
| + tmp_hash = nios2_hash[i]; |
| + if (tmp_hash != NULL) |
| + { |
| + while (tmp_hash != NULL) |
| + { |
| + printf ("%s ", tmp_hash->opcode->name); |
| + tmp_hash = tmp_hash->next; |
| + } |
| + } |
| + printf ("\n"); |
| + } |
| + |
| + for (i = 0; i <= OP_MASK_OP; ++i) |
| + { |
| + printf ("index: 0x%02X ops: ", i); |
| + tmp_hash = nios2_ps_hash[i]; |
| + if (tmp_hash != NULL) |
| + { |
| + while (tmp_hash != NULL) |
| + { |
| + printf ("%s ", tmp_hash->opcode->name); |
| + tmp_hash = tmp_hash->next; |
| + } |
| + } |
| + printf ("\n"); |
| + } |
| +#endif |
| +} |
| + |
| +/* Function which returns a pointer to an nios2_opcode struct for |
| + a given instruction opcode, or NULL if there is an error */ |
| + |
| +const struct nios2_opcode * |
| +nios2_find_opcode_hash (unsigned long opcode) |
| +{ |
| + nios2_opcode_hash *entry; |
| + |
| + /* Build a hash table to shorten the search time. */ |
| + if (!nios2_hash_init) |
| + { |
| + nios2_init_opcode_hash (); |
| + } |
| + |
| + /* first look in the pseudo-op hashtable */ |
| + entry = nios2_ps_hash[(opcode >> OP_SH_OP) & OP_MASK_OP]; |
| + |
| + /* look for a match and if we get one, this is the instruction we decode */ |
| + while (entry != NULL) |
| + { |
| + if ((entry->opcode->match) == (opcode & entry->opcode->mask)) |
| + return entry->opcode; |
| + else |
| + entry = entry->next; |
| + } |
| + |
| + /* if we haven't yet returned, then we need to look in the main |
| + hashtable */ |
| + entry = nios2_hash[(opcode >> OP_SH_OP) & OP_MASK_OP]; |
| + |
| + if (entry == NULL) |
| + return NULL; |
| + |
| + |
| + while (entry != NULL) |
| + { |
| + if ((entry->opcode->match) == (opcode & entry->opcode->mask)) |
| + return entry->opcode; |
| + else |
| + entry = entry->next; |
| + } |
| + |
| + return NULL; |
| +} |
| + |
| +/* nios2_disassemble does all the work of disassembling a New Jersey |
| + instruction opcode */ |
| + |
| +int |
| +nios2_disassemble (bfd_vma address, unsigned long opcode, |
| + disassemble_info * info) |
| +{ |
| + const struct nios2_opcode *op; |
| + const char *argstr; |
| + |
| + info->bytes_per_line = INSNLEN; |
| + info->bytes_per_chunk = INSNLEN; |
| + info->display_endian = info->endian; |
| + info->insn_info_valid = 1; |
| + info->branch_delay_insns = 0; |
| + info->data_size = 0; |
| + info->insn_type = dis_nonbranch; |
| + info->target = 0; |
| + info->target2 = 0; |
| + |
| + /* Find the major opcode and use this to disassemble |
| + the instruction and its arguments */ |
| + op = nios2_find_opcode_hash (opcode); |
| + |
| + if (op != NULL) |
| + { |
| + bfd_boolean is_nop = FALSE; |
| + if (op->pinfo == NIOS2_INSN_MACRO_MOV) |
| + { |
| + /* check for mov r0, r0 and if it is |
| + change to nop */ |
| + int dst, src; |
| + dst = GET_INSN_FIELD (RRD, opcode); |
| + src = GET_INSN_FIELD (RRS, opcode); |
| + if (dst == 0 && src == 0) |
| + { |
| + (*info->fprintf_func) (info->stream, "nop"); |
| + is_nop = TRUE; |
| + } |
| + else |
| + { |
| + (*info->fprintf_func) (info->stream, "%s", op->name); |
| + } |
| + } |
| + else |
| + { |
| + (*info->fprintf_func) (info->stream, "%s", op->name); |
| + } |
| + |
| + if (!is_nop) |
| + { |
| + argstr = op->args; |
| + if (argstr != NULL && *argstr != '\0') |
| + { |
| + (*info->fprintf_func) (info->stream, "\t"); |
| + while (*argstr != '\0') |
| + { |
| + nios2_print_insn_arg (argstr, opcode, address, info); |
| + ++argstr; |
| + } |
| + } |
| + } |
| + } |
| + else |
| + { |
| + /* Handle undefined instructions. */ |
| + info->insn_type = dis_noninsn; |
| + (*info->fprintf_func) (info->stream, "0x%x", (unsigned int) opcode); |
| + } |
| + // this tells the caller how far to advance the program counter |
| + return INSNLEN; |
| +} |
| + |
| +/* The function nios2_print_insn_arg uses the character pointed |
| + to by argptr to determine how it print the next token or separator |
| + character in the arguments to an instruction */ |
| +int |
| +nios2_print_insn_arg (const char *argptr, |
| + unsigned long opcode, bfd_vma address, |
| + disassemble_info * info) |
| +{ |
| + unsigned long i = 0; |
| + unsigned long reg_base; |
| + |
| + assert (argptr != NULL); |
| + assert (info != NULL); |
| + |
| + switch (*argptr) |
| + { |
| + case ',': |
| + case '(': |
| + case ')': |
| + (*info->fprintf_func) (info->stream, "%c", *argptr); |
| + break; |
| + case 'd': |
| + i = GET_INSN_FIELD (RRD, opcode); |
| + |
| + if (GET_INSN_FIELD (OP, opcode) == OP_MATCH_CUSTOM |
| + && GET_INSN_FIELD (CUSTOM_C, opcode) == 0) |
| + reg_base = COPROCREGBASE; |
| + else |
| + reg_base = 0; |
| + |
| + if (i < NUMREGNAMES) |
| + (*info->fprintf_func) (info->stream, "%s", |
| + nios2_regs[i + reg_base].name); |
| + else |
| + (*info->fprintf_func) (info->stream, "unknown"); |
| + break; |
| + case 's': |
| + i = GET_INSN_FIELD (RRS, opcode); |
| + |
| + if (GET_INSN_FIELD (OP, opcode) == OP_MATCH_CUSTOM |
| + && GET_INSN_FIELD (CUSTOM_A, opcode) == 0) |
| + reg_base = COPROCREGBASE; |
| + else |
| + reg_base = 0; |
| + |
| + if (i < NUMREGNAMES) |
| + (*info->fprintf_func) (info->stream, "%s", |
| + nios2_regs[i + reg_base].name); |
| + else |
| + (*info->fprintf_func) (info->stream, "unknown"); |
| + break; |
| + case 't': |
| + i = GET_INSN_FIELD (RRT, opcode); |
| + |
| + if (GET_INSN_FIELD (OP, opcode) == OP_MATCH_CUSTOM |
| + && GET_INSN_FIELD (CUSTOM_B, opcode) == 0) |
| + reg_base = COPROCREGBASE; |
| + else |
| + reg_base = 0; |
| + |
| + if (i < NUMREGNAMES) |
| + (*info->fprintf_func) (info->stream, "%s", |
| + nios2_regs[i + reg_base].name); |
| + else |
| + (*info->fprintf_func) (info->stream, "unknown"); |
| + break; |
| + case 'i': |
| + /* 16-bit signed immediate */ |
| + i = (signed) (GET_INSN_FIELD (IMM16, opcode) << 16) >> 16; |
| + (*info->fprintf_func) (info->stream, "%d", (int) i); |
| + break; |
| + case 'u': |
| + /* 16-bit unsigned immediate */ |
| + i = GET_INSN_FIELD (IMM16, opcode); |
| + (*info->fprintf_func) (info->stream, "%d", (int) i); |
| + break; |
| + case 'o': |
| + /* 16-bit signed immediate address offset */ |
| + i = (signed) (GET_INSN_FIELD (IMM16, opcode) << 16) >> 16; |
| + address = address + 4 + i; /* NG changed to byte offset 1/9/03 */ |
| + (*info->print_address_func) (address, info); |
| + break; |
| + case 'p': |
| + /* 5-bit unsigned immediate */ |
| + i = GET_INSN_FIELD (CACHE_OPX, opcode); |
| + (*info->fprintf_func) (info->stream, "%d", (int) i); |
| + break; |
| + case 'j': |
| + /* 5-bit unsigned immediate */ |
| + i = GET_INSN_FIELD (IMM5, opcode); |
| + (*info->fprintf_func) (info->stream, "%d", (int) i); |
| + break; |
| + case 'l': |
| + /* 8-bit unsigned immediate */ |
| + /* FIXME - not yet implemented */ |
| + i = GET_INSN_FIELD (CUSTOM_N, opcode); |
| + (*info->fprintf_func) (info->stream, "%u", (int) i); |
| + break; |
| + case 'm': |
| + /* 26-bit unsigned immediate */ |
| + i = GET_INSN_FIELD (IMM26, opcode); |
| + /* this translates to an address because its only used in call instructions */ |
| + address = (address & 0xf0000000) | (i << 2); |
| + (*info->print_address_func) (address, info); |
| + break; |
| + case 'c': |
| + i = GET_INSN_FIELD (IMM5, opcode); /* ctrl register index */ |
| + (*info->fprintf_func) (info->stream, "%s", |
| + nios2_regs[CTLREGBASE + i].name); |
| + break; |
| + case 'b': |
| + i = GET_INSN_FIELD (IMM5, opcode); |
| + (*info->fprintf_func) (info->stream, "%d", (int) i); |
| + break; |
| + default: |
| + (*info->fprintf_func) (info->stream, "unknown"); |
| + break; |
| + } |
| + return 0; |
| +} |
| diff --git a/opcodes/nios2-opc.c b/opcodes/nios2-opc.c |
| new file mode 100644 |
| index 0000000..c860207 |
| --- /dev/null |
| +++ b/opcodes/nios2-opc.c |
| @@ -0,0 +1,320 @@ |
| +/* nios2-opc.c -- Altera New Jersey opcode list. |
| + |
| + Copyright (C) 2003 |
| + by Nigel Gray (ngray@altera.com). |
| + |
| +This file is part of GDB, GAS, and the GNU binutils. |
| + |
| +GDB, GAS, and the GNU binutils are free software; you can redistribute |
| +them and/or modify them under the terms of the GNU General Public |
| +License as published by the Free Software Foundation; either version |
| +1, or (at your option) any later version. |
| + |
| +GDB, GAS, and the GNU binutils are distributed in the hope that they |
| +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 file; see the file COPYING. If not, write to the Free |
| +Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ |
| + |
| +#include <stdio.h> |
| +#include "opcode/nios2.h" |
| + |
| +/* Register string table */ |
| + |
| +const struct nios2_reg nios2_builtin_regs[] = { |
| + {"zero", 0}, |
| + {"at", 1}, // assembler temporary |
| + {"r2", 2}, |
| + {"r3", 3}, |
| + {"r4", 4}, |
| + {"r5", 5}, |
| + {"r6", 6}, |
| + {"r7", 7}, |
| + {"r8", 8}, |
| + {"r9", 9}, |
| + {"r10", 10}, |
| + {"r11", 11}, |
| + {"r12", 12}, |
| + {"r13", 13}, |
| + {"r14", 14}, |
| + {"r15", 15}, |
| + {"r16", 16}, |
| + {"r17", 17}, |
| + {"r18", 18}, |
| + {"r19", 19}, |
| + {"r20", 20}, |
| + {"r21", 21}, |
| + {"r22", 22}, |
| + {"r23", 23}, |
| + {"et", 24}, |
| + {"bt", 25}, |
| + {"gp", 26}, /* global pointer */ |
| + {"sp", 27}, /* stack pointer */ |
| + {"fp", 28}, /* frame pointer */ |
| + {"ea", 29}, /* exception return address */ |
| + {"ba", 30}, /* breakpoint return address */ |
| + {"ra", 31}, /* return address */ |
| + |
| + /* alternative names for special registers */ |
| + {"r0", 0}, |
| + {"r1", 1}, |
| + {"r24", 24}, |
| + {"r25", 25}, |
| + {"r26", 26}, |
| + {"r27", 27}, |
| + {"r28", 28}, |
| + {"r29", 29}, |
| + {"r30", 30}, |
| + {"r31", 31}, |
| + |
| + /* control register names */ |
| + {"status", 0}, |
| + {"estatus", 1}, |
| + {"bstatus", 2}, |
| + {"ienable", 3}, |
| + {"ipending", 4}, |
| + {"cpuid", 5}, |
| + {"ctl6", 6}, |
| + {"ctl7", 7}, |
| + {"pteaddr", 8}, |
| + {"tlbacc", 9}, |
| + {"tlbmisc", 10}, |
| + {"fstatus", 11}, |
| + {"ctl12", 12}, |
| + {"ctl13", 13}, |
| + {"ctl14", 14}, |
| + {"ctl15", 15}, |
| + {"ctl16", 16}, |
| + {"ctl17", 17}, |
| + {"ctl18", 18}, |
| + {"ctl19", 19}, |
| + {"ctl20", 20}, |
| + {"ctl21", 21}, |
| + {"ctl22", 22}, |
| + {"ctl23", 23}, |
| + {"ctl24", 24}, |
| + {"ctl25", 25}, |
| + {"ctl26", 26}, |
| + {"ctl27", 27}, |
| + {"ctl28", 28}, |
| + {"ctl29", 29}, |
| + {"ctl30", 30}, |
| + {"ctl31", 31}, |
| + |
| + /* alternative names for special control registers */ |
| + {"ctl0", 0}, |
| + {"ctl1", 1}, |
| + {"ctl2", 2}, |
| + {"ctl3", 3}, |
| + {"ctl4", 4}, |
| + {"ctl5", 5}, |
| + {"ctl8", 8}, |
| + {"ctl9", 9}, |
| + {"ctl10", 10}, |
| + {"ctl11", 11}, |
| + |
| + /* coprocessor register names */ |
| + {"c0", 0}, |
| + {"c1", 1}, |
| + {"c2", 2}, |
| + {"c3", 3}, |
| + {"c4", 4}, |
| + {"c5", 5}, |
| + {"c6", 6}, |
| + {"c7", 7}, |
| + {"c8", 8}, |
| + {"c9", 9}, |
| + {"c10", 10}, |
| + {"c11", 11}, |
| + {"c12", 12}, |
| + {"c13", 13}, |
| + {"c14", 14}, |
| + {"c15", 15}, |
| + {"c16", 16}, |
| + {"c17", 17}, |
| + {"c18", 18}, |
| + {"c19", 19}, |
| + {"c20", 20}, |
| + {"c21", 21}, |
| + {"c22", 22}, |
| + {"c23", 23}, |
| + {"c24", 24}, |
| + {"c25", 25}, |
| + {"c26", 26}, |
| + {"c27", 27}, |
| + {"c28", 28}, |
| + {"c29", 29}, |
| + {"c30", 30}, |
| + {"c31", 31}, |
| +}; |
| + |
| +#define NIOS2_NUM_REGS \ |
| + ((sizeof nios2_builtin_regs) / (sizeof (nios2_builtin_regs[0]))) |
| +const int nios2_num_builtin_regs = NIOS2_NUM_REGS; |
| + |
| +/* const removed from the following to allow for dynamic extensions to the |
| + * built-in instruction set. */ |
| +struct nios2_reg *nios2_regs = (struct nios2_reg *) nios2_builtin_regs; |
| +int nios2_num_regs = NIOS2_NUM_REGS; |
| +#undef NIOS2_NUM_REGS |
| + |
| +/* overflow message string templates */ |
| + |
| +char *overflow_msgs[] = { |
| + "call target address 0x%08x out of range 0x%08x to 0x%08x", |
| + "branch offset %d out of range %d to %d", |
| + "%s offset %d out of range %d to %d", |
| + "immediate value %d out of range %d to %d", |
| + "immediate value %u out of range %u to %u", |
| + "immediate value %u out of range %u to %u", |
| + "custom instruction opcode %u out of range %u to %u", |
| +}; |
| + |
| + |
| + |
| +/*-------------------------------------------------------------------------------- |
| + This is the opcode table used by the New Jersey GNU as, disassembler and GDB |
| + --------------------------------------------------------------------------------*/ |
| + |
| +/* |
| + The following letters can appear in the args field of the nios2_opcode |
| + structure: |
| + |
| + c - a 5-bit control register index or break opcode |
| + d - a 5-bit destination register index |
| + s - a 5-bit left source register index |
| + t - a 5-bit right source register index |
| + i - a 16-bit signed immediate |
| + u - a 16-bit unsigned immediate |
| + |
| + j - a 5-bit unsigned immediate |
| + k - a 6-bit unsigned immediate |
| + l - an 8-bit unsigned immediate |
| + m - a 26-bit unsigned immediate |
| +*/ |
| + |
| +/* *INDENT-OFF* */ |
| +/* FIXME: Re-format for GNU standards */ |
| +const struct nios2_opcode nios2_builtin_opcodes[] = |
| +{ |
| + /* name, args, args_test num_args, match, mask, pinfo */ |
| + {"add", "d,s,t", "d,s,t,E", 3, OP_MATCH_ADD, OP_MASK_ROPX | OP_MASK_ROP, 0, no_overflow }, |
| + {"addi", "t,s,i", "t,s,i,E", 3, OP_MATCH_ADDI, OP_MASK_IOP, NIOS2_INSN_ADDI, signed_immed16_overflow }, |
| + {"subi", "t,s,i", "t,s,i,E", 3, OP_MATCH_ADDI, OP_MASK_IOP, NIOS2_INSN_MACRO, signed_immed16_overflow }, |
| + {"and", "d,s,t", "d,s,t,E", 3, OP_MATCH_AND, OP_MASK_ROPX | OP_MASK_ROP, 0, no_overflow }, |
| + {"andhi", "t,s,u", "t,s,u,E", 3, OP_MATCH_ANDHI, OP_MASK_IOP, 0, unsigned_immed16_overflow }, |
| + {"andi", "t,s,u", "t,s,u,E", 3, OP_MATCH_ANDI, OP_MASK_IOP, NIOS2_INSN_ANDI, unsigned_immed16_overflow }, |
| + {"beq", "s,t,o", "s,t,o,E", 3, OP_MATCH_BEQ, OP_MASK_IOP, NIOS2_INSN_CBRANCH, branch_target_overflow }, |
| + {"bge", "s,t,o", "s,t,o,E", 3, OP_MATCH_BGE, OP_MASK_IOP, NIOS2_INSN_CBRANCH, branch_target_overflow }, |
| + {"bgeu", "s,t,o", "s,t,o,E", 3, OP_MATCH_BGEU, OP_MASK_IOP, NIOS2_INSN_CBRANCH, branch_target_overflow }, |
| + {"bgt", "s,t,o", "s,t,o,E", 3, OP_MATCH_BLT, OP_MASK_IOP, NIOS2_INSN_MACRO|NIOS2_INSN_CBRANCH, branch_target_overflow }, |
| + {"bgtu", "s,t,o", "s,t,o,E", 3, OP_MATCH_BLTU, OP_MASK_IOP, NIOS2_INSN_MACRO|NIOS2_INSN_CBRANCH, branch_target_overflow }, |
| + {"ble", "s,t,o", "s,t,o,E", 3, OP_MATCH_BGE, OP_MASK_IOP, NIOS2_INSN_MACRO|NIOS2_INSN_CBRANCH, branch_target_overflow }, |
| + {"bleu", "s,t,o", "s,t,o,E", 3, OP_MATCH_BGEU, OP_MASK_IOP, NIOS2_INSN_MACRO|NIOS2_INSN_CBRANCH, branch_target_overflow }, |
| + {"blt", "s,t,o", "s,t,o,E", 3, OP_MATCH_BLT, OP_MASK_IOP, NIOS2_INSN_CBRANCH, branch_target_overflow }, |
| + {"bltu", "s,t,o", "s,t,o,E", 3, OP_MATCH_BLTU, OP_MASK_IOP, NIOS2_INSN_CBRANCH, branch_target_overflow }, |
| + {"bne", "s,t,o", "s,t,o,E", 3, OP_MATCH_BNE, OP_MASK_IOP, NIOS2_INSN_CBRANCH, branch_target_overflow }, |
| + {"br", "o", "o,E", 1, OP_MATCH_BR, OP_MASK_IOP, NIOS2_INSN_UBRANCH, branch_target_overflow }, |
| + {"break", "b", "b,E", 1, OP_MATCH_BREAK, OP_MASK_BREAK, 0, no_overflow }, |
| + {"bret", "", "E", 0, OP_MATCH_BRET, OP_MASK, 0, no_overflow }, |
| + {"flushd", "i(s)", "i(s)E", 2, OP_MATCH_FLUSHD, OP_MASK_IOP, 0, signed_immed16_overflow }, |
| + {"flushda", "i(s)", "i(s)E", 2, OP_MATCH_FLUSHDA, OP_MASK_IOP, 0, signed_immed16_overflow }, |
| + {"flushi", "s", "s,E", 1, OP_MATCH_FLUSHI, OP_MASK_FLUSHI, 0, no_overflow }, |
| + {"flushp", "", "E", 0, OP_MATCH_FLUSHP, OP_MASK, 0, no_overflow }, |
| + {"initd", "i(s)", "i(s)E", 2, OP_MATCH_INITD, OP_MASK_IOP, 0, signed_immed16_overflow }, |
| + {"initi", "s", "s,E", 1, OP_MATCH_INITI, OP_MASK_INITI, 0, no_overflow }, |
| + {"call", "m", "m,E", 1, OP_MATCH_CALL, OP_MASK_IOP, NIOS2_INSN_CALL, call_target_overflow }, |
| + {"callr", "s", "s,E", 1, OP_MATCH_CALLR, OP_MASK_CALLR, 0, no_overflow }, |
| + {"cmpeq", "d,s,t", "d,s,t,E", 3, OP_MATCH_CMPEQ, OP_MASK_ROPX | OP_MASK_ROP, 0, no_overflow }, |
| + {"cmpeqi", "t,s,i", "t,s,i,E", 3, OP_MATCH_CMPEQI, OP_MASK_IOP, 0, signed_immed16_overflow }, |
| + {"cmpge", "d,s,t", "d,s,t,E", 3, OP_MATCH_CMPGE, OP_MASK_ROPX | OP_MASK_ROP, 0, no_overflow }, |
| + {"cmpgei", "t,s,i", "t,s,i,E", 3, OP_MATCH_CMPGEI, OP_MASK_IOP, 0, signed_immed16_overflow }, |
| + {"cmpgeu", "d,s,t", "d,s,t,E", 3, OP_MATCH_CMPGEU, OP_MASK_ROPX | OP_MASK_ROP, 0, no_overflow }, |
| + {"cmpgeui", "t,s,u", "t,s,u,E", 3, OP_MATCH_CMPGEUI, OP_MASK_IOP, 0, unsigned_immed16_overflow }, |
| + {"cmpgt", "d,s,t", "d,s,t,E", 3, OP_MATCH_CMPLT, OP_MASK_ROPX | OP_MASK_ROP, NIOS2_INSN_MACRO, no_overflow }, |
| + {"cmpgti", "t,s,i", "t,s,i,E", 3, OP_MATCH_CMPGEI, OP_MASK_IOP, NIOS2_INSN_MACRO, signed_immed16_overflow }, |
| + {"cmpgtu", "d,s,t", "d,s,t,E", 3, OP_MATCH_CMPLTU, OP_MASK_ROPX | OP_MASK_ROP, NIOS2_INSN_MACRO, no_overflow }, |
| + {"cmpgtui", "t,s,u", "t,s,u,E", 3, OP_MATCH_CMPGEUI, OP_MASK_IOP, NIOS2_INSN_MACRO, unsigned_immed16_overflow }, |
| + {"cmple", "d,s,t", "d,s,t,E", 3, OP_MATCH_CMPGE, OP_MASK_ROPX | OP_MASK_ROP, NIOS2_INSN_MACRO, no_overflow }, |
| + {"cmplei", "t,s,i", "t,s,i,E", 3, OP_MATCH_CMPLTI, OP_MASK_IOP, NIOS2_INSN_MACRO, signed_immed16_overflow }, |
| + {"cmpleu", "d,s,t", "d,s,t,E", 3, OP_MATCH_CMPGEU, OP_MASK_ROPX | OP_MASK_ROP, NIOS2_INSN_MACRO, no_overflow }, |
| + {"cmpleui", "t,s,u", "t,s,u,E", 3, OP_MATCH_CMPLTUI, OP_MASK_IOP, NIOS2_INSN_MACRO, unsigned_immed16_overflow }, |
| + {"cmplt", "d,s,t", "d,s,t,E", 3, OP_MATCH_CMPLT, OP_MASK_ROPX | OP_MASK_ROP, 0, no_overflow }, |
| + {"cmplti", "t,s,i", "t,s,i,E", 3, OP_MATCH_CMPLTI, OP_MASK_IOP, 0, signed_immed16_overflow }, |
| + {"cmpltu", "d,s,t", "d,s,t,E", 3, OP_MATCH_CMPLTU, OP_MASK_ROPX | OP_MASK_ROP, 0, no_overflow }, |
| + {"cmpltui", "t,s,u", "t,s,u,E", 3, OP_MATCH_CMPLTUI, OP_MASK_IOP, 0, unsigned_immed16_overflow }, |
| + {"cmpne", "d,s,t", "d,s,t,E", 3, OP_MATCH_CMPNE, OP_MASK_ROPX | OP_MASK_ROP, 0, no_overflow }, |
| + {"cmpnei", "t,s,i", "t,s,i,E", 3, OP_MATCH_CMPNEI, OP_MASK_IOP, 0, signed_immed16_overflow }, |
| + {"div", "d,s,t", "d,s,t,E", 3, OP_MATCH_DIV, OP_MASK_ROPX | OP_MASK_ROP, 0, no_overflow }, |
| + {"divu", "d,s,t", "d,s,t,E", 3, OP_MATCH_DIVU, OP_MASK_ROPX | OP_MASK_ROP, 0, no_overflow }, |
| + {"jmp", "s", "s,E", 1, OP_MATCH_JMP, OP_MASK_JMP, 0, no_overflow }, |
| + {"jmpi", "m", "m,E", 1, OP_MATCH_JMPI, OP_MASK_IOP, 0, no_overflow }, |
| + {"ldb", "t,i(s)", "t,i(s)E", 3, OP_MATCH_LDB, OP_MASK_IOP, 0, address_offset_overflow }, |
| + {"ldbio", "t,i(s)", "t,i(s)E", 3, OP_MATCH_LDBIO, OP_MASK_IOP, 0, address_offset_overflow }, |
| + {"ldbu", "t,i(s)", "t,i(s)E", 3, OP_MATCH_LDBU, OP_MASK_IOP, 0, address_offset_overflow }, |
| + {"ldbuio", "t,i(s)", "t,i(s)E", 3, OP_MATCH_LDBUIO, OP_MASK_IOP, 0, address_offset_overflow }, |
| + {"ldh", "t,i(s)", "t,i(s)E", 3, OP_MATCH_LDH, OP_MASK_IOP, 0, address_offset_overflow }, |
| + {"ldhio", "t,i(s)", "t,i(s)E", 3, OP_MATCH_LDHIO, OP_MASK_IOP, 0, address_offset_overflow }, |
| + {"ldhu", "t,i(s)", "t,i(s)E", 3, OP_MATCH_LDHU, OP_MASK_IOP, 0, address_offset_overflow }, |
| + {"ldhuio", "t,i(s)", "t,i(s)E", 3, OP_MATCH_LDHUIO, OP_MASK_IOP, 0, address_offset_overflow }, |
| + {"ldw", "t,i(s)", "t,i(s)E", 3, OP_MATCH_LDW, OP_MASK_IOP, 0, address_offset_overflow }, |
| + {"ldwio", "t,i(s)", "t,i(s)E", 3, OP_MATCH_LDWIO, OP_MASK_IOP, 0, address_offset_overflow }, |
| + {"mov", "d,s", "d,s,E", 2, OP_MATCH_ADD, OP_MASK_RRT|OP_MASK_ROPX|OP_MASK_ROP, NIOS2_INSN_MACRO_MOV, no_overflow }, |
| + {"movhi", "t,u", "t,u,E", 2, OP_MATCH_ORHI, OP_MASK_IRS|OP_MASK_IOP, NIOS2_INSN_MACRO_MOVI, unsigned_immed16_overflow }, |
| + {"movui", "t,u", "t,u,E", 2, OP_MATCH_ORI, OP_MASK_IRS|OP_MASK_IOP, NIOS2_INSN_MACRO_MOVI, unsigned_immed16_overflow }, |
| + {"movi", "t,i", "t,i,E", 2, OP_MATCH_ADDI, OP_MASK_IRS|OP_MASK_IOP, NIOS2_INSN_MACRO_MOVI, signed_immed16_overflow }, |
| + /* movia expands to two instructions so there is no mask or match */ |
| + {"movia", "t,o", "t,o,E", 2, OP_MATCH_ORHI, OP_MASK_IOP, NIOS2_INSN_MACRO_MOVIA, no_overflow }, |
| + {"mul", "d,s,t", "d,s,t,E", 3, OP_MATCH_MUL, OP_MASK_ROPX | OP_MASK_ROP, 0, no_overflow }, |
| + {"muli", "t,s,i", "t,s,i,E", 3, OP_MATCH_MULI, OP_MASK_IOP, 0, signed_immed16_overflow }, |
| + {"mulxss", "d,s,t", "d,s,t,E", 3, OP_MATCH_MULXSS, OP_MASK_ROPX | OP_MASK_ROP, 0, no_overflow }, |
| + {"mulxsu", "d,s,t", "d,s,t,E", 3, OP_MATCH_MULXSU, OP_MASK_ROPX | OP_MASK_ROP, 0, no_overflow }, |
| + {"mulxuu", "d,s,t", "d,s,t,E", 3, OP_MATCH_MULXUU, OP_MASK_ROPX | OP_MASK_ROP, 0, no_overflow }, |
| + {"nextpc", "d", "d,E", 1, OP_MATCH_NEXTPC, OP_MASK_NEXTPC, 0, no_overflow }, |
| + {"nop", "", "E", 0, OP_MATCH_ADD, OP_MASK, NIOS2_INSN_MACRO_MOV, no_overflow }, |
| + {"nor", "d,s,t", "d,s,t,E", 3, OP_MATCH_NOR, OP_MASK_ROPX | OP_MASK_ROP, 0, no_overflow }, |
| + {"or", "d,s,t", "d,s,t,E", 3, OP_MATCH_OR, OP_MASK_ROPX | OP_MASK_ROP, 0, no_overflow }, |
| + {"orhi", "t,s,u", "t,s,u,E", 3, OP_MATCH_ORHI, OP_MASK_IOP, 0, unsigned_immed16_overflow }, |
| + {"ori", "t,s,u", "t,s,u,E", 3, OP_MATCH_ORI, OP_MASK_IOP, NIOS2_INSN_ORI, unsigned_immed16_overflow }, |
| + {"rdctl", "d,c", "d,c,E", 2, OP_MATCH_RDCTL, OP_MASK_RDCTL, 0, no_overflow }, |
| + {"ret", "", "E", 0, OP_MATCH_RET, OP_MASK, 0, no_overflow }, |
| + {"rol", "d,s,t", "d,s,t,E", 3, OP_MATCH_ROL, OP_MASK_ROPX | OP_MASK_ROP, 0, no_overflow }, |
| + {"roli", "d,s,j", "d,s,j,E", 3, OP_MATCH_ROLI, OP_MASK_ROLI, 0, unsigned_immed5_overflow }, |
| + {"ror", "d,s,t", "d,s,t,E", 3, OP_MATCH_ROR, OP_MASK_ROPX | OP_MASK_ROP, 0, no_overflow }, |
| + {"sll", "d,s,t", "d,s,t,E", 3, OP_MATCH_SLL, OP_MASK_ROPX | OP_MASK_ROP, 0, no_overflow }, |
| + {"slli", "d,s,j", "d,s,j,E", 3, OP_MATCH_SLLI, OP_MASK_SLLI, 0, unsigned_immed5_overflow }, |
| + {"sra", "d,s,t", "d,s,t,E", 3, OP_MATCH_SRA, OP_MASK_ROPX | OP_MASK_ROP, 0, no_overflow }, |
| + {"srai", "d,s,j", "d,s,j,E", 3, OP_MATCH_SRAI, OP_MASK_SRAI, 0, unsigned_immed5_overflow }, |
| + {"srl", "d,s,t", "d,s,t,E", 3, OP_MATCH_SRL, OP_MASK_ROPX | OP_MASK_ROP, 0, no_overflow }, |
| + {"srli", "d,s,j", "d,s,j,E", 3, OP_MATCH_SRLI, OP_MASK_SRLI, 0, unsigned_immed5_overflow }, |
| + {"stb", "t,i(s)", "t,i(s)E", 3, OP_MATCH_STB, OP_MASK_IOP, 0, address_offset_overflow }, |
| + {"stbio", "t,i(s)", "t,i(s)E", 3, OP_MATCH_STBIO, OP_MASK_IOP, 0, address_offset_overflow }, |
| + {"sth", "t,i(s)", "t,i(s)E", 3, OP_MATCH_STH, OP_MASK_IOP, 0, address_offset_overflow }, |
| + {"sthio", "t,i(s)", "t,i(s)E", 3, OP_MATCH_STHIO, OP_MASK_IOP, 0, address_offset_overflow }, |
| + {"stw", "t,i(s)", "t,i(s)E", 3, OP_MATCH_STW, OP_MASK_IOP, 0, address_offset_overflow }, |
| + {"stwio", "t,i(s)", "t,i(s)E", 3, OP_MATCH_STWIO, OP_MASK_IOP, 0, address_offset_overflow }, |
| + {"sub", "d,s,t", "d,s,t,E", 3, OP_MATCH_SUB, OP_MASK_ROPX | OP_MASK_ROP, 0, no_overflow }, |
| + {"sync", "", "E", 0, OP_MATCH_SYNC, OP_MASK_SYNC, 0, no_overflow }, |
| + {"trap", "", "E", 0, OP_MATCH_TRAP, OP_MASK_TRAP, 0, no_overflow }, |
| + {"eret", "", "E", 0, OP_MATCH_ERET, OP_MASK, 0, no_overflow }, |
| + {"custom", "l,d,s,t", "l,d,s,t,E", 4, OP_MATCH_CUSTOM, OP_MASK_ROP, 0, custom_opcode_overflow }, |
| + {"wrctl", "c,s", "c,s,E", 2, OP_MATCH_WRCTL, OP_MASK_WRCTL, 0, no_overflow }, |
| + {"xor", "d,s,t", "d,s,t,E", 3, OP_MATCH_XOR, OP_MASK_ROPX | OP_MASK_ROP, 0, no_overflow }, |
| + {"xorhi", "t,s,u", "t,s,u,E", 3, OP_MATCH_XORHI, OP_MASK_IOP, 0, unsigned_immed16_overflow }, |
| + {"xori", "t,s,u", "t,s,u,E", 3, OP_MATCH_XORI, OP_MASK_IOP, NIOS2_INSN_XORI, unsigned_immed16_overflow } |
| +}; |
| +/* *INDENT-ON* */ |
| + |
| +#define NIOS2_NUM_OPCODES \ |
| + ((sizeof nios2_builtin_opcodes) / (sizeof (nios2_builtin_opcodes[0]))) |
| +const int bfd_nios2_num_builtin_opcodes = NIOS2_NUM_OPCODES; |
| + |
| +/* const removed from the following to allow for dynamic extensions to the |
| + * built-in instruction set. */ |
| +struct nios2_opcode *nios2_opcodes = |
| + (struct nios2_opcode *) nios2_builtin_opcodes; |
| +int bfd_nios2_num_opcodes = NIOS2_NUM_OPCODES; |
| +#undef NIOS2_NUM_OPCODES |