This is hppa-aux.c in view mode; [Download] [Up]
/* hppa-aux.c -- Assembler for the PA - PA-RISC specific support routines 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. */ #include <stdio.h> #include <string.h> #include <ctype.h> #include "obstack.h" #include "as.h" #include "frags.h" #include "flonum.h" #include "expr.h" #include "hash.h" #include "md.h" #include "symbols.h" #include "messages.h" #include "hppa-aux.h" #include "stuff/hppa.h" extern char *expr_end; /* defined in hppa.c */ static const int print_errors = 1; static int reg_name_search( char *name); int pa_parse_number(s) char **s; { int num; char *name; char c; symbolS *sym; int status; char * p = *s; while ( *p == ' ' || *p == '\t' ) p = p + 1; num=-1; /* assume invalid number to begin with */ if (isdigit(*p)) { num = 0; /* now we know it is a number */ if ( *p == '0' && ( *(p+1) == 'x' || *(p+1) == 'X' ) ) { /* hex input */ p = p + 2; while ( isdigit(*p) || ( (*p >= 'a') && (*p <= 'f') ) || ( (*p >= 'A') && (*p <= 'F') ) ){ if ( isdigit(*p) ) num = num*16 + *p-'0'; else if ( *p >= 'a' && *p <= 'f' ) num = num*16 + *p-'a' + 10; else num = num*16 + *p-'A' + 10; ++p; } } else { while (isdigit(*p)) { num= num*10 + *p-'0'; ++p; } } } else if ( *p == '%' ) { /* could be a pre-defined register */ num = 0; name = p; p++; c = *p; /* * tege hack: Special case for general registers as the * general code makes a binary search with case translation, * and is VERY slow. */ if (c == 'r') { p++; if (!isdigit(*p)) as_bad("Undefined register: '%s'. ASSUMING 0",name); else { do num= num*10 + *p++ - '0'; while (isdigit(*p)); } } else { while ( is_part_of_name(c) ) { p = p + 1; c = *p; } /* Terminate string with \0. Restore below. */ *p = 0; status = reg_name_search(name); if ( status >= 0 ) num = status; else { if ( print_errors ) as_bad("Undefined register: '%s'. ASSUMING 0",name); else num = -1; } /* Restore orignal value of string. */ *p = c; } } else { num = 0; name = p; c = *p; while ( is_part_of_name(c) ) { p = p + 1; c = *p; } *p = 0; if ( (sym = symbol_find(name)) != NULL ) { if ( sym->sy_type == N_ABS && sym->sy_other == NO_SECT ) { num = sym->sy_value; } else { if ( print_errors ) as_bad("Non-absolute constant: '%s'. ASSUMING 0",name); else num = -1; } } else { if ( print_errors ) as_bad("Undefined absolute constant: '%s'. ASSUMING 0",name); else num = -1; } *p = c; } *s = p; return num; } struct pd_reg { char *name; int value; }; /* List of registers that are pre-defined: General Registers: Name Value Name Value %r0 0 %r16 16 %r1 1 %r17 17 %r2 2 %r18 18 %r3 3 %r19 19 %r4 4 %r20 20 %r5 5 %r21 21 %r6 6 %r22 22 %r7 7 %r23 23 %r8 8 %r24 24 %r9 9 %r25 25 %r10 10 %r26 26 %r11 11 %r27 27 %r12 12 %r28 28 %r13 13 %r29 29 %r14 14 %r30 30 %r15 15 %r31 31 Floating-point Registers: [NOTE: Also includes L and R versions of these (e.g. %fr19L, %fr19R)] Name Value Name Value %fr0 0 %fr16 16 %fr1 1 %fr17 17 %fr2 2 %fr18 18 %fr3 3 %fr19 19 %fr4 4 %fr20 20 %fr5 5 %fr21 21 %fr6 6 %fr22 22 %fr7 7 %fr23 23 %fr8 8 %fr24 24 %fr9 9 %fr25 25 %fr10 10 %fr26 26 %fr11 11 %fr27 27 %fr12 12 %fr28 28 %fr13 13 %fr29 29 %fr14 14 %fr30 30 %fr15 15 %fr31 31 Space Registers: Name Value Name Value %sr0 0 %sr4 4 %sr1 1 %sr5 5 %sr2 2 %sr6 6 %sr3 3 %sr7 7 Control registers and their synonyms: Names Value %cr0 %rctr 0 %cr8 %pidr1 8 %cr9 %pidr2 9 %cr10 %ccr 10 %cr11 %sar 11 %cr12 %pidr3 12 %cr13 %pidr4 13 %cr14 %iva 14 %cr15 %eiem 15 %cr16 %itmr 16 %cr17 %pcsq 17 %cr18 %pcoq 18 %cr19 %iir 19 %cr20 %isr 20 %cr21 %ior 21 %cr22 %ipsw 22 %cr23 %eirr 23 %cr24 %tr0 %ppda 24 %cr25 %tr1 %hta 25 %cr26 %tr2 26 %cr27 %tr3 27 %cr28 %tr4 28 %cr29 %tr5 29 %cr30 %tr6 30 %cr31 %tr7 31 */ /* This table is sorted. Suitable for searching by a binary search. */ static struct pd_reg pre_defined_registers[] = { { "%ccr", 10 }, { "%cr0", 0 }, { "%cr10", 10 }, { "%cr11", 11 }, { "%cr12", 12 }, { "%cr13", 13 }, { "%cr14", 14 }, { "%cr15", 15 }, { "%cr16", 16 }, { "%cr17", 17 }, { "%cr18", 18 }, { "%cr19", 19 }, { "%cr20", 20 }, { "%cr21", 21 }, { "%cr22", 22 }, { "%cr23", 23 }, { "%cr24", 24 }, { "%cr25", 25 }, { "%cr26", 26 }, { "%cr27", 27 }, { "%cr28", 28 }, { "%cr29", 29 }, { "%cr30", 30 }, { "%cr31", 31 }, { "%cr8", 8 }, { "%cr9", 9 }, { "%eiem", 15 }, { "%eirr", 23 }, { "%fr0", 0 }, { "%fr0L", 0 }, { "%fr0R", 0 }, { "%fr1", 1 }, { "%fr10", 10 }, { "%fr10L", 10 }, { "%fr10R", 10 }, { "%fr11", 11 }, { "%fr11L", 11 }, { "%fr11R", 11 }, { "%fr12", 12 }, { "%fr12L", 12 }, { "%fr12R", 12 }, { "%fr13", 13 }, { "%fr13L", 13 }, { "%fr13R", 13 }, { "%fr14", 14 }, { "%fr14L", 14 }, { "%fr14R", 14 }, { "%fr15", 15 }, { "%fr15L", 15 }, { "%fr15R", 15 }, { "%fr16", 16 }, { "%fr16L", 16 }, { "%fr16R", 16 }, { "%fr17", 17 }, { "%fr17L", 17 }, { "%fr17R", 17 }, { "%fr18", 18 }, { "%fr18L", 18 }, { "%fr18R", 18 }, { "%fr19", 19 }, { "%fr19L", 19 }, { "%fr19R", 19 }, { "%fr1L", 1 }, { "%fr1R", 1 }, { "%fr2", 2 }, { "%fr20", 20 }, { "%fr20L", 20 }, { "%fr20R", 20 }, { "%fr21", 21 }, { "%fr21L", 21 }, { "%fr21R", 21 }, { "%fr22", 22 }, { "%fr22L", 22 }, { "%fr22R", 22 }, { "%fr23", 23 }, { "%fr23L", 23 }, { "%fr23R", 23 }, { "%fr24", 24 }, { "%fr24L", 24 }, { "%fr24R", 24 }, { "%fr25", 25 }, { "%fr25L", 25 }, { "%fr25R", 25 }, { "%fr26", 26 }, { "%fr26L", 26 }, { "%fr26R", 26 }, { "%fr27", 27 }, { "%fr27L", 27 }, { "%fr27R", 27 }, { "%fr28", 28 }, { "%fr28L", 28 }, { "%fr28R", 28 }, { "%fr29", 29 }, { "%fr29L", 29 }, { "%fr29R", 29 }, { "%fr2L", 2 }, { "%fr2R", 2 }, { "%fr3", 3 }, { "%fr30", 30 }, { "%fr30L", 30 }, { "%fr30R", 30 }, { "%fr31", 31 }, { "%fr31L", 31 }, { "%fr31R", 31 }, { "%fr3L", 3 }, { "%fr3R", 3 }, { "%fr4", 4 }, { "%fr4L", 4 }, { "%fr4R", 4 }, { "%fr5", 5 }, { "%fr5L", 5 }, { "%fr5R", 5 }, { "%fr6", 6 }, { "%fr6L", 6 }, { "%fr6R", 6 }, { "%fr7", 7 }, { "%fr7L", 7 }, { "%fr7R", 7 }, { "%fr8", 8 }, { "%fr8L", 8 }, { "%fr8R", 8 }, { "%fr9", 9 }, { "%fr9L", 9 }, { "%fr9R", 9 }, { "%hta", 25 }, { "%iir", 19 }, { "%ior", 21 }, { "%ipsw", 22 }, { "%isr", 20 }, { "%itmr", 16 }, { "%iva", 14 }, { "%pcoq", 18 }, { "%pcsq", 17 }, { "%pidr1", 8 }, { "%pidr2", 9 }, { "%pidr3", 12 }, { "%pidr4", 13 }, { "%ppda", 24 }, { "%r0", 0 }, { "%r1", 1 }, { "%r10", 10 }, { "%r11", 11 }, { "%r12", 12 }, { "%r13", 13 }, { "%r14", 14 }, { "%r15", 15 }, { "%r16", 16 }, { "%r17", 17 }, { "%r18", 18 }, { "%r19", 19 }, { "%r2", 2 }, { "%r20", 20 }, { "%r21", 21 }, { "%r22", 22 }, { "%r23", 23 }, { "%r24", 24 }, { "%r25", 25 }, { "%r26", 26 }, { "%r27", 27 }, { "%r28", 28 }, { "%r29", 29 }, { "%r3", 3 }, { "%r30", 30 }, { "%r31", 31 }, { "%r4", 4 }, { "%r4L", 4 }, { "%r4R", 4 }, { "%r5", 5 }, { "%r5L", 5 }, { "%r5R", 5 }, { "%r6", 6 }, { "%r6L", 6 }, { "%r6R", 6 }, { "%r7", 7 }, { "%r7L", 7 }, { "%r7R", 7 }, { "%r8", 8 }, { "%r8L", 8 }, { "%r8R", 8 }, { "%r9", 9 }, { "%r9L", 9 }, { "%r9R", 9 }, { "%rctr", 0 }, { "%sar", 11 }, { "%sr0", 0 }, { "%sr1", 1 }, { "%sr2", 2 }, { "%sr3", 3 }, { "%sr4", 4 }, { "%sr5", 5 }, { "%sr6", 6 }, { "%sr7", 7 }, { "%tr0", 24 }, { "%tr1", 25 }, { "%tr2", 26 }, { "%tr3", 27 }, { "%tr4", 28 }, { "%tr5", 9 }, { "%tr6", 30 }, { "%tr7", 31 } }; #define REG_NAME_CNT (sizeof(pre_defined_registers) / sizeof(struct pd_reg)) static int reg_name_search( char *name) { int x,l,r; l = 0; r = REG_NAME_CNT - 1; do { x = (l + r) / 2; if (strcasecmp(name,pre_defined_registers[x].name) < 0) r = x - 1; else l = x + 1; } while ( !( (strcasecmp(name,pre_defined_registers[x].name) == 0) || (l > r) ) ); if ( strcasecmp(name,pre_defined_registers[x].name) == 0 ) return(pre_defined_registers[x].value); else return(-1); } static int is_R_select( char *s) { if ( *s == 'R' || *s == 'r' ) return(TRUE); else return(FALSE); } static int is_L_select( char *s) { if ( *s == 'L' || *s == 'l' ) return(TRUE); else return(FALSE); } int need_89_opcode(insn,result) struct pa_it *insn; struct pa_89_fp_reg_struct *result; { if ( result->L_R_select == 1 && !(insn->fpof1 == DBL && insn->fpof2 == DBL) ) return TRUE; else return FALSE; } int pa_89_parse_number(s,result) char **s; struct pa_89_fp_reg_struct *result; { int num; char *name; char c; symbolS *sym; int status; char * p = *s; while ( *p == ' ' || *p == '\t' ) p = p + 1; num=-1; /* assume invalid number to begin with */ result->number_part = -1; result->L_R_select = -1; if (isdigit(*p)) { num = 0; /* now we know it is a number */ if ( *p == '0' && ( *(p+1) == 'x' || *(p+1) == 'X' ) ) { /* hex input */ p = p + 2; while ( isdigit(*p) || ( (*p >= 'a') && (*p <= 'f') ) || ( (*p >= 'A') && (*p <= 'F') ) ){ if ( isdigit(*p) ) num = num*16 + *p-'0'; else if ( *p >= 'a' && *p <= 'f' ) num = num*16 + *p-'a' + 10; else num = num*16 + *p-'A' + 10; ++p; } } else { while (isdigit(*p)) { num= num*10 + *p-'0'; ++p; } } result->number_part = num; if ( is_R_select(p) ) { result->L_R_select = 1; ++p; } else if ( is_L_select(p) ) { result->L_R_select = 0; ++p; } else result->L_R_select = 0; } else if ( *p == '%' ) { /* could be a pre-defined register */ num = 0; name = p; p = p + 1; c = *p; /* tege hack: Special case for general registers as the general code makes a binary search with case translation, and is VERY slow. */ if (c == 'r') { p++; if (!isdigit(*p)) as_bad("Undefined register: '%s'. ASSUMING 0",name); else { do num= num*10 + *p++ - '0'; while (isdigit(*p)); } } else { while ( is_part_of_name(c) ) { p = p + 1; c = *p; } /* Terminate string with \0. Restore below. */ *p = 0; status = reg_name_search(name); if ( status >= 0 ) num = status; else { if ( print_errors ) as_bad("Undefined register: '%s'. ASSUMING 0",name); else num = -1; } *p = c; } result->number_part = num; if ( is_R_select(p-1) ) result->L_R_select = 1; else if ( is_L_select(p-1) ) result->L_R_select = 0; else result->L_R_select = 0; } else { num = 0; name = p; c = *p; while ( is_part_of_name(c) ) { p = p + 1; c = *p; } *p = 0; if ( (sym = symbol_find(name)) != NULL ) { if ( sym->sy_type == N_ABS && sym->sy_other == NO_SECT ) { num = sym->sy_value; } else { if ( print_errors ) as_bad("Non-absolute constant: '%s'. ASSUMING 0",name); else num = -1; } } else { if ( print_errors ) as_bad("Undefined absolute constant: '%s'. ASSUMING 0",name); else num = -1; } *p = c; result->number_part = num; if ( is_R_select(p-1) ) { result->L_R_select = 1; } else if ( is_L_select(p-1) ) { result->L_R_select = 0; } else result->L_R_select = 0; } *s = p; return num; } int pa_parse_fp_cmp_cond(s) char **s; { int cond,i; struct possibleS { char *string; int cond; }; /* This table is sorted by order of the length of the string. This is so we check for <> before we check for <. If we had a <> and checked for < first, we would get a false match. */ static struct possibleS poss[] = { { "false?", 0 }, { "false", 1 }, { "true?", 30 }, { "true", 31 }, { "!<=>", 3 }, { "!?>=", 8 }, { "!?<=", 16 }, { "!<>", 7 }, { "!>=", 11 }, { "!?>", 12 }, { "?<=", 14 }, { "!<=", 19 }, { "!?<", 20 }, { "?>=", 22 }, { "!?=", 24 }, { "!=t", 27 }, { "<=>", 29 }, { "=t", 5 }, { "?=", 6 }, { "?<", 10 }, { "<=", 13 }, { "!>", 15 }, { "?>", 18 }, { ">=", 21 }, { "!<", 23 }, { "<>", 25 }, { "!=", 26 }, { "!?", 28 }, { "?", 2 }, { "=", 4 }, { "<", 9 }, { ">", 17 } }; cond=0; for ( i = 0; i < 32; i++ ) { if ( strncasecmp(*s,poss[i].string,strlen(poss[i].string)) == 0 ) { cond = poss[i].cond; *s += strlen(poss[i].string); while ( **s == ' ' || **s == '\t' ) *s = *s + 1; return cond; } } as_bad("Illegal FP Compare Condition: %c",**s); return 0; } FP_Operand_Format pa_parse_fp_format(s) char **s; { int f; f = SGL; if ( **s == ',' ) { *s += 1; if ( strncasecmp(*s,"sgl",3) == 0 ) { f = SGL; *s += 4; } else if ( strncasecmp(*s,"dbl",3) == 0 ) { f = DBL; *s += 4; } else if ( strncasecmp(*s,"quad",4) == 0 ) { f = QUAD; *s += 5; } else { f = ILLEGAL_FMT; as_bad("Unrecognized FP Operand Format: %3s",*s); } } while ( **s == ' ' || **s == '\t' || **s == 0 ) *s = *s + 1; return f; } int getExpression( char *str) { char *save_in; segT seg; save_in = input_line_pointer; input_line_pointer = str; switch (seg = expression(&the_insn.exp)) { case SEG_ABSOLUTE: case SEG_SECT: case SEG_DIFFSECT: case SEG_UNKNOWN: case SEG_NONE: case SEG_BIG: break; default: the_insn.error = "illegal segment"; expr_end = input_line_pointer; input_line_pointer=save_in; return 1; } expr_end = input_line_pointer; input_line_pointer = save_in; return 0; } int getAbsoluteExpression( char *str) { char *save_in; segT seg; for ( ; *str == ' ' || *str == '\t' ; str++) ; /* do nothing */ save_in = input_line_pointer; input_line_pointer = str; switch (seg = expression(&the_insn.exp)) { case SEG_ABSOLUTE: break; default: the_insn.error = "segment should be ABSOLUTE"; expr_end = input_line_pointer; input_line_pointer=save_in; return 1; } expr_end = input_line_pointer; input_line_pointer = save_in; return 0; } int evaluateAbsolute( expressionS exp, int field_selector) { int value; unsigned int left21, right14; value = exp.X_add_number; calc_hppa_HILO(0, value, &left21, &right14); if ( exp.X_add_symbol ) { value += exp.X_add_symbol->sy_value; } if ( exp.X_subtract_symbol ) { value -= exp.X_subtract_symbol->sy_value; } switch (field_selector) { case /* no selector */ 0: break; case /* e_lsel */ 1: /* L` */ value = left21; break; case /* e_rsel */ 2: /* R` */ value = right14; break; default: BAD_CASE(field_selector); break; } return value; } int pa_parse_nullif(s) char **s; { int nullif; nullif = 0; if ( **s == ',' ) { *s = *s + 1; if ( strncasecmp(*s,"n",1) == 0 ) nullif = 1; else { as_bad("Unrecognized Nullification: (%c)",**s); nullif = 0; } *s = *s + 1; } while ( **s == ' ' || **s == '\t' ) *s = *s + 1; return nullif; } int pa_parse_nonneg_cmpsub_cmpltr(s) char **s; { int cmpltr; char *name; char c; cmpltr = 0; if ( **s == ',' ) { *s+=1; name = *s; while ( **s != ',' && **s != ' ' && **s != '\t' ) *s += 1; c = **s; **s = 0x00; if ( strcmp(name,"=") == 0 ) { cmpltr = 1; } else if ( strcmp(name,"<") == 0 ) { cmpltr = 2; } else if ( strcmp(name,"<=") == 0 ) { cmpltr = 3; } else if ( strcmp(name,"<<") == 0 ) { cmpltr = 4; } else if ( strcmp(name,"<<=") == 0 ) { cmpltr = 5; } else if ( strcasecmp(name,"sv") == 0 ) { cmpltr = 6; } else if ( strcasecmp(name,"od") == 0 ) { cmpltr = 7; } else cmpltr = -1; **s = c; } if ( cmpltr >= 0 ) { while ( **s == ' ' || **s == '\t' ) *s = *s + 1; } return cmpltr; } int pa_parse_neg_cmpsub_cmpltr(s) char **s; { int cmpltr; char *name; char c; cmpltr = -1; if ( **s == ',' ) { *s+=1; name = *s; while ( **s != ',' && **s != ' ' && **s != '\t' ) *s += 1; c = **s; **s = 0x00; if ( strcasecmp(name,"tr") == 0 ) { cmpltr = 0; } else if ( strcmp(name,"<>") == 0 ) { cmpltr = 1; } else if ( strcmp(name,">=") == 0 ) { cmpltr = 2; } else if ( strcmp(name,">") == 0 ) { cmpltr = 3; } else if ( strcmp(name,">>=") == 0 ) { cmpltr = 4; } else if ( strcmp(name,">>") == 0 ) { cmpltr = 5; } else if ( strcasecmp(name,"nsv") == 0 ) { cmpltr = 6; } else if ( strcasecmp(name,"ev") == 0 ) { cmpltr = 7; } **s = c; } if ( cmpltr >= 0 ) { while ( **s == ' ' || **s == '\t' ) *s = *s + 1; } return cmpltr; } int pa_parse_nonneg_add_cmpltr(s) char **s; { int cmpltr; char *name; char c; cmpltr = -1; if ( **s == ',' ) { *s+=1; name = *s; while ( **s != ',' && **s != ' ' && **s != '\t' ) *s += 1; c = **s; **s = 0x00; if ( strcmp(name,"=") == 0 ) { cmpltr = 1; } else if ( strcmp(name,"<") == 0 ) { cmpltr = 2; } else if ( strcmp(name,"<=") == 0 ) { cmpltr = 3; } else if ( strcasecmp(name,"nuv") == 0 ) { cmpltr = 4; } else if ( strcasecmp(name,"znv") == 0 ) { cmpltr = 5; } else if ( strcasecmp(name,"sv") == 0 ) { cmpltr = 6; } else if ( strcasecmp(name,"od") == 0 ) { cmpltr = 7; } **s = c; } if ( cmpltr >= 0 ) { while ( **s == ' ' || **s == '\t' ) *s = *s + 1; } return cmpltr; } int pa_parse_neg_add_cmpltr(s) char **s; { int cmpltr; char *name; char c; cmpltr = -1; if ( **s == ',' ) { *s+=1; name = *s; while ( **s != ',' && **s != ' ' && **s != '\t' ) *s += 1; c = **s; **s = 0x00; if ( strcasecmp(name,"tr") == 0 ) { cmpltr = 0; } else if ( strcmp(name,"<>") == 0 ) { cmpltr = 1; } else if ( strcmp(name,">=") == 0 ) { cmpltr = 2; } else if ( strcmp(name,">") == 0 ) { cmpltr = 3; } else if ( strcmp(name,"uv") == 0 ) { cmpltr = 4; } else if ( strcmp(name,"vnz") == 0 ) { cmpltr = 5; } else if ( strcasecmp(name,"nsv") == 0 ) { cmpltr = 6; } else if ( strcasecmp(name,"ev") == 0 ) { cmpltr = 7; } **s = c; } if ( cmpltr >= 0 ) { while ( **s == ' ' || **s == '\t' ) *s = *s + 1; } return cmpltr; } static int is_same_frag(frag1P,frag2P) fragS *frag1P; fragS *frag2P; { if ( frag1P == NULL ) return (FALSE); else if ( frag2P == NULL ) return (FALSE); else if ( frag1P == frag2P ) return (TRUE); else if ( frag2P->fr_type == rs_fill && frag2P->fr_fix == 0 ) return is_same_frag(frag1P,frag2P->fr_next); else if ( frag2P->fr_type == rs_align ) return is_same_frag(frag1P,frag2P->fr_next); else return (FALSE); } /* end hppa-aux.c */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.