/* tc-hppa.h -- Header file for the PA */

/* Copyright (C) 1989 Free Software Foundation, Inc.

This file is part of GAS, the GNU Assembler.

GAS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.

GAS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with GAS; see the file COPYING.  If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */


/*
   HP PA-RISC support was contributed by the Center for Software Science
   at the University of Utah.
 */

#ifndef _TC_HPPA_H
#define _TC_HPPA_H

#ifndef TC_HPPA
#define TC_HPPA	1
#endif

#define TARGET_ARCH bfd_arch_hppa
#define TARGET_FORMAT "elf-big"

#define ASEC_NULL (asection *)0

/* We can do sym1 - sym2 as long as sym2 is $global$ */

#define SEG_DIFF_ALLOWED

typedef enum FPOF { SGL, DBL, ILLEGAL_FMT, QUAD } FP_Operand_Format;

extern char *expr_end;

extern void s_globl(), s_long(), s_short(), s_space(), cons();
extern void stringer();
extern unsigned int next_char_of_string();

int pa_parse_number();

int pa_parse_fp_cmp_cond();

FP_Operand_Format pa_parse_fp_format();

#ifdef __STDC__
int getExpression(char *str);
#else
int getExpression();
#endif

int getAbsoluteExpression();

int evaluateAbsolute();

int pa_build_arg_reloc();

unsigned int pa_align_arg_reloc();

void pa_skip();

int pa_parse_nullif();

int pa_parse_nonneg_cmpsub_cmpltr();

int pa_parse_neg_cmpsub_cmpltr();

int pa_parse_nonneg_add_cmpltr();

int pa_parse_neg_add_cmpltr();

int  pa_build_arg_reloc();

void s_seg(), s_proc(), s_data1();

void pa_block(),	pa_call(),	pa_call_args(),	pa_callinfo();
void pa_code(),		pa_comm(),	pa_copyright(),	pa_end();
void pa_enter();
void pa_entry(),	pa_equ(),	pa_exit(),	pa_export();
void pa_export_args(),	pa_import(),	pa_label(),	pa_leave();
void pa_origin(),	pa_proc(),	pa_procend(),	pa_space();
void pa_spnum(),	pa_subspace(),	pa_version();

extern const pseudo_typeS md_pseudo_table[];

/*
  PA-89 floating point registers are arranged like this:


  +--------------+--------------+
  |   0 or 16L   |  16 or 16R   |
  +--------------+--------------+
  |   1 or 17L   |  17 or 17R   |
  +--------------+--------------+
  |              |              |

  .              .              .
  .              .              .
  .              .              .

  |              |              |
  +--------------+--------------+
  |  14 or 30L   |  30 or 30R   |
  +--------------+--------------+
  |  15 or 31L   |  31 or 31R   |
  +--------------+--------------+


  The following is a version of pa_parse_number that
  handles the L/R notation and returns the correct
  value to put into the instruction register field.
  The correct value to put into the instruction is
  encoded in the structure 'pa_89_fp_reg_struct'.

 */

struct pa_89_fp_reg_struct {
  char number_part;
  char L_R_select;
};

int need_89_opcode();
int pa_89_parse_number();


/* pa-ctrl-func.h -- Control Structures and Functions for the PA */

extern unsigned int assemble_3( /* unsigned int x; */ );

extern void dis_assemble_3( /* unsigned int x, *r; */ );

extern unsigned int assemble_12( /* unsigned int x,y; */ );

extern void dis_assemble_12( /* unsigned int as12, *x,*y */ );

extern unsigned long assemble_17( /* unsigned int x,y,z */ );

extern void dis_assemble_17( /* unsigned int as17, *x,*y,*z */ );

extern unsigned long assemble_21( /* unsigned int x; */ );

extern void dis_assemble_21( /* unsigned int as21,*x; */ );

extern unsigned long sign_ext( /* unsigned int x,len; */ );

extern void sign_unext( /* unsigned int x,len; unsigned int *result */ );

extern unsigned long low_sign_ext( /* unsigned int x,len; */ );

extern void low_sign_unext( /* unsigned int x,len; unsigned int *result */ );

struct call_desc {
   unsigned int arg_reloc;
   unsigned int arg_count;
};

