/* xa65 - 65xx/65816 cross-assembler and utility suite * * Copyright (C) 1989-1997 André Fachat (a.fachat@physik.tu-chemnitz.de) * * Preprocessing arithmetic module * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include "xah.h" #include "xad.h" #include "xar.h" #include "xa.h" #include "xal.h" #include "xaa.h" #include "xat.h" static int pr[]= { P_START,P_ADD,P_ADD,P_MULT,P_MULT,P_SHIFT,P_SHIFT,P_CMP, P_CMP,P_EQU,P_CMP,P_CMP,P_EQU,P_AND,P_XOR,P_OR, P_LAND,P_LOR,P_EQU,P_START }; static int pp,pcc; static int fundef; static int ag_term(signed char*,int,int*,int*,int*); static int get_op(signed char*,int*); static int do_op(int*,int,int); /* s = string, v = variable */ int a_term(signed char *s, int *v, int *l, int xpc, int *pfl, int *label, int f) { int er=E_OK; int afl = 0, bfl; *pfl = 0; fundef = f; pp=0; pcc=xpc; if(s[0]=='<') { pp++; er=ag_term(s,P_START,v,&afl, label); bfl = afl & (A_MASK>>8); if( bfl && (bfl != (A_ADR>>8)) && (bfl != (A_LOW>>8)) ) { /*fprintf(stderr,"low byte relocation for a high byte - won't work!\n");*/ errout(W_LOWACC); } if(afl) *pfl=A_LOW | ((afl<<8) & A_FMASK); *v = *v & 255; } else if(s[pp]=='>') { pp++; er=ag_term(s,P_START,v,&afl, label); bfl = afl & (A_MASK>>8); if( bfl && (bfl != (A_ADR>>8)) && (bfl != (A_HIGH>>8)) ) { /*fprintf(stderr,"high byte relocation for a low byte - won't work!\n");*/ errout(W_HIGHACC); } if(afl) *pfl=A_HIGH | ((afl<<8) & A_FMASK) | (*v & 255); *v=(*v>>8)&255; } else if(s[pp]!=T_END) { er=ag_term(s,P_START,v,&afl, label); bfl = afl & (A_MASK>>8); if(bfl && (bfl != (A_ADR>>8)) ) { /*fprintf(stderr,"address relocation for a low or high byte - won't work!\n");*/ errout(W_ADDRACC); } if(afl) *pfl = A_ADR | ((afl<<8) & A_FMASK); } else { er = E_SYNTAX; } *l=pp; //fprintf(stderr, "a_term: nolink=%d, noundef=%d ->er=%d; l=%d, pp=%d, afl->%04x *pfl=%04x, (pc=%04x)\n",nolink, noundef ,er, *l, pp, afl,*pfl, xpc); return(er); } static int ag_term(signed char *s, int p, int *v, int *nafl, int *label) { int er=E_OK,o,w,mf=1,afl; afl = 0; //fprintf(stderr, "ag_term(%02x %02x %02x %02x %02x %02x\n",s[0],s[1],s[2],s[3],s[4],s[5]); while(s[pp]=='-') { pp++; mf=-mf; } #if(0) /* NYI: this is hacked into .assert for now */ if(s[pp]==18) /* logical not */ { pp++; if(!(er=ag_term(s,P_START,v,&afl,label))) { if(s[pp]!=')') er=E_SYNTAX; else pp++; } *v = !(*v); } else #endif if(s[pp]=='(') { pp++; if(!(er=ag_term(s,P_START,v,&afl,label))) { if(s[pp]!=')') er=E_SYNTAX; else pp++; } } else if(s[pp]==T_LABEL) { er=l_get(cval(s+pp+1),v, &afl); /* printf("label: er=%d, seg=%d, afl=%d, nolink=%d, fundef=%d\n", er, segment, afl, nolink, fundef); */ if(er==E_NODEF && segment != SEG_ABS && fundef ) { if( nolink || ((afl==SEG_UNDEF) || (afl==SEG_UNDEFZP))) { er = E_OK; *v = 0; if(afl!=SEG_UNDEFZP) { afl = SEG_UNDEF; } *label = cval(s+pp+1); } } pp+=3; } else if(s[pp]==T_VALUE || s[pp] == T_CAST) { while (s[pp] == T_CAST) { pp+=2; } *v=lval(s+pp+1); pp+=5; /* printf("value: v=%04x\n",*v); */ } else if(s[pp]==T_POINTER) { afl = s[pp+1]; *v=cval(s+pp+2); pp+=6; /* printf("pointer: v=%04x, afl=%04x\n",*v,afl); */ } else if(s[pp]=='*') { *v=pcc; pp++; afl = segment; } else { er=E_SYNTAX; } *v *= mf; while(!er && s[pp]!=')' && s[pp]!=']' && s[pp]!=',' && s[pp]!=T_END && s[pp]!=T_COMMENT) { //fprintf(stderr, "ag_term while: s[pp=%d]=%02x\n", pp, s[pp]); er=get_op(s,&o); if(!er && pr[o]>p) { pp+=1; if(!(er=ag_term(s,pr[o],&w, nafl, label))) { if(afl || *nafl) { /* check pointer arithmetic */ if((afl == *nafl) && (afl!=SEG_UNDEFZP) && (afl!=SEG_UNDEF) && o==2) { afl = 0; /* subtract two pointers */ } else if(((afl && !*nafl) || (*nafl && !afl)) && o==1) { afl=(afl | *nafl); /* add constant to pointer */ } else if((afl && !*nafl) && o==2) { afl=(afl | *nafl); /* subtract constant from pointer */ } else { if((!afl && *nafl) && o==2) { /* subtract pointer from constant */ errout(W_SUBTRACT); } /* allow math in the same segment */ if(segment!=SEG_ABS && segment != afl) { if(!dsb_len) { /*printf("ILLPOINTER=dsb_len=%d,segment=%d\n",dsb_len, segment);*/ /* e.g. adding two pointers, adding two undefined values */ er=E_ILLSEGMENT; } } afl=0; } } if(!er) er=do_op(v,w,o); } } else { break; } } *nafl = afl; return(er); } static int get_op(signed char *s, int *o) { int er; *o=s[pp]; if(*o<1 || *o>17) { /* printf("*o=%d, pp=%d, s=%s\n", *o, pp, s); for (int i=0; i< 10; i++) { printf(" %02x", s[i]); } printf("\n"); */ er=E_SYNTAX; } else { er=E_OK; } return(er); } static int do_op(int *w,int w2,int o) { int er=E_OK; switch (o) { case 1: *w +=w2; break; case 2: *w -=w2; break; case 3: *w *=w2; break; case 4: if (w2!=0) *w /=w2; else er =E_DIV; break; case 5: *w >>=w2; break; case 6: *w <<=w2; break; case 7: *w = *ww2; break; case 9: *w = *w==w2; break; case 10: *w = *w<=w2; break; case 11: *w = *w>=w2; break; case 12: *w = *w!=w2; break; case 13: *w &=w2; break; case 14: *w ^=w2; break; case 15: *w |=w2; break; case 16: *w =*w&&w2; break; case 17: *w =*w||w2; break; } return(er); }