From eae097c73ae38206603f177cf2b63c70f39a015b Mon Sep 17 00:00:00 2001 From: Andre Fachat Date: Fri, 16 Dec 2011 23:30:15 +0100 Subject: [PATCH] added more ca65 compatibility fixes, like Implement CA65 "cheap local labels", ":=" label definitions, and various pseudo opcodes (.include, .import, .importzp, .zeropage, .proc (anonymous only), .endproc, .code, .org, .reloc) --- xa/ChangeLog | 16 +++++++ xa/man/xa.1 | 37 ++++++++++++++-- xa/src/Makefile | 3 +- xa/src/xaa.c | 8 ++-- xa/src/xah.h | 3 ++ xa/src/xal.c | 38 +++++++++++++--- xa/src/xal.h | 2 + xa/src/xap.c | 3 +- xa/src/xap.h | 3 ++ xa/src/xar.c | 22 +++++++--- xa/src/xar.h | 2 +- xa/src/xar2.c | 12 ++++-- xa/src/xat.c | 112 +++++++++++++++++++++++++++++++++++++++++++----- 13 files changed, 228 insertions(+), 33 deletions(-) diff --git a/xa/ChangeLog b/xa/ChangeLog index a5eb775..ca83d68 100644 --- a/xa/ChangeLog +++ b/xa/ChangeLog @@ -295,3 +295,19 @@ xa-2.3.5 * Documentation updated. -- Cameron Kaiser 7 February, 2009 + +xa-2.x.x + + * Add -E commandline option to not stop after 20 errors, but show all + of them + * Introduce -X compatibility set commandline option, to distinguish + between MASM and CA65 compatibility options + * Implement CA65 "cheap local labels", ":=" label definitions, + and various pseudo opcodes (.include, .import, .importzp, + .zeropage, .proc (anonymous only), .endproc, .code, .org, .reloc) + * some bugfixes around error/warning logs + * some more comments + * Stuff is mostly untested... + + -- André Fachat 25 June, 2011 + diff --git a/xa/man/xa.1 b/xa/man/xa.1 index e1a8e66..8b443ce 100644 --- a/xa/man/xa.1 +++ b/xa/man/xa.1 @@ -453,7 +453,7 @@ and are synonymous, so you can mix things such as .B .byt $43, 22, """a character string""" and get the expected result. The string is subject to the current character -set, but the remaining bytes are inserted wtihout modification. +set, but the remaining bytes are inserted without modification. .TP .B .aasc """text1""","text2",... Specifies a character string that is @@ -503,10 +503,21 @@ a block, precede the label with or precede it with .B & to declare it within the previous level only (or globally if you are only -one level deep). Sixteen levels of scoping are permitted. +one level deep). Sixteen levels of scoping are permitted. +.B \&.) +is equivalent to +.B .block +or +.B .proc +. The latter is similar to the ca65 pseudo-opcode, but only anonymous blocks +are supported. .TP .B \&.) -Closes a block. +Closes a block. This is equivalent to +.B .bend +or +.B .endproc +. .TP .B \.as \.al \.xs \.xl Only relevant in 65816 mode (with the @@ -533,6 +544,11 @@ and generate errors if .B \-w is not specified. +.TP +.B .include "filename" +Includes another file in place of the pseudo opcode. Same as the preprocessor +.B #include + .LP The following pseudo-ops apply primarily to relocatable .o65 objects. A full discussion of the relocatable format is beyond the @@ -552,6 +568,8 @@ are valid in relative and absolute modes. .TP .B .code For CA65 compatibility this is currently mapped to ".text". +.B .zeropage +For CA65 compatibility this is currently mapped to ".zero". .TP .B .align value Aligns the current segment to a byte boundary (2, 4 or 256) as specified by @@ -570,6 +588,17 @@ is used to specify the file option being referenced. A table of these options is in the relocatable o65 file format description. The remainder of the options are interpreted as values to insert. Any number of values may be specified, and may also be strings. +.TP +.B .import label1, label2, label3, ... +Defines the given labels as global labels which are imported and resolved during +the link stage. Similar to the +.B -L +command line parameter +.TP +.B .importzp label1, label2, label3, ... +Similar to +.B .import +only it imports zeropage labels (i.e. byte values) .SH PREPROCESSOR @@ -845,7 +874,7 @@ This manual page was written by David Weinehall , Andre Fachat and Cameron Kaiser . Original xa package (C)1989-1997 Andre Fachat. Additional changes -(C)1989-2009 Andre Fachat, Jolse Maginnis, David Weinehall, +(C)1989-2011 Andre Fachat, Jolse Maginnis, David Weinehall, Cameron Kaiser. The official maintainer is Cameron Kaiser. .SH WEBSITE diff --git a/xa/src/Makefile b/xa/src/Makefile index 08fb114..62b4cae 100644 --- a/xa/src/Makefile +++ b/xa/src/Makefile @@ -1,7 +1,8 @@ OBJ = xa.o xaa.o xal.o xap.o xat.o xar.o xar2.o xao.o xau.o xam.o xacharset.o -#CFLAGS=-W -Wall -pedantic -ansi #-g +#CFLAGS=-W -Wall -pedantic -ansi -g #CFLAGS=-W -Wall -ansi -O2 +CFLAGS=-g #LD = ${CC} #LDFLAGS = "-lc" diff --git a/xa/src/xaa.c b/xa/src/xaa.c index ac65795..a23f1a9 100644 --- a/xa/src/xaa.c +++ b/xa/src/xaa.c @@ -122,10 +122,12 @@ static int ag_term(signed char *s, int p, int *v, int *nafl, int *label) /* 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)) { + if( nolink || ((afl==SEG_UNDEF) || (afl==SEG_UNDEFZP))) { er = E_OK; *v = 0; - afl = SEG_UNDEF; + if(afl!=SEG_UNDEFZP) { + afl = SEG_UNDEF; + } *label = cval(s+pp+1); } } @@ -169,7 +171,7 @@ static int ag_term(signed char *s, int p, int *v, int *nafl, int *label) if(!(er=ag_term(s,pr[o],&w, nafl, label))) { if(afl || *nafl) { /* check pointer arithmetic */ - if((afl == *nafl) && (afl!=SEG_UNDEF) && o==2) { + if((afl == *nafl) && (afl!=SEG_UNDEFZP) && (afl!=SEG_UNDEF) && o==2) { afl = 0; /* substract two pointers */ } else if(((afl && !*nafl) || (*nafl && !afl)) && o==1) { diff --git a/xa/src/xah.h b/xa/src/xah.h index 710c64e..78ec1b8 100644 --- a/xa/src/xah.h +++ b/xa/src/xah.h @@ -49,6 +49,7 @@ typedef struct { int len; int fl; /* 0 = label value not valid/known, * 1 = label value known + * 2 = label value not known, external global label (imported on link) */ int afl; /* 0 = no address (no relocation), 1 = address label */ int nextindex; @@ -175,6 +176,8 @@ typedef struct { #define SEG_ZERO 5 #define SEG_MAX 6 +#define SEG_UNDEFZP 7 /* is being mapped to UNDEF */ + typedef struct Fopt { signed char *text; /* text after pass1 */ int len; diff --git a/xa/src/xal.c b/xa/src/xal.c index 3fcfade..de18b7b 100644 --- a/xa/src/xal.c +++ b/xa/src/xal.c @@ -183,7 +183,7 @@ int cll_getcur() { /**********************************************************************************/ /** - * define a global label + * define a global label (from the "-L" command line parameter) */ int lg_set(char *s ) { int n, er; @@ -194,14 +194,42 @@ int lg_set(char *s ) { fprintf(stderr,"Warning: global label doubly defined!\n"); } else { if(!(er=ll_def(s,&n,0))) { - ltp=afile->la.lt+n; - ltp->fl=2; - ltp->afl=SEG_UNDEF; - } + return lg_import(n); + } } return er; } +/** + * define a global label (from the .import pseudo opcode)) + * "s" is a pointer to the first label character, end is at \0 + * or at non-alphanumeric/_ char + */ +int lg_import(int n) { + int er=E_OK; + + ltp=afile->la.lt+n; + ltp->fl=2; + ltp->afl=SEG_UNDEF; + + return er; +} + +/** + * define a global zeropage label (from the .importzp pseudo opcode)) + * "s" is a pointer to the first label character, end is at \0 + * or at non-alphanumeric/_ char + */ +int lg_importzp(int n) { + int er=E_OK; + + ltp=afile->la.lt+n; + ltp->fl=2; + ltp->afl=SEG_UNDEFZP; + + return er; +} + /**********************************************************************************/ int l_def(char *s, int *l, int *x, int *f) diff --git a/xa/src/xal.h b/xa/src/xal.h index af78995..c0330c5 100644 --- a/xa/src/xal.h +++ b/xa/src/xal.h @@ -30,6 +30,8 @@ long gm_labm(void); long ga_labm(void); int lg_set(char *); +int lg_import(int); +int lg_importzp(int); int b_init(void); int b_depth(void); diff --git a/xa/src/xap.c b/xa/src/xap.c index 3b5c58b..f50196c 100644 --- a/xa/src/xap.c +++ b/xa/src/xap.c @@ -50,7 +50,8 @@ static int pp_replace(char*,char*,int,int); static int searchdef(char*); static int fgetline(char*,int len, int *rlen, FILE*); -static int icl_open(char*),pp_ifdef(char*),pp_ifndef(char*); +/*static int icl_open(char*);*/ +static int pp_ifdef(char*),pp_ifndef(char*); static int pp_else(char*),pp_endif(char*); static int pp_echo(char*),pp_if(char*),pp_print(char*),pp_prdef(char*); static int pp_ifldef(char*),pp_iflused(char*); diff --git a/xa/src/xap.h b/xa/src/xap.h index ba5f0ba..156d725 100644 --- a/xa/src/xap.h +++ b/xa/src/xap.h @@ -30,6 +30,9 @@ void pp_end(void); int pgetline(char *t); Datei *pp_getidat(void); +/* needed for .include pseudo opcode */ +int icl_open(char*); + int ga_pp(void); int gm_pp(void); long gm_ppm(void); diff --git a/xa/src/xar.c b/xa/src/xar.c index 25d9aae..2b4f09b 100644 --- a/xa/src/xar.c +++ b/xa/src/xar.c @@ -34,18 +34,22 @@ File *afile = NULL; int rmode = RMODE_RELOC; +/* int r_set(int pc, int afl, int l) { -/*printf("set relocation @$%04x, l=%d, afl=%04x, segment=%d\n",pc, l, afl,segment);*/ if(segment==SEG_TEXT) return rt_set(pc,afl,l,0); if(segment==SEG_DATA) return rd_set(pc,afl,l,0); return 0; } +*/ int u_set(int pc, int afl, int label, int l) { /*printf("set relocation @$%04x, l=%d, afl=%04x, segment=%d, label=%d\n", pc, l, afl,segment, label);*/ - if((afl & A_FMASK) == (SEG_UNDEF<<8)) + if(((afl & A_FMASK) == (SEG_UNDEF<<8)) + || ((afl & A_FMASK) == (SEG_UNDEFZP<<8)) + ) { label = u_label(label); /* set label as undefined */ + } if(segment==SEG_TEXT) return rt_set(pc,afl,l,label); if(segment==SEG_DATA) return rd_set(pc,afl,l,label); return 0; @@ -77,7 +81,9 @@ int rt_set(int pc, int afl, int l, int lab) { /*printf("Warning: byte relocation in word value at PC=$%04x!\n",pc);*/ } if(l==1 && ((afl&A_MASK)==A_ADR)) { - if((afl & A_FMASK) != (SEG_ZERO<<8)) { + if(((afl & A_FMASK) != (SEG_ZERO<<8)) + && ((afl & A_FMASK) != (SEG_UNDEFZP<<8)) + ) { /*printf("afl=%04x\n",afl);*/ errout(W_ADRRELOC); } @@ -147,10 +153,16 @@ int rt_write(FILE *fp, int pc) { } fputc(pc2-pc, fp); pc=pc2; - fputc((afl>>8)&255, fp); - if((afile->rt.rlist[p].afl&A_FMASK)==(SEG_UNDEF<<8)) { + if((afile->rt.rlist[p].afl&A_FMASK)==(SEG_UNDEFZP<<8)) { + fputc( (((afl & ~A_FMASK)>>8)&255)|SEG_UNDEF, fp); + fputc(afile->rt.rlist[p].lab & 255, fp); + fputc((afile->rt.rlist[p].lab>>8) & 255, fp); + } else { + fputc( (afl>>8)&255, fp); + if((afile->rt.rlist[p].afl&A_FMASK)==(SEG_UNDEF<<8)) { fputc(afile->rt.rlist[p].lab & 255, fp); fputc((afile->rt.rlist[p].lab>>8) & 255, fp); + } } if((afl&A_MASK)==A_HIGH) fputc(afl&255,fp); } diff --git a/xa/src/xar.h b/xa/src/xar.h index 01aa887..947c618 100644 --- a/xa/src/xar.h +++ b/xa/src/xar.h @@ -25,7 +25,7 @@ extern File *alloc_file(void); /* jumps to r[td]_set, depending on segment */ -int r_set(int pc, int reloc, int len); +/*int r_set(int pc, int reloc, int len);*/ int u_set(int pc, int reloc, int label, int len); int rt_set(int pc, int reloc, int len, int label); diff --git a/xa/src/xar2.c b/xa/src/xar2.c index fcf87b1..5075917 100644 --- a/xa/src/xar2.c +++ b/xa/src/xar2.c @@ -111,11 +111,17 @@ int rd_write(FILE *fp, int pc) { } fputc(pc2-pc, fp); pc=pc2; - fputc((afl>>8)&255, fp); - if((afile->rd.rlist[p].afl&A_FMASK)==(SEG_UNDEF<<8)) { + if((afile->rd.rlist[p].afl&A_FMASK)==(SEG_UNDEFZP<<8)) { + fputc((((afl & ~A_FMASK)>>8)&255)|SEG_UNDEF, fp); + fputc(afile->rd.rlist[p].lab & 255, fp); + fputc((afile->rd.rlist[p].lab>>8) & 255, fp); + } else { + fputc((afl>>8)&255, fp); + if(((afile->rd.rlist[p].afl&A_FMASK)==(SEG_UNDEF<<8))) { fputc(afile->rd.rlist[p].lab & 255, fp); fputc((afile->rd.rlist[p].lab>>8) & 255, fp); - } + } + } if((afl&A_MASK)==A_HIGH) fputc(afl&255,fp); } p=afile->rd.rlist[p].next; diff --git a/xa/src/xat.c b/xa/src/xat.c index 821a05d..ee0ee42 100644 --- a/xa/src/xat.c +++ b/xa/src/xat.c @@ -51,6 +51,16 @@ static void tg_bin(signed char*,int*,int*); /* assembly mnemonics and pseudo-op tokens */ /* ina and dea don't work yet */ +/* Note AF 20110624: added some ca65 compatibility pseudo opcodes, + * many are still missing (and will most likely never by supported in this + * code base). Potential candidates are .hibytes, .lobytes, .asciiz, + * .addr, .charmap, .dbyt, .faraddr, .bankbytes, .segment (at least for the known ones) + * .incbin is similar to our .bin, but with parameters reversed (argh...) + * I like the .popseg/.pushseg pair; + * .global/.globalzp is equivalent to forward-defining a label in the global block + * .export/.exportzp could be implemented with a commandline switch to NOT export + * global labels, where .exported labels would still be exported in an o65 file. + */ static char *kt[] ={ /* 1 2 3 4 5 6 7 8 9 10 */ "adc","and","asl","bbr","bbs","bcc","bcs","beq","bit","bmi", @@ -75,7 +85,9 @@ static char *kt[] ={ ".byt",".word",".asc",".dsb", ".(", ".)", "*=", ".text",".data",".bss", ".zero",".fopt", ".byte", ".end", ".list", ".xlist", ".dupb", ".blkb", ".db", ".dw", - ".align",".block", ".bend",".al",".as",".xl",".xs", ".bin", ".aasc", ".code" + ".align",".block", ".bend",".al",".as",".xl",".xs", ".bin", ".aasc", ".code", + ".include", ".import", ".importzp", ".proc", ".endproc", + ".zeropage", ".org", ".reloc" }; @@ -84,8 +96,6 @@ static int lp[]= { 0,1,1,1,1,2,2,1,1,1,2,2,2,1,1,1,2,2 }; /* index into token array for pseudo-ops */ /* last valid mnemonic */ #define Lastbef 93 -/* last valid token+1 */ -#define Anzkey 124 #define Kbyt Lastbef+1 #define Kword Lastbef+2 @@ -121,8 +131,24 @@ static int lp[]= { 0,1,1,1,1,2,2,1,1,1,2,2,2,1,1,1,2,2 }; #define Kcode Lastbef+30 /* gets remapped to Ktext */ -#define Kreloc Anzkey /* *= (relocation mode) */ -#define Ksegment Anzkey+1 +/* 93 + 30 -> 123 */ + +#define Kinclude Lastbef+31 +#define Kimport Lastbef+32 +#define Kimportzp Lastbef+33 +#define Kproc Lastbef+34 /* mapped to Kopen */ +/* 93 + 35 -> 128 */ +#define Kendproc Lastbef+35 /* mapped to Kclose */ +#define Kzeropage Lastbef+36 /* mapped to Kzero */ +#define Korg Lastbef+37 /* mapped to Kpcdef - with parameter equivalent to "*=$abcd" */ +#define Krelocx Lastbef+38 /* mapped to Kpcdef - without parameter equivalent to "*=" */ + +/* last valid token+1 */ +#define Anzkey Lastbef+39 /* define last valid token number; last define above plus one */ + + +#define Kreloc (Anzkey-256) /* *= (relocation mode) */ +#define Ksegment (Anzkey+1-256) /* this actually now is 129, which might be a problem as char is signed ... */ /* array used for hashing tokens (26 entries, a-z) */ @@ -342,7 +368,6 @@ fprintf(stderr, "- p1 %d starting -\n", pc[segment]); #endif er=t_conv(s,t,&l,pc[segment],&nk,&na1,&na2,0,&byte); /* leaving our token sequence in t */ - *ll=l; /* printf("t_conv (er=%d):",er); @@ -372,7 +397,26 @@ fprintf(stderr, "- p1 %d starting -\n", pc[segment]); if(n==Kend || n==Klist || n==Kxlist) { *ll = 0; /* ignore */ } else - + if(n==Kinclude) { + *ll = 0; /* no output length */ + i=1; + if(t[i]=='\"') { + int k,j=0; + char binfname[255]; + i++; + k=t[i]+i+1; + i++; + while(i 255) + er = E_NOMEM; /* buffer overflow */ + } + binfname[j] = '\0'; + er=icl_open(binfname); + } else { + er=E_SYNTAX; + } + } else if(n==Kfopt) { if(romable==1) er=E_ROMOPT; t[0] = Kbyt; @@ -777,6 +821,48 @@ fprintf(stderr, "E_NODEF pass1 xat.c\n"); /* .byt, .asc, .word, .dsb, .fopt pseudo-op dispatch */ } else + if(n==Kimportzp) { + int i; + *ll=0; /* no output */ + bl = 0; /* no output length */ + /* import labels; next follow a comma-separated list of labels that are + imported. Tokenizer has already created label entries, we only need to + set the flags appropriately */ + i=1; +/*printf("Kimport: t[i]=%d\n",t[i]);*/ + while(t[i]==T_LABEL) { + int n = (t[i+1] & 255) | (t[i+2] << 8); /* label number */ +/*printf("lg_import: %d\n",n);*/ + lg_importzp(n); + i+=3; + while (t[i]==' ') i++; + if (t[i]!=',') break; + i++; + while (t[i]==' ') i++; + } + er=E_NOLINE; + } else + if(n==Kimport) { + int i; + *ll=0; /* no output */ + bl = 0; /* no output length */ + /* import labels; next follow a comma-separated list of labels that are + imported. Tokenizer has already created label entries, we only need to + set the flags appropriately */ + i=1; +/*printf("Kimport: t[i]=%d\n",t[i]);*/ + while(t[i]==T_LABEL) { + int n = (t[i+1] & 255) | (t[i+2] << 8); /* label number */ +/*printf("lg_import: %d\n",n);*/ + lg_import(n); + i+=3; + while (t[i]==' ') i++; + if (t[i]!=',') break; + i++; + while (t[i]==' ') i++; + } + er=E_NOLINE; + } else if(n==Kbyt || n==Kasc || n==Kaasc) { #ifdef DEBUG_AM @@ -858,7 +944,8 @@ int t_p2(signed char *t, int *ll, int fl, int *al) v2=v; } else { if( (!(er=l_get(n,&v2, &afl))) - && ((afl & A_FMASK)!=(SEG_UNDEF<<8)) ) + && ((afl & A_FMASK)!=(SEG_UNDEF<<8)) + && ((afl & A_FMASK)!=(SEG_UNDEFZP<<8)) ) { if(t[3]=='+') { @@ -1175,7 +1262,7 @@ fprintf(stderr, "Kdsb E_DSB %i\n", j); } dsb_len = 0; } else - if(n<=Lastbef) + if(n>=0 && n<=Lastbef) { if((c=t[1])=='#') { @@ -1633,7 +1720,7 @@ static int t_conv(signed char *s, signed char *t, int *l, int pc, int *nk, } - if((n & 0xff) <=Lastbef) + if(n>=0 && n<=Lastbef) mk=1; /* 1= nur 1 Komma erlaubt *//* = only 1 comma ok */ } @@ -1980,6 +2067,11 @@ static int t_keyword(signed char *s, int *l, int *n) if(i==Kblock) i=Kopen; if(i==Kbend) i=Kclose; if(i==Kcode) i=Ktext; + if(i==Kproc) i=Kopen; + if(i==Kendproc) i=Kclose; + if(i==Kzeropage) i=Kzero; + if(i==Korg) i=Kpcdef; + if(i==Krelocx) i=Kpcdef; *l=j;