typedef struct call_desc call_descS;

extern call_descS last_call_desc;

/* GDB debug support */

#define GDB_DEBUG_SPACE_NAME "$GDB_DEBUG$"
#define GDB_STRINGS_SUBSPACE_NAME "$GDB_STRINGS$"
#define GDB_SYMBOLS_SUBSPACE_NAME "$GDB_SYMBOLS$"

/* pre-defined subsegments (subspaces) for the HP 9000 Series 800 */

#define SUBSEG_CODE   0
#define SUBSEG_DATA   0
#define SUBSEG_LIT    1
#define SUBSEG_BSS    2
#define SUBSEG_UNWIND 3
#define SUBSEG_GDB_STRINGS 0
#define SUBSEG_GDB_SYMBOLS 1

#define UNWIND_SECTION_NAME	".hppa_unwind"
/* subspace dictionary chain entry structure */

struct subspace_dictionary_chain {
#if defined(OBJ_OSFROSE) | defined(OBJ_ELF)
#ifdef OBJ_OSFROSE
	region_command_t * ssd_entry; /* XXX: not sure this is what we need here */
#else
	Elf_Internal_Shdr *ssd_entry;
	unsigned long	ssd_vm_addr;
#endif
	char * ssd_name;	/* used until time of writing object file	*/
	                        /* then we use ssd_entry->regc_region_name	*/
	unsigned char ssd_quadrant;
	unsigned char ssd_sort_key;
	unsigned char ssd_common;
	unsigned char ssd_dup_common;
	unsigned char ssd_loadable;
	unsigned char ssd_code_only;
#else
	subspace_dictS *ssd_entry;                /* this dictionary */
#endif
        int ssd_defined;                          /* this subspace has been used */
        int ssd_space_number;                     /* space # this subspace is in */
        asection * ssd_seg;                       /* this subspace =  this seg */
        int ssd_subseg;                           /*                  and subseg */
        int ssd_zero;
        int object_file_index;                    /* index of this entry within
                                                     the subspace dictionary of
                                                     the object file (not used until
                                                     the object file is written */
        int ssd_last_align;                       /* the size of the last alignment
                                                     request for this subspace */
        symbolS *ssd_start_sym;                   /* a symbol whose value is the
                                                     start of this subspace */
        struct subspace_dictionary_chain *ssd_next; /* next subspace dict. entry */
};

typedef struct subspace_dictionary_chain subspace_dict_chainS;

/* space dictionary chain entry structure */

struct space_dictionary_chain {
#ifdef OBJ_OSFROSE
	region_command_t * sd_entry; /* XXX: not sure this is what we need here */
	char * sd_name;		/* used until time of writing object file	*/
	                        /* then we use sd_entry->regc_region_name	*/
	unsigned int sd_loadable;
	unsigned int sd_private;
	unsigned int sd_spnum;
	unsigned char sd_sort_key;
#else
#ifdef OBJ_ELF
	Elf_Internal_Shdr *sd_entry;
	char * sd_name;		/* used until time of writing object file	*/
	                        /* then we use sd_entry->sh_name	*/
	unsigned int sd_loadable;
	unsigned int sd_private;
	unsigned int sd_spnum;
	unsigned char sd_sort_key;
#else
        space_dictS *sd_entry;                     /* this dictionary */
#endif
#endif
        int sd_defined;                            /* this space has been used */
        asection * sd_seg;      /* GAS segment to which this space corresponds */
        int sd_last_subseg;     /* current subsegment number we are using */
        subspace_dict_chainS *sd_subspaces;        /* all subspaces in this space */
        struct space_dictionary_chain *sd_next;    /* the next space dict. entry */
};

typedef struct space_dictionary_chain space_dict_chainS; 

/*
    Macros to maintain spaces and subspaces
 */

#ifdef OBJ_OSFROSE
#define SPACE_DEFINED(space_chain)	(space_chain)->sd_defined
#define SPACE_PRIVATE(space_chain)	(space_chain)->sd_private
#define SPACE_LOADABLE(space_chain)	(space_chain)->sd_loadable
#define SPACE_SPNUM(space_chain)	(space_chain)->sd_spnum
#define SPACE_SORT(space_chain)		(space_chain)->sd_sort_key
#define SPACE_NAME(space_chain)		(space_chain)->sd_name

#define SUBSPACE_QUADRANT(ss_chain)	(ss_chain)->ssd_quadrant
#define SUBSPACE_ALIGN(ss_chain)	(ss_chain)->ssd_entry->regc_addralign
#define SUBSPACE_ACCESS(ss_chain)	(ss_chain)->ssd_entry->regc_initprot
#define SUBSPACE_SORT(ss_chain)		(ss_chain)->ssd_sort_key
#define SUBSPACE_COMMON(ss_chain)	(ss_chain)->ssd_common
#define SUBSPACE_ZERO(ss_chain)		(ss_chain)->ssd_zero
#define SUBSPACE_DUP_COMM(ss_chain)	(ss_chain)->ssd_dup_common
#define SUBSPACE_CODE_ONLY(ssch)	((ssch)->ssd_entry->regc_flags & REG_TEXT_T)
#define SET_SUBSPACE_CODE_ONLY(ssch,val) (ssch)->ssd_entry->regc_flags |= ((val) ? REG_TEXT_T : 0)
#define SUBSPACE_LOADABLE(ss_chain)	(ss_chain)->ssd_loadable
#define SUBSPACE_SUBSPACE_START(ss_chain) (ss_chain)->ssd_entry->regc_addr.vm_addr
#define SUBSPACE_SUBSPACE_LENGTH(ss_chain) (ss_chain)->ssd_entry->regc_vm_size
#define SUBSPACE_REGION_NAME(ss_chain)	(ss_chain)->ssd_entry->regc_region_name
#define SUBSPACE_NAME(ss_chain)		(ss_chain)->ssd_name
#endif

#ifdef OBJ_ELF
#define SPACE_DEFINED(space_chain)	(space_chain)->sd_defined
#define SPACE_PRIVATE(space_chain)	(space_chain)->sd_private
#define SPACE_LOADABLE(space_chain)	(space_chain)->sd_loadable
#define SPACE_SPNUM(space_chain)	(space_chain)->sd_spnum
#define SPACE_SORT(space_chain)		(space_chain)->sd_sort_key
#define SPACE_NAME(space_chain)		(space_chain)->sd_name

#define SUBSPACE_QUADRANT(ss_chain)	(ss_chain)->ssd_quadrant
#define SUBSPACE_ALIGN(ss_chain)	(ss_chain)->ssd_entry->sh_addralign
#define SUBSPACE_ACCESS(ss_chain)	(ss_chain)->ssd_entry->sh_flags
#define SUBSPACE_SORT(ss_chain)		(ss_chain)->ssd_sort_key
#define SUBSPACE_COMMON(ss_chain)	(ss_chain)->ssd_common
#define SUBSPACE_ZERO(ss_chain)		(ss_chain)->ssd_zero
#define SUBSPACE_DUP_COMM(ss_chain)	(ss_chain)->ssd_dup_common
#define SUBSPACE_CODE_ONLY(ssch) \
	(((ssch)->ssd_entry->sh_flags & (SHF_ALLOC | SHF_EXECINSTR | SHF_WRITE)) \
	 == (SHF_ALLOC | SHF_EXECINSTR))
#define SET_SUBSPACE_CODE_ONLY(ssch,val) \
		(ssch)->ssd_entry->sh_flags &= ((val) ? ~SHF_WRITE : 0xffffffff)
#define SUBSPACE_LOADABLE(ss_chain)	(ss_chain)->ssd_loadable
#define SUBSPACE_SUBSPACE_START(ss_chain) (ss_chain)->ssd_vm_addr
#define SUBSPACE_SUBSPACE_LENGTH(ss_chain) (ss_chain)->ssd_entry->sh_size
#define SUBSPACE_NAME(ss_chain)		(ss_chain)->ssd_name
#endif

#ifdef OBJ_SOM
#define SPACE_DEFINED(space_chain)	(space_chain)->sd_entry->is_defined
#define SPACE_PRIVATE(space_chain)	(space_chain)->sd_entry->is_private
#define SPACE_LOADABLE(space_chain)	(space_chain)->sd_entry->is_loadable
#define SPACE_SPNUM(space_chain)	(space_chain)->sd_entry->space_number
#define SPACE_SORT(space_chain)		(space_chain)->sd_entry->sort_key
#define SPACE_NAME(space_chain)		(space_chain)->sd_entry->name

#define SUBSPACE_QUADRANT(ss_chain)	(ss_chain)->ssd_entry->quadrant
#define SUBSPACE_ALIGN(ss_chain)	(ss_chain)->ssd_entry->alignment
#define SUBSPACE_ACCESS(ss_chain)	(ss_chain)->ssd_entry->access_control_bits
#define SUBSPACE_SORT(ss_chain)		(ss_chain)->ssd_entry->sort_key
#define SUBSPACE_COMMON(ss_chain)	(ss_chain)->ssd_entry->is_common
#define SUBSPACE_ZERO(ss_chain)		(ss_chain)->ssd_zero
#define SUBSPACE_DUP_COMM(ss_chain)	(ss_chain)->ssd_entry->dup_common
#define SUBSPACE_CODE_ONLY(ss_chain)	(ss_chain)->ssd_entry->code_only
#define SUBSPACE_LOADABLE(ss_chain)	(ss_chain)->ssd_entry->is_loadable
#define SUBSPACE_SUBSPACE_START(ss_chain) (ss_chain)->ssd_entry->subspace_start
#define SUBSPACE_SUBSPACE_LENGTH(ss_chain) (ss_chain)->ssd_entry->subspace_length
#define SUBSPACE_NAME(ss_chain)		(ss_chain)->ssd_entry->name
#endif

extern space_dict_chainS *space_dict_root;
extern space_dict_chainS *space_dict_last;

extern space_dict_chainS *current_space;
extern subspace_dict_chainS *current_subspace;

extern space_dict_chainS *create_new_space();

extern subspace_dict_chainS *create_new_subspace();

extern subspace_dict_chainS *update_subspace();

extern space_dict_chainS *is_defined_space();

extern space_dict_chainS *pa_segment_to_space();

extern subspace_dict_chainS *is_defined_subspace();

extern subspace_dict_chainS *pa_subsegment_to_subspace();

extern space_dict_chainS *pa_find_space_by_number();

extern unsigned int pa_subspace_start();

extern int is_last_defined_subspace();

/* symbol support */

extern symbolS * pa_get_start_symbol();

extern symbolS * pa_set_start_symbol();

/* default space and subspace dictionaries */

struct default_subspace_dict {
     char *name;
     char defined;
     char loadable,code_only,common,dup_common,zero,sort;
     int access,space_index,alignment,quadrant;
#ifdef OBJ_SOM
     segT segment;
#else
     int def_space_index;  /* this is an index in the default spaces array */
#endif
     subsegT subsegment;
   };

extern struct default_subspace_dict pa_def_subspaces[];

struct default_space_dict {
     char *name;
     int spnum;
     char loadable;
     char defined;
     char private;
     char sort;
#ifdef OBJ_SOM
     segT segment;
#else
     asection * segment;
     char * alias;  /* an alias for this section (or NULL if there isn't one) */
#endif
   };

extern struct default_space_dict pa_def_spaces[];

/*
	Support for keeping track of the most recent label in each
	space.
 */

typedef struct label_symbol_struct {
	symbolS *lss_label;			/* the label symbol		*/
	space_dict_chainS *lss_space;		/* the space to which it applies*/
	struct label_symbol_struct *lss_next;	/* the next label symbol	*/
} label_symbolS;

extern label_symbolS *label_symbols_rootP;

label_symbolS *pa_get_label();
int pa_label_is_defined();
void pa_define_label();
void pa_undefine_label();
int pa_pseudo_op_moves_pc();

/* end of label symbol support. */

#define is_DP_relative(exp)  ( (exp).X_subtract_symbol		\
                              && strcmp((exp).X_subtract_symbol->bsym->name,	\
                                        "$global$") == 0 )

#define tc_crawl_symbol_chain(headers) {;}  /* Not used. */

#define tc_headers_hook(headers) {;}  /* Not used. */

#endif /* _TC_HPPA_H */
