From f28af4a9171157df900f8781a90e3411b3ac3288 Mon Sep 17 00:00:00 2001 From: Andre Fachat Date: Fri, 16 Dec 2011 23:22:32 +0100 Subject: [PATCH 01/52] added ca65 compatibiltiy patch --- xa/man/xa.1 | 19 ++++- xa/src/Makefile | 2 +- xa/src/xa.c | 91 ++++++++++++++++++++--- xa/src/xa.h | 2 +- xa/src/xaa.c | 2 + xa/src/xah.h | 13 +++- xa/src/xal.c | 194 ++++++++++++++++++++++++++++++++++++++++-------- xa/src/xal.h | 2 +- xa/src/xap.c | 2 +- xa/src/xat.c | 35 +++++++-- 10 files changed, 303 insertions(+), 59 deletions(-) diff --git a/xa/man/xa.1 b/xa/man/xa.1 index 8dc5e88..e1a8e66 100644 --- a/xa/man/xa.1 +++ b/xa/man/xa.1 @@ -19,6 +19,9 @@ further in this manual page. .SH OPTIONS .TP +.B \-E +Do not stop after 20 errors, but show all errors. +.TP .B \-v Verbose output. .TP @@ -67,9 +70,18 @@ to reconstruct source. Add cross-reference list to labellist (requires .BR \-l ). .TP +.B \-Xcompatset +Enables compatibility settings to become more (not fully!) compatible with other 6502 assemblers. +Currently supported are compatibility set "MASM" and "CA65". +"MASM" allows colons to appear in comments. This does not affect colon interpretation elsewhere. +"CA65" allows the ":=" label definition (instead of "="), and also the "cheap local labels" using +the "@" character. This, however, disables the "@" 24-bit enforcement. +.TP .B \-M Allow colons to appear in comments; for MASM compatibility. This does -not affect colon interpretation elsewhere. +not affect colon interpretation elsewhere. This option is deprecated. Use +.BR -X +instead. .TP .B \-R Start assembler in relocating mode. @@ -339,7 +351,7 @@ for those opcodes that support it (i.e., keep as 16 bit word) .B @ render as 24-bit quantity for 65816 (must specify .B \-w -command-line option). +command-line option, must not specify the CA65 compatibility). .B This is required to specify any .B 24-bit quantity! .TP @@ -538,6 +550,9 @@ space for allocation and .zero being uninitialized zero page space for allocation. In .bss and .zero, only labels are evaluated. These pseudo-ops are valid in relative and absolute modes. .TP +.B .code +For CA65 compatibility this is currently mapped to ".text". +.TP .B .align value Aligns the current segment to a byte boundary (2, 4 or 256) as specified by .B diff --git a/xa/src/Makefile b/xa/src/Makefile index dc15ea6..08fb114 100644 --- a/xa/src/Makefile +++ b/xa/src/Makefile @@ -1,4 +1,4 @@ -OBJ = xa.o xaa.o xal.o xap.o xat.o xar.o xar2.o xao.o xau.o xam.o xacharset.o +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 -ansi -O2 diff --git a/xa/src/xa.c b/xa/src/xa.c index 3a54e6c..836c885 100644 --- a/xa/src/xa.c +++ b/xa/src/xa.c @@ -61,7 +61,10 @@ /* exported globals */ int ncmos, cmosfl, w65816, n65816; -int masm = 0; +/* compatibility flags */ +int masm = 0; /* MASM */ +int ca65 = 0; /* CA65 */ + int nolink = 0; int romable = 0; int romaddr = 0; @@ -71,10 +74,12 @@ int crossref = 0; char altppchar; /* local variables */ + static char out[MAXLINE]; static time_t tim1, tim2; static FILE *fpout, *fperr, *fplab; static int ner = 0; +static int ner_max = 20; static int align = 1; @@ -91,6 +96,7 @@ static int getline(char *); static void lineout(void); static long ga_p1(void); static long gm_p1(void); +static int set_compat(char *compat_name); /* text */ int memode,xmode; @@ -191,6 +197,9 @@ int main(int argc,char *argv[]) while(i 0) { fprintf(stderr, "Break after %d error%c\n",ner,ner?'s':0); + } else { + /* ner_max==0, i.e. show all errors */ + fprintf(stderr, "End after %d error%c\n",ner,ner?'s':0); + } /*unlink();*/ if(ofile) { unlink(ofile); @@ -615,7 +642,7 @@ static int pass2(void) filep=&datei; afile->mn.tmpe=0L; - while(ner<20 && afile->mn.tmpemn.tmpz) + while((ner_max==0 || nermn.tmpemn.tmpz) { l=afile->mn.tmp[afile->mn.tmpe++]; ll=l; @@ -827,6 +854,7 @@ static void usage(int default816, FILE *fp) programname); fprintf(fp, " -v verbose output\n" + " -E do not break after 20 errors, but show all\n" " -x old filename behaviour (overrides `-o', `-e', `-l')\n" " This is deprecated and may disappear in future versions!\n" " -C no CMOS-opcodes\n" @@ -844,6 +872,8 @@ static void usage(int default816, FILE *fp) " -l filename sets labellist filename, default is none\n" " -r adds crossreference list to labellist (if `-l' given)\n" " -M allow ``:'' to appear in comments for MASM compatibility\n" + " -Xcompatset set compatibility flags for other assemblers, known values are:\n" + " MASM, CA65\n" " -R start assembler in relocating mode\n"); fprintf(fp, " -Llabel defines `label' as absolute, undefined label even when linking\n" @@ -900,7 +930,7 @@ static char *ertxt[] = { "NewFile", "CMOS-Befehl", "pp:Wrong parameter count", - "Illegal pointer arithmetic", + "Illegal pointer arithmetic (-26)", "Illegal segment", "File header option too long", "File option not at file start (when ROM-able)", @@ -939,11 +969,10 @@ static char *ertxt[] = { "", "", "", - "", /* warnings */ "Cutting word relocation in byte value", "Byte relocation in word value", - "Illegal pointer arithmetic", + "Illegal pointer arithmetic (-66)", "Address access to low or high byte pointer", "High byte access to low byte pointer", "Low byte access to high byte pointer", @@ -1062,9 +1091,20 @@ static int getline(char *s) comcom = 1; if (c=='\0') break; /* hkfl = comcom = 0 */ - if (c==':' && !hkfl && (!comcom || !masm)) { - gl=1; - break; + if (c==':' && !hkfl) { + /* if the next char is a "=" - so that we have a ":=" - and we + we have ca65 compatibility, we ignore the colon */ + if (l[i]!='=' || !ca65 || comcom) { + /* but otherwise we check if it is in a comment and we have + MASM or CA65 compatibility, then we ignore the colon as well */ + if(!comcom || !(masm || ca65)) { + /* we found a colon, so we keep the current line in memory + but return the part before the colon, and next time the part + after the colon, so we can parse C64 BASIC text assembler... */ + gl=1; + break; + } + } } j++; } while (c!='\0' && j-1) { - if(er>=-(ANZERR+ANZWARN) && er < -ANZERR) { + if (er<=-ANZERR || er>-1) { + if(er>=-(ANZERR+ANZWARN) && er <= -ANZERR) { sprintf(out,"%s:line %d: %04x: Warning - %s\n", filep->fname, filep->fline, pc[segment], ertxt[(-er)-1]); } else { @@ -1129,3 +1171,30 @@ void logout(char *s) fprintf(fperr,"%s",s); } +/*****************************************************************/ + +typedef struct { + char *name; + int *flag; +} compat_set; + +static compat_set compat_sets[] = { + { "MASM", &masm }, + { "CA65", &ca65 }, + { NULL, NULL } +}; + +int set_compat(char *compat_name) { + int i = 0; + while (compat_sets[i].name != NULL) { + if (strcmp(compat_sets[i].name, compat_name) == 0) { + /* set appropriate compatibility flag */ + (*compat_sets[i].flag) = 1; + return 0; + } + i++; + } + return -1; +} + + diff --git a/xa/src/xa.h b/xa/src/xa.h index 67ee3fe..fd4d7cf 100644 --- a/xa/src/xa.h +++ b/xa/src/xa.h @@ -22,7 +22,7 @@ #include "xah.h" /* For SEG_MAX */ extern int ncmos, cmosfl, w65816, n65816; -extern int masm, nolink; +extern int masm, ca65, nolink; extern int noglob; extern int showblk; extern int relmode; diff --git a/xa/src/xaa.c b/xa/src/xaa.c index 73dd861..ac65795 100644 --- a/xa/src/xaa.c +++ b/xa/src/xaa.c @@ -180,6 +180,8 @@ static int ag_term(signed char *s, int p, int *v, int *nafl, int *label) } else { if(segment!=SEG_ABS) { 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_ILLPOINTER; } } diff --git a/xa/src/xah.h b/xa/src/xah.h index 8b98bc8..710c64e 100644 --- a/xa/src/xah.h +++ b/xa/src/xah.h @@ -20,15 +20,22 @@ #ifndef __XA65_XAH_H__ #define __XA65_XAH_H__ -#define ANZLAB 5000 /* mal 14 -> Byte */ +/* + * Note: the computations to get the number of bytes necessary to allocate are + * a historic remnant of the Atari ST (the original platform) not being able to efficiently allocate small chunks + * of memory so I had to allocate a large chunk myself and manage the tables myself. + * This has changed and some parts of xa65 are modified to just do a malloc() now. + * These fixed numbers should actually go away. AF 20110623 + */ +#define ANZLAB 5000 /* multiplied by sizeof(Labtab) -> Byte */ #define LABMEM 40000L #define MAXLAB 32 #define MAXBLK 16 #define MAXFILE 7 #define MAXLINE 2048 #define MAXPP 40000L -#define ANZDEF 2340 /* mal 14 -> Byte, ANZDEF * 14 < 32768 */ -#define TMPMEM 200000L /* Zwischenspeicher von Pass1 nach Pass 2 */ +#define ANZDEF 2340 /* multiplied by sizeof(List) -> Byte, ANZDEF * 20 < 32768 */ +#define TMPMEM 200000L /* temporary memory buffer from Pass1 to Pass 2 */ typedef struct LabOcc { struct LabOcc *next; diff --git a/xa/src/xal.c b/xa/src/xal.c index 5598c75..3fcfade 100644 --- a/xa/src/xal.c +++ b/xa/src/xal.c @@ -50,6 +50,12 @@ static int b_get(int*); static int b_test(int); static int ll_def(char *s, int *n, int b); +static int b_new(void); +static void cll_init(); +static int cll_get(); +static void cll_clear(); +static int cll_getcur(); + /* local variables */ /* @@ -69,6 +75,7 @@ static Labtab *ltp; int l_init(void) { + cll_init(); return 0; #if 0 int er; @@ -139,10 +146,49 @@ FILE *fp; } } +/********************************************************************************** + * cheap local labels + */ + +static int cll_current = 0; /* the current cheap local labels block */ + +/** + * init the cheap local labels + */ +void cll_init() { + cll_current = 0; +} + +/** + * get the block number for a new cheap local label block + */ +int cll_get() { + if (cll_current == 0) { + cll_current = b_new(); + } + return cll_current; +} + +/** + * clear the local labels + */ +void cll_clear() { + cll_current = 0; +} + +int cll_getcur() { + return cll_current; +} + +/**********************************************************************************/ + +/** + * define a global label + */ int lg_set(char *s ) { int n, er; - er = ll_search(s,&n); + er = ll_search(s,&n, 0); if(er==E_OK) { fprintf(stderr,"Warning: global label doubly defined!\n"); @@ -156,52 +202,73 @@ int lg_set(char *s ) { return er; } +/**********************************************************************************/ int l_def(char *s, int *l, int *x, int *f) { int n,er,b,i=0; + int cll_fl; - *f=0; - b=0; - n=0; + *f=0; /* flag (given as param) that the label is to be re-defined and the + "label defined error" is to be skipped */ + b=0; /* block level on block stack, resp. block number */ + n=0; /* flag, when set, b is absolute block number and not being translated */ + cll_fl=0; /* when set, clear the cheap local label block */ if(s[0]=='-') { - *f+=1; + *f+=1; /* label is being redefined */ i++; } else + if(s[0]=='@') + { + i++; + n++; /* block number b is absolute */ + b=cll_get(); /* current (possibly newly allocated) cheap label block */ + cll_fl=1; /* do not clear the cll block again... */ + } else if(s[0]=='+') { i++; - n++; - b=0; + n++; /* block number b is absolute */ + b=0; /* global block number */ } while(s[i]=='&') { - n=0; + if (n) b=0; /* reset block number */ + n=0; /* block number is relative */ i++; - b++; + b++; /* one (more) level up the block stack */ } - if(!n) + if(!n) { + /* translate from block stack level to absolute block number */ b_fget(&b,b); + } + if(!cll_fl) { + /* clear cheap local labels */ + cll_clear(); + } - if(!isalpha(s[i]) && s[i]!='_') + if(!isalpha(s[i]) && s[i]!='_' && !(ca65 && isdigit(s[i]) ) ) er=E_SYNTAX; else { - er=ll_search(s+i,&n); + er=ll_search(s+i,&n, cll_fl); if(er==E_OK) { + /* we actually found an existing label in the same scope */ ltp=afile->la.lt+n; if(*f) { + /* redefinition of label */ *l=ltp->len+i; } else if(ltp->fl==0) { + /* label has not been defined yet, (e.g. pass1 forward ref), so we try to set it. */ *l=ltp->len+i; if(b_ltest(ltp->blk,b)) er=E_LABDEF; @@ -213,7 +280,7 @@ int l_def(char *s, int *l, int *x, int *f) } else if(er==E_NODEF) { - if(!(er=ll_def(s+i,&n,b))) /* ll_def(...,*f) */ + if(!(er=ll_def(s+i,&n,b))) /* store the label in the table of labels */ { ltp=afile->la.lt+n; *l=ltp->len+i; @@ -229,15 +296,23 @@ int l_def(char *s, int *l, int *x, int *f) int l_search(char *s, int *l, int *x, int *v, int *afl) { int n,er,b; + int cll_fl; *afl=0; - er=ll_search(s,&n); -/*printf("l_search: lab=%s(l=%d), afl=%d, er=%d, n=%d\n",s,*l, *afl,er,n);*/ + /* check cheap local label */ + cll_fl=0; + if (s[0]=='@') { + cll_fl=1; /* also used as offset to the label length, so must be 1 */ + s++; + } + + er=ll_search(s,&n, cll_fl); +/*printf("l_search: lab=%s(l=%d, afl=%d, er=%d, n=%d, cll_fl=%d, cll_cur=%d)\n",s,*l, *afl,er,n, cll_fl, cll_getcur());*/ if(er==E_OK) { ltp=afile->la.lt+n; - *l=ltp->len; + *l=ltp->len + cll_fl; if(ltp->fl == 1) { l_get(n,v,afl);/* *v=lt[n].val;*/ @@ -251,12 +326,17 @@ int l_search(char *s, int *l, int *x, int *v, int *afl) } else { - b_get(&b); + if(cll_fl) { + b=cll_get(); + } else { + b_get(&b); + } + er=ll_def(s,x,b); /* ll_def(...,*v); */ ltp=afile->la.lt+(*x); - *l=ltp->len; + *l=ltp->len + cll_fl; if(!er) { @@ -401,8 +481,14 @@ static int ll_def(char *s, int *n, int b) /* definiert naechstes Label return(er); } - -int ll_search(char *s, int *n) /* search Label in Tabelle ,nr->n */ +/** + * search a label name in the label table. Return the label number + * in "n". Finds only labels that are in a block that is in the current + * set of blocks (in the block stack) + * + * If cll_fl is set, the label is also searched in the local cheap label scope + */ +int ll_search(char *s, int *n, int cll_fl) /* search Label in Tabelle ,nr->n */ { int i,j=0,k,er=E_NODEF,hash; @@ -411,7 +497,6 @@ int ll_search(char *s, int *n) /* search Label in Tabelle ,nr->n */ hash=hashcode(s,j); i=afile->la.hashindex[hash]; -/*printf("search?\n");*/ if(i>=afile->la.ltm) return E_NODEF; do @@ -422,11 +507,21 @@ int ll_search(char *s, int *n) /* search Label in Tabelle ,nr->n */ { for (k=0;(kn[k]==s[k]);k++); - if((j==k)&&(!b_test(ltp->blk))) - { - er=E_OK; - break; - } + if (cll_fl) { + if (ltp->blk == cll_getcur()) { + er=E_OK; + break; + } + } else { + /* check if the found label is in any of the blocks in the + current block stack */ + if((j==k)&&(!b_test(ltp->blk))) + { + /* ok, label found and it is reachable (its block nr is in the current block stack */ + er=E_OK; + break; + } + } } if(!i) @@ -451,7 +546,7 @@ int ll_pdef(char *t) { int n; - if(ll_search(t,&n)==E_OK) + if(ll_search(t,&n, 0)==E_OK) { ltp=afile->la.lt+n; if(ltp->fl) @@ -496,9 +591,22 @@ int l_write(FILE *fp) return 0; } -static int bt[MAXBLK]; -static int blk; -static int bi; +/******************************************************************************************* + * block management code. Here the ".(" and ".)" blocks are maintained. + * + * Blocks are numbered uniquely, every time a new block is opened, the "blk" variable + * is increased and its number used as block number. + * + * The currently open blocks are maintained in a stack (bt[]). The lowest entry is the outermost + * block number, adding block numbers as blocks are opened. When a block is closed, + * the block stack is shortened again (bi has the length of the block stack) + * + * Methods exist to open new blocks, close a block, and do some checks, e.g. whether + * a specific block number is contained in the current block stack. + */ +static int bt[MAXBLK]; /* block stack */ +static int bi; /* length of the block stack (minus 1, i.e. bi[bi] has the innermost block) */ +static int blk; /* current block number for allocation */ int b_init(void) { @@ -509,6 +617,11 @@ int b_init(void) return(E_OK); } +int b_new(void) +{ + return ++blk; +} + int b_depth(void) { return bi; @@ -519,19 +632,25 @@ int ga_blk(void) return(blk); } +/** + * open a new block scope + */ int b_open(void) { int er=E_BLKOVR; if(bi=0) @@ -562,6 +687,10 @@ static int b_fget(int *n, int i) return(E_OK); } +/** + * tests whether the given block number n is in the current stack of + * current block numbers bt[] + */ static int b_test(int n) { int i=bi; @@ -572,6 +701,9 @@ static int b_test(int n) return( i+1 ? E_OK : E_NOBLK ); } +/** + * tests whether the given block number "a" is in the + */ static int b_ltest(int a, int b) /* testet ob bt^-1(b) in intervall [0,bt^-1(a)] */ { int i=0,er=E_OK; diff --git a/xa/src/xal.h b/xa/src/xal.h index 98a1d75..af78995 100644 --- a/xa/src/xal.h +++ b/xa/src/xal.h @@ -42,7 +42,7 @@ int l_search(char *s, int *l, int *x, int *v, int *afl); void l_set(int n, int v, int afl); int l_get(int n, int *v, int *afl); int l_vget(int n, int *v, char **s); -int ll_search(char *s, int *n); +int ll_search(char *s, int *n, int cll_fl); int ll_pdef(char *t); int b_open(void); diff --git a/xa/src/xap.c b/xa/src/xap.c index da8e3c3..3b5c58b 100644 --- a/xa/src/xap.c +++ b/xa/src/xap.c @@ -130,7 +130,7 @@ int pp_ifldef(char *t) int pp_iflused(char *t) { int n; - loopfl=(loopfl<<1)+( ll_search(t,&n) ? 1 : 0 ); + loopfl=(loopfl<<1)+( ll_search(t,&n,0) ? 1 : 0 ); return(0); } diff --git a/xa/src/xat.c b/xa/src/xat.c index a08539b..821a05d 100644 --- a/xa/src/xat.c +++ b/xa/src/xat.c @@ -75,7 +75,7 @@ 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" + ".align",".block", ".bend",".al",".as",".xl",".xs", ".bin", ".aasc", ".code" }; @@ -85,7 +85,7 @@ static int lp[]= { 0,1,1,1,1,2,2,1,1,1,2,2,2,1,1,1,2,2 }; /* last valid mnemonic */ #define Lastbef 93 /* last valid token+1 */ -#define Anzkey 123 +#define Anzkey 124 #define Kbyt Lastbef+1 #define Kword Lastbef+2 @@ -119,6 +119,8 @@ static int lp[]= { 0,1,1,1,1,2,2,1,1,1,2,2,2,1,1,1,2,2 }; #define Kbin Lastbef+28 #define Kaasc Lastbef+29 +#define Kcode Lastbef+30 /* gets remapped to Ktext */ + #define Kreloc Anzkey /* *= (relocation mode) */ #define Ksegment Anzkey+1 @@ -349,6 +351,7 @@ fprintf(stderr, "- p1 %d starting -\n", pc[segment]); printf("\n"); */ /* if text/data produced, then no more fopt allowed in romable mode */ + /* TODO: need to check, Kbyte is being remapped to Kbyt. What is the effect here? */ if((romable>1) && (t[0]base[SEG_TEXT] = pc[SEG_TEXT] = romaddr + h_length(); romable=1; @@ -1536,7 +1539,8 @@ static int t_conv(signed char *s, signed char *t, int *l, int pc, int *nk, static int v,f; static int operand,o; int fl,afl; - int p,q,ud,n,ll,mk,er; + int p,q,ud,ll,mk,er; + int n; /* label number to be passed between l_def (definition) and l_set (set the value) */ int m, uz, byte; static unsigned char cast; @@ -1586,6 +1590,7 @@ static int t_conv(signed char *s, signed char *t, int *l, int pc, int *nk, if(s[p]=='=') { + /*printf("Found = @%s\n",s+p);*/ t[q++]=T_OP; t[q++]=n&255; t[q++]=(n>>8)&255; @@ -1594,6 +1599,17 @@ static int t_conv(signed char *s, signed char *t, int *l, int pc, int *nk, ll=n=0; break; } else + if(s[p]==':' && s[p+1]=='=') /* support := label assignments (ca65 compatibility) */ + { + /*printf("Found := @%s\n", s+p);*/ + t[q++]=T_OP; + t[q++]=n&255; + t[q++]=(n>>8)&255; + t[q++]='='; + p+=2; + ll=n=0; + break; + } else if(f && s[p]!='\0' && s[p+1]=='=') { t[q++]=T_OP; @@ -1674,8 +1690,10 @@ static int t_conv(signed char *s, signed char *t, int *l, int pc, int *nk, if(operand) { /* are we forcing the operand into a particular - addressing mode? !, @, ` operators */ - if(s[p]=='!' || s[p]=='@' || s[p]=='`') + addressing mode? !, @, ` operators + Note these are not available in ca65, but we only + switch off "@" which are used for cheap local labels*/ + if(s[p]=='!' || (s[p]=='@' && !ca65) || s[p]=='`') { cast=s[p]; operand= -operand+1; @@ -1691,12 +1709,12 @@ static int t_conv(signed char *s, signed char *t, int *l, int pc, int *nk, { t[q++]=s[p++]; } else - /* maybe it's a label */ - if(isalpha(s[p]) || s[p]=='_') + /* maybe it's a label + Note that for ca65 cheap local labels, we check for "@" */ + if(isalpha(s[p]) || s[p]=='_' || (s[p]=='@' && ca65)) { m=n; er=l_search((char*)s+p,&ll,&n,&v,&afl); - /* if(m==Kglobl || m==Kextzero) { if(er==E_NODEF) { @@ -1961,6 +1979,7 @@ static int t_keyword(signed char *s, int *l, int *n) if(i==Kdw) i=Kword; if(i==Kblock) i=Kopen; if(i==Kbend) i=Kclose; + if(i==Kcode) i=Ktext; *l=j; From eae097c73ae38206603f177cf2b63c70f39a015b Mon Sep 17 00:00:00 2001 From: Andre Fachat Date: Fri, 16 Dec 2011 23:30:15 +0100 Subject: [PATCH 02/52] 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; From 1691f5fb46a28588de04f63792f8e7976661fa31 Mon Sep 17 00:00:00 2001 From: Andre Fachat Date: Fri, 16 Dec 2011 23:35:53 +0100 Subject: [PATCH 03/52] added first listing feature! --- xa/man/xa.1 | 5 + xa/src/xa.c | 33 +++- xa/src/xah.h | 29 ++-- xa/src/xal.c | 14 +- xa/src/xal.h | 5 + xa/src/xao.c | 2 +- xa/src/xat.c | 465 +++++++++++++++++++++++++++++++++++++++++++++++++-- xa/src/xat.h | 3 +- 8 files changed, 518 insertions(+), 38 deletions(-) diff --git a/xa/man/xa.1 b/xa/man/xa.1 index 8b443ce..df28951 100644 --- a/xa/man/xa.1 +++ b/xa/man/xa.1 @@ -57,6 +57,11 @@ use the special filename .BR \- to output to standard output. .TP +.B \-P filename +Set listing filename, default is none. use the special filename +.BR \- +to print the listing to standard output. +.TP .B \-e filename Set errorlog filename, default is none. .TP diff --git a/xa/src/xa.c b/xa/src/xa.c index 836c885..012fe45 100644 --- a/xa/src/xa.c +++ b/xa/src/xa.c @@ -77,7 +77,7 @@ char altppchar; static char out[MAXLINE]; static time_t tim1, tim2; -static FILE *fpout, *fperr, *fplab; +static FILE *fpout, *fperr, *fplab, *fplist; static int ner = 0; static int ner_max = 20; @@ -123,9 +123,10 @@ int main(int argc,char *argv[]) int no_link = 0; char **ifiles; - char *ofile; - char *efile; - char *lfile; + char *printfile; /* print listing to this file */ + char *ofile; /* output file */ + char *efile; /* error listing goes there */ + char *lfile; /* labels go here */ char *ifile; char old_e[MAXLINE]; @@ -179,6 +180,7 @@ int main(int argc,char *argv[]) ofile="a.o65"; efile=NULL; lfile=NULL; + printfile=NULL; if(pp_init()) { logout("fatal: pp: no memory!"); @@ -298,6 +300,13 @@ int main(int argc,char *argv[]) reg_include(argv[i]+2); } break; + case 'P': + if(argv[i][2]==0) { + printfile=argv[++i]; + } else { + printfile=argv[i]+2; + } + break; case 'o': if(argv[i][2]==0) { ofile=argv[++i]; @@ -378,6 +387,12 @@ int main(int argc,char *argv[]) if(setfext(old_l,".lab")==0) lfile = old_l; } + if (printfile!=NULL && !strcmp(printfile, "-")) { + printfile=NULL; + fplist = stdout; + } else { + fplist= printfile ? xfopen(printfile,"w") : NULL; + } fplab= lfile ? xfopen(lfile,"w") : NULL; fperr= efile ? xfopen(efile,"w") : NULL; if(!strcmp(ofile,"-")) { @@ -393,6 +408,7 @@ int main(int argc,char *argv[]) if(verbose) fprintf(stderr, "%s\n",copyright); + if(1 /*!m_init()*/) { if(1 /*!b_init()*/) @@ -406,6 +422,8 @@ int main(int argc,char *argv[]) if(fperr) fprintf(fperr,"%s\n",copyright); if(verbose) logout(ctime(&tim1)); + list_setfile(fplist); + /* Pass 1 */ pc[SEG_ABS]= 0; /* abs addressing */ @@ -498,9 +516,10 @@ int main(int argc,char *argv[]) if((!er) && relmode) seg_end(fpout); /* write reloc/label info */ + if(fplist && fplist!=stdout) fclose(fplist); if(fperr) fclose(fperr); if(fplab) fclose(fplab); - if(fpout) fclose(fpout); + if(fpout && fpout!=stdout) fclose(fpout); } else { logout("fatal: x: no memory!\n"); @@ -673,7 +692,7 @@ static int pass2(void) } else { /* do not attempt address mode optimization on pass 2 */ - er=t_p2(afile->mn.tmp+afile->mn.tmpe,&ll,1,&al); + er=t_p2_l(afile->mn.tmp+afile->mn.tmpe,&ll,1,&al); if(er==E_NOLINE) { @@ -779,7 +798,7 @@ fprintf(stderr, "offset = %i length = %i fstart = %i flen = %i charo = %c\n", static int pass1(void) { - signed char o[MAXLINE]; + signed char o[2*MAXLINE]; /* doubled for token listing */ int l,er,temp_er,al; memode=0; diff --git a/xa/src/xah.h b/xa/src/xah.h index 78ec1b8..d295c06 100644 --- a/xa/src/xah.h +++ b/xa/src/xah.h @@ -53,6 +53,7 @@ typedef struct { */ int afl; /* 0 = no address (no relocation), 1 = address label */ int nextindex; + int is_cll; /* 0 is normal label, 1 is cheap local label (used for listing) */ char *n; struct LabOcc *occlist; } Labtab; @@ -134,18 +135,24 @@ typedef struct { #define W_OVER16M -73 /* included binary over 16M in 65816 mode */ /* warnings 74-76 are placeholders */ -#define T_VALUE -1 -#define T_LABEL -2 -#define T_OP -3 -#define T_END -4 -#define T_LINE -5 -#define T_FILE -6 -#define T_POINTER -7 +/* Meta-values for the token list. Note must not overlap with the + * K* definitions in xat.c, which have outgrown the positive numbers + * and are now growing up from -128 ... */ +#define T_VALUE -1 /* following is a 24 bit value in the token list */ +#define T_LABEL -2 /* referring to a label, following the token is the 16bit label number */ +#define T_OP -3 /* label oriented operation; following is the label number (16bit), plus the operation char (e.g. '+') */ +#define T_END -4 /* end of line marker */ +#define T_LINE -5 /* new line indicator; following is the 16 bit line number */ +#define T_FILE -6 /* new file indicator; following is the 16 bit line number, then the file name (zero-term) */ +#define T_POINTER -7 /* ??? */ +#define T_COMMENT -8 /* unused */ +#define T_DEFINE -9 /* define a label; inserted at conversion and discarded in pass1, only used in listing output */ +#define T_LISTING -10 /* meta token, inserted after conversion before pass1, used after pass2 to create listing */ -#define P_START 0 /* Prioritaeten fuer Arithmetik */ -#define P_LOR 1 /* Von zwei Operationen wird immer */ -#define P_LAND 2 /* die mit der hoeheren Prioritaet */ -#define P_OR 3 /* zuerst ausgefuehrt */ +#define P_START 0 /* arithmetic operation priorities */ +#define P_LOR 1 /* of any two operations, the one with */ +#define P_LAND 2 /* the higher priority will be done first */ +#define P_OR 3 #define P_XOR 4 #define P_AND 5 #define P_EQU 6 diff --git a/xa/src/xal.c b/xa/src/xal.c index de18b7b..5aa59b6 100644 --- a/xa/src/xal.c +++ b/xa/src/xal.c @@ -313,6 +313,7 @@ int l_def(char *s, int *l, int *x, int *f) ltp=afile->la.lt+n; *l=ltp->len+i; ltp->fl=0; + ltp->is_cll=cll_fl; } } @@ -363,7 +364,8 @@ int l_search(char *s, int *l, int *x, int *v, int *afl) er=ll_def(s,x,b); /* ll_def(...,*v); */ ltp=afile->la.lt+(*x); - + ltp->is_cll = cll_fl; + *l=ltp->len + cll_fl; if(!er) @@ -411,6 +413,13 @@ void l_addocc(int n, int *v, int *afl) { } } +/* for the list functionality */ +char *l_get_name(int n, int *is_cll) { + ltp=afile->la.lt+n; + *is_cll = ltp->is_cll; + return ltp->n; +} + int l_get(int n, int *v, int *afl) { if(crossref) l_addocc(n,v,afl); @@ -495,6 +504,7 @@ static int ll_def(char *s, int *n, int b) /* definiert naechstes Label ltp->blk=b; ltp->fl=0; ltp->afl=0; + ltp->is_cll=0; ltp->occlist=NULL; hash=hashcode(s,j); ltp->nextindex=afile->la.hashindex[hash]; @@ -689,7 +699,7 @@ int b_close(void) } else { return E_BLOCK; } - + cll_clear(); return(E_OK); } diff --git a/xa/src/xal.h b/xa/src/xal.h index c0330c5..f44f720 100644 --- a/xa/src/xal.h +++ b/xa/src/xal.h @@ -21,6 +21,10 @@ #include /* for FILE */ +/* nasty stuff - "lz" is exported from xal.c so xa.c can print the name + * of the label that was last searched for in the error message that the + * label was not found... + */ extern char *lz; int l_init(void); @@ -42,6 +46,7 @@ int ga_blk(void); int l_def(char *s, int* l, int *x, int *f); int l_search(char *s, int *l, int *x, int *v, int *afl); void l_set(int n, int v, int afl); +char* l_get_name(int n, int *is_cll); int l_get(int n, int *v, int *afl); int l_vget(int n, int *v, char **s); int ll_search(char *s, int *n, int cll_fl); diff --git a/xa/src/xao.c b/xa/src/xao.c index 686b30d..be2bda0 100644 --- a/xa/src/xao.c +++ b/xa/src/xao.c @@ -66,7 +66,7 @@ void o_write(FILE *fp) { l=afile->fo.olist[i].len; t=afile->fo.olist[i].text; /* do not optimize */ - t_p2(t, &l, 1, &afl); + t_p2_l(t, &l, 1, &afl); if(l>254) { errout(E_OPTLEN); diff --git a/xa/src/xat.c b/xa/src/xat.c index ee0ee42..8000240 100644 --- a/xa/src/xat.c +++ b/xa/src/xat.c @@ -25,6 +25,7 @@ #include #include +#include #include "xad.h" #include "xah.h" @@ -48,6 +49,8 @@ static void tg_dez(signed char*,int*,int*); static void tg_hex(signed char*,int*,int*); static void tg_oct(signed char*,int*,int*); static void tg_bin(signed char*,int*,int*); +static int t_p2(signed char *t, int *ll, int fl, int *al); +static void do_listing(signed char *listing, int listing_len, signed char *bincode, int bincode_len); /* assembly mnemonics and pseudo-op tokens */ /* ina and dea don't work yet */ @@ -148,7 +151,7 @@ static int lp[]= { 0,1,1,1,1,2,2,1,1,1,2,2,2,1,1,1,2,2 }; #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 ... */ +#define Ksegment (Anzkey+1-256) /* this actually now is above 127, which might be a problem as char is signed ... */ /* array used for hashing tokens (26 entries, a-z) */ @@ -347,11 +350,14 @@ static int le[] ={ 1,2,2,2,2,2,2,2,3,3,3,2,3,3,3,2, static int opt[] ={ -1,-1,-1,-1,-1,-1,-1,-1,1,2,3,-1,4,5,-1,-1, /*new*/ -1,8,9,-1,-1,-1,-1,-1 }; /* abs -> zp */ +/*********************************************************************************************/ /* pass 1 */ int t_p1(signed char *s, signed char *t, int *ll, int *al) { static int er,l,n,v,nk,na1,na2,bl,am,sy,i,label,byte; /*,j,v2 ;*/ int afl = 0; + int tlen; /* token listing length, to adjust length that is returned */ + int inp; /* input pointer in t[] */ /* notes and typical conventions ... er = error code am = addressing mode in use @@ -366,18 +372,68 @@ int t_p1(signed char *s, signed char *t, int *ll, int *al) #ifdef DEBUG_AM 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 */ + + /* As the t_p1 code below always works through the tokens + * from t_conv in such a way that it always produces a shorter + * result, the conversion below takes place "in place". + * This, however, means that the original token sequence, which + * would be useful for some assembler listing, is overwritten. + * While the original assumption was ok for a constrained + * environment like the Atari ST, this is no longer true. + * Converting the code below to have separate input and output + * areas would be error-prone, so we do some copy-magic here + * instead...*/ + /* we keep three bytes buffer for "T_LISTING" and the length of the + * token list + */ + t[0]=T_LISTING; + er=t_conv(s,t+6,&l,pc[segment],&nk,&na1,&na2,0,&byte); + tlen = l+6; + t[1]=tlen&255; + t[2]=(tlen>>8)&255; + t[3]=segment; + t[4]=pc[segment]&255; + t[5]=(pc[segment]>>8)&255; + /* now duplicate the token sequence from the T_LISTING buffer + * to the end of "t", so we can then in-place convert it + * below. Non-overlapping, size is known in advance, so + * using memcpy is fine here + */ + memcpy(t+tlen, t+6, l); + t=t+tlen; + + /* the result of this is that we always have a Klisting entry in the buffer + * for each tokenization call */ + /* here continue as before, except for adjusting the returne *ll length + * in the end, just before return */ + + inp = 0; + /* discard label definitions */ + while (inp1) && (t[0]1) && (t[inp]base[SEG_TEXT] = pc[SEG_TEXT] = romaddr + h_length(); romable=1; } @@ -705,6 +761,8 @@ printf(" wrote %02x %02x %02x %02x %02x %02x\n", #ifdef DEBUG_AM fprintf(stderr, "E_OK ... t_p2 xat.c\n"); #endif + /* this actually calls pass2 on the current tokenization stream, + * but without including the Klisting token listing */ er=t_p2(t,ll,(0 | byte), al); } @@ -732,7 +790,7 @@ fprintf(stderr, "E_NODEF pass1 xat.c\n"); if(n>=0 && n<=Lastbef) { - if(t[1]==T_END) + if(t[1]==T_END || t[1]==T_COMMENT) { sy=0; /* implied */ } else @@ -906,10 +964,75 @@ fprintf(stderr, "guessing instruction length is %d\n", bl); if(segment==SEG_TEXT) pc[SEG_ABS]+=bl; if(segment==SEG_ABS) pc[SEG_TEXT]+=bl; + /* adjust length by token listing buffer length */ + *ll = *ll + tlen; return(er); } -/*t_pass 2*/ +/*********************************************************************************************/ +/* t_pass 2 + * + * *t is the token list as given from pass1 + * *ll is the returned length of bytes (doubles as + * input for whether OK or OKDEF status from pass1) + * fl defines if we allow zeropage optimization + * + * Conversion takes place "in place" in the *t array. + */ + +/** + * function called from the main loop, where "only" the + * undefined labels have to be resolved and the affected + * opcodes are assembled, the rest is passed through from + * pass1 (pass-through is done in t_p2, when *ll<0) + * + * *t is the input token list + * *ll is the input length of the token list, + * and the output of how many bytes of the buffer are to be taken + * into the file + */ +int t_p2_l(signed char *t, int *ll, int fl, int *al) +{ + int er = E_OK; + + if (t[0] == T_LISTING) { + int tlen; + tlen=((t[2]&255)<<8) | (t[1]&255); + if (*ll<0) { + *ll=(*ll) + tlen; + } else { + *ll=(*ll) - tlen; + } + + if (*ll != 0) { + er = t_p2(t+tlen, ll, fl, al); + } + + /* do the actual listing (*ll-2 as we need to substract the place for the tlen value */ + do_listing(t+3, tlen-3, t+tlen, *ll); + + /* adapt back, i.e. remove token listing */ + if (*ll != 0) { + memmove(t, t+tlen, abs(*ll)); + } + } else { + er = t_p2(t, ll, fl, al); + } + return er; +} + +/** + * This method does not handle a token list. Thus it + * is called internally from pass1 without the token listing, and + * from the t_p2_l() method that strips the token listing + * as well + * + * *t is the input token list + * *ll is the input length of the token list, + * and the output of how many bytes of the buffer are to be taken + * into the file + * + */ int t_p2(signed char *t, int *ll, int fl, int *al) { static int afl,nafl, i,j,k,er,v,n,l,bl,sy,am,c,vv[3],v2,label; @@ -924,11 +1047,12 @@ int t_p2(signed char *t, int *ll, int fl, int *al) er=E_OK; bl=0; - if(*ll<0) /* <0 bei E_OK, >0 bei E_OKDEF */ + if(*ll<0) /* <0 when E_OK, >0 when E_OKDEF */ { *ll=-*ll; bl=*ll; er=E_OK; + } else { n=t[0]; @@ -1591,10 +1715,11 @@ fprintf(stderr, "address mode: %i address: %i\n", am, vv[0]); er=E_SYNTAX; } } - + } else er=E_SYNTAX; } + #ifdef DEBUG_AM fprintf(stderr, "-- endof P2\n"); #endif @@ -1605,6 +1730,11 @@ fprintf(stderr, "-- endof P2\n"); return(er); } +/*********************************************************************************************/ +/* helper function for the preprocessor, to compute an arithmetic value + * (e.g. for #if or #print). + * First tokenizes it, then calculates the value + */ int b_term(char *s, int *v, int *l, int pc) { static signed char t[MAXLINE]; @@ -1618,10 +1748,14 @@ int b_term(char *s, int *v, int *l, int pc) return(er); } -/* translate a string into a first-pass sequence of tokens */ +/*********************************************************************************************/ +/* translate a string into a first-pass sequence of tokens; + * Take the text from *s (stopping at \0 or ';'), tokenize it + * and write the result to *t, returning the length of the + * token sequence in *l + */ static int t_conv(signed char *s, signed char *t, int *l, int pc, int *nk, - int *na1, int *na2, int af, int *bytep) /* Pass1 von s nach t */ -/* tr. pass1, from s to t */ + int *na1, int *na2, int af, int *bytep) { static int v,f; static int operand,o; @@ -1712,10 +1846,17 @@ static int t_conv(signed char *s, signed char *t, int *l, int pc, int *nk, p++; while(s[p]==' ') p++; l_set(n,pc,segment); /* set as address value */ + t[q++]=T_DEFINE; + t[q++]=n&255; + t[q++]=(n>>8)&255; n=0; + } else { /* label ... syntax */ l_set(n,pc,segment); /* set as address value */ - n=0; + t[q++]=T_DEFINE; + t[q++]=n&255; + t[q++]=(n>>8)&255; + n=0; } } @@ -2017,13 +2158,17 @@ fprintf(stderr, "could not find %s\n", (char *)s+p); } } /* FIXME: this is an unholy union of two "!" implementations :-( */ - t[q++]='\0'; - t[q++]=cast; + /* FIXME FIXME FIXME ... */ + if (operand==1) { + t[q++]='\0'; + t[q++]=cast; + } *l=q; if(bytep) *bytep=byte; return(er); } +/*********************************************************************************************/ static int t_keyword(signed char *s, int *l, int *n) { int i = 0, j = 0, hash; @@ -2206,3 +2351,291 @@ fprintf(stderr, "tg_asc token = %i\n", n); return(er); } +/*********************************************************************************************/ +/* this is the listing code + * + * Unfortunately this code has to go here (for now), as this file is the only one + * where we have access to the tables that allow to convert the tokens back to + * a listing + */ + +static FILE *listfp = NULL; + +static int list_string(char *buf, char *string); +static int list_tokens(char *buf, signed char *input, int len); +static int list_value(char *buf, int val); +static int list_nchar(char *buf, signed char c, int n); +static int list_char(char *buf, signed char c); +static int list_sp(char *buf); +static int list_word(char *buf, int outword); +static int list_byte(char *buf, int outbyte); +static int list_nibble(char *buf, int outnib); + +void list_setfile(FILE *fp) { + listfp = fp; +} + +/** + * listing/listing_len give the buffer address and length respectively that contains + * the token as they are produced by the tokenizer. + * bincode/bincode_len give the buffer address and length that contain the binary code + * that is produced from the token listing + * + * Note that both lengths may be zero + */ +void do_listing(signed char *listing, int listing_len, signed char *bincode, int bincode_len) { + + int i, n_hexb; + + char outline[MAXLINE]; + char *buf = outline; + + int lst_seg = listing[0]; + int lst_pc = (listing[2]<<8) | (listing[1] & 255); + + signed char c = '?'; + + /* no output file (not even stdout) */ + if (listfp == NULL) return; + + /*printf("do_listing: listing=%p (%d), bincode=%p (%d)\n", listing, listing_len, bincode, bincode_len);*/ + + if (bincode_len < 0) bincode_len = -bincode_len; + + /* preamble ':'
' ' */ + switch(lst_seg) { + case SEG_ABS: c='A'; break; + case SEG_TEXT: c='T'; break; + case SEG_BSS: c='B'; break; + case SEG_DATA: c='D'; break; + case SEG_UNDEF: c='U'; break; + case SEG_ZERO: c='Z'; break; + } + buf = buf + list_char(buf, c); + buf = buf + list_char(buf, ':'); + buf = buf + list_word(buf, lst_pc); + buf = buf + list_sp(buf); + + /* binary output (up to 8 byte. If more than 8 byte, print 7 plus "..." */ + n_hexb = bincode_len; + if (n_hexb >= 8) { + n_hexb = 7; + } + for (i = 0; i < n_hexb; i++) { + buf = buf + list_byte(buf, bincode[i]); + buf = buf + list_sp(buf); + } + if ((n_hexb == 7) && (bincode_len > 7)) { + buf = buf + list_nchar(buf, '.', 3); + } else { + /* can move loop into nchar ... */ + for (; i < 8; i++) { + buf = buf + list_nchar(buf, ' ', 3); + } + } + buf = buf + list_sp(buf); + + buf += list_tokens(buf, listing + 3, listing_len - 3); + + /* for now only do a hex dump so we see what actually happens */ + i = buf - outline; + if (i<80) buf += list_nchar(buf, ' ', 80-i); + + buf += list_string(buf, " >>"); + for (i = 3; i < listing_len; i++) { + buf = buf + list_byte(buf, listing[i]); + buf = buf + list_sp(buf); + } + buf[0] = 0; + + + fprintf(listfp, "%s\n", outline); +} + +int list_tokens(char *buf, signed char *input, int len) { + int outp = 0; + int inp = 0; + int tmp; + char *name; + signed char c; + int is_cll; + int tabval; + + if (inp >= len) return 0; + + tmp = input[inp] & 255; + + tabval = 0; + if (tmp == (T_DEFINE & 255)) { + while (tmp == (T_DEFINE & 255)) { + tmp = ((input[inp+2]&255)<<8) | (input[inp+1]&255); + name=l_get_name(tmp, &is_cll); + if (is_cll) outp += list_char(buf+outp, '@'); + tmp = list_string(buf+outp, name); + tabval += tmp + 1 + is_cll; + outp += tmp; + outp += list_char(buf+outp, ' '); + inp += 3; + tmp = input[inp] & 255; + } + if (tabval < 10) { + outp += list_nchar(buf+outp, ' ', 10-tabval); + } + } else { + if (tmp >= 0 && tmp < Anzkey) { + outp += list_string(buf+outp, " "); + } + } + + if (tmp >= 0 && tmp < Anzkey) { + /* assembler keyword */ + /*printf("tmp=%d, kt[tmp]=%p\n", tmp, kt[tmp]);*/ + if (kt[tmp] != NULL) { + outp += list_string(buf+outp, kt[tmp]); + } + outp += list_sp(buf + outp); + inp += 1; + } + + while (inp < len) { + switch(input[inp]) { + case T_VALUE: + /*outp += list_char(buf+outp, 'V');*/ + /* 24 bit value */ + tmp = ((input[inp+3]&255)<<16) | ((input[inp+2]&255)<<8) | (input[inp+1]&255); + outp += list_value(buf+outp, tmp); + inp += 4; + break; + case T_LABEL: + /*outp += list_char(buf+outp, 'L');*/ + /* 16 bit label number */ + tmp = ((input[inp+2]&255)<<8) | (input[inp+1]&255); + name=l_get_name(tmp, &is_cll); + if (is_cll) outp += list_char(buf+outp, '@'); + outp += list_string(buf+outp, name); + inp += 3; + break; + case T_OP: + /* arithmetic operation; inp[3] is operation like '=' or '+' */ + tmp = ((input[inp+2]&255)<<8) | (input[inp+1]&255); + name=l_get_name(tmp, &is_cll); + if (is_cll) outp += list_char(buf+outp, '@'); + outp += list_string(buf+outp, name); + outp += list_char(buf+outp, input[inp+3]); + inp += 4; + break; + case T_END: + /* end of operation */ + /*outp += list_string(buf+outp, ";");*/ + inp += 1; + goto end; + break; + case T_LINE: + /* newline marker - ignored? */ + outp += list_string(buf+outp, "\\n "); + /* line number */ + tmp = ((input[inp+2]&255)<<8) | (input[inp+1]&255); + outp += list_word(buf+outp, tmp); + inp += 3; + break; + case T_FILE: + /* new file marker - ignored? */ + outp += list_string(buf+outp, "\\f "); + /* line number */ + tmp = ((input[inp+2]&255)<<8) | (input[inp+1]&255); + outp += list_word(buf+outp, tmp); + /* file name */ + tmp = list_string(buf+outp, (char*)input+inp+3); + outp += tmp; + inp += tmp + 3; + break; + case T_POINTER: + /* what is this? It's actually resolved during token conversion */ + outp += list_byte(buf+outp, input[inp+1]); + outp += list_char(buf+outp, '#'); + tmp = ((input[inp+3]&255)<<8) | (input[inp+2]&255); + outp += list_value(buf+outp, tmp); + inp += 4; + break; + default: + c = input[inp]; + if (c > 31) { + outp += list_char(buf+outp, input[inp]); + } else { + outp += list_char(buf+outp, '\''); + outp += list_byte(buf+outp, input[inp]); + } + inp += 1; + break; + } + } +end: + return outp; +} + +int list_string(char *buf, char *string) { + int p = 0; + while (string[p] != 0) { + buf[p] = string[p]; + p++; + } + return p; +} + +int list_value(char *buf, int val) { + int p = 0; + p += list_char(buf + p, '$'); + if (val & (255<<16)) { + p += list_byte(buf+p, val>>16); + p += list_word(buf+p, val); + } else + if (val & (255<<8)) { + p += list_word(buf+p, val); + } else { + p += list_byte(buf+p, val); + } + return p; +} + +int list_nchar(char *buf, signed char c, int n) { + int i; + for (i = 0; i < n; i++) { + buf[i]=c; + } + return n; +} + +int list_char(char *buf, signed char c) { + buf[0] = c; + return 1; +} + +int list_sp(char *buf) { + buf[0] = ' '; + return 1; +} + +int list_word(char *buf, int outword) { + buf = buf + list_byte(buf, outword >> 8); + list_byte(buf, outword); + return 4; +} + +int list_byte(char *buf, int outbyte) { + buf = buf + list_nibble(buf, (outbyte >> 4)); + list_nibble(buf, outbyte); + return 2; +} + +int list_nibble(char *buf, int outnib) { + outnib = outnib & 0xf; + if (outnib < 10) { + buf[0]='0'+outnib; + } else { + buf[0]='a'-10+outnib; + } + return 1; +} + + + diff --git a/xa/src/xat.h b/xa/src/xat.h index ad7b82b..3620f67 100644 --- a/xa/src/xat.h +++ b/xa/src/xat.h @@ -21,8 +21,9 @@ extern int dsb_len; +void list_setfile(FILE *fp); int t_p1(signed char *s, signed char *t, int *ll, int *al); -int t_p2(signed char *t, int *ll, int fl, int *al); +int t_p2_l(signed char *t, int *ll, int fl, int *al); int b_term(char *s, int *v, int *l, int pc); #endif /* __XA65_XAT_H__ */ From 314660fb768c8f0418431af8c3951acb42a0d92d Mon Sep 17 00:00:00 2001 From: Andre Fachat Date: Fri, 16 Dec 2011 23:40:05 +0100 Subject: [PATCH 04/52] finished first set of listing features --- xa/src/Makefile | 2 +- xa/src/xa.c | 7 +- xa/src/xaa.c | 6 +- xa/src/xad.h | 3 +- xa/src/xah.h | 1 + xa/src/xao.c | 2 +- xa/src/xat.c | 549 ++++++++++++++++++++++++++++++++++-------------- xa/src/xat.h | 5 +- 8 files changed, 415 insertions(+), 160 deletions(-) diff --git a/xa/src/Makefile b/xa/src/Makefile index 62b4cae..173d634 100644 --- a/xa/src/Makefile +++ b/xa/src/Makefile @@ -2,7 +2,7 @@ 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 -ansi -O2 -CFLAGS=-g +CFLAGS=-g -std=c99 #LD = ${CC} #LDFLAGS = "-lc" diff --git a/xa/src/xa.c b/xa/src/xa.c index 012fe45..9f1d74c 100644 --- a/xa/src/xa.c +++ b/xa/src/xa.c @@ -672,6 +672,7 @@ static int pass2(void) { datei.fline=(afile->mn.tmp[afile->mn.tmpe+1]&255)+(afile->mn.tmp[afile->mn.tmpe+2]<<8); afile->mn.tmpe+=3; + list_line(datei.fline); /* set line number of next listing output */ } else if(afile->mn.tmp[afile->mn.tmpe]==T_FILE) { @@ -679,6 +680,8 @@ static int pass2(void) memcpy(&datei.fname, afile->mn.tmp+afile->mn.tmpe+3, sizeof(datei.fname)); afile->mn.tmpe+=3+sizeof(datei.fname); + + list_filename(datei.fname); /* set file name of next listing output */ /* datei.fname = malloc(strlen((char*) afile->mn.tmp+afile->mn.tmpe+3)+1); if(!datei.fname) { @@ -692,7 +695,9 @@ static int pass2(void) } else { /* do not attempt address mode optimization on pass 2 */ - er=t_p2_l(afile->mn.tmp+afile->mn.tmpe,&ll,1,&al); + + /* t_p2_l() includes the listing call to do_listing() */ + er=t_p2_l(afile->mn.tmp+afile->mn.tmpe,&ll,&al); if(er==E_NOLINE) { diff --git a/xa/src/xaa.c b/xa/src/xaa.c index a23f1a9..2f4dcaa 100644 --- a/xa/src/xaa.c +++ b/xa/src/xaa.c @@ -137,7 +137,7 @@ static int ag_term(signed char *s, int p, int *v, int *nafl, int *label) if(s[pp]==T_VALUE) { *v=lval(s+pp+1); - pp+=4; + pp+=5; /* printf("value: v=%04x\n",*v); */ } else @@ -145,7 +145,7 @@ static int ag_term(signed char *s, int p, int *v, int *nafl, int *label) { afl = s[pp+1]; *v=cval(s+pp+2); - pp+=4; + pp+=6; /* printf("pointer: v=%04x, afl=%04x\n",*v,afl); */ } else @@ -161,7 +161,7 @@ static int ag_term(signed char *s, int p, int *v, int *nafl, int *label) *v *= mf; - while(!er && s[pp]!=')' && s[pp]!=']' && s[pp]!=',' && s[pp]!=T_END) + while(!er && s[pp]!=')' && s[pp]!=']' && s[pp]!=',' && s[pp]!=T_END && s[pp]!=T_COMMENT) { er=get_op(s,&o); diff --git a/xa/src/xad.h b/xa/src/xad.h index 79528fc..2c2a64c 100644 --- a/xa/src/xad.h +++ b/xa/src/xad.h @@ -31,11 +31,12 @@ #define cval(s) 256 * ((s)[1] & 255) + ((s)[0]&255) #define lval(s) 65536 * ((s)[2] & 255) + 256 * ((s)[1] & 255) + ((s)[0] & 255) -#define wval(i, v) do { \ +#define wval(i, v, f) do { \ t[i++] = T_VALUE; \ t[i++] = v & 255; \ t[i++] = (v >> 8) & 255; \ t[i++] = (v >> 16) & 255; \ + t[i++] = f & 255; \ } while (0) #endif /* __XA65_XAD_H__ */ diff --git a/xa/src/xah.h b/xa/src/xah.h index d295c06..6902242 100644 --- a/xa/src/xah.h +++ b/xa/src/xah.h @@ -148,6 +148,7 @@ typedef struct { #define T_COMMENT -8 /* unused */ #define T_DEFINE -9 /* define a label; inserted at conversion and discarded in pass1, only used in listing output */ #define T_LISTING -10 /* meta token, inserted after conversion before pass1, used after pass2 to create listing */ +#define T_CAST -11 /* token inserted for a cast */ #define P_START 0 /* arithmetic operation priorities */ #define P_LOR 1 /* of any two operations, the one with */ diff --git a/xa/src/xao.c b/xa/src/xao.c index be2bda0..7077f02 100644 --- a/xa/src/xao.c +++ b/xa/src/xao.c @@ -66,7 +66,7 @@ void o_write(FILE *fp) { l=afile->fo.olist[i].len; t=afile->fo.olist[i].text; /* do not optimize */ - t_p2_l(t, &l, 1, &afl); + t_p2_l(t, &l, &afl); if(l>254) { errout(E_OPTLEN); diff --git a/xa/src/xat.c b/xa/src/xat.c index 8000240..39b5793 100644 --- a/xa/src/xat.c +++ b/xa/src/xat.c @@ -22,6 +22,7 @@ /* enable this to turn on (copious) optimization output */ /* #define DEBUG_AM */ +#undef LISTING_DEBUG #include #include @@ -94,6 +95,18 @@ static char *kt[] ={ }; +/* arithmetic operators (purely for listing, parsing is done programmatically */ +static char *arith_ops[] = { + "", "+", "-", + "*", "/", + ">>", "<<", + "<", ">", "=" + "<=", ">=", "<>", + "&", "^", "|", + "&&", "||" +}; + +/* length of arithmetic operators indexed by operator number */ 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 */ @@ -358,11 +371,13 @@ int t_p1(signed char *s, signed char *t, int *ll, int *al) int afl = 0; int tlen; /* token listing length, to adjust length that is returned */ int inp; /* input pointer in t[] */ + unsigned char cast; /* notes and typical conventions ... er = error code am = addressing mode in use */ + cast='\0'; bl=0; *al = 0; @@ -394,33 +409,25 @@ fprintf(stderr, "- p1 %d starting -\n", pc[segment]); t[3]=segment; t[4]=pc[segment]&255; t[5]=(pc[segment]>>8)&255; - /* now duplicate the token sequence from the T_LISTING buffer + /* now we have to duplicate the token sequence from the T_LISTING buffer * to the end of "t", so we can then in-place convert it * below. Non-overlapping, size is known in advance, so * using memcpy is fine here */ - memcpy(t+tlen, t+6, l); + inp = 0; + /* discard label definitions before copying the buffer */ + while (inp=0 && n<=Lastbef) { - if(t[1]==T_END || t[1]==T_COMMENT) + int inp = 1; /* input pointer */ + + if(t[inp]==T_END || t[inp]==T_COMMENT) { sy=0; /* implied */ + inp++; } else - if(t[1]=='#') + if(t[inp]=='#') { sy=1+nk; /* immediate */ + inp++; } else - if(t[1]=='(') + if(t[inp]=='(') { sy=7+nk; /* computed */ - } else + inp++; + } else { sy=4+nk; /* absolute or zero page */ + } + /* this actually finds the cast for all addressing modes, + but t_conv() only puts it there for immediate (#) or absolute/ + absolute indexed addressing modes */ + if (t[inp] == T_CAST) { + inp++; + cast = t[inp]; + inp++; + } + + /* length counter set to maximum length + 1 */ bl=Maxbyt+1; @@ -842,20 +865,20 @@ fprintf(stderr, "E_NODEF pass1 xat.c\n"); /* optimize operand length for 24-bit quantities */ /* look at cast byte from t_conv */ - if (t[l-1]!='@' && t[l-1] != '!') + if (cast!='@' && cast!= '!') { if(bl && !er && opt[am]>=0 && am>16) /* <<< NOTE! */ if(ct[n][opt[am]]>=0) am=opt[am]; } /* if ` is declared, force further optimization */ - if (t[l-1]=='`') { + if (cast=='`') { if (opt[am]<0 || ct[n][opt[am]]<0) errout(E_ADRESS); am=opt[am]; } /* if ! is declared, force to 16-bit quantity */ - if (t[l-1]=='!' && am>16 && opt[am]>=0 && bl) { + if (cast=='!' && am>16 && opt[am]>=0 && bl) { am=opt[am]; } @@ -985,13 +1008,15 @@ fprintf(stderr, "guessing instruction length is %d\n", bl); * undefined labels have to be resolved and the affected * opcodes are assembled, the rest is passed through from * pass1 (pass-through is done in t_p2, when *ll<0) + * As this is not called from p1, assume that we do not + * do length optimization * * *t is the input token list * *ll is the input length of the token list, * and the output of how many bytes of the buffer are to be taken * into the file */ -int t_p2_l(signed char *t, int *ll, int fl, int *al) +int t_p2_l(signed char *t, int *ll, int *al) { int er = E_OK; @@ -1005,10 +1030,10 @@ int t_p2_l(signed char *t, int *ll, int fl, int *al) } if (*ll != 0) { - er = t_p2(t+tlen, ll, fl, al); + er = t_p2(t+tlen, ll, 1, al); } - /* do the actual listing (*ll-2 as we need to substract the place for the tlen value */ + /* do the actual listing (*ll-2 as we need to substract the place for the tlen value) */ do_listing(t+3, tlen-3, t+tlen, *ll); /* adapt back, i.e. remove token listing */ @@ -1016,7 +1041,7 @@ int t_p2_l(signed char *t, int *ll, int fl, int *al) memmove(t, t+tlen, abs(*ll)); } } else { - er = t_p2(t, ll, fl, al); + er = t_p2(t, ll, 1, al); } return er; } @@ -1031,7 +1056,8 @@ int t_p2_l(signed char *t, int *ll, int fl, int *al) * *ll is the input length of the token list, * and the output of how many bytes of the buffer are to be taken * into the file - * + * fl when set, do not do length optimization, when not set, + * allow length optimization (when called from p1) */ int t_p2(signed char *t, int *ll, int fl, int *al) { @@ -1039,12 +1065,6 @@ int t_p2(signed char *t, int *ll, int fl, int *al) static int rlt[3]; /* relocation table */ static int lab[3]; /* undef. label table */ -#if(0) - (void)fl; /* quench warning */ -#endif -/* fl was not used in 2.2.0 so I'm overloading it for zp-optimization - control */ - er=E_OK; bl=0; if(*ll<0) /* <0 when E_OK, >0 when E_OKDEF */ @@ -1124,7 +1144,7 @@ int t_p2(signed char *t, int *ll, int fl, int *al) { i=1; j=0; - while(!er && t[i]!=T_END) + while(!er && t[i]!=T_END && t[i] != T_COMMENT) { if(!(er=a_term(t+i,&v,&l,pc[segment],&afl,&label,1))) { @@ -1135,7 +1155,7 @@ int t_p2(signed char *t, int *ll, int fl, int *al) t[j++]=(v>>8)&255; i+=l; - if(t[i]!=T_END && t[i]!=',') + if(t[i]!=T_END && t[i] != T_COMMENT && t[i]!=',') er=E_SYNTAX; else if(t[i]==',') @@ -1217,7 +1237,7 @@ int t_p2(signed char *t, int *ll, int fl, int *al) } /* three arguments only please */ - if (!er && t[i] != T_END) { + if (!er && t[i] != T_END && t[i] != T_COMMENT) { er = E_SYNTAX; } @@ -1266,7 +1286,7 @@ int t_p2(signed char *t, int *ll, int fl, int *al) } else if(n==Kasc || n==Kbyt || n==Kaasc) { i=1; j=0; - while(!er && t[i]!=T_END) + while(!er && t[i]!=T_END && t[i] != T_COMMENT) { if(t[i]=='\"') { @@ -1290,7 +1310,7 @@ int t_p2(signed char *t, int *ll, int fl, int *al) } } } - if(t[i]!=T_END && t[i]!=',') + if(t[i]!=T_END && t[i] != T_COMMENT && t[i]!=',') er=E_SYNTAX; else if(t[i]==',') @@ -1388,44 +1408,54 @@ fprintf(stderr, "Kdsb E_DSB %i\n", j); } else if(n>=0 && n<=Lastbef) { - if((c=t[1])=='#') + int inp = 1; /* input pointer */ + signed char cast = '\0'; /* cast value */ + + c = t[inp]; + + if(c=='#') { - i=2; + inp++; + if (t[inp] == T_CAST) { + inp++; + cast = t[inp]; + inp++; + } sy=1; - if(!(er=a_term(t+i,vv,&l,pc[segment],&afl,&label,1))) + if(!(er=a_term(t+inp,vv,&l,pc[segment],&afl,&label,1))) { /* if(1) printf("a_term returns afl=%04x\n",afl); */ rlt[0] = afl; lab[0] = label; - i+=l; - if(t[i]!=T_END) + inp+=l; + if(t[inp]!=T_END && t[inp] != T_COMMENT) { - if(t[i]!=',') + if(t[inp]!=',') er=E_SYNTAX; else { - i++; + inp++; sy++; - if(!(er=a_term(t+i,vv+1,&l,pc[segment],&afl,&label,1))) + if(!(er=a_term(t+inp,vv+1,&l,pc[segment],&afl,&label,1))) { rlt[1] = afl; lab[1] = label; - i+=l; - if(t[i]!=T_END) + inp+=l; + if(t[inp]!=T_END && t[inp] != T_COMMENT) { - if(t[i]!=',') + if(t[inp]!=',') er=E_SYNTAX; else { - i++; + inp++; sy++; - if(!(er=a_term(t+i,vv+2,&l,pc[segment],&afl,&label,1))) + if(!(er=a_term(t+inp,vv+2,&l,pc[segment],&afl,&label,1))) { rlt[2] = afl; lab[2] = label; - i+=l; - if(t[i]!=T_END) + inp+=l; + if(t[inp]!=T_END && t[inp]!=T_COMMENT) er=E_SYNTAX; } } @@ -1435,38 +1465,48 @@ fprintf(stderr, "Kdsb E_DSB %i\n", j); } } } else - if(c==T_END) + if(c==T_END || c==T_COMMENT) { sy=0; } else if(c=='(') { + inp++; + if (t[inp] == T_CAST) { + inp++; + cast = t[inp]; + inp++; + } sy=7; - if(!(er=a_term(t+2,vv,&l,pc[segment],&afl,&label,1))) + if(!(er=a_term(t+inp,vv,&l,pc[segment],&afl,&label,1))) { + inp += l; rlt[0] = afl; lab[0] = label; - if(t[2+l]!=T_END) + if(t[inp]!=T_END && t[inp]!=T_COMMENT) { - if(t[2+l]==',') + if(t[inp]==',') { - if (tolower(t[3+l])=='x') + inp++; + if (tolower(t[inp])=='x') sy=8; else sy=13; } else - if(t[2+l]==')') + if(t[inp]==')') { - if(t[3+l]==',') + inp++; + if(t[inp]==',') { - if(tolower(t[4+l])=='y') + inp++; + if(tolower(t[inp])=='y') sy=9; else er=E_SYNTAX; } else - if(t[3+l]!=T_END) + if(t[inp]!=T_END && t[inp]!=T_COMMENT) er=E_SYNTAX; } } else @@ -1475,24 +1515,33 @@ fprintf(stderr, "Kdsb E_DSB %i\n", j); } else if(c=='[') { + inp++; + if (t[inp] == T_CAST) { + inp++; + cast = t[inp]; + inp++; + } sy=10; - if(!(er=a_term(t+2,vv,&l,pc[segment],&afl,&label,1))) + if(!(er=a_term(t+inp,vv,&l,pc[segment],&afl,&label,1))) { + inp += l; rlt[0] = afl; lab[0] = label; - if(t[2+l]!=T_END) + if(t[inp]!=T_END && t[inp]!=T_COMMENT) { - if(t[2+l]==']') + if(t[inp]==']') { - if(t[3+l]==',') + inp++; + if(t[inp]==',') { - if(tolower(t[4+l])=='y') + inp++; + if(tolower(t[inp])=='y') sy=11; else er=E_SYNTAX; } else - if(t[3+l]!=T_END) + if(t[inp]!=T_END && t[inp]!=T_COMMENT) er=E_SYNTAX; } } else @@ -1500,19 +1549,26 @@ fprintf(stderr, "Kdsb E_DSB %i\n", j); } } else { + if (t[inp] == T_CAST) { + inp++; + cast = t[inp]; + inp++; + } sy=4; - if(!(er=a_term(t+1,vv,&l,pc[segment],&afl,&label,1))) + if(!(er=a_term(t+inp,vv,&l,pc[segment],&afl,&label,1))) { + inp += l; rlt[0] = afl; lab[0] = label; - if(t[1+l]!=T_END) + if(t[inp]!=T_END && t[inp]!=T_COMMENT) { - if(t[1+l]==',') + if(t[inp]==',') { - if(tolower(t[2+l])=='y') + inp++; + if(tolower(t[inp])=='y') sy=6; else - if(tolower(t[2+l])=='s') + if(tolower(t[inp])=='s') sy=12; else sy=5; @@ -1557,7 +1613,7 @@ fprintf(stderr, "Kdsb E_DSB %i\n", j); /* only do optimization if we're being called in pass 1 -- never pass 2 */ /* look at cast byte */ - if (t[*ll-1]!='@') + if (cast!='@') { #ifdef DEBUG_AM fprintf(stderr, @@ -1578,10 +1634,10 @@ fprintf(stderr, "aftaa1: pc= %d, am = %d and vv[0] = %d, optimize = %d, bitmask = %d\n", pc[segment], am, vv[0], fl, (vv[0]&0xffff00)); #endif - if(t[*ll-1]!='!') { + if(cast!='!') { if(bl && !er && !(vv[0]&0xffff00) && opt[am]>=0) { if(ct[n][opt[am]]>=0) { - if (!fl || t[*ll-1]=='`') { + if (!fl || cast=='`') { am=opt[am]; } else { errout(W_FORLAB); @@ -1753,6 +1809,19 @@ int b_term(char *s, int *v, int *l, int pc) * Take the text from *s (stopping at \0 or ';'), tokenize it * and write the result to *t, returning the length of the * token sequence in *l + * + * Input params: + * s source input line + * t output token sequence buffer + * l return length of output token sequence here + * pc the current PC to set address labels to that value + * nk return number of comma in the parameters + * na1 asc text count returned + * na2 total byte count in asc texts returned + * af arithmetic flag: 0=do label definitions, parse opcodes and params; + * 1=only tokenize parameters, for b_term() call from the preprocessor + * for arithmetic conditions + * bytep ??? */ static int t_conv(signed char *s, signed char *t, int *l, int pc, int *nk, int *na1, int *na2, int af, int *bytep) @@ -1760,10 +1829,12 @@ static int t_conv(signed char *s, signed char *t, int *l, int pc, int *nk, static int v,f; static int operand,o; int fl,afl; - int p,q,ud,ll,mk,er; + int p,q,ll,mk,er; + int ud; /* counts undefined labels */ int n; /* label number to be passed between l_def (definition) and l_set (set the value) */ - int m, uz, byte; - static unsigned char cast; + int m, byte; + int uz; /* unused at the moment */ + /*static unsigned char cast;*/ /* ich verstehe deutsch, aber verstehen andere leute nicht; so, werde ich diese bemerkungen uebersetzen ... cameron */ @@ -1786,7 +1857,7 @@ static int t_conv(signed char *s, signed char *t, int *l, int pc, int *nk, while(s[p]==' ') p++; n=T_END; - cast='\0'; + /*cast='\0';*/ if(!af) { @@ -1923,7 +1994,9 @@ static int t_conv(signed char *s, signed char *t, int *l, int pc, int *nk, switch off "@" which are used for cheap local labels*/ if(s[p]=='!' || (s[p]=='@' && !ca65) || s[p]=='`') { - cast=s[p]; + t[q++]=T_CAST; + t[q++]=s[p]; + /*cast=s[p];*/ operand= -operand+1; p++; } else @@ -1961,8 +2034,13 @@ static int t_conv(signed char *s, signed char *t, int *l, int pc, int *nk, t[q++]=afl & 255; t[q++]=v & 255; t[q++]=(v>>8) & 255; + t[q++]=n & 255; /* cheap fix for listing */ + t[q++]=(n>>8) & 255; /* why is the label already resolved in t_conv? */ } else { - wval(q,v); + t[q++]=T_LABEL; + t[q++]=n & 255; + t[q++]=(n>>8) & 255; + /*wval(q,v, 0);*/ } } else if(er==E_NODEF) @@ -1986,7 +2064,7 @@ fprintf(stderr, "could not find %s\n", (char *)s+p); { tg_dez(s+p,&ll,&v); p+=ll; - wval(q,v); + wval(q,v, 'd'); } else @@ -1995,17 +2073,17 @@ fprintf(stderr, "could not find %s\n", (char *)s+p); case '$': tg_hex(s+p+1,&ll,&v); p+=1+ll; - wval(q,v); + wval(q,v, '$'); break; case '%': tg_bin(s+p+1,&ll,&v); p+=1+ll; - wval(q,v); + wval(q,v, '%'); break; case '&': tg_oct(s+p+1,&ll,&v); p+=1+ll; - wval(q,v); + wval(q,v, '&'); break; case '\'': case '\"': @@ -2127,9 +2205,6 @@ fprintf(stderr, "could not find %s\n", (char *)s+p); { t[q++]=o; p+=lp[o]; -#if(0) - uz++; /* disable 8-bit detection */ -#endif } operand= -operand+1; } @@ -2151,18 +2226,35 @@ fprintf(stderr, "could not find %s\n", (char *)s+p); } */ byte = 0; - t[q++]=T_END; if(ud > 0) { er=E_NODEF; byte = 1; } } + + if (s[p] == ';') { + /* handle comments */ + /* first find out how long */ + int i; + for (i = p+1; s[i] != '\0'; i++); + i = i - p; /* actual length of the comment, including zero-byte terminator */ + /*if (i >= 1) {*/ + /* there actually is a comment */ + t[q++] = T_COMMENT; + t[q++] = i&255; + t[q++] = (i>>8)&255; + memcpy(t+q, s+p+1, i); /* also copy zero terminator, used in listing */ + q += i; + /*}*/ + } + t[q++]=T_END; /* FIXME: this is an unholy union of two "!" implementations :-( */ - /* FIXME FIXME FIXME ... */ + /* FIXME FIXME FIXME ... if (operand==1) { t[q++]='\0'; t[q++]=cast; } + */ *l=q; if(bytep) *bytep=byte; return(er); @@ -2336,7 +2428,8 @@ fprintf(stderr, "tg_asc token = %i\n", n); t[1]=t[2]; t[2]=0; t[3]=0; - j++; + t[4]=delimiter; + j+=2; } else { /* handle as string */ t[1]=j-2; @@ -2360,17 +2453,42 @@ fprintf(stderr, "tg_asc token = %i\n", n); */ static FILE *listfp = NULL; +static int list_lineno = 1; /* current line number */ +static int list_last_lineno = 0; /* current line number */ +static char *list_filenamep = NULL; /* current file name pointer */ static int list_string(char *buf, char *string); static int list_tokens(char *buf, signed char *input, int len); -static int list_value(char *buf, int val); +static int list_value(char *buf, int val, signed char format); static int list_nchar(char *buf, signed char c, int n); static int list_char(char *buf, signed char c); static int list_sp(char *buf); static int list_word(char *buf, int outword); +static int list_word_f(char *buf, int outword, signed char format); static int list_byte(char *buf, int outbyte); -static int list_nibble(char *buf, int outnib); +static int list_byte_f(char *buf, int outbyte, signed char format); +static int list_nibble_f(char *buf, int outnib, signed char format); +/* set line number for the coming listing output */ +void list_line(int l) { + list_lineno = l; +} + +/* set file name for the coming listing output */ +void list_filename(char *fname) { + if (list_filenamep == NULL || (fname != NULL && strcmp(fname, list_filenamep) != 0)) { + list_filenamep = fname; + list_lineno = 1; + list_last_lineno = 0; + + /* Hack */ + fprintf(listfp, "\n%s\n\n", fname); + } +} + +/** + * set the output file descriptor where to write the listing + */ void list_setfile(FILE *fp) { listfp = fp; } @@ -2402,6 +2520,20 @@ void do_listing(signed char *listing, int listing_len, signed char *bincode, int if (bincode_len < 0) bincode_len = -bincode_len; + /* do we need a separation line? */ + if (list_lineno > list_last_lineno+1) { + /* yes */ + /*fprintf(listfp, "line=%d, last=%d\n", list_lineno, list_last_lineno);*/ + fprintf(listfp, "\n"); + } + list_last_lineno = list_lineno; + + /* line number in file */ + snprintf(buf, 10, "% 5d", list_lineno); + i = strlen(buf); + buf += i; + buf += list_char(buf, ' '); + /* preamble ':'
' ' */ switch(lst_seg) { case SEG_ABS: c='A'; break; @@ -2414,7 +2546,7 @@ void do_listing(signed char *listing, int listing_len, signed char *bincode, int buf = buf + list_char(buf, c); buf = buf + list_char(buf, ':'); buf = buf + list_word(buf, lst_pc); - buf = buf + list_sp(buf); + buf = buf + list_nchar(buf, ' ', 2); /* binary output (up to 8 byte. If more than 8 byte, print 7 plus "..." */ n_hexb = bincode_len; @@ -2437,6 +2569,7 @@ void do_listing(signed char *listing, int listing_len, signed char *bincode, int buf += list_tokens(buf, listing + 3, listing_len - 3); +#ifdef LISTING_DEBUG /* for now only do a hex dump so we see what actually happens */ i = buf - outline; if (i<80) buf += list_nchar(buf, ' ', 80-i); @@ -2446,8 +2579,8 @@ void do_listing(signed char *listing, int listing_len, signed char *bincode, int buf = buf + list_byte(buf, listing[i]); buf = buf + list_sp(buf); } +#endif buf[0] = 0; - fprintf(listfp, "%s\n", outline); } @@ -2460,6 +2593,7 @@ int list_tokens(char *buf, signed char *input, int len) { signed char c; int is_cll; int tabval; + signed char format; if (inp >= len) return 0; @@ -2467,8 +2601,9 @@ int list_tokens(char *buf, signed char *input, int len) { tabval = 0; if (tmp == (T_DEFINE & 255)) { - while (tmp == (T_DEFINE & 255)) { + while (inp < len && tmp == (T_DEFINE & 255)) { tmp = ((input[inp+2]&255)<<8) | (input[inp+1]&255); +/*printf("define: len=%d, inp=%d, tmp=%d\n", len, inp, tmp);*/ name=l_get_name(tmp, &is_cll); if (is_cll) outp += list_char(buf+outp, '@'); tmp = list_string(buf+outp, name); @@ -2495,16 +2630,36 @@ int list_tokens(char *buf, signed char *input, int len) { } outp += list_sp(buf + outp); inp += 1; + + if (tmp == Kinclude) { + /* just another exception from the rule... */ + /* next char is terminator (", ') then the length and then the file name */ + char term = input[inp]; + int len = input[inp+1] & 255; + outp += list_char(buf+outp, term); + for (tmp = 2; tmp < len+2; tmp++) { + outp += list_char(buf+outp, input[inp+tmp]); + } + outp += list_char(buf+outp, term); + inp += len + 2; + } } while (inp < len) { + int operator = 0; + switch(input[inp]) { + case T_CAST: + outp += list_char(buf+outp, input[inp+1]); + break; case T_VALUE: /*outp += list_char(buf+outp, 'V');*/ /* 24 bit value */ tmp = ((input[inp+3]&255)<<16) | ((input[inp+2]&255)<<8) | (input[inp+1]&255); - outp += list_value(buf+outp, tmp); - inp += 4; + format = input[inp+4]; + outp += list_value(buf+outp, tmp, format); + inp += 5; + operator = 1; /* check if arithmetic operator follows */ break; case T_LABEL: /*outp += list_char(buf+outp, 'L');*/ @@ -2514,15 +2669,17 @@ int list_tokens(char *buf, signed char *input, int len) { if (is_cll) outp += list_char(buf+outp, '@'); outp += list_string(buf+outp, name); inp += 3; + operator = 1; /* check if arithmetic operator follows */ break; case T_OP: - /* arithmetic operation; inp[3] is operation like '=' or '+' */ + /* label arithmetic operation; inp[3] is operation like '=' or '+' */ tmp = ((input[inp+2]&255)<<8) | (input[inp+1]&255); name=l_get_name(tmp, &is_cll); if (is_cll) outp += list_char(buf+outp, '@'); outp += list_string(buf+outp, name); outp += list_char(buf+outp, input[inp+3]); inp += 4; + break; case T_END: /* end of operation */ @@ -2530,32 +2687,34 @@ int list_tokens(char *buf, signed char *input, int len) { inp += 1; goto end; break; - case T_LINE: - /* newline marker - ignored? */ - outp += list_string(buf+outp, "\\n "); - /* line number */ + case T_COMMENT: + if (inp > 0 && inp < 20) { + outp += list_nchar(buf+outp, ' ', 20-inp); + } tmp = ((input[inp+2]&255)<<8) | (input[inp+1]&255); - outp += list_word(buf+outp, tmp); - inp += 3; - break; - case T_FILE: - /* new file marker - ignored? */ - outp += list_string(buf+outp, "\\f "); - /* line number */ - tmp = ((input[inp+2]&255)<<8) | (input[inp+1]&255); - outp += list_word(buf+outp, tmp); - /* file name */ - tmp = list_string(buf+outp, (char*)input+inp+3); - outp += tmp; + outp += list_char(buf+outp, ';'); + outp += list_string(buf+outp, (char*)input+inp+3); inp += tmp + 3; break; + case T_LINE: + case T_FILE: + /* those two are meta-tokens, evaluated outside the t_p2 call, + * they result in calls to list_line(), list_filename() */ + break; case T_POINTER: /* what is this? It's actually resolved during token conversion */ + tmp = ((input[inp+5]&255)<<8) | (input[inp+4]&255); + name=l_get_name(tmp, &is_cll); + if (is_cll) outp += list_char(buf+outp, '@'); + outp += list_string(buf+outp, name); + /* outp += list_byte(buf+outp, input[inp+1]); outp += list_char(buf+outp, '#'); tmp = ((input[inp+3]&255)<<8) | (input[inp+2]&255); outp += list_value(buf+outp, tmp); - inp += 4; + */ + inp += 6; + operator = 1; /* check if arithmetic operator follows */ break; default: c = input[inp]; @@ -2568,6 +2727,15 @@ int list_tokens(char *buf, signed char *input, int len) { inp += 1; break; } + + if (operator && inp < len) { + signed char op = input[inp]; + if (op > 0 && op <= 17) { + outp += list_string(buf+outp, arith_ops[op]); + inp += 1; + } + operator = 0; + } } end: return outp; @@ -2582,17 +2750,63 @@ int list_string(char *buf, char *string) { return p; } -int list_value(char *buf, int val) { +int list_value(char *buf, int val, signed char format) { int p = 0; - p += list_char(buf + p, '$'); - if (val & (255<<16)) { - p += list_byte(buf+p, val>>16); - p += list_word(buf+p, val); - } else - if (val & (255<<8)) { - p += list_word(buf+p, val); - } else { - p += list_byte(buf+p, val); + char valbuf[32]; + + switch (format) { + case '$': + p += list_char(buf + p, '$'); + if (val & (255<<16)) { + p += list_byte(buf+p, val>>16); + p += list_word(buf+p, val); + } else + if (val & (255<<8)) { + p += list_word(buf+p, val); + } else { + p += list_byte(buf+p, val); + } + break; + case '%': + p += list_char(buf + p, '%'); + if (val & (255<<16)) { + p += list_byte_f(buf+p, val>>16,'%'); + p += list_word_f(buf+p, val,'%'); + } else + if (val & (255<<8)) { + p += list_word_f(buf+p, val,'%'); + } else { + p += list_byte_f(buf+p, val,'%'); + } + break; + case '&': + snprintf(valbuf, 32, "%o",val); + p+= list_char(buf+p, '&'); + p+= list_string(buf+p, valbuf); + break; + case 'd': + snprintf(valbuf, 32, "%d",val); + p+= list_string(buf+p, valbuf); + break; + case '\'': + case '"': + p+= list_char(buf+p, format); + p+= list_char(buf+p, val); + p+= list_char(buf+p, format); + break; + default: + /* hex format as fallback */ + p += list_char(buf + p, '$'); + if (val & (255<<16)) { + p += list_byte(buf+p, val>>16); + p += list_word(buf+p, val); + } else + if (val & (255<<8)) { + p += list_word(buf+p, val); + } else { + p += list_byte(buf+p, val); + } + break; } return p; } @@ -2616,25 +2830,56 @@ int list_sp(char *buf) { } int list_word(char *buf, int outword) { - buf = buf + list_byte(buf, outword >> 8); - list_byte(buf, outword); - return 4; + return list_word_f(buf, outword, '$'); +} + +int list_word_f(char *buf, int outword, signed char format) { + int p = 0; + p+= list_byte_f(buf+p, outword >> 8, format); + p+= list_byte_f(buf+p, outword, format); + return p; } int list_byte(char *buf, int outbyte) { - buf = buf + list_nibble(buf, (outbyte >> 4)); - list_nibble(buf, outbyte); - return 2; + return list_byte_f(buf, outbyte, '$'); } -int list_nibble(char *buf, int outnib) { +int list_byte_f(char *buf, int outbyte, signed char format) { + int p = 0; + p+= list_nibble_f(buf+p, (outbyte >> 4), format); + p+= list_nibble_f(buf+p, outbyte, format); + return p; +} + +int list_nibble_f(char *buf, int outnib, signed char format) { + int p = 0; outnib = outnib & 0xf; - if (outnib < 10) { - buf[0]='0'+outnib; - } else { - buf[0]='a'-10+outnib; + switch(format) { + case '$': + if (outnib < 10) { + buf[p]='0'+outnib; + } else { + buf[p]='a'-10+outnib; + } + p++; + break; + case '%': + buf[p++] = (outnib&8)?'1':'0'; + buf[p++] = (outnib&4)?'1':'0'; + buf[p++] = (outnib&2)?'1':'0'; + buf[p++] = (outnib&1)?'1':'0'; + break; + default: + /* hex as default */ + if (outnib < 10) { + buf[p]='0'+outnib; + } else { + buf[p]='a'-10+outnib; + } + p++; + break; } - return 1; + return p; } diff --git a/xa/src/xat.h b/xa/src/xat.h index 3620f67..cd684bc 100644 --- a/xa/src/xat.h +++ b/xa/src/xat.h @@ -23,7 +23,10 @@ extern int dsb_len; void list_setfile(FILE *fp); int t_p1(signed char *s, signed char *t, int *ll, int *al); -int t_p2_l(signed char *t, int *ll, int fl, int *al); +int t_p2_l(signed char *t, int *ll, int *al); int b_term(char *s, int *v, int *l, int pc); +void list_line(int l); /* set line number for the coming listing output */ +void list_filename(char *fname);/* set file name for the coming listing output */ + #endif /* __XA65_XAT_H__ */ From 61f81d4e5e37b5ed416863bbaf28d09f8c4d6132 Mon Sep 17 00:00:00 2001 From: Andre Fachat Date: Fri, 16 Dec 2011 23:49:03 +0100 Subject: [PATCH 05/52] add some more readme --- README | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README b/README index 426f5ca..dbb013d 100644 --- a/README +++ b/README @@ -13,3 +13,8 @@ These are the directories: xa - contains the main source. The master branch is the stable version (currently 2.3.5) +These are the current branches: + +master - stable branch, currently 2.3.5 +listing - experimental branch that adds ca65 compatibility features and assembler listing + From 05c7799e9b17516410a3e48e27b72ebfe3ef71f4 Mon Sep 17 00:00:00 2001 From: "A. Fachat" Date: Wed, 28 Dec 2011 20:38:12 +0100 Subject: [PATCH 06/52] fix a nasty one-off bug giving a syntax error on *= assignments --- xa/src/xa.c | 2 ++ xa/src/xaa.c | 12 ++++++++++-- xa/src/xat.c | 12 +++++++----- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/xa/src/xa.c b/xa/src/xa.c index 9f1d74c..5a3d0a3 100644 --- a/xa/src/xa.c +++ b/xa/src/xa.c @@ -894,6 +894,7 @@ static void usage(int default816, FILE *fp) fprintf(fp, " -e filename sets errorlog filename, default is none\n" " -l filename sets labellist filename, default is none\n" + " -P filename sets filename for listing, default is none, '-' is stdout\n" " -r adds crossreference list to labellist (if `-l' given)\n" " -M allow ``:'' to appear in comments for MASM compatibility\n" " -Xcompatset set compatibility flags for other assemblers, known values are:\n" @@ -901,6 +902,7 @@ static void usage(int default816, FILE *fp) " -R start assembler in relocating mode\n"); fprintf(fp, " -Llabel defines `label' as absolute, undefined label even when linking\n" + " -p replace preprocessor char '#' with custom, e.g. '-p%' replaces it with '%'\n" " -b? addr set segment base address to integer value addr\n" " `?' stands for t(ext), d(ata), b(ss) and z(ero) segment\n" " (address can be given more than once, last one is used)\n"); diff --git a/xa/src/xaa.c b/xa/src/xaa.c index 2f4dcaa..ffedbe5 100644 --- a/xa/src/xaa.c +++ b/xa/src/xaa.c @@ -206,10 +206,18 @@ static int get_op(signed char *s, int *o) *o=s[pp]; - if(*o<1 || *o>17) + 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 + } else { er=E_OK; + } return(er); } diff --git a/xa/src/xat.c b/xa/src/xat.c index 39b5793..56e3d4a 100644 --- a/xa/src/xat.c +++ b/xa/src/xat.c @@ -492,14 +492,14 @@ fprintf(stderr, "- p1 %d starting -\n", pc[segment]); if(!(er=a_term(t+1,&tmp /*&pc[SEG_ABS]*/,&l,pc[segment],&afl,&label,0))) { i=1; - wval(i,tmp /*pc[SEG_ABS]*/, 0); + wval(i,tmp /*pc[SEG_ABS]*/, 0); /* writes T_VALUE, 3 bytes value, plus one byte */ t[i++]=T_END; - *ll=6; + *ll=7; er=E_OKDEF; /*printf("set pc=%04x, oldsegment=%d, pc[segm]=%04x, ", pc[SEG_ABS], segment, pc[segment]); -printf(" wrote %02x %02x %02x %02x %02x %02x\n", - t[0],t[1],t[2],t[3],t[4],t[5]);*/ +printf(" wrote %02x %02x %02x %02x %02x %02x, %02x, %02x\n", + t[0],t[1],t[2],t[3],t[4],t[5],t[6],t[7]);*/ if(segment==SEG_TEXT) { pc[SEG_ABS] = tmp; r_mode(RMODE_ABS); @@ -2482,7 +2482,9 @@ void list_filename(char *fname) { list_last_lineno = 0; /* Hack */ - fprintf(listfp, "\n%s\n\n", fname); + if (listfp != NULL) { + fprintf(listfp, "\n%s\n\n", fname); + } } } From f04d44d141ed0ac6e413cfeceab085e1fad0b767 Mon Sep 17 00:00:00 2001 From: fachat Date: Sat, 28 Jul 2012 14:47:04 +0200 Subject: [PATCH 07/52] Updates for .listbytes, and ca65 unnamed labels --- xa/src/xa.c | 31 +++--- xa/src/xaa.c | 4 +- xa/src/xah.h | 19 +++- xa/src/xal.c | 247 +++++++++++++++++++++++++++++++++++------------- xa/src/xal.h | 5 +- xa/src/xam.c | 5 +- xa/src/xap.c | 2 +- xa/src/xat.c | 149 ++++++++++++++++++++++++----- xa/tests/README | 1 + 9 files changed, 352 insertions(+), 111 deletions(-) diff --git a/xa/src/xa.c b/xa/src/xa.c index 5a3d0a3..50cdce5 100644 --- a/xa/src/xa.c +++ b/xa/src/xa.c @@ -804,15 +804,13 @@ fprintf(stderr, "offset = %i length = %i fstart = %i flen = %i charo = %c\n", static int pass1(void) { signed char o[2*MAXLINE]; /* doubled for token listing */ - int l,er,temp_er,al; + int l,er,al; memode=0; xmode=0; tlen=0; ner=0; - temp_er = 0; - /*FIXIT*/ while(!(er=getline(s))) { @@ -825,7 +823,7 @@ static int pass1(void) case SEG_ZERO: zlen += al; break; } - /*printf(": er= %d, l=%d, tmpz=%d\n",er,l,tmpz); */ + //printf(": er= %d, l=%d\n",er,l); if(l) { @@ -902,7 +900,7 @@ static void usage(int default816, FILE *fp) " -R start assembler in relocating mode\n"); fprintf(fp, " -Llabel defines `label' as absolute, undefined label even when linking\n" - " -p replace preprocessor char '#' with custom, e.g. '-p%' replaces it with '%'\n" + " -p replace preprocessor char '#' with custom, e.g. '-p!' replaces it with '!'\n" " -b? addr set segment base address to integer value addr\n" " `?' stands for t(ext), d(ata), b(ss) and z(ero) segment\n" " (address can be given more than once, last one is used)\n"); @@ -1108,19 +1106,27 @@ static int getline(char *s) gl=0; if(!ec || ec==E_EOF) { + int startofline = 1; do { c=s[j]=l[i++]; - if (c=='\"') + if (c=='\"') { hkfl^=1; - if (c==';' && !hkfl) + } + if (c==';' && !hkfl) { + // start of comment comcom = 1; - if (c=='\0') - break; /* hkfl = comcom = 0 */ + } + if (c=='\0') { + // end of line + break; /* hkfl = comcom = 0 */ + } if (c==':' && !hkfl) { /* if the next char is a "=" - so that we have a ":=" - and we we have ca65 compatibility, we ignore the colon */ - if (l[i]!='=' || !ca65 || comcom) { + // also check for ":+" and ":-" + + if (((!startofline) && l[i]!='=' && l[i]!='+' && l[i]!='-') || !ca65 || comcom) { /* but otherwise we check if it is in a comment and we have MASM or CA65 compatibility, then we ignore the colon as well */ if(!comcom || !(masm || ca65)) { @@ -1131,7 +1137,10 @@ static int getline(char *s) break; } } - } + } + if (!isspace(c)) { + startofline = 0; + } j++; } while (c!='\0' && j Byte, ANZDEF * 20 < 32768 */ -#define TMPMEM 200000L /* temporary memory buffer from Pass1 to Pass 2 */ +#define TMPMEM 2000000L /* temporary memory buffer from Pass1 to Pass 2 (includes all source, thus enlarged) */ + +typedef enum { + STD = 0, + CHEAP = 1, + UNNAMED = 2, + UNNAMED_DEF = 3 +} label_t; typedef struct LabOcc { struct LabOcc *next; @@ -43,6 +50,9 @@ typedef struct LabOcc { char *fname; } LabOcc; +/** + * struct that defines a label, after it has been parsed + */ typedef struct { int blk; int val; @@ -53,9 +63,14 @@ typedef struct { */ int afl; /* 0 = no address (no relocation), 1 = address label */ int nextindex; - int is_cll; /* 0 is normal label, 1 is cheap local label (used for listing) */ + label_t is_cll; /* 0 is normal label, 1 is cheap local label (used for listing) */ char *n; struct LabOcc *occlist; + // within a block, make a linked list for the unnamed label counting + // use indexes, as the label table can be re-alloced (so pointers change) + // -1 is the "undef'd" end of list + int blknext; + int blkprev; } Labtab; typedef struct { diff --git a/xa/src/xal.c b/xa/src/xal.c index 5aa59b6..3d3b32e 100644 --- a/xa/src/xal.c +++ b/xa/src/xal.c @@ -48,14 +48,22 @@ static int b_fget(int*,int); static int b_ltest(int,int); static int b_get(int*); static int b_test(int); -static int ll_def(char *s, int *n, int b); +static int ll_def(char *s, int *n, int b, label_t ltype); +static int b_link(int); static int b_new(void); + static void cll_init(); static int cll_get(); static void cll_clear(); static int cll_getcur(); +/* +static void unn_init(); +static int unn_get(); +static void unn_clear(); +*/ + /* local variables */ /* @@ -76,6 +84,7 @@ static Labtab *ltp; int l_init(void) { cll_init(); + //unn_init(); return 0; #if 0 int er; @@ -180,6 +189,41 @@ int cll_getcur() { return cll_current; } +/********************************************************************************** + * unnamed labels + */ +#if 0 +static int unn_current = 0; /* the current cheap local labels block */ + +/** + * init the cheap local labels + */ +void unn_init() { + unn_current = 0; +} + +/** + * get the block number for a new cheap local label block + */ +int unn_get() { + if (unn_current == 0) { + unn_current = b_new(); + } + return unn_current; +} + +/** + * clear the local labels + */ +void unn_clear() { + unn_current = 0; +} + +int unn_getcur() { + return cll_current; +} +#endif + /**********************************************************************************/ /** @@ -188,12 +232,12 @@ int cll_getcur() { int lg_set(char *s ) { int n, er; - er = ll_search(s,&n, 0); + er = ll_search(s,&n, STD); if(er==E_OK) { fprintf(stderr,"Warning: global label doubly defined!\n"); } else { - if(!(er=ll_def(s,&n,0))) { + if(!(er=ll_def(s,&n,0, STD))) { return lg_import(n); } } @@ -235,14 +279,21 @@ int lg_importzp(int n) { int l_def(char *s, int *l, int *x, int *f) { int n,er,b,i=0; - int cll_fl; + label_t cll_fl; *f=0; /* flag (given as param) that the label is to be re-defined and the "label defined error" is to be skipped */ b=0; /* block level on block stack, resp. block number */ n=0; /* flag, when set, b is absolute block number and not being translated */ - cll_fl=0; /* when set, clear the cheap local label block */ + cll_fl=STD; /* when 0, clear the cheap local label block */ + if(s[0]==':') { + // ca65 unnamed label + i++; + //n++; /* block number b is absolute */ + //b=unn_get(); /* current (possibly newly allocated) unnamed label block */ + cll_fl = UNNAMED; // keep the cheap local label block + } else if(s[0]=='-') { *f+=1; /* label is being redefined */ @@ -253,7 +304,7 @@ int l_def(char *s, int *l, int *x, int *f) i++; n++; /* block number b is absolute */ b=cll_get(); /* current (possibly newly allocated) cheap label block */ - cll_fl=1; /* do not clear the cll block again... */ + cll_fl=CHEAP; /* do not clear the cll block again... */ } else if(s[0]=='+') { @@ -273,16 +324,20 @@ int l_def(char *s, int *l, int *x, int *f) b_fget(&b,b); } - if(!cll_fl) { + if(cll_fl == STD) { /* clear cheap local labels */ cll_clear(); } - if(!isalpha(s[i]) && s[i]!='_' && !(ca65 && isdigit(s[i]) ) ) + if((!isalpha(s[i])) && (s[i]!='_') && !(ca65 && ((cll_fl == UNNAMED) || isdigit(s[i])) ) ) { + //printf("SYNTAX cll_fl=%d, i=%d, s[i]=%02x (%c)\n", cll_fl, i, s[i], s[i]); er=E_SYNTAX; - else + } else { - er=ll_search(s+i,&n, cll_fl); + er = E_NODEF; + if (cll_fl != UNNAMED) { + er=ll_search(s+i,&n, cll_fl); + } if(er==E_OK) { @@ -308,7 +363,8 @@ int l_def(char *s, int *l, int *x, int *f) } else if(er==E_NODEF) { - if(!(er=ll_def(s+i,&n,b))) /* store the label in the table of labels */ + + if(!(er=ll_def(s+i,&n,b, cll_fl) )) /* store the label in the table of labels */ { ltp=afile->la.lt+n; *l=ltp->len+i; @@ -325,23 +381,31 @@ int l_def(char *s, int *l, int *x, int *f) int l_search(char *s, int *l, int *x, int *v, int *afl) { int n,er,b; - int cll_fl; + label_t cll_fl; *afl=0; /* check cheap local label */ - cll_fl=0; + cll_fl=STD; if (s[0]=='@') { - cll_fl=1; /* also used as offset to the label length, so must be 1 */ + cll_fl=CHEAP; + s++; + } else + if (s[0]==':') { + cll_fl = UNNAMED_DEF; s++; } + + er = E_NODEF; + if (cll_fl != UNNAMED_DEF) { + er=ll_search(s,&n, cll_fl); + } - er=ll_search(s,&n, cll_fl); -/*printf("l_search: lab=%s(l=%d, afl=%d, er=%d, n=%d, cll_fl=%d, cll_cur=%d)\n",s,*l, *afl,er,n, cll_fl, cll_getcur());*/ +//printf("l_search: lab=%s(afl=%d, er=%d, cll_fl=%d, cll_cur=%d)\n",s,*afl,er, cll_fl, cll_getcur()); if(er==E_OK) { ltp=afile->la.lt+n; - *l=ltp->len + cll_fl; + *l=ltp->len + ((cll_fl == STD) ? 0 : 1); if(ltp->fl == 1) { l_get(n,v,afl);/* *v=lt[n].val;*/ @@ -355,18 +419,22 @@ int l_search(char *s, int *l, int *x, int *v, int *afl) } else { - if(cll_fl) { + if(cll_fl == CHEAP) { b=cll_get(); + } else + if(cll_fl == UNNAMED_DEF) { + b_get(&b); // b=unn_get(); } else { b_get(&b); } - er=ll_def(s,x,b); /* ll_def(...,*v); */ + er=ll_def(s,x,b, cll_fl); /* ll_def(...,*v); */ ltp=afile->la.lt+(*x); ltp->is_cll = cll_fl; - *l=ltp->len + cll_fl; + *l=ltp->len + ((cll_fl == STD) ? 0 : 1); + //*l=ltp->len + cll_fl; if(!er) { @@ -414,7 +482,7 @@ void l_addocc(int n, int *v, int *afl) { } /* for the list functionality */ -char *l_get_name(int n, int *is_cll) { +char *l_get_name(int n, label_t *is_cll) { ltp=afile->la.lt+n; *is_cll = ltp->is_cll; return ltp->n; @@ -424,7 +492,32 @@ int l_get(int n, int *v, int *afl) { if(crossref) l_addocc(n,v,afl); - ltp=afile->la.lt+n; + ltp = afile->la.lt+n; + + if (ltp->is_cll == UNNAMED_DEF) { + // need to count up/down in the linkd label list for the block + char *namep = ltp->n; + //printf("::: unnamed_def: %s, n=%d\n", namep, n); + while ((*namep == '+') || (*namep == '-')) { + char c = *namep; + int nextp = -1; + if (c == '+') { + nextp = ltp->blknext; + } else + if (c == '-') { + nextp = ltp->blkprev; + } + //printf("::: nextp=%d\n", nextp); + if (nextp == -1) { + return E_NODEF; + } + ltp = afile->la.lt+nextp; + //printf("::: leads to: %s, nextp=%d\n", ltp->n, nextp); + if (ltp->is_cll == UNNAMED) { + namep++; + } + } + } (*v)=ltp->val; lz=ltp->n; *afl = ltp->afl; @@ -452,19 +545,23 @@ static void ll_exblk(int a, int b) } } -static int ll_def(char *s, int *n, int b) /* definiert naechstes Label nr->n */ +/* defines next label, returns new label number in out param n */ +static int ll_def(char *s, int *n, int b, label_t ltype) { int j=0,er=E_NOMEM,hash; - char *s2; + char *s2 = NULL; -/*printf("ll_def: s=%s\n",s); */ +//printf("ll_def: s=%s, ltype=%d, no_name=%d\n",s, ltype, no_name); + // label table for the file ... if(!afile->la.lt) { + // ... does not exist yet, so malloc it afile->la.lti = 0; afile->la.ltm = 1000; afile->la.lt = malloc(afile->la.ltm * sizeof(Labtab)); } if(afile->la.lti>=afile->la.ltm) { + // ... or is at its capacity limit, so realloc it afile->la.ltm *= 1.5; afile->la.lt = realloc(afile->la.lt, afile->la.ltm * sizeof(Labtab)); } @@ -472,50 +569,51 @@ static int ll_def(char *s, int *n, int b) /* definiert naechstes Label fprintf(stderr, "Oops: no memory!\n"); exit(1); } -#if 0 - if((ltila.lt+afile->la.lti; -/* - s2=ltp->n=ln+lni; - while((jla.lt + afile->la.lti; + + if (ltype != UNNAMED) { + // alloc space and copy over name + if (ltype == UNNAMED_DEF) { + // unnamed lables are like ":--" or ":+" with variable length + while((s[j]!='\0') && (s[j]=='+' || s[j]=='-')) j++; + } else { + // standard (and cheap) labels are normal text + while((s[j]!='\0') && (isalnum(s[j]) || (s[j]=='_'))) j++; + } + s2 = malloc(j+1); + if(!s2) { fprintf(stderr,"Oops: no memory!\n"); exit(1); + } + strncpy(s2,s,j); + s2[j]=0; } - strncpy(s2,s,j); - s2[j]=0; -/* - if(jlen=j; - ltp->n = s2; - ltp->blk=b; + ltp->len=j; // length of label + ltp->n = s2; // name of label (char*) + ltp->blk=b; // block number ltp->fl=0; ltp->afl=0; - ltp->is_cll=0; - ltp->occlist=NULL; - hash=hashcode(s,j); - ltp->nextindex=afile->la.hashindex[hash]; - afile->la.hashindex[hash]=afile->la.lti; - *n=afile->la.lti; - afile->la.lti++; -/* lni+=j+1;*/ -/* } - } -*/ -/*printf("ll_def return: %d\n",er);*/ + ltp->is_cll=ltype; // STD, CHEAP, or UNNAMED label + ltp->occlist=NULL; + hash=hashcode(s,j); // compute hashcode + ltp->nextindex=afile->la.hashindex[hash]; // and link in before last entry with same hashcode + afile->la.hashindex[hash]=afile->la.lti; // set as start of list for that hashcode + + // TODO: does not work across files! + ltp->blknext = -1; // no next block + ltp->blkprev = b_link( afile->la.lti ); // previous block, linked within block + + ltp = afile->la.lt + ltp->blkprev; + ltp->blknext = afile->la.lti; + + *n=afile->la.lti; // return the list index for that file in the out parameter n + afile->la.lti++; // increase last index in lable table + return(er); } @@ -525,8 +623,10 @@ static int ll_def(char *s, int *n, int b) /* definiert naechstes Label * set of blocks (in the block stack) * * If cll_fl is set, the label is also searched in the local cheap label scope + * + * Do not define the label (as is done in l_search()!) */ -int ll_search(char *s, int *n, int cll_fl) /* search Label in Tabelle ,nr->n */ +int ll_search(char *s, int *n, label_t cll_fl) /* search Label in Tabelle ,nr->n */ { int i,j=0,k,er=E_NODEF,hash; @@ -545,11 +645,14 @@ int ll_search(char *s, int *n, int cll_fl) /* search Label in Tabelle , { for (k=0;(kn[k]==s[k]);k++); - if (cll_fl) { + if (cll_fl == CHEAP) { if (ltp->blk == cll_getcur()) { er=E_OK; break; } + } else + if (cll_fl == UNNAMED) { + // TODO } else { /* check if the found label is in any of the blocks in the current block stack */ @@ -584,7 +687,7 @@ int ll_pdef(char *t) { int n; - if(ll_search(t,&n, 0)==E_OK) + if(ll_search(t,&n, STD)==E_OK) { ltp=afile->la.lt+n; if(ltp->fl) @@ -643,6 +746,7 @@ int l_write(FILE *fp) * a specific block number is contained in the current block stack. */ static int bt[MAXBLK]; /* block stack */ +static int labind[MAXBLK]; /* last allocated label (as index) for the current block, -1 none yet alloc'd */ static int bi; /* length of the block stack (minus 1, i.e. bi[bi] has the innermost block) */ static int blk; /* current block number for allocation */ @@ -651,6 +755,7 @@ int b_init(void) blk =0; bi =0; bt[bi]=blk; + labind[bi]=-1; return(E_OK); } @@ -679,7 +784,9 @@ int b_open(void) if(bibase[SEG_TEXT] = pc[SEG_TEXT] = romaddr + h_length(); romable=1; } - if(!er) { @@ -453,7 +455,9 @@ fprintf(stderr, "- p1 %d starting -\n", pc[segment]); * pseudo-op dispatch (except .byt, .asc) * */ - n=t[0]; + // fix sign + n=t[0]; // & 0xff; + /* TODO: make that a big switch statement... */ /* maybe later. Cameron */ @@ -486,6 +490,17 @@ fprintf(stderr, "- p1 %d starting -\n", pc[segment]); set_fopt(l,t,nk+1-na1+na2); *ll = 0; } else + if(n==Klistbytes) { + int p = 0; + if(!(er=a_term(t+1,&p,&l,pc[segment],&afl,&label,0))) { + er=E_OKDEF; + } + *ll = 3; + t[0] = Klistbytes; + t[1] = p & 0xff; + t[2] = (p >> 8) & 0xff; + //printf("Klistbytes p1: er=%d, l=%d\n", er, l); + } else if(n==Kpcdef) { int tmp; @@ -636,7 +651,6 @@ printf(" wrote %02x %02x %02x %02x %02x %02x, %02x, %02x\n", char binfnam[255]; int offset; int length; - int fstart; i = 1; j = 0; @@ -672,7 +686,7 @@ printf(" wrote %02x %02x %02x %02x %02x %02x, %02x, %02x\n", if (!er) { int k; - fstart = i; + //fstart = i; if(t[i]=='\"') { i++; k=t[i]+i+1; @@ -1065,6 +1079,7 @@ int t_p2(signed char *t, int *ll, int fl, int *al) static int rlt[3]; /* relocation table */ static int lab[3]; /* undef. label table */ + er=E_OK; bl=0; if(*ll<0) /* <0 when E_OK, >0 when E_OKDEF */ @@ -1360,6 +1375,14 @@ int t_p2(signed char *t, int *ll, int fl, int *al) pc[segment] = npc; /*printf("Kreloc: newsegment=%d, pc[seg]=%04x\n", segment, pc[segment]);*/ } else + if(n==Klistbytes) { + int nbytes = (t[1] & 0xff) + (t[2] << 8); + //printf("Klistbytes --> er=%d, nbytes=%d\n", er, nbytes); + list_setbytes(nbytes); + l = 2; + *ll=0; + bl =0; + } else if(n==Ksegment) { segment = t[1]; *ll=0; @@ -1832,7 +1855,7 @@ static int t_conv(signed char *s, signed char *t, int *l, int pc, int *nk, int p,q,ll,mk,er; int ud; /* counts undefined labels */ int n; /* label number to be passed between l_def (definition) and l_set (set the value) */ - int m, byte; + int byte; int uz; /* unused at the moment */ /*static unsigned char cast;*/ @@ -1854,7 +1877,7 @@ static int t_conv(signed char *s, signed char *t, int *l, int pc, int *nk, fl=0; /* 1 = pass text thru */ afl=0; /* pointer flag for label */ - while(s[p]==' ') p++; + while(isspace(s[p])) p++; n=T_END; /*cast='\0';*/ @@ -1863,7 +1886,28 @@ static int t_conv(signed char *s, signed char *t, int *l, int pc, int *nk, { while(s[p]!='\0' && s[p]!=';') { + //printf("CONV: %s\n", s); + if (s[p] == ':') { + // this is a ca65 unnamed label + if ((er = l_def((char*)s+p, &ll, &n, &f))) + break; + l_set(n,pc,segment); /* set as address value */ + t[q++]=T_DEFINE; + t[q++]=n&255; + t[q++]=(n>>8)&255; + n=0; + + p+=ll; + + while(isspace(s[p])) p++; + + // end of line + if (s[p] == 0 || s[p] == ';') { + break; + } + } + /* is keyword? */ if(!(er=t_keyword(s+p,&ll,&n))) break; @@ -1872,13 +1916,14 @@ static int t_conv(signed char *s, signed char *t, int *l, int pc, int *nk, if(er && er!=E_NOKEY) break; - /* if so, try to understand as label */ + // if so, try to understand as label + // it returns the label number in n if((er=l_def((char*)s+p,&ll,&n,&f))) break; p+=ll; - while(s[p]==' ') p++; + while(isspace(s[p])) p++; if(s[p]=='=') { @@ -2010,11 +2055,29 @@ static int t_conv(signed char *s, signed char *t, int *l, int pc, int *nk, { t[q++]=s[p++]; } else - /* maybe it's a label + /* maybe it's a label Note that for ca65 cheap local labels, we check for "@" */ - if(isalpha(s[p]) || s[p]=='_' || (s[p]=='@' && ca65)) + if(isalpha(s[p]) || s[p]=='_' || ((s[p]==':' || s[p]=='@') && ca65)) { - m=n; + + int p2 = 0; + if (n == (Klistbytes & 0xff)) { + // check for "unlimited" + // Note: this could be done by a more general "constants" handling, + // where in appropriate places (like the one here), constants are + // replaced by a pointer to a predefined constants info, e.g. using + // a T_CONSTANT. Which would also fix the listing of this constant + // (which is currently listed as "0") + static char *unlimited = "unlimited"; + while (s[p+p2] != 0 && unlimited[p2] != 0 && s[p+p2] == unlimited[p2]) p2++; + } + if (p2 == 9) { // length of "unlimited" + er = E_OK; + // found constant + wval(q, 0, 'd'); + p += p2; + } else { + //m=n; er=l_search((char*)s+p,&ll,&n,&v,&afl); /* if(m==Kglobl || m==Kextzero) { @@ -2058,6 +2121,7 @@ fprintf(stderr, "could not find %s\n", (char *)s+p); er=E_OK; } p+=ll; + } } else if(s[p]<='9' && s[p]>='0') @@ -2213,6 +2277,7 @@ fprintf(stderr, "could not find %s\n", (char *)s+p); } } } +//printf("er=%d, ud=%d\n", er, ud); if(!er) { /* @@ -2260,20 +2325,28 @@ fprintf(stderr, "could not find %s\n", (char *)s+p); return(er); } -/*********************************************************************************************/ +/********************************************************************************************* + * identifies a keyword in s, if it is found, starting with s[0] + * A keyword is either a mnemonic, or a pseudo-opcode + */ static int t_keyword(signed char *s, int *l, int *n) { - int i = 0, j = 0, hash; + int i = 0; // index into keywords + int j = 0; + int hash; + // keywords either start with a character, a "." or "*" if(!isalpha(s[0]) && s[0]!='.' && s[0]!='*' ) return(E_NOKEY); + // if first char is a character, use it as hash... if(isalpha(s[0])) hash=tolower(s[0])-'a'; else hash=26; + // check for "*=" if(s[0]=='*') { j=1; while(s[j] && isspace(s[j])) j++; @@ -2282,9 +2355,14 @@ static int t_keyword(signed char *s, int *l, int *n) j++; } } + + // no keyword yet found? if(!i) { + // get sub-table from hash code, and compare with table content + // (temporarily) redefine i as start index in opcode table, and hash as end index i=ktp[hash]; hash=ktp[hash+1]; + // check all entries in opcode table from start to end for that hash code while(i= 8) { - n_hexb = 7; + if (list_numbytes != 0 && n_hexb >= list_numbytes) { + n_hexb = list_numbytes-1; } for (i = 0; i < n_hexb; i++) { buf = buf + list_byte(buf, bincode[i]); @@ -2593,7 +2678,7 @@ int list_tokens(char *buf, signed char *input, int len) { int tmp; char *name; signed char c; - int is_cll; + label_t is_cll; int tabval; signed char format; @@ -2607,10 +2692,17 @@ int list_tokens(char *buf, signed char *input, int len) { tmp = ((input[inp+2]&255)<<8) | (input[inp+1]&255); /*printf("define: len=%d, inp=%d, tmp=%d\n", len, inp, tmp);*/ name=l_get_name(tmp, &is_cll); - if (is_cll) outp += list_char(buf+outp, '@'); - tmp = list_string(buf+outp, name); - tabval += tmp + 1 + is_cll; - outp += tmp; + if (is_cll == CHEAP) { + outp += list_char(buf+outp, '@'); + } else + if (is_cll == UNNAMED_DEF || is_cll == UNNAMED) { + outp += list_char(buf+outp, ':'); + } + if (is_cll != UNNAMED) { + tmp = list_string(buf+outp, name); + tabval += tmp + 1 + is_cll; + outp += tmp; + } outp += list_char(buf+outp, ' '); inp += 3; tmp = input[inp] & 255; @@ -2668,8 +2760,15 @@ int list_tokens(char *buf, signed char *input, int len) { /* 16 bit label number */ tmp = ((input[inp+2]&255)<<8) | (input[inp+1]&255); name=l_get_name(tmp, &is_cll); - if (is_cll) outp += list_char(buf+outp, '@'); - outp += list_string(buf+outp, name); + if (is_cll == CHEAP) { + outp += list_char(buf+outp, '@'); + } else + if (is_cll == UNNAMED || is_cll == UNNAMED_DEF) { + outp += list_char(buf+outp, ':'); + } + if (is_cll != UNNAMED) { + outp += list_string(buf+outp, name); + } inp += 3; operator = 1; /* check if arithmetic operator follows */ break; diff --git a/xa/tests/README b/xa/tests/README index 58442e8..8ecb6df 100644 --- a/xa/tests/README +++ b/xa/tests/README @@ -19,6 +19,7 @@ incerr/ 1) .xl/.al should error without -w 2) error should be in binclude/ Binary include code with some weird casing chppch/ Changing preprocessor characters (-p) charset/ Tests of when charsets should be honoured and when not +cc65/ Compatibility tests for ca65 compatibility Cameron Kaiser, André Fachat From f25481778bdf6f72092b8586b5abaa62d838e939 Mon Sep 17 00:00:00 2001 From: fachat Date: Sat, 28 Jul 2012 14:53:23 +0200 Subject: [PATCH 08/52] First tests for ca65 features --- xa/tests/ca65/Makefile | 20 ++++++++++++++++++++ xa/tests/ca65/unnamed1.a65 | 14 ++++++++++++++ xa/tests/ca65/unnamed1.o | Bin 0 -> 13 bytes xa/tests/ca65/unnamed2.a65 | 16 ++++++++++++++++ xa/tests/ca65/unnamed2.err | 2 ++ 5 files changed, 52 insertions(+) create mode 100755 xa/tests/ca65/Makefile create mode 100755 xa/tests/ca65/unnamed1.a65 create mode 100755 xa/tests/ca65/unnamed1.o create mode 100755 xa/tests/ca65/unnamed2.a65 create mode 100755 xa/tests/ca65/unnamed2.err diff --git a/xa/tests/ca65/Makefile b/xa/tests/ca65/Makefile new file mode 100755 index 0000000..1a887a7 --- /dev/null +++ b/xa/tests/ca65/Makefile @@ -0,0 +1,20 @@ +# +# Makefile for tests +# + +XA=../../xa + +tests: unn1 unn2 + + +unn1: unnamed1.a65 + ${XA} -XCA65 $< + cmp unnamed1.o a.o65 + +unn2: unnamed2.a65 + ${XA} -XCA65 $< 2>a.err || true + cmp unnamed2.err a.err + +clean: + rm -f a.err a.o65 + diff --git a/xa/tests/ca65/unnamed1.a65 b/xa/tests/ca65/unnamed1.a65 new file mode 100755 index 0000000..6e3b745 --- /dev/null +++ b/xa/tests/ca65/unnamed1.a65 @@ -0,0 +1,14 @@ + +// test of unnamed labels + +start *=$4000 + + lda #$00 +: iny ; first + bne :- ; go to first + beq :++ ; go to third +: ; second + jmp :- ; go to second +: ldy #1 ; third + nop + diff --git a/xa/tests/ca65/unnamed1.o b/xa/tests/ca65/unnamed1.o new file mode 100755 index 0000000000000000000000000000000000000000..af5b9deaa80c8289807dcd75becfc476e1efa1ff GIT binary patch literal 13 VcmZ356nL74htAx0RS(H22cP1 literal 0 HcmV?d00001 diff --git a/xa/tests/ca65/unnamed2.a65 b/xa/tests/ca65/unnamed2.a65 new file mode 100755 index 0000000..d319caa --- /dev/null +++ b/xa/tests/ca65/unnamed2.a65 @@ -0,0 +1,16 @@ + +// test of unnamed labels + +start *=$4000 + + lda #$00 +: iny ; first + bne :- ; go to first + beq :++ ; go to third + .block +: ; second + jmp :- ; go to second +: ldy #1 ; third + .bend + nop + diff --git a/xa/tests/ca65/unnamed2.err b/xa/tests/ca65/unnamed2.err new file mode 100755 index 0000000..5d877f6 --- /dev/null +++ b/xa/tests/ca65/unnamed2.err @@ -0,0 +1,2 @@ +unnamed2.a65:line 9: 4007:Label '(null)' not defined +Break after 1 errors From 0bb027f032cae1267c7d4210042878a22f107650 Mon Sep 17 00:00:00 2001 From: fachat Date: Sun, 29 Jul 2012 19:05:02 +0200 Subject: [PATCH 09/52] Fix memory pointer bug if index is -1 --- xa/src/xal.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/xa/src/xal.c b/xa/src/xal.c index 3d3b32e..6779e98 100644 --- a/xa/src/xal.c +++ b/xa/src/xal.c @@ -608,8 +608,10 @@ static int ll_def(char *s, int *n, int b, label_t ltype) ltp->blknext = -1; // no next block ltp->blkprev = b_link( afile->la.lti ); // previous block, linked within block - ltp = afile->la.lt + ltp->blkprev; - ltp->blknext = afile->la.lti; + if (ltp->blkprev != -1) { + ltp = afile->la.lt + ltp->blkprev; + ltp->blknext = afile->la.lti; + } *n=afile->la.lti; // return the list index for that file in the out parameter n afile->la.lti++; // increase last index in lable table From 91ace0a6bf18638c24fcba7be9dc258ec367a5ae Mon Sep 17 00:00:00 2001 From: fachat Date: Sun, 29 Jul 2012 19:06:35 +0200 Subject: [PATCH 10/52] small cleanups --- xa/src/xa.c | 20 +++++--------------- xa/src/xah.h | 3 +++ xa/src/xap.c | 13 +++++++++---- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/xa/src/xa.c b/xa/src/xa.c index 50cdce5..0dde88d 100644 --- a/xa/src/xa.c +++ b/xa/src/xa.c @@ -676,21 +676,15 @@ static int pass2(void) } else if(afile->mn.tmp[afile->mn.tmpe]==T_FILE) { + // copy the current line number from the current file descriptor datei.fline=(afile->mn.tmp[afile->mn.tmpe+1]&255)+(afile->mn.tmp[afile->mn.tmpe+2]<<8); - + // copy the pointer to the file name in the current file descriptor + // Note: the filename in the current file descriptor is separately malloc'd and + // thus save to store the pointer memcpy(&datei.fname, afile->mn.tmp+afile->mn.tmpe+3, sizeof(datei.fname)); afile->mn.tmpe+=3+sizeof(datei.fname); list_filename(datei.fname); /* set file name of next listing output */ -/* - datei.fname = malloc(strlen((char*) afile->mn.tmp+afile->mn.tmpe+3)+1); - if(!datei.fname) { - fprintf(stderr,"Oops, no more memory\n"); - exit(1); - } - strcpy(datei.fname,(char*) afile->mn.tmp+afile->mn.tmpe+3); - afile->mn.tmpe+=3+strlen(datei.fname); -*/ } } else { @@ -1083,7 +1077,7 @@ static int getline(char *s) puttmp(T_LINE); puttmp((filep->fline)&255); puttmp(((filep->fline)>>8)&255); - ec=E_OK; + ec=E_OK; } else @@ -1094,10 +1088,6 @@ static int getline(char *s) puttmp((filep->fline)&255); puttmp(((filep->fline)>>8)&255); puttmps((signed char*)&(filep->fname), sizeof(filep->fname)); -/* - puttmps((signed char*)filep->fname, - 1+(int)strlen(filep->fname)); -*/ ec=E_OK; } } while(!ec && l[i]=='\0'); diff --git a/xa/src/xah.h b/xa/src/xah.h index 8da2c42..3f33fa0 100644 --- a/xa/src/xah.h +++ b/xa/src/xah.h @@ -221,8 +221,11 @@ typedef struct File { int base[SEG_MAX]; int len[SEG_MAX]; struct { + // temporary memory between pass1 and pass2 signed char *tmp; + // write pointer unsigned long tmpz; + // read pointer unsigned long tmpe; } mn; struct { diff --git a/xa/src/xap.c b/xa/src/xap.c index 16c1de4..c53a9bf 100644 --- a/xa/src/xap.c +++ b/xa/src/xap.c @@ -753,14 +753,16 @@ int pp_open(char *name) fp=xfopen(name,"r"); + int l = strlen(name); + /* we have to alloc it dynamically to make the name survive another pp_open - it's used in the cross-reference list */ - flist[0].fname = malloc(strlen(name)+1); + flist[0].fname = malloc(l+1); if(!flist[0].fname) { fprintf(stderr,"Oops, no more memory!\n"); exit(1); } - (void)strcpy(flist[0].fname,name); + (void)strncpy(flist[0].fname,name,l+1); flist[0].fline=0; flist[0].bdepth=b_depth(); flist[0].filep=fp; @@ -827,14 +829,17 @@ int icl_open(char *tt) fsp++; + char *namep = s+i; + int len = strlen(namep); + /* we have to alloc it dynamically to make the name survive another pp_open - it's used in the cross-reference list */ - flist[fsp].fname = malloc(strlen(s+i)+1); + flist[fsp].fname = malloc(len+1); if(!flist[fsp].fname) { fprintf(stderr,"Oops, no more memory!\n"); exit(1); } - strcpy(flist[fsp].fname,s+i); + strncpy(flist[fsp].fname,namep, len+1); flist[fsp].fline=0; flist[fsp].bdepth=b_depth(); flist[fsp].flinep=NULL; From d2953a516f21c3a096886ce0dfc1237d2a398df6 Mon Sep 17 00:00:00 2001 From: fachat Date: Sun, 29 Jul 2012 19:06:57 +0200 Subject: [PATCH 11/52] add .scope / .endscope for ca65 compatibility --- xa/src/xat.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/xa/src/xat.c b/xa/src/xat.c index 536fa8a..a7a9299 100644 --- a/xa/src/xat.c +++ b/xa/src/xat.c @@ -93,7 +93,8 @@ static char *kt[] ={ ".zero",".fopt", ".byte", ".end", ".list", ".xlist", ".dupb", ".blkb", ".db", ".dw", ".align",".block", ".bend",".al",".as",".xl",".xs", ".bin", ".aasc", ".code", ".include", ".import", ".importzp", ".proc", ".endproc", - ".zeropage", ".org", ".reloc", ".listbytes" + ".zeropage", ".org", ".reloc", ".listbytes", + ".scope", ".endscope" }; @@ -161,9 +162,11 @@ static int lp[]= { 0,1,1,1,1,2,2,1,1,1,2,2,2,1,1,1,2,2 }; #define Korg Lastbef+37 /* mapped to Kpcdef - with parameter equivalent to "*=$abcd" */ #define Krelocx Lastbef+38 /* mapped to Kpcdef - without parameter equivalent to "*=" */ #define Klistbytes (Lastbef+39-256) +#define Kscope (Lastbef+40) /* mapped to Kopen */ +#define Kendscope (Lastbef+41) /* mapped to Kclose */ /* last valid token+1 */ -#define Anzkey Lastbef+40 /* define last valid token number; last define above plus one */ +#define Anzkey Lastbef+42 /* define last valid token number; last define above plus one */ #define Kreloc (Anzkey-256) /* *= (relocation mode) */ @@ -2382,8 +2385,8 @@ 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==Kproc || i==Kscope) i=Kopen; + if(i==Kendproc || i==Kendscope) i=Kclose; if(i==Kzeropage) i=Kzero; if(i==Korg) i=Kpcdef; if(i==Krelocx) i=Kpcdef; @@ -2464,7 +2467,7 @@ fprintf(stderr, "tg_asc token = %i\n", n); /* do NOT convert for Kbin or Kaasc, or for initial parse */ if (!n || n == Kbin || n == Kaasc) { t[j++]=s[i]; - } else if(s[i]!='^') { /* no escape code "^" */ + } else if(ca65 || s[i]!='^') { /* no escape code "^" - TODO: does ca65 has an escape code */ t[j++]=convert_char(s[i]); } else { /* escape code */ signed char payload = s[i+1]; From 69b1d8fb7e202f95d2a97e1cb9aa214910464ad1 Mon Sep 17 00:00:00 2001 From: fachat Date: Sun, 29 Jul 2012 19:08:14 +0200 Subject: [PATCH 12/52] fixed and added tests for ca65 compatibility --- xa/tests/ca65/Makefile | 22 ++++++++++++++++++---- xa/tests/ca65/escape1.a65 | 6 ++++++ xa/tests/ca65/escape1.out | 1 + xa/tests/ca65/escape2.a65 | 6 ++++++ xa/tests/ca65/escape2.ca65 | 1 + xa/tests/ca65/unnamed1.a65 | 7 ++++--- xa/tests/ca65/unnamed1.ca65 | Bin 0 -> 16 bytes xa/tests/ca65/unnamed1.o | Bin 13 -> 0 bytes xa/tests/ca65/unnamed2.a65 | 11 ++++++----- xa/tests/ca65/unnamed2.ca65 | Bin 0 -> 16 bytes xa/tests/ca65/unnamed2.err | 3 ++- 11 files changed, 44 insertions(+), 13 deletions(-) mode change 100755 => 100644 xa/tests/ca65/Makefile create mode 100644 xa/tests/ca65/escape1.a65 create mode 100644 xa/tests/ca65/escape1.out create mode 100644 xa/tests/ca65/escape2.a65 create mode 100644 xa/tests/ca65/escape2.ca65 mode change 100755 => 100644 xa/tests/ca65/unnamed1.a65 create mode 100644 xa/tests/ca65/unnamed1.ca65 delete mode 100755 xa/tests/ca65/unnamed1.o mode change 100755 => 100644 xa/tests/ca65/unnamed2.a65 create mode 100644 xa/tests/ca65/unnamed2.ca65 mode change 100755 => 100644 xa/tests/ca65/unnamed2.err diff --git a/xa/tests/ca65/Makefile b/xa/tests/ca65/Makefile old mode 100755 new mode 100644 index 1a887a7..79f0b41 --- a/xa/tests/ca65/Makefile +++ b/xa/tests/ca65/Makefile @@ -4,17 +4,31 @@ XA=../../xa -tests: unn1 unn2 +CA65=ca65 +LD65=ld65 + +tests: unnamed1 unnamed2 escape1 escape2 clean -unn1: unnamed1.a65 +unnamed1: unnamed1.a65 + #${CA65} $<; ${LD65} -t none -o unnamed1.ca65 unnamed1.o; rm unnamed1.o ${XA} -XCA65 $< - cmp unnamed1.o a.o65 + cmp unnamed1.ca65 a.o65 -unn2: unnamed2.a65 +unnamed2: unnamed2.a65 + #${CA65} $<; ${LD65} -t none -o unnamed2.ca65 unnamed2.o; rm unnamed2.o ${XA} -XCA65 $< 2>a.err || true cmp unnamed2.err a.err +escape1: escape1.a65 + ${XA} $< + cmp escape1.out a.o65 + +escape2: escape2.a65 + #${CA65} $<; ${LD65} -t none -o escape2.ca65 escape2.o; rm escape2.o + ${XA} -XCA65 $< 2>a.err || true + cmp escape2.ca65 a.o65 + clean: rm -f a.err a.o65 diff --git a/xa/tests/ca65/escape1.a65 b/xa/tests/ca65/escape1.a65 new file mode 100644 index 0000000..74e8c09 --- /dev/null +++ b/xa/tests/ca65/escape1.a65 @@ -0,0 +1,6 @@ + + *=$1000 + + lda #"^^" + + diff --git a/xa/tests/ca65/escape1.out b/xa/tests/ca65/escape1.out new file mode 100644 index 0000000..8943227 --- /dev/null +++ b/xa/tests/ca65/escape1.out @@ -0,0 +1 @@ +©^ \ No newline at end of file diff --git a/xa/tests/ca65/escape2.a65 b/xa/tests/ca65/escape2.a65 new file mode 100644 index 0000000..fce5372 --- /dev/null +++ b/xa/tests/ca65/escape2.a65 @@ -0,0 +1,6 @@ + + .org $1000 + + lda #'^' + + diff --git a/xa/tests/ca65/escape2.ca65 b/xa/tests/ca65/escape2.ca65 new file mode 100644 index 0000000..8943227 --- /dev/null +++ b/xa/tests/ca65/escape2.ca65 @@ -0,0 +1 @@ +©^ \ No newline at end of file diff --git a/xa/tests/ca65/unnamed1.a65 b/xa/tests/ca65/unnamed1.a65 old mode 100755 new mode 100644 index 6e3b745..37f8379 --- a/xa/tests/ca65/unnamed1.a65 +++ b/xa/tests/ca65/unnamed1.a65 @@ -1,7 +1,7 @@ -// test of unnamed labels +; test of unnamed labels -start *=$4000 +start: .org $4000 lda #$00 : iny ; first @@ -9,6 +9,7 @@ start *=$4000 beq :++ ; go to third : ; second jmp :- ; go to second + jmp :++ : ldy #1 ; third - nop +: nop diff --git a/xa/tests/ca65/unnamed1.ca65 b/xa/tests/ca65/unnamed1.ca65 new file mode 100644 index 0000000000000000000000000000000000000000..54ddb553d91e19fa13604066ba2208597a8a581f GIT binary patch literal 16 YcmZ34{Sc{4nF)23m9Jk06_}|?f?J) literal 0 HcmV?d00001 diff --git a/xa/tests/ca65/unnamed1.o b/xa/tests/ca65/unnamed1.o deleted file mode 100755 index af5b9deaa80c8289807dcd75becfc476e1efa1ff..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13 VcmZ356nL74htAx0RS(H22cP1 diff --git a/xa/tests/ca65/unnamed2.a65 b/xa/tests/ca65/unnamed2.a65 old mode 100755 new mode 100644 index d319caa..4851f06 --- a/xa/tests/ca65/unnamed2.a65 +++ b/xa/tests/ca65/unnamed2.a65 @@ -1,16 +1,17 @@ -// test of unnamed labels +; test of unnamed labels -start *=$4000 +start: .org $4000 lda #$00 : iny ; first bne :- ; go to first beq :++ ; go to third - .block + .scope : ; second jmp :- ; go to second + jmp :++ : ldy #1 ; third - .bend - nop + .endscope +: nop diff --git a/xa/tests/ca65/unnamed2.ca65 b/xa/tests/ca65/unnamed2.ca65 new file mode 100644 index 0000000000000000000000000000000000000000..54ddb553d91e19fa13604066ba2208597a8a581f GIT binary patch literal 16 YcmZ34{Sc{4nF)23m9Jk06_}|?f?J) literal 0 HcmV?d00001 diff --git a/xa/tests/ca65/unnamed2.err b/xa/tests/ca65/unnamed2.err old mode 100755 new mode 100644 index 5d877f6..f89e1d2 --- a/xa/tests/ca65/unnamed2.err +++ b/xa/tests/ca65/unnamed2.err @@ -1,2 +1,3 @@ unnamed2.a65:line 9: 4007:Label '(null)' not defined -Break after 1 errors +unnamed2.a65:line 13: 400e:Label '(null)' not defined +Break after 2 errors From 30a8eb61c2e6cd4073dab36d18af9c0b15df6529 Mon Sep 17 00:00:00 2001 From: fachat Date: Sun, 29 Jul 2012 19:20:44 +0200 Subject: [PATCH 13/52] ups --- xa/src/xap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xa/src/xap.c b/xa/src/xap.c index c53a9bf..29fd0d3 100644 --- a/xa/src/xap.c +++ b/xa/src/xap.c @@ -935,7 +935,7 @@ int pgetline(char *t) /*************************************************************************/ /* this is the most disgusting code I have ever written, but Andre drove me -to it because I can't think of any other F$%Y#*U(%&Y##^#KING way to fix the +to it because I can't think of any other way to fix the last line bug ... a very irritated Cameron */ /* however, it also solved the problem of open #ifdefs not bugging out */ From 451e446016ccff0c72b6412d9ed7b462ef4d675b Mon Sep 17 00:00:00 2001 From: fachat Date: Sun, 29 Jul 2012 20:40:58 +0200 Subject: [PATCH 14/52] fix string display in listing, fix listing line breaks with .listbytes --- xa/src/xat.c | 106 +++++++++++++++------ xa/tests/listing/Makefile | 16 ++++ xa/tests/listing/linebreak.a65 | 160 ++++++++++++++++++++++++++++++++ xa/tests/listing/linebreak.out | 162 +++++++++++++++++++++++++++++++++ 4 files changed, 417 insertions(+), 27 deletions(-) create mode 100644 xa/tests/listing/Makefile create mode 100644 xa/tests/listing/linebreak.a65 create mode 100644 xa/tests/listing/linebreak.out diff --git a/xa/src/xat.c b/xa/src/xat.c index a7a9299..dddf7f2 100644 --- a/xa/src/xat.c +++ b/xa/src/xat.c @@ -2583,6 +2583,32 @@ void list_setfile(FILE *fp) { listfp = fp; } +char *list_preamble(char *buf, int lineno, int seg, int pc) { + /* line number in file */ + snprintf(buf, 10, "% 5d", lineno); + int i = strlen(buf); + buf += i; + buf += list_char(buf, ' '); + + char c = '?'; + /* preamble ':'
' ' */ + switch(seg) { + case SEG_ABS: c='A'; break; + case SEG_TEXT: c='T'; break; + case SEG_BSS: c='B'; break; + case SEG_DATA: c='D'; break; + case SEG_UNDEF: c='U'; break; + case SEG_ZERO: c='Z'; break; + } + buf = buf + list_char(buf, c); + buf = buf + list_char(buf, ':'); + buf = buf + list_word(buf, pc); + buf = buf + list_nchar(buf, ' ', 2); + + return buf; +} + + /** * listing/listing_len give the buffer address and length respectively that contains * the token as they are produced by the tokenizer. @@ -2601,8 +2627,6 @@ void do_listing(signed char *listing, int listing_len, signed char *bincode, int int lst_seg = listing[0]; int lst_pc = (listing[2]<<8) | (listing[1] & 255); - signed char c = '?'; - /* no output file (not even stdout) */ if (listfp == NULL) return; @@ -2618,43 +2642,59 @@ void do_listing(signed char *listing, int listing_len, signed char *bincode, int } list_last_lineno = list_lineno; - /* line number in file */ - snprintf(buf, 10, "% 5d", list_lineno); - i = strlen(buf); - buf += i; - buf += list_char(buf, ' '); + buf = list_preamble(buf, list_lineno, lst_seg, lst_pc); - /* preamble ':'
' ' */ - switch(lst_seg) { - case SEG_ABS: c='A'; break; - case SEG_TEXT: c='T'; break; - case SEG_BSS: c='B'; break; - case SEG_DATA: c='D'; break; - case SEG_UNDEF: c='U'; break; - case SEG_ZERO: c='Z'; break; + // check if we have labels, so we can adjust the max printable number of + // bytes in the last line + int num_last_line = 11; + int tmp = listing[3] & 255; + if (tmp == (T_DEFINE & 255)) { + // we have label definition + num_last_line = 8; } - buf = buf + list_char(buf, c); - buf = buf + list_char(buf, ':'); - buf = buf + list_word(buf, lst_pc); - buf = buf + list_nchar(buf, ' ', 2); + int overflow = 0; /* binary output (up to 8 byte. If more than 8 byte, print 7 plus "..." */ n_hexb = bincode_len; if (list_numbytes != 0 && n_hexb >= list_numbytes) { n_hexb = list_numbytes-1; + overflow = 1; } for (i = 0; i < n_hexb; i++) { buf = buf + list_byte(buf, bincode[i]); buf = buf + list_sp(buf); - } - if ((n_hexb == 7) && (bincode_len > 7)) { - buf = buf + list_nchar(buf, '.', 3); - } else { - /* can move loop into nchar ... */ - for (; i < 8; i++) { - buf = buf + list_nchar(buf, ' ', 3); + if ( (i%16) == 15) { + // make a break + buf[0] = 0; + fprintf(listfp, "%s\n", outline); + buf = outline; + buf = list_preamble(buf, list_lineno, lst_seg, lst_pc + i + 1); } } + if (overflow) { + // are we at the last byte? + if (n_hexb + 1 == bincode_len) { + // just print the last byte + buf = buf + list_byte(buf, bincode[i]); + buf = buf + list_sp(buf); + } else { + // display "..." + buf = buf + list_nchar(buf, '.', 3); + } + n_hexb++; + } + i = n_hexb % 16; + if (i > num_last_line) { + // make a break (Note: with original PC, as now the assembler text follows + buf[0] = 0; + fprintf(listfp, "%s\n", outline); + buf = outline; + buf = list_preamble(buf, list_lineno, lst_seg, lst_pc); + i = 0; + } + i = num_last_line - i; + buf = buf + list_nchar(buf, ' ', i * 3); + buf = buf + list_sp(buf); buf += list_tokens(buf, listing + 3, listing_len - 3); @@ -2715,7 +2755,7 @@ int list_tokens(char *buf, signed char *input, int len) { } } else { if (tmp >= 0 && tmp < Anzkey) { - outp += list_string(buf+outp, " "); + outp += list_string(buf+outp, " "); } } @@ -2820,6 +2860,18 @@ int list_tokens(char *buf, signed char *input, int len) { inp += 6; operator = 1; /* check if arithmetic operator follows */ break; + case '"': + // string display + inp++; + outp += list_char(buf+outp, '"'); + int len = input[inp] & 0xff; + for (int i = 0; i < len; i++) { + inp++; + outp += list_char(buf+outp, input[inp]); + } + inp++; + outp += list_char(buf+outp, '"'); + break; default: c = input[inp]; if (c > 31) { diff --git a/xa/tests/listing/Makefile b/xa/tests/listing/Makefile new file mode 100644 index 0000000..f151618 --- /dev/null +++ b/xa/tests/listing/Makefile @@ -0,0 +1,16 @@ +# +# Makefile for tests +# + +XA=../../xa + +tests: linebreak clean + + +linebreak: linebreak.a65 + ${XA} -P- $< > a.out + cmp linebreak.out a.out + +clean: + rm -f a.err a.o65 a.out + diff --git a/xa/tests/listing/linebreak.a65 b/xa/tests/listing/linebreak.a65 new file mode 100644 index 0000000..1b4f8a8 --- /dev/null +++ b/xa/tests/listing/linebreak.a65 @@ -0,0 +1,160 @@ + + *=$1000 + + // default listbytes is 8 + + lda #$0 + + // first without labels + + .( + // less than 8 bytes + .byt 0,1,2,3,4,5 ; 6 + // seven bytes + .byt 0,1,2,3,4,5,6 ; 7 + // eight bytes + .byt 0,1,2,3,4,5,6,7 ; 8 + // nine bytes + .byt 0,1,2,3,4,5,6,7,8 ; 9 + // ten bytes + .byt 0,1,2,3,4,5,6,7,8,9 ; 10 + // eleven bytes + .byt 0,1,2,3,4,5,6,7,8,9,10 ; 11 + // fifteen bytes + .asc "012345678901234" ; 15, asc test as well + // sixteen bytes + .asc "0123456789012345" ; 16 + // seventeen bytes + .asc "01234567890123456"; 17 + // thirtythree + .asc "012345678901234567890123456789012"; 32 + + // now with labels + + // less than 8 bytes +l6 .byt 0,1,2,3,4,5 ; 6 + // seven bytes +l7 .byt 0,1,2,3,4,5,6 ; 7 + // eight bytes +l8 .byt 0,1,2,3,4,5,6,7 ; 8 + // nine bytes +l9 .byt 0,1,2,3,4,5,6,7,8 ; 9 + // ten bytes +l10 .byt 0,1,2,3,4,5,6,7,8,9 ; 10 + // eleven bytes +l11 .byt 0,1,2,3,4,5,6,7,8,9,10 ; 11 + // fifteen bytes +l15 .asc "012345678901234" ; 15, asc test as well + // sixteen bytes +l16 .asc "0123456789012345" ; 16 + // seventeen bytes +l17 .asc "01234567890123456"; 17 + // thirtythree +l32 .asc "012345678901234567890123456789012"; 32 + + .) + + // now set number of bytes per listing line to 10 + + .listbytes 10 + + .( + // less than 8 bytes + .byt 0,1,2,3,4,5 ; 6 + // seven bytes + .byt 0,1,2,3,4,5,6 ; 7 + // eight bytes + .byt 0,1,2,3,4,5,6,7 ; 8 + // nine bytes + .byt 0,1,2,3,4,5,6,7,8 ; 9 + // ten bytes + .byt 0,1,2,3,4,5,6,7,8,9 ; 10 + // eleven bytes + .byt 0,1,2,3,4,5,6,7,8,9,10 ; 11 + // fifteen bytes + .asc "012345678901234" ; 15, asc test as well + // sixteen bytes + .asc "0123456789012345" ; 16 + // seventeen bytes + .asc "01234567890123456"; 17 + // thirtythree + .asc "012345678901234567890123456789012"; 32 + + + // now with labels + + // less than 8 bytes +l6 .byt 0,1,2,3,4,5 ; 6 + // seven bytes +l7 .byt 0,1,2,3,4,5,6 ; 7 + // eight bytes +l8 .byt 0,1,2,3,4,5,6,7 ; 8 + // nine bytes +l9 .byt 01,2,3,4,5,6,7,8 ; 9 + // ten bytes +l10 .byt 01,2,3,4,5,6,7,8,9 ; 10 + // eleven bytes +l11 .byt 01,2,3,4,5,6,7,8,9,10 ; 11 + // fifteen bytes +l15 .asc "012345678901234" ; 15, asc test as well + // sixteen bytes +l16 .asc "0123456789012345" ; 16 + // seventeen bytes +l17 .asc "01234567890123456"; 17 + // thirtythree +l32 .asc "012345678901234567890123456789012"; 32 + + .) + + // set number of listing bytes to unlimited + .listbytes unlimited + + .( + // less than 8 bytes + .byt 0,1,2,3,4,5 ; 6 + // seven bytes + .byt 0,1,2,3,4,5,6 ; 7 + // eight bytes + .byt 0,1,2,3,4,5,6,7 ; 8 + // nine bytes + .byt 0,1,2,3,4,5,6,7,8 ; 9 + // ten bytes + .byt 0,1,2,3,4,5,6,7,8,9 ; 10 + // eleven bytes + .byt 0,1,2,3,4,5,6,7,8,9,10 ; 11 + // fifteen bytes + .asc "012345678901234" ; 15, asc test as well + // sixteen bytes + .asc "0123456789012345" ; 16 + // seventeen bytes + .asc "01234567890123456"; 17 + // thirtythree + .asc "012345678901234567890123456789012"; 32 + + + // now with labels + + // less than 8 bytes +l6 .byt 0,1,2,3,4,5 ; 6 + // seven bytes +l7 .byt 0,1,2,3,4,5,6 ; 7 + // eight bytes +l8 .byt 0,1,2,3,4,5,6,7 ; 8 + // nine byte +l9 .byt 0,1,2,3,4,5,6,7,8 ; 9 + // ten bytes +l10 .byt 0,1,2,3,4,5,6,7,8,9 ; 10 + // eleven bytes +l11 .byt 0,1,2,3,4,5,6,7,8,9,10 ; 11 + // fifteen bytes +l15 .asc "012345678901234" ; 15, test as well + // sixteen bytes +l16 .asc "0123456789012345" ; 16 + // seventeen bytes +l17 .asc "01234567890123456"; 17 + // thirtythree +l32 .asc "012345678901234567890123456789012"; 32 + + .) + + diff --git a/xa/tests/listing/linebreak.out b/xa/tests/listing/linebreak.out new file mode 100644 index 0000000..723f4a4 --- /dev/null +++ b/xa/tests/listing/linebreak.out @@ -0,0 +1,162 @@ + +linebreak.a65 + + + 2 A:1000 *= $1000 + + 6 A:1000 a9 00 lda #$00 + + 10 A:1002 .( + + 12 A:1002 00 01 02 03 04 05 .byt 0,1,2,3,4,5; 6 + + 14 A:1008 00 01 02 03 04 05 06 .byt 0,1,2,3,4,5,6; 7 + + 16 A:100f 00 01 02 03 04 05 06 07 .byt 0,1,2,3,4,5,6,7; 8 + + 18 A:1017 00 01 02 03 04 05 06 ... .byt 0,1,2,3,4,5,6,7,8; 9 + + 20 A:1020 00 01 02 03 04 05 06 ... .byt 0,1,2,3,4,5,6,7,8,9; 10 + + 22 A:102a 00 01 02 03 04 05 06 ... .byt 0,1,2,3,4,5,6,7,8,9,10; 11 + + 24 A:1035 30 31 32 33 34 35 36 ... .asc "012345678901234" ; 15, asc test as well + + 26 A:1044 30 31 32 33 34 35 36 ... .asc "0123456789012345" ; 16 + + 28 A:1054 30 31 32 33 34 35 36 ... .asc "01234567890123456"; 17 + + 30 A:1065 30 31 32 33 34 35 36 ... .asc "012345678901234567890123456789012"; 32 + + 35 A:1086 00 01 02 03 04 05 l6 .byt 0,1,2,3,4,5; 6 + + 37 A:108c 00 01 02 03 04 05 06 l7 .byt 0,1,2,3,4,5,6; 7 + + 39 A:1093 00 01 02 03 04 05 06 07 l8 .byt 0,1,2,3,4,5,6,7; 8 + + 41 A:109b 00 01 02 03 04 05 06 ... l9 .byt 0,1,2,3,4,5,6,7,8; 9 + + 43 A:10a4 00 01 02 03 04 05 06 ... l10 .byt 0,1,2,3,4,5,6,7,8,9; 10 + + 45 A:10ae 00 01 02 03 04 05 06 ... l11 .byt 0,1,2,3,4,5,6,7,8,9,10; 11 + + 47 A:10b9 30 31 32 33 34 35 36 ... l15 .asc "012345678901234"; 15, asc test as well + + 49 A:10c8 30 31 32 33 34 35 36 ... l16 .asc "0123456789012345"; 16 + + 51 A:10d8 30 31 32 33 34 35 36 ... l17 .asc "01234567890123456"; 17 + + 53 A:10e9 30 31 32 33 34 35 36 ... l32 .asc "012345678901234567890123456789012"; 32 + + 55 A:110a .) + + 59 A:110a .listbytes 10 + + 61 A:110a .( + + 63 A:110a 00 01 02 03 04 05 .byt 0,1,2,3,4,5; 6 + + 65 A:1110 00 01 02 03 04 05 06 .byt 0,1,2,3,4,5,6; 7 + + 67 A:1117 00 01 02 03 04 05 06 07 .byt 0,1,2,3,4,5,6,7; 8 + + 69 A:111f 00 01 02 03 04 05 06 07 08 .byt 0,1,2,3,4,5,6,7,8; 9 + + 71 A:1128 00 01 02 03 04 05 06 07 08 09 .byt 0,1,2,3,4,5,6,7,8,9; 10 + + 73 A:1132 00 01 02 03 04 05 06 07 08 ... .byt 0,1,2,3,4,5,6,7,8,9,10; 11 + + 75 A:113d 30 31 32 33 34 35 36 37 38 ... .asc "012345678901234" ; 15, asc test as well + + 77 A:114c 30 31 32 33 34 35 36 37 38 ... .asc "0123456789012345" ; 16 + + 79 A:115c 30 31 32 33 34 35 36 37 38 ... .asc "01234567890123456"; 17 + + 81 A:116d 30 31 32 33 34 35 36 37 38 ... .asc "012345678901234567890123456789012"; 32 + + 87 A:118e 00 01 02 03 04 05 l6 .byt 0,1,2,3,4,5; 6 + + 89 A:1194 00 01 02 03 04 05 06 l7 .byt 0,1,2,3,4,5,6; 7 + + 91 A:119b 00 01 02 03 04 05 06 07 l8 .byt 0,1,2,3,4,5,6,7; 8 + + 93 A:11a3 01 02 03 04 05 06 07 08 l9 .byt 1,2,3,4,5,6,7,8; 9 + + 95 A:11ab 01 02 03 04 05 06 07 08 09 + 95 A:11ab l10 .byt 1,2,3,4,5,6,7,8,9; 10 + + 97 A:11b4 01 02 03 04 05 06 07 08 09 0a + 97 A:11b4 l11 .byt 1,2,3,4,5,6,7,8,9,10; 11 + + 99 A:11be 30 31 32 33 34 35 36 37 38 ... + 99 A:11be l15 .asc "012345678901234"; 15, asc test as well + + 101 A:11cd 30 31 32 33 34 35 36 37 38 ... + 101 A:11cd l16 .asc "0123456789012345"; 16 + + 103 A:11dd 30 31 32 33 34 35 36 37 38 ... + 103 A:11dd l17 .asc "01234567890123456"; 17 + + 105 A:11ee 30 31 32 33 34 35 36 37 38 ... + 105 A:11ee l32 .asc "012345678901234567890123456789012"; 32 + + 107 A:120f .) + + 110 A:120f .listbytes 0 + + 112 A:120f .( + + 114 A:120f 00 01 02 03 04 05 .byt 0,1,2,3,4,5; 6 + + 116 A:1215 00 01 02 03 04 05 06 .byt 0,1,2,3,4,5,6; 7 + + 118 A:121c 00 01 02 03 04 05 06 07 .byt 0,1,2,3,4,5,6,7; 8 + + 120 A:1224 00 01 02 03 04 05 06 07 08 .byt 0,1,2,3,4,5,6,7,8; 9 + + 122 A:122d 00 01 02 03 04 05 06 07 08 09 .byt 0,1,2,3,4,5,6,7,8,9; 10 + + 124 A:1237 00 01 02 03 04 05 06 07 08 09 0a .byt 0,1,2,3,4,5,6,7,8,9,10; 11 + + 126 A:1242 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 + 126 A:1242 .asc "012345678901234" ; 15, asc test as well + + 128 A:1251 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 + 128 A:1261 .asc "0123456789012345" ; 16 + + 130 A:1261 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 + 130 A:1271 36 .asc "01234567890123456"; 17 + + 132 A:1272 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 + 132 A:1282 36 37 38 39 30 31 32 33 34 35 36 37 38 39 30 31 + 132 A:1292 32 .asc "012345678901234567890123456789012"; 32 + + 138 A:1293 00 01 02 03 04 05 l6 .byt 0,1,2,3,4,5; 6 + + 140 A:1299 00 01 02 03 04 05 06 l7 .byt 0,1,2,3,4,5,6; 7 + + 142 A:12a0 00 01 02 03 04 05 06 07 l8 .byt 0,1,2,3,4,5,6,7; 8 + + 144 A:12a8 00 01 02 03 04 05 06 07 08 + 144 A:12a8 l9 .byt 0,1,2,3,4,5,6,7,8; 9 + + 146 A:12b1 00 01 02 03 04 05 06 07 08 09 + 146 A:12b1 l10 .byt 0,1,2,3,4,5,6,7,8,9; 10 + + 148 A:12bb 00 01 02 03 04 05 06 07 08 09 0a + 148 A:12bb l11 .byt 0,1,2,3,4,5,6,7,8,9,10; 11 + + 150 A:12c6 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 + 150 A:12c6 l15 .asc "012345678901234"; 15, test as well + + 152 A:12d5 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 + 152 A:12e5 l16 .asc "0123456789012345"; 16 + + 154 A:12e5 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 + 154 A:12f5 36 l17 .asc "01234567890123456"; 17 + + 156 A:12f6 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35 + 156 A:1306 36 37 38 39 30 31 32 33 34 35 36 37 38 39 30 31 + 156 A:1316 32 l32 .asc "012345678901234567890123456789012"; 32 + + 158 A:1317 .) From f296538a90b8afdd4d5471cd8ff175b23551091a Mon Sep 17 00:00:00 2001 From: fachat Date: Mon, 30 Jul 2012 13:22:57 +0200 Subject: [PATCH 15/52] Fix ca65 unnamed labels to work across blocks (according to the ca65 creator U. v. Bassewitz, this is intentional) --- xa/src/xal.c | 44 ++++-------------------------------------- xa/tests/ca65/Makefile | 2 +- 2 files changed, 5 insertions(+), 41 deletions(-) diff --git a/xa/src/xal.c b/xa/src/xal.c index 6779e98..a249150 100644 --- a/xa/src/xal.c +++ b/xa/src/xal.c @@ -189,41 +189,6 @@ int cll_getcur() { return cll_current; } -/********************************************************************************** - * unnamed labels - */ -#if 0 -static int unn_current = 0; /* the current cheap local labels block */ - -/** - * init the cheap local labels - */ -void unn_init() { - unn_current = 0; -} - -/** - * get the block number for a new cheap local label block - */ -int unn_get() { - if (unn_current == 0) { - unn_current = b_new(); - } - return unn_current; -} - -/** - * clear the local labels - */ -void unn_clear() { - unn_current = 0; -} - -int unn_getcur() { - return cll_current; -} -#endif - /**********************************************************************************/ /** @@ -748,7 +713,7 @@ int l_write(FILE *fp) * a specific block number is contained in the current block stack. */ static int bt[MAXBLK]; /* block stack */ -static int labind[MAXBLK]; /* last allocated label (as index) for the current block, -1 none yet alloc'd */ +static int labind; /* last allocated label, -1 none yet alloc'd - used for linking to find unnamed labels */ static int bi; /* length of the block stack (minus 1, i.e. bi[bi] has the innermost block) */ static int blk; /* current block number for allocation */ @@ -757,7 +722,7 @@ int b_init(void) blk =0; bi =0; bt[bi]=blk; - labind[bi]=-1; + labind=-1; return(E_OK); } @@ -788,7 +753,6 @@ int b_open(void) { bi++; bt[bi]=b_new(); - labind[bi] = -1; er=E_OK; } @@ -874,9 +838,9 @@ static int b_ltest(int a, int b) /* testet ob bt^-1(b) in intervall [0,bt^-1( } int b_link(int newlab) { - int tmp = labind[bi]; + int tmp = labind; //printf("b_link: old was %d, set to %d\n", tmp, newlab); - labind[bi] = newlab; + labind = newlab; return tmp; } diff --git a/xa/tests/ca65/Makefile b/xa/tests/ca65/Makefile index 79f0b41..7c4abd5 100644 --- a/xa/tests/ca65/Makefile +++ b/xa/tests/ca65/Makefile @@ -18,7 +18,7 @@ unnamed1: unnamed1.a65 unnamed2: unnamed2.a65 #${CA65} $<; ${LD65} -t none -o unnamed2.ca65 unnamed2.o; rm unnamed2.o ${XA} -XCA65 $< 2>a.err || true - cmp unnamed2.err a.err + cmp unnamed2.ca65 a.o65 escape1: escape1.a65 ${XA} $< From 93d832b04a179329b2770d4832feb2efadd8ff99 Mon Sep 17 00:00:00 2001 From: fachat Date: Mon, 30 Jul 2012 14:14:39 +0200 Subject: [PATCH 16/52] break out listing code from xat.c into separate file --- xa/src/Makefile | 2 +- xa/src/xalisting.c | 550 +++++++++++++++++++++++++++++++++ xa/src/xalisting.h | 24 ++ xa/src/xat.c | 522 +------------------------------ xa/src/xat.h | 4 + xa/tests/listing/Makefile | 6 +- xa/tests/listing/include1.a65 | 8 + xa/tests/listing/include1.out | 23 ++ xa/tests/listing/include1a.a65 | 3 + 9 files changed, 623 insertions(+), 519 deletions(-) create mode 100644 xa/src/xalisting.c create mode 100644 xa/src/xalisting.h create mode 100644 xa/tests/listing/include1.a65 create mode 100644 xa/tests/listing/include1.out create mode 100644 xa/tests/listing/include1a.a65 diff --git a/xa/src/Makefile b/xa/src/Makefile index 173d634..8e32165 100644 --- a/xa/src/Makefile +++ b/xa/src/Makefile @@ -1,4 +1,4 @@ -OBJ = xa.o xaa.o xal.o xap.o xat.o xar.o xar2.o xao.o xau.o xam.o xacharset.o +OBJ = xa.o xaa.o xal.o xap.o xat.o xar.o xar2.o xao.o xau.o xam.o xacharset.o xalisting.o #CFLAGS=-W -Wall -pedantic -ansi -g #CFLAGS=-W -Wall -ansi -O2 diff --git a/xa/src/xalisting.c b/xa/src/xalisting.c new file mode 100644 index 0000000..9bbb4a7 --- /dev/null +++ b/xa/src/xalisting.c @@ -0,0 +1,550 @@ +/* xa65 - 65xx/65816 cross-assembler and utility suite + * + * Copyright (C) 1989-1997 André Fachat (a.fachat@physik.tu-chemnitz.de) + * maintained by Cameron Kaiser + * + * Core tokenizing module/pass 1 and pass 2 + * + * 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. + */ + +/* enable this to turn on (copious) optimization output */ +/* #define DEBUG_AM */ +#undef LISTING_DEBUG + +#include +#include + +#include "xah.h" +#include "xal.h" +#include "xat.h" + + +/*********************************************************************************************/ +/* this is the listing code + * + * Unfortunately this code has to go here (for now), as this file is the only one + * where we have access to the tables that allow to convert the tokens back to + * a listing + */ + +static FILE *listfp = NULL; +static int list_lineno = 1; /* current line number */ +static int list_last_lineno = 0; /* current line number */ +static char *list_filenamep = NULL; /* current file name pointer */ + +static int list_numbytes = 8; + +static int list_string(char *buf, char *string); +static int list_tokens(char *buf, signed char *input, int len); +static int list_value(char *buf, int val, signed char format); +static int list_nchar(char *buf, signed char c, int n); +static int list_char(char *buf, signed char c); +static int list_sp(char *buf); +static int list_word(char *buf, int outword); +static int list_word_f(char *buf, int outword, signed char format); +static int list_byte(char *buf, int outbyte); +static int list_byte_f(char *buf, int outbyte, signed char format); +static int list_nibble_f(char *buf, int outnib, signed char format); + +// set number of bytes per line displayed as hex +void list_setbytes(int number_of_bytes_per_line) { + list_numbytes = number_of_bytes_per_line; +} + +/* set line number for the coming listing output */ +void list_line(int l) { + list_lineno = l; +} + +/* set file name for the coming listing output */ +void list_filename(char *fname) { + if (list_filenamep == NULL || (fname != NULL && strcmp(fname, list_filenamep) != 0)) { + list_filenamep = fname; + list_lineno = 1; + list_last_lineno = 0; + + /* Hack */ + if (listfp != NULL) { + fprintf(listfp, "\n%s\n\n", fname); + } + } +} + +/** + * set the output file descriptor where to write the listing + */ +void list_setfile(FILE *fp) { + listfp = fp; +} + +char *list_preamble(char *buf, int lineno, int seg, int pc) { + /* line number in file */ + snprintf(buf, 10, "% 5d", lineno); + int i = strlen(buf); + buf += i; + buf += list_char(buf, ' '); + + char c = '?'; + /* preamble ':'
' ' */ + switch(seg) { + case SEG_ABS: c='A'; break; + case SEG_TEXT: c='T'; break; + case SEG_BSS: c='B'; break; + case SEG_DATA: c='D'; break; + case SEG_UNDEF: c='U'; break; + case SEG_ZERO: c='Z'; break; + } + buf = buf + list_char(buf, c); + buf = buf + list_char(buf, ':'); + buf = buf + list_word(buf, pc); + buf = buf + list_nchar(buf, ' ', 2); + + return buf; +} + + +/** + * listing/listing_len give the buffer address and length respectively that contains + * the token as they are produced by the tokenizer. + * bincode/bincode_len give the buffer address and length that contain the binary code + * that is produced from the token listing + * + * Note that both lengths may be zero + */ +void do_listing(signed char *listing, int listing_len, signed char *bincode, int bincode_len) { + + int i, n_hexb; + + char outline[MAXLINE]; + char *buf = outline; + + int lst_seg = listing[0]; + int lst_pc = (listing[2]<<8) | (listing[1] & 255); + + /* no output file (not even stdout) */ + if (listfp == NULL) return; + + /*printf("do_listing: listing=%p (%d), bincode=%p (%d)\n", listing, listing_len, bincode, bincode_len);*/ + + if (bincode_len < 0) bincode_len = -bincode_len; + + /* do we need a separation line? */ + if (list_lineno > list_last_lineno+1) { + /* yes */ + /*fprintf(listfp, "line=%d, last=%d\n", list_lineno, list_last_lineno);*/ + fprintf(listfp, "\n"); + } + list_last_lineno = list_lineno; + + buf = list_preamble(buf, list_lineno, lst_seg, lst_pc); + + // check if we have labels, so we can adjust the max printable number of + // bytes in the last line + int num_last_line = 11; + int tmp = listing[3] & 255; + if (tmp == (T_DEFINE & 255)) { + // we have label definition + num_last_line = 8; + } + int overflow = 0; + + /* binary output (up to 8 byte. If more than 8 byte, print 7 plus "..." */ + n_hexb = bincode_len; + if (list_numbytes != 0 && n_hexb >= list_numbytes) { + n_hexb = list_numbytes-1; + overflow = 1; + } + for (i = 0; i < n_hexb; i++) { + buf = buf + list_byte(buf, bincode[i]); + buf = buf + list_sp(buf); + if ( (i%16) == 15) { + // make a break + buf[0] = 0; + fprintf(listfp, "%s\n", outline); + buf = outline; + buf = list_preamble(buf, list_lineno, lst_seg, lst_pc + i + 1); + } + } + if (overflow) { + // are we at the last byte? + if (n_hexb + 1 == bincode_len) { + // just print the last byte + buf = buf + list_byte(buf, bincode[i]); + buf = buf + list_sp(buf); + } else { + // display "..." + buf = buf + list_nchar(buf, '.', 3); + } + n_hexb++; + } + i = n_hexb % 16; + if (i > num_last_line) { + // make a break (Note: with original PC, as now the assembler text follows + buf[0] = 0; + fprintf(listfp, "%s\n", outline); + buf = outline; + buf = list_preamble(buf, list_lineno, lst_seg, lst_pc); + i = 0; + } + i = num_last_line - i; + buf = buf + list_nchar(buf, ' ', i * 3); + + buf = buf + list_sp(buf); + + buf += list_tokens(buf, listing + 3, listing_len - 3); + +#ifdef LISTING_DEBUG + /* for now only do a hex dump so we see what actually happens */ + i = buf - outline; + if (i<80) buf += list_nchar(buf, ' ', 80-i); + + buf += list_string(buf, " >>"); + for (i = 3; i < listing_len; i++) { + buf = buf + list_byte(buf, listing[i]); + buf = buf + list_sp(buf); + } +#endif + buf[0] = 0; + + fprintf(listfp, "%s\n", outline); +} + +int list_tokens(char *buf, signed char *input, int len) { + int outp = 0; + int inp = 0; + int tmp; + char *name; + signed char c; + label_t is_cll; + int tabval; + signed char format; + + if (inp >= len) return 0; + + tmp = input[inp] & 255; + + tabval = 0; + if (tmp == (T_DEFINE & 255)) { + while (inp < len && tmp == (T_DEFINE & 255)) { + tmp = ((input[inp+2]&255)<<8) | (input[inp+1]&255); +/*printf("define: len=%d, inp=%d, tmp=%d\n", len, inp, tmp);*/ + name=l_get_name(tmp, &is_cll); + if (is_cll == CHEAP) { + outp += list_char(buf+outp, '@'); + } else + if (is_cll == UNNAMED_DEF || is_cll == UNNAMED) { + outp += list_char(buf+outp, ':'); + } + if (is_cll != UNNAMED) { + tmp = list_string(buf+outp, name); + tabval += tmp + 1 + is_cll; + outp += tmp; + } + outp += list_char(buf+outp, ' '); + inp += 3; + tmp = input[inp] & 255; + } + if (tabval < 10) { + outp += list_nchar(buf+outp, ' ', 10-tabval); + } + } else { + if (tmp >= 0 && tmp < number_of_valid_tokens) { + outp += list_string(buf+outp, " "); + } + } + + if (tmp >= 0 && tmp < number_of_valid_tokens) { + /* assembler keyword */ + /*printf("tmp=%d, kt[tmp]=%p\n", tmp, kt[tmp]);*/ + if (kt[tmp] != NULL) { + outp += list_string(buf+outp, kt[tmp]); + } + outp += list_sp(buf + outp); + inp += 1; +#if 0 + if (tmp == Kinclude) { + /* just another exception from the rule... */ + /* next char is terminator (", ') then the length and then the file name */ + char term = input[inp]; + int len = input[inp+1] & 255; + outp += list_char(buf+outp, term); + for (tmp = 2; tmp < len+2; tmp++) { + outp += list_char(buf+outp, input[inp+tmp]); + } + outp += list_char(buf+outp, term); + inp += len + 2; + } +#endif + } + + while (inp < len) { + int operator = 0; + + switch(input[inp]) { + case T_CAST: + outp += list_char(buf+outp, input[inp+1]); + break; + case T_VALUE: + /*outp += list_char(buf+outp, 'V');*/ + /* 24 bit value */ + tmp = ((input[inp+3]&255)<<16) | ((input[inp+2]&255)<<8) | (input[inp+1]&255); + format = input[inp+4]; + outp += list_value(buf+outp, tmp, format); + inp += 5; + operator = 1; /* check if arithmetic operator follows */ + break; + case T_LABEL: + /*outp += list_char(buf+outp, 'L');*/ + /* 16 bit label number */ + tmp = ((input[inp+2]&255)<<8) | (input[inp+1]&255); + name=l_get_name(tmp, &is_cll); + if (is_cll == CHEAP) { + outp += list_char(buf+outp, '@'); + } else + if (is_cll == UNNAMED || is_cll == UNNAMED_DEF) { + outp += list_char(buf+outp, ':'); + } + if (is_cll != UNNAMED) { + outp += list_string(buf+outp, name); + } + inp += 3; + operator = 1; /* check if arithmetic operator follows */ + break; + case T_OP: + /* label arithmetic operation; inp[3] is operation like '=' or '+' */ + tmp = ((input[inp+2]&255)<<8) | (input[inp+1]&255); + name=l_get_name(tmp, &is_cll); + if (is_cll) outp += list_char(buf+outp, '@'); + outp += list_string(buf+outp, name); + outp += list_char(buf+outp, input[inp+3]); + inp += 4; + + break; + case T_END: + /* end of operation */ + /*outp += list_string(buf+outp, ";");*/ + inp += 1; + goto end; + break; + case T_COMMENT: + if (inp > 0 && inp < 20) { + outp += list_nchar(buf+outp, ' ', 20-inp); + } + tmp = ((input[inp+2]&255)<<8) | (input[inp+1]&255); + outp += list_char(buf+outp, ';'); + outp += list_string(buf+outp, (char*)input+inp+3); + inp += tmp + 3; + break; + case T_LINE: + case T_FILE: + /* those two are meta-tokens, evaluated outside the t_p2 call, + * they result in calls to list_line(), list_filename() */ + break; + case T_POINTER: + /* what is this? It's actually resolved during token conversion */ + tmp = ((input[inp+5]&255)<<8) | (input[inp+4]&255); + name=l_get_name(tmp, &is_cll); + if (is_cll) outp += list_char(buf+outp, '@'); + outp += list_string(buf+outp, name); + /* + outp += list_byte(buf+outp, input[inp+1]); + outp += list_char(buf+outp, '#'); + tmp = ((input[inp+3]&255)<<8) | (input[inp+2]&255); + outp += list_value(buf+outp, tmp); + */ + inp += 6; + operator = 1; /* check if arithmetic operator follows */ + break; + case '"': + // string display + inp++; + outp += list_char(buf+outp, '"'); + int len = input[inp] & 0xff; + for (int i = 0; i < len; i++) { + inp++; + outp += list_char(buf+outp, input[inp]); + } + inp++; + outp += list_char(buf+outp, '"'); + break; + default: + c = input[inp]; + if (c > 31) { + outp += list_char(buf+outp, input[inp]); + } else { + outp += list_char(buf+outp, '\''); + outp += list_byte(buf+outp, input[inp]); + } + inp += 1; + break; + } + + if (operator && inp < len) { + signed char op = input[inp]; + if (op > 0 && op <= 17) { + outp += list_string(buf+outp, arith_ops[op]); + inp += 1; + } + operator = 0; + } + } +end: + return outp; +} + +int list_string(char *buf, char *string) { + int p = 0; + while (string[p] != 0) { + buf[p] = string[p]; + p++; + } + return p; +} + +int list_value(char *buf, int val, signed char format) { + int p = 0; + char valbuf[32]; + + switch (format) { + case '$': + p += list_char(buf + p, '$'); + if (val & (255<<16)) { + p += list_byte(buf+p, val>>16); + p += list_word(buf+p, val); + } else + if (val & (255<<8)) { + p += list_word(buf+p, val); + } else { + p += list_byte(buf+p, val); + } + break; + case '%': + p += list_char(buf + p, '%'); + if (val & (255<<16)) { + p += list_byte_f(buf+p, val>>16,'%'); + p += list_word_f(buf+p, val,'%'); + } else + if (val & (255<<8)) { + p += list_word_f(buf+p, val,'%'); + } else { + p += list_byte_f(buf+p, val,'%'); + } + break; + case '&': + snprintf(valbuf, 32, "%o",val); + p+= list_char(buf+p, '&'); + p+= list_string(buf+p, valbuf); + break; + case 'd': + snprintf(valbuf, 32, "%d",val); + p+= list_string(buf+p, valbuf); + break; + case '\'': + case '"': + p+= list_char(buf+p, format); + p+= list_char(buf+p, val); + p+= list_char(buf+p, format); + break; + default: + /* hex format as fallback */ + p += list_char(buf + p, '$'); + if (val & (255<<16)) { + p += list_byte(buf+p, val>>16); + p += list_word(buf+p, val); + } else + if (val & (255<<8)) { + p += list_word(buf+p, val); + } else { + p += list_byte(buf+p, val); + } + break; + } + return p; +} + +int list_nchar(char *buf, signed char c, int n) { + int i; + for (i = 0; i < n; i++) { + buf[i]=c; + } + return n; +} + +int list_char(char *buf, signed char c) { + buf[0] = c; + return 1; +} + +int list_sp(char *buf) { + buf[0] = ' '; + return 1; +} + +int list_word(char *buf, int outword) { + return list_word_f(buf, outword, '$'); +} + +int list_word_f(char *buf, int outword, signed char format) { + int p = 0; + p+= list_byte_f(buf+p, outword >> 8, format); + p+= list_byte_f(buf+p, outword, format); + return p; +} + +int list_byte(char *buf, int outbyte) { + return list_byte_f(buf, outbyte, '$'); +} + +int list_byte_f(char *buf, int outbyte, signed char format) { + int p = 0; + p+= list_nibble_f(buf+p, (outbyte >> 4), format); + p+= list_nibble_f(buf+p, outbyte, format); + return p; +} + +int list_nibble_f(char *buf, int outnib, signed char format) { + int p = 0; + outnib = outnib & 0xf; + switch(format) { + case '$': + if (outnib < 10) { + buf[p]='0'+outnib; + } else { + buf[p]='a'-10+outnib; + } + p++; + break; + case '%': + buf[p++] = (outnib&8)?'1':'0'; + buf[p++] = (outnib&4)?'1':'0'; + buf[p++] = (outnib&2)?'1':'0'; + buf[p++] = (outnib&1)?'1':'0'; + break; + default: + /* hex as default */ + if (outnib < 10) { + buf[p]='0'+outnib; + } else { + buf[p]='a'-10+outnib; + } + p++; + break; + } + return p; +} + + + diff --git a/xa/src/xalisting.h b/xa/src/xalisting.h new file mode 100644 index 0000000..91ce008 --- /dev/null +++ b/xa/src/xalisting.h @@ -0,0 +1,24 @@ +/* xa65 - 65xx/65816 cross-assembler and utility suite + * + * Copyright (C) 1989-1997 André Fachat (a.fachat@physik.tu-chemnitz.de) + * + * 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. + */ +#ifndef __XA65_XALISTING_H__ +#define __XA65_XALISTING_H__ + +void do_listing(signed char *listing, int listing_len, signed char *bincode, int bincode_len); + +#endif /* __XA65_XALISTING_H__ */ diff --git a/xa/src/xat.c b/xa/src/xat.c index dddf7f2..b208855 100644 --- a/xa/src/xat.c +++ b/xa/src/xat.c @@ -51,7 +51,7 @@ static void tg_hex(signed char*,int*,int*); static void tg_oct(signed char*,int*,int*); static void tg_bin(signed char*,int*,int*); static int t_p2(signed char *t, int *ll, int fl, int *al); -static void do_listing(signed char *listing, int listing_len, signed char *bincode, int bincode_len); +//static void do_listing(signed char *listing, int listing_len, signed char *bincode, int bincode_len); void list_setbytes(int number_of_bytes_per_line); @@ -67,7 +67,7 @@ void list_setbytes(int number_of_bytes_per_line); * .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[] ={ +char *kt[] ={ /* 1 2 3 4 5 6 7 8 9 10 */ "adc","and","asl","bbr","bbs","bcc","bcs","beq","bit","bmi", "bne","bpl","bra","brk","bvc","bvs","brl","clc","cld","cli", @@ -99,7 +99,7 @@ static char *kt[] ={ }; /* arithmetic operators (purely for listing, parsing is done programmatically */ -static char *arith_ops[] = { +char *arith_ops[] = { "", "+", "-", "*", "/", ">>", "<<", @@ -172,6 +172,8 @@ static int lp[]= { 0,1,1,1,1,2,2,1,1,1,2,2,2,1,1,1,2,2 }; #define Kreloc (Anzkey-256) /* *= (relocation mode) */ #define Ksegment (Anzkey+1-256) /* this actually now is above 127, which might be a problem as char is signed ... */ +int number_of_valid_tokens = Anzkey; + /* array used for hashing tokens (26 entries, a-z) */ static int ktp[]={ 0,3,17,25,28,29,29,29,29,32,34,34,38,40,41,42,58, @@ -2525,518 +2527,4 @@ fprintf(stderr, "tg_asc token = %i\n", n); return(er); } -/*********************************************************************************************/ -/* this is the listing code - * - * Unfortunately this code has to go here (for now), as this file is the only one - * where we have access to the tables that allow to convert the tokens back to - * a listing - */ - -static FILE *listfp = NULL; -static int list_lineno = 1; /* current line number */ -static int list_last_lineno = 0; /* current line number */ -static char *list_filenamep = NULL; /* current file name pointer */ - -static int list_numbytes = 8; - -static int list_string(char *buf, char *string); -static int list_tokens(char *buf, signed char *input, int len); -static int list_value(char *buf, int val, signed char format); -static int list_nchar(char *buf, signed char c, int n); -static int list_char(char *buf, signed char c); -static int list_sp(char *buf); -static int list_word(char *buf, int outword); -static int list_word_f(char *buf, int outword, signed char format); -static int list_byte(char *buf, int outbyte); -static int list_byte_f(char *buf, int outbyte, signed char format); -static int list_nibble_f(char *buf, int outnib, signed char format); - -// set number of bytes per line displayed as hex -void list_setbytes(int number_of_bytes_per_line) { - list_numbytes = number_of_bytes_per_line; -} - -/* set line number for the coming listing output */ -void list_line(int l) { - list_lineno = l; -} - -/* set file name for the coming listing output */ -void list_filename(char *fname) { - if (list_filenamep == NULL || (fname != NULL && strcmp(fname, list_filenamep) != 0)) { - list_filenamep = fname; - list_lineno = 1; - list_last_lineno = 0; - - /* Hack */ - if (listfp != NULL) { - fprintf(listfp, "\n%s\n\n", fname); - } - } -} - -/** - * set the output file descriptor where to write the listing - */ -void list_setfile(FILE *fp) { - listfp = fp; -} - -char *list_preamble(char *buf, int lineno, int seg, int pc) { - /* line number in file */ - snprintf(buf, 10, "% 5d", lineno); - int i = strlen(buf); - buf += i; - buf += list_char(buf, ' '); - - char c = '?'; - /* preamble ':'
' ' */ - switch(seg) { - case SEG_ABS: c='A'; break; - case SEG_TEXT: c='T'; break; - case SEG_BSS: c='B'; break; - case SEG_DATA: c='D'; break; - case SEG_UNDEF: c='U'; break; - case SEG_ZERO: c='Z'; break; - } - buf = buf + list_char(buf, c); - buf = buf + list_char(buf, ':'); - buf = buf + list_word(buf, pc); - buf = buf + list_nchar(buf, ' ', 2); - - return buf; -} - - -/** - * listing/listing_len give the buffer address and length respectively that contains - * the token as they are produced by the tokenizer. - * bincode/bincode_len give the buffer address and length that contain the binary code - * that is produced from the token listing - * - * Note that both lengths may be zero - */ -void do_listing(signed char *listing, int listing_len, signed char *bincode, int bincode_len) { - - int i, n_hexb; - - char outline[MAXLINE]; - char *buf = outline; - - int lst_seg = listing[0]; - int lst_pc = (listing[2]<<8) | (listing[1] & 255); - - /* no output file (not even stdout) */ - if (listfp == NULL) return; - - /*printf("do_listing: listing=%p (%d), bincode=%p (%d)\n", listing, listing_len, bincode, bincode_len);*/ - - if (bincode_len < 0) bincode_len = -bincode_len; - - /* do we need a separation line? */ - if (list_lineno > list_last_lineno+1) { - /* yes */ - /*fprintf(listfp, "line=%d, last=%d\n", list_lineno, list_last_lineno);*/ - fprintf(listfp, "\n"); - } - list_last_lineno = list_lineno; - - buf = list_preamble(buf, list_lineno, lst_seg, lst_pc); - - // check if we have labels, so we can adjust the max printable number of - // bytes in the last line - int num_last_line = 11; - int tmp = listing[3] & 255; - if (tmp == (T_DEFINE & 255)) { - // we have label definition - num_last_line = 8; - } - int overflow = 0; - - /* binary output (up to 8 byte. If more than 8 byte, print 7 plus "..." */ - n_hexb = bincode_len; - if (list_numbytes != 0 && n_hexb >= list_numbytes) { - n_hexb = list_numbytes-1; - overflow = 1; - } - for (i = 0; i < n_hexb; i++) { - buf = buf + list_byte(buf, bincode[i]); - buf = buf + list_sp(buf); - if ( (i%16) == 15) { - // make a break - buf[0] = 0; - fprintf(listfp, "%s\n", outline); - buf = outline; - buf = list_preamble(buf, list_lineno, lst_seg, lst_pc + i + 1); - } - } - if (overflow) { - // are we at the last byte? - if (n_hexb + 1 == bincode_len) { - // just print the last byte - buf = buf + list_byte(buf, bincode[i]); - buf = buf + list_sp(buf); - } else { - // display "..." - buf = buf + list_nchar(buf, '.', 3); - } - n_hexb++; - } - i = n_hexb % 16; - if (i > num_last_line) { - // make a break (Note: with original PC, as now the assembler text follows - buf[0] = 0; - fprintf(listfp, "%s\n", outline); - buf = outline; - buf = list_preamble(buf, list_lineno, lst_seg, lst_pc); - i = 0; - } - i = num_last_line - i; - buf = buf + list_nchar(buf, ' ', i * 3); - - buf = buf + list_sp(buf); - - buf += list_tokens(buf, listing + 3, listing_len - 3); - -#ifdef LISTING_DEBUG - /* for now only do a hex dump so we see what actually happens */ - i = buf - outline; - if (i<80) buf += list_nchar(buf, ' ', 80-i); - - buf += list_string(buf, " >>"); - for (i = 3; i < listing_len; i++) { - buf = buf + list_byte(buf, listing[i]); - buf = buf + list_sp(buf); - } -#endif - buf[0] = 0; - - fprintf(listfp, "%s\n", outline); -} - -int list_tokens(char *buf, signed char *input, int len) { - int outp = 0; - int inp = 0; - int tmp; - char *name; - signed char c; - label_t is_cll; - int tabval; - signed char format; - - if (inp >= len) return 0; - - tmp = input[inp] & 255; - - tabval = 0; - if (tmp == (T_DEFINE & 255)) { - while (inp < len && tmp == (T_DEFINE & 255)) { - tmp = ((input[inp+2]&255)<<8) | (input[inp+1]&255); -/*printf("define: len=%d, inp=%d, tmp=%d\n", len, inp, tmp);*/ - name=l_get_name(tmp, &is_cll); - if (is_cll == CHEAP) { - outp += list_char(buf+outp, '@'); - } else - if (is_cll == UNNAMED_DEF || is_cll == UNNAMED) { - outp += list_char(buf+outp, ':'); - } - if (is_cll != UNNAMED) { - tmp = list_string(buf+outp, name); - tabval += tmp + 1 + is_cll; - outp += tmp; - } - outp += list_char(buf+outp, ' '); - inp += 3; - tmp = input[inp] & 255; - } - if (tabval < 10) { - outp += list_nchar(buf+outp, ' ', 10-tabval); - } - } else { - if (tmp >= 0 && tmp < Anzkey) { - outp += list_string(buf+outp, " "); - } - } - - if (tmp >= 0 && tmp < Anzkey) { - /* assembler keyword */ - /*printf("tmp=%d, kt[tmp]=%p\n", tmp, kt[tmp]);*/ - if (kt[tmp] != NULL) { - outp += list_string(buf+outp, kt[tmp]); - } - outp += list_sp(buf + outp); - inp += 1; - - if (tmp == Kinclude) { - /* just another exception from the rule... */ - /* next char is terminator (", ') then the length and then the file name */ - char term = input[inp]; - int len = input[inp+1] & 255; - outp += list_char(buf+outp, term); - for (tmp = 2; tmp < len+2; tmp++) { - outp += list_char(buf+outp, input[inp+tmp]); - } - outp += list_char(buf+outp, term); - inp += len + 2; - } - } - - while (inp < len) { - int operator = 0; - - switch(input[inp]) { - case T_CAST: - outp += list_char(buf+outp, input[inp+1]); - break; - case T_VALUE: - /*outp += list_char(buf+outp, 'V');*/ - /* 24 bit value */ - tmp = ((input[inp+3]&255)<<16) | ((input[inp+2]&255)<<8) | (input[inp+1]&255); - format = input[inp+4]; - outp += list_value(buf+outp, tmp, format); - inp += 5; - operator = 1; /* check if arithmetic operator follows */ - break; - case T_LABEL: - /*outp += list_char(buf+outp, 'L');*/ - /* 16 bit label number */ - tmp = ((input[inp+2]&255)<<8) | (input[inp+1]&255); - name=l_get_name(tmp, &is_cll); - if (is_cll == CHEAP) { - outp += list_char(buf+outp, '@'); - } else - if (is_cll == UNNAMED || is_cll == UNNAMED_DEF) { - outp += list_char(buf+outp, ':'); - } - if (is_cll != UNNAMED) { - outp += list_string(buf+outp, name); - } - inp += 3; - operator = 1; /* check if arithmetic operator follows */ - break; - case T_OP: - /* label arithmetic operation; inp[3] is operation like '=' or '+' */ - tmp = ((input[inp+2]&255)<<8) | (input[inp+1]&255); - name=l_get_name(tmp, &is_cll); - if (is_cll) outp += list_char(buf+outp, '@'); - outp += list_string(buf+outp, name); - outp += list_char(buf+outp, input[inp+3]); - inp += 4; - - break; - case T_END: - /* end of operation */ - /*outp += list_string(buf+outp, ";");*/ - inp += 1; - goto end; - break; - case T_COMMENT: - if (inp > 0 && inp < 20) { - outp += list_nchar(buf+outp, ' ', 20-inp); - } - tmp = ((input[inp+2]&255)<<8) | (input[inp+1]&255); - outp += list_char(buf+outp, ';'); - outp += list_string(buf+outp, (char*)input+inp+3); - inp += tmp + 3; - break; - case T_LINE: - case T_FILE: - /* those two are meta-tokens, evaluated outside the t_p2 call, - * they result in calls to list_line(), list_filename() */ - break; - case T_POINTER: - /* what is this? It's actually resolved during token conversion */ - tmp = ((input[inp+5]&255)<<8) | (input[inp+4]&255); - name=l_get_name(tmp, &is_cll); - if (is_cll) outp += list_char(buf+outp, '@'); - outp += list_string(buf+outp, name); - /* - outp += list_byte(buf+outp, input[inp+1]); - outp += list_char(buf+outp, '#'); - tmp = ((input[inp+3]&255)<<8) | (input[inp+2]&255); - outp += list_value(buf+outp, tmp); - */ - inp += 6; - operator = 1; /* check if arithmetic operator follows */ - break; - case '"': - // string display - inp++; - outp += list_char(buf+outp, '"'); - int len = input[inp] & 0xff; - for (int i = 0; i < len; i++) { - inp++; - outp += list_char(buf+outp, input[inp]); - } - inp++; - outp += list_char(buf+outp, '"'); - break; - default: - c = input[inp]; - if (c > 31) { - outp += list_char(buf+outp, input[inp]); - } else { - outp += list_char(buf+outp, '\''); - outp += list_byte(buf+outp, input[inp]); - } - inp += 1; - break; - } - - if (operator && inp < len) { - signed char op = input[inp]; - if (op > 0 && op <= 17) { - outp += list_string(buf+outp, arith_ops[op]); - inp += 1; - } - operator = 0; - } - } -end: - return outp; -} - -int list_string(char *buf, char *string) { - int p = 0; - while (string[p] != 0) { - buf[p] = string[p]; - p++; - } - return p; -} - -int list_value(char *buf, int val, signed char format) { - int p = 0; - char valbuf[32]; - - switch (format) { - case '$': - p += list_char(buf + p, '$'); - if (val & (255<<16)) { - p += list_byte(buf+p, val>>16); - p += list_word(buf+p, val); - } else - if (val & (255<<8)) { - p += list_word(buf+p, val); - } else { - p += list_byte(buf+p, val); - } - break; - case '%': - p += list_char(buf + p, '%'); - if (val & (255<<16)) { - p += list_byte_f(buf+p, val>>16,'%'); - p += list_word_f(buf+p, val,'%'); - } else - if (val & (255<<8)) { - p += list_word_f(buf+p, val,'%'); - } else { - p += list_byte_f(buf+p, val,'%'); - } - break; - case '&': - snprintf(valbuf, 32, "%o",val); - p+= list_char(buf+p, '&'); - p+= list_string(buf+p, valbuf); - break; - case 'd': - snprintf(valbuf, 32, "%d",val); - p+= list_string(buf+p, valbuf); - break; - case '\'': - case '"': - p+= list_char(buf+p, format); - p+= list_char(buf+p, val); - p+= list_char(buf+p, format); - break; - default: - /* hex format as fallback */ - p += list_char(buf + p, '$'); - if (val & (255<<16)) { - p += list_byte(buf+p, val>>16); - p += list_word(buf+p, val); - } else - if (val & (255<<8)) { - p += list_word(buf+p, val); - } else { - p += list_byte(buf+p, val); - } - break; - } - return p; -} - -int list_nchar(char *buf, signed char c, int n) { - int i; - for (i = 0; i < n; i++) { - buf[i]=c; - } - return n; -} - -int list_char(char *buf, signed char c) { - buf[0] = c; - return 1; -} - -int list_sp(char *buf) { - buf[0] = ' '; - return 1; -} - -int list_word(char *buf, int outword) { - return list_word_f(buf, outword, '$'); -} - -int list_word_f(char *buf, int outword, signed char format) { - int p = 0; - p+= list_byte_f(buf+p, outword >> 8, format); - p+= list_byte_f(buf+p, outword, format); - return p; -} - -int list_byte(char *buf, int outbyte) { - return list_byte_f(buf, outbyte, '$'); -} - -int list_byte_f(char *buf, int outbyte, signed char format) { - int p = 0; - p+= list_nibble_f(buf+p, (outbyte >> 4), format); - p+= list_nibble_f(buf+p, outbyte, format); - return p; -} - -int list_nibble_f(char *buf, int outnib, signed char format) { - int p = 0; - outnib = outnib & 0xf; - switch(format) { - case '$': - if (outnib < 10) { - buf[p]='0'+outnib; - } else { - buf[p]='a'-10+outnib; - } - p++; - break; - case '%': - buf[p++] = (outnib&8)?'1':'0'; - buf[p++] = (outnib&4)?'1':'0'; - buf[p++] = (outnib&2)?'1':'0'; - buf[p++] = (outnib&1)?'1':'0'; - break; - default: - /* hex as default */ - if (outnib < 10) { - buf[p]='0'+outnib; - } else { - buf[p]='a'-10+outnib; - } - p++; - break; - } - return p; -} - - diff --git a/xa/src/xat.h b/xa/src/xat.h index cd684bc..13be740 100644 --- a/xa/src/xat.h +++ b/xa/src/xat.h @@ -29,4 +29,8 @@ int b_term(char *s, int *v, int *l, int pc); void list_line(int l); /* set line number for the coming listing output */ void list_filename(char *fname);/* set file name for the coming listing output */ +extern char *kt[]; // table of key words, needed for listing +extern char *arith_ops[]; // table of arithmetic operators, needed for listing +extern int number_of_valid_tokens; // as it says, in the "kt" table + #endif /* __XA65_XAT_H__ */ diff --git a/xa/tests/listing/Makefile b/xa/tests/listing/Makefile index f151618..a225637 100644 --- a/xa/tests/listing/Makefile +++ b/xa/tests/listing/Makefile @@ -4,9 +4,13 @@ XA=../../xa -tests: linebreak clean +tests: linebreak include1 clean +include1: include1.a65 + ${XA} -P- $< > a.out + cmp include1.out a.out + linebreak: linebreak.a65 ${XA} -P- $< > a.out cmp linebreak.out a.out diff --git a/xa/tests/listing/include1.a65 b/xa/tests/listing/include1.a65 new file mode 100644 index 0000000..070429e --- /dev/null +++ b/xa/tests/listing/include1.a65 @@ -0,0 +1,8 @@ + + .org $1000 + +#include "include1a.a65" + +.include "include1a.a65" + + diff --git a/xa/tests/listing/include1.out b/xa/tests/listing/include1.out new file mode 100644 index 0000000..4b6a923 --- /dev/null +++ b/xa/tests/listing/include1.out @@ -0,0 +1,23 @@ + +include1.a65 + + + 2 A:1000 *= $1000 + +include1a.a65 + + + 2 A:1000 a9 00 lda #$00 + +include1.a65 + + + 6 A:1002 .include "include1a.a65" + +include1a.a65 + + + 2 A:1002 a9 00 lda #$00 + +include1.a65 + diff --git a/xa/tests/listing/include1a.a65 b/xa/tests/listing/include1a.a65 new file mode 100644 index 0000000..554af8f --- /dev/null +++ b/xa/tests/listing/include1a.a65 @@ -0,0 +1,3 @@ + + lda #$00 + From 4517bcb87e0a49a80f210e81c088638f305f5c95 Mon Sep 17 00:00:00 2001 From: fachat Date: Mon, 30 Jul 2012 16:22:13 +0200 Subject: [PATCH 17/52] Add HTML output for listing --- xa/src/xa.c | 16 +++ xa/src/xal.c | 60 +++++++++-- xa/src/xal.h | 1 + xa/src/xalisting.c | 168 ++++++++++++++++++++++++++++++- xa/src/xalisting.h | 8 ++ xa/src/xat.c | 1 + xa/src/xat.h | 4 - xa/tests/listing/Makefile | 15 ++- xa/tests/listing/listblocks.a65 | 23 +++++ xa/tests/listing/listblocks.html | 24 +++++ xa/tests/listing/listca65.a65 | 24 +++++ xa/tests/listing/listca65.ca65 | Bin 0 -> 18 bytes xa/tests/listing/listca65.html | 30 ++++++ xa/tests/listing/listca65.o | Bin 0 -> 423 bytes 14 files changed, 355 insertions(+), 19 deletions(-) create mode 100644 xa/tests/listing/listblocks.a65 create mode 100644 xa/tests/listing/listblocks.html create mode 100644 xa/tests/listing/listca65.a65 create mode 100644 xa/tests/listing/listca65.ca65 create mode 100644 xa/tests/listing/listca65.html create mode 100644 xa/tests/listing/listca65.o diff --git a/xa/src/xa.c b/xa/src/xa.c index 0dde88d..ba050b0 100644 --- a/xa/src/xa.c +++ b/xa/src/xa.c @@ -45,6 +45,7 @@ #include "xar.h" #include "xat.h" #include "xacharset.h" +#include "xalisting.h" #include "version.h" @@ -116,6 +117,8 @@ int main(int argc,char *argv[]) signed char *s=NULL; char *tmpp; + char *listformat = NULL; + int mifiles = 5; int nifiles = 0; int verbose = 0; @@ -307,6 +310,13 @@ int main(int argc,char *argv[]) printfile=argv[i]+2; } break; + case 'F': + if (argv[i][2]==0) { + listformat = argv[++i]; + } else { + listformat = argv[i]+2; + } + break; case 'o': if(argv[i][2]==0) { ofile=argv[++i]; @@ -499,6 +509,8 @@ int main(int argc,char *argv[]) { if(verbose) logout("xAss65: Pass 2:\n"); + list_start(listformat); + seg_pass2(); if(!relmode) { @@ -508,6 +520,8 @@ int main(int argc,char *argv[]) segment = SEG_TEXT; } er=pass2(); + + list_end(); } if(fplab) printllist(fplab); @@ -887,6 +901,8 @@ static void usage(int default816, FILE *fp) " -e filename sets errorlog filename, default is none\n" " -l filename sets labellist filename, default is none\n" " -P filename sets filename for listing, default is none, '-' is stdout\n" + " -F format sets format for listing, default is plain, 'html' is current only other\n" + " supported format\n" " -r adds crossreference list to labellist (if `-l' given)\n" " -M allow ``:'' to appear in comments for MASM compatibility\n" " -Xcompatset set compatibility flags for other assemblers, known values are:\n" diff --git a/xa/src/xal.c b/xa/src/xal.c index a249150..0c2bebf 100644 --- a/xa/src/xal.c +++ b/xa/src/xal.c @@ -453,19 +453,16 @@ char *l_get_name(int n, label_t *is_cll) { return ltp->n; } -int l_get(int n, int *v, int *afl) -{ - if(crossref) l_addocc(n,v,afl); - - ltp = afile->la.lt+n; - - if (ltp->is_cll == UNNAMED_DEF) { +// works on the static(!) ltp "label table pointer" +// also returns the actual index in the table of the current ltp +static int resolve_unnamed() { // need to count up/down in the linkd label list for the block char *namep = ltp->n; + int nextp = -1; //printf("::: unnamed_def: %s, n=%d\n", namep, n); while ((*namep == '+') || (*namep == '-')) { char c = *namep; - int nextp = -1; + nextp = -1; if (c == '+') { nextp = ltp->blknext; } else @@ -474,7 +471,7 @@ int l_get(int n, int *v, int *afl) } //printf("::: nextp=%d\n", nextp); if (nextp == -1) { - return E_NODEF; + return -1; // E_NODEF } ltp = afile->la.lt+nextp; //printf("::: leads to: %s, nextp=%d\n", ltp->n, nextp); @@ -482,7 +479,50 @@ int l_get(int n, int *v, int *afl) namep++; } } - } + return nextp; +} + +/* for the listing, esp. html links; returns a pointer to a static buffer, available till next call */ +char *l_get_unique_name(int n) { + static char buf[MAXLINE]; + ltp=afile->la.lt+n; + + if (ltp->is_cll == CHEAP || ltp->is_cll == STD) { + sprintf(buf, "%d%c%s", ltp->blk, + (ltp->is_cll == CHEAP) ? 'C' : '_', + ltp->n); + } else + if (ltp->is_cll == UNNAMED) { + // definition of unnamed label - name is NULL + // so use the actual index + sprintf(buf, "%dU%d", ltp->blk, n); + } else + if (ltp->is_cll == UNNAMED_DEF) { + // we actually need to find the correct label from the "+" and "-" + // in the name + int tmp = resolve_unnamed(); + if (tmp >= 0) { + sprintf(buf, "%dU%d", ltp->blk, tmp); + } else { + sprintf(buf, "__%d", tmp); + } + } else { + buf[0] = 0; // no value + } + return buf; +} + +int l_get(int n, int *v, int *afl) +{ + if(crossref) l_addocc(n,v,afl); + + ltp = afile->la.lt+n; + + if (ltp->is_cll == UNNAMED_DEF) { + int tmp = resolve_unnamed(); + if (tmp == -1) return E_NODEF; + // now ltp is set to the actual label + } (*v)=ltp->val; lz=ltp->n; *afl = ltp->afl; diff --git a/xa/src/xal.h b/xa/src/xal.h index f614baa..d4c53b5 100644 --- a/xa/src/xal.h +++ b/xa/src/xal.h @@ -48,6 +48,7 @@ int l_def(char *s, int* l, int *x, int *f); int l_search(char *s, int *l, int *x, int *v, int *afl); void l_set(int n, int v, int afl); char* l_get_name(int n, label_t *is_cll); +char* l_get_unique_name(int n); int l_get(int n, int *v, int *afl); int l_vget(int n, int *v, char **s); int ll_search(char *s, int *n, label_t labeltype); diff --git a/xa/src/xalisting.c b/xa/src/xalisting.c index 9bbb4a7..de8a58b 100644 --- a/xa/src/xalisting.c +++ b/xa/src/xalisting.c @@ -3,7 +3,7 @@ * Copyright (C) 1989-1997 André Fachat (a.fachat@physik.tu-chemnitz.de) * maintained by Cameron Kaiser * - * Core tokenizing module/pass 1 and pass 2 + * Assembler listing * * 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 @@ -59,6 +59,131 @@ static int list_byte(char *buf, int outbyte); static int list_byte_f(char *buf, int outbyte, signed char format); static int list_nibble_f(char *buf, int outnib, signed char format); +/*********************************************************************************************/ + +// formatter +typedef struct { + void (*start_listing)(char *name); + void (*start_line)(); + int (*set_anchor)(char *buf, char *name); // returns number of bytes added to buf + int (*start_label)(char *buf, char *name); // returns number of bytes added to buf + int (*end_label)(char *buf); + void (*end_line)(); + void (*end_listing)(); + char* (*escape)(char *toescape); // returns pointer to static buffer, valid until next call + char* (*escape_char)(char toescape); // returns pointer to static buffer, valid until next call +} formatter_t; + +static char *def_escape(char *toescape) { + return toescape; +} + +static char *def_escape_char(char toescape) { + static char buf[2]; + buf[0] = toescape; + buf[1] = 0; + return buf; +} + +static formatter_t def_format = { + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, + def_escape, def_escape_char +}; + +static void html_start_listing(char *name) { + // really short version for now + fprintf(listfp, "%s
\n", 
+		(name == NULL) ? "(null)" : name);
+}
+
+static int html_set_anchor(char *buf, char *name) {
+	sprintf(buf, " ", name);
+	return strlen(buf);
+}
+
+static int html_start_label(char *buf, char *name) {
+	sprintf(buf, "", name);
+	return strlen(buf);
+}
+
+static int html_end_label(char *buf) {
+	sprintf(buf, "");
+	return strlen(buf);
+}
+
+static void html_end_listing() {
+	fprintf(listfp, "
\n"); +} + +static char *html_escape(char *toescape) { + static char buf[MAXLINE]; + + char *p = toescape; + char *q = buf; + + while (*p != 0) { + if (*p == '<') { + strcpy(q, "<"); + q+=4; + p++; + } else + if (*p == '&') { + strcpy(q, "&"); + q+=5; + p++; + } else { + *q = *p; + q++; + p++; + } + } + *q = 0; // string terminator + return buf; +} + +static char *html_escape_char(char toescape) { + static char buf[2]; + + buf[0] = toescape; + buf[1] = 0; + + return html_escape(buf); +} + +static formatter_t html_format = { + html_start_listing, + NULL, + html_set_anchor, + html_start_label, + html_end_label, + NULL, + html_end_listing, + html_escape, html_escape_char +}; + +static formatter_t *formatp = &def_format; + +/*********************************************************************************************/ + +void list_start(const char *formatname) { + formatp = &def_format; + + if (formatname != NULL && strcmp("html", formatname) == 0) { + formatp = &html_format; + } + + if (listfp != NULL) { + if (formatp->start_listing != NULL) formatp->start_listing(list_filenamep); + } +} + +void list_end() { + if (listfp != NULL) { + if (formatp->end_listing != NULL) formatp->end_listing(); + } +} + // set number of bytes per line displayed as hex void list_setbytes(int number_of_bytes_per_line) { list_numbytes = number_of_bytes_per_line; @@ -137,6 +262,7 @@ void do_listing(signed char *listing, int listing_len, signed char *bincode, int /* no output file (not even stdout) */ if (listfp == NULL) return; + /*printf("do_listing: listing=%p (%d), bincode=%p (%d)\n", listing, listing_len, bincode, bincode_len);*/ if (bincode_len < 0) bincode_len = -bincode_len; @@ -149,6 +275,9 @@ void do_listing(signed char *listing, int listing_len, signed char *bincode, int } list_last_lineno = list_lineno; + // could be extended to include the preamble... + if (formatp->start_line != NULL) formatp->start_line(); + buf = list_preamble(buf, list_lineno, lst_seg, lst_pc); // check if we have labels, so we can adjust the max printable number of @@ -174,6 +303,8 @@ void do_listing(signed char *listing, int listing_len, signed char *bincode, int // make a break buf[0] = 0; fprintf(listfp, "%s\n", outline); + if (formatp->end_line != NULL) formatp->end_line(); + if (formatp->start_line != NULL) formatp->start_line(); buf = outline; buf = list_preamble(buf, list_lineno, lst_seg, lst_pc + i + 1); } @@ -195,6 +326,8 @@ void do_listing(signed char *listing, int listing_len, signed char *bincode, int // make a break (Note: with original PC, as now the assembler text follows buf[0] = 0; fprintf(listfp, "%s\n", outline); + if (formatp->end_line != NULL) formatp->end_line(); + if (formatp->start_line != NULL) formatp->start_line(); buf = outline; buf = list_preamble(buf, list_lineno, lst_seg, lst_pc); i = 0; @@ -220,6 +353,8 @@ void do_listing(signed char *listing, int listing_len, signed char *bincode, int buf[0] = 0; fprintf(listfp, "%s\n", outline); + + if (formatp->end_line != NULL) formatp->end_line(); } int list_tokens(char *buf, signed char *input, int len) { @@ -242,6 +377,12 @@ int list_tokens(char *buf, signed char *input, int len) { tmp = ((input[inp+2]&255)<<8) | (input[inp+1]&255); /*printf("define: len=%d, inp=%d, tmp=%d\n", len, inp, tmp);*/ name=l_get_name(tmp, &is_cll); + + // duplicate anchor names? + if (formatp->set_anchor != NULL) { + outp += formatp->set_anchor(buf+outp, l_get_unique_name(tmp)); + } + if (is_cll == CHEAP) { outp += list_char(buf+outp, '@'); } else @@ -295,7 +436,7 @@ int list_tokens(char *buf, signed char *input, int len) { switch(input[inp]) { case T_CAST: - outp += list_char(buf+outp, input[inp+1]); + outp += list_string(buf+outp, formatp->escape_char(input[inp+1])); break; case T_VALUE: /*outp += list_char(buf+outp, 'V');*/ @@ -311,6 +452,11 @@ int list_tokens(char *buf, signed char *input, int len) { /* 16 bit label number */ tmp = ((input[inp+2]&255)<<8) | (input[inp+1]&255); name=l_get_name(tmp, &is_cll); + + // duplicate label name + if (formatp->start_label != NULL) { + outp += formatp->start_label(buf+outp, l_get_unique_name(tmp)); + } if (is_cll == CHEAP) { outp += list_char(buf+outp, '@'); } else @@ -320,6 +466,9 @@ int list_tokens(char *buf, signed char *input, int len) { if (is_cll != UNNAMED) { outp += list_string(buf+outp, name); } + + if (formatp->end_label != NULL) outp += formatp->end_label(buf+outp); + inp += 3; operator = 1; /* check if arithmetic operator follows */ break; @@ -327,6 +476,12 @@ int list_tokens(char *buf, signed char *input, int len) { /* label arithmetic operation; inp[3] is operation like '=' or '+' */ tmp = ((input[inp+2]&255)<<8) | (input[inp+1]&255); name=l_get_name(tmp, &is_cll); + if (input[inp+3] == '=') { + // label definition + if (formatp->set_anchor != NULL) { + outp += formatp->set_anchor(buf+outp, l_get_unique_name(tmp)); + } + } if (is_cll) outp += list_char(buf+outp, '@'); outp += list_string(buf+outp, name); outp += list_char(buf+outp, input[inp+3]); @@ -357,8 +512,13 @@ int list_tokens(char *buf, signed char *input, int len) { /* what is this? It's actually resolved during token conversion */ tmp = ((input[inp+5]&255)<<8) | (input[inp+4]&255); name=l_get_name(tmp, &is_cll); + if (formatp->start_label != NULL) { + outp += formatp->start_label(buf+outp, l_get_unique_name(tmp)); + } if (is_cll) outp += list_char(buf+outp, '@'); outp += list_string(buf+outp, name); + + if (formatp->end_label != NULL) outp += formatp->end_label(buf+outp); /* outp += list_byte(buf+outp, input[inp+1]); outp += list_char(buf+outp, '#'); @@ -383,7 +543,7 @@ int list_tokens(char *buf, signed char *input, int len) { default: c = input[inp]; if (c > 31) { - outp += list_char(buf+outp, input[inp]); + outp += list_string(buf+outp, formatp->escape_char(input[inp])); } else { outp += list_char(buf+outp, '\''); outp += list_byte(buf+outp, input[inp]); @@ -395,7 +555,7 @@ int list_tokens(char *buf, signed char *input, int len) { if (operator && inp < len) { signed char op = input[inp]; if (op > 0 && op <= 17) { - outp += list_string(buf+outp, arith_ops[op]); + outp += list_string(buf+outp, formatp->escape(arith_ops[op])); inp += 1; } operator = 0; diff --git a/xa/src/xalisting.h b/xa/src/xalisting.h index 91ce008..5b14b60 100644 --- a/xa/src/xalisting.h +++ b/xa/src/xalisting.h @@ -19,6 +19,14 @@ #ifndef __XA65_XALISTING_H__ #define __XA65_XALISTING_H__ +void list_start(char *formatname); //either NULL or "html" +void list_end(); + +void list_setfile(FILE *fp); +void list_line(int l); /* set line number for the coming listing output */ +void list_filename(char *fname);/* set file name for the coming listing output */ + +// list a single line/token set void do_listing(signed char *listing, int listing_len, signed char *bincode, int bincode_len); #endif /* __XA65_XALISTING_H__ */ diff --git a/xa/src/xat.c b/xa/src/xat.c index b208855..b250a0e 100644 --- a/xa/src/xat.c +++ b/xa/src/xat.c @@ -40,6 +40,7 @@ #include "xao.h" #include "xap.h" #include "xacharset.h" +#include "xalisting.h" int dsb_len = 0; diff --git a/xa/src/xat.h b/xa/src/xat.h index 13be740..6e88bdd 100644 --- a/xa/src/xat.h +++ b/xa/src/xat.h @@ -21,14 +21,10 @@ extern int dsb_len; -void list_setfile(FILE *fp); int t_p1(signed char *s, signed char *t, int *ll, int *al); int t_p2_l(signed char *t, int *ll, int *al); int b_term(char *s, int *v, int *l, int pc); -void list_line(int l); /* set line number for the coming listing output */ -void list_filename(char *fname);/* set file name for the coming listing output */ - extern char *kt[]; // table of key words, needed for listing extern char *arith_ops[]; // table of arithmetic operators, needed for listing extern int number_of_valid_tokens; // as it says, in the "kt" table diff --git a/xa/tests/listing/Makefile b/xa/tests/listing/Makefile index a225637..49e2ec8 100644 --- a/xa/tests/listing/Makefile +++ b/xa/tests/listing/Makefile @@ -4,7 +4,10 @@ XA=../../xa -tests: linebreak include1 clean +CA65=ca65 +LD65=ld65 + +tests: linebreak include1 listblocks listca65 clean include1: include1.a65 @@ -15,6 +18,16 @@ linebreak: linebreak.a65 ${XA} -P- $< > a.out cmp linebreak.out a.out +listblocks: listblocks.a65 + ${XA} -P- -Fhtml listblocks.a65 > a.out + cmp listblocks.html a.out + +listca65: listca65.a65 + ${XA} -XCA65 -P- -Fhtml listca65.a65 > a.out + #${CA65} $<; ${LD65} -t none -o unnamed2.ca65 unnamed2.o; rm unnamed2.o + cmp listca65.html a.out + cmp listca65.ca65 a.o65 + clean: rm -f a.err a.o65 a.out diff --git a/xa/tests/listing/listblocks.a65 b/xa/tests/listing/listblocks.a65 new file mode 100644 index 0000000..0e615e9 --- /dev/null +++ b/xa/tests/listing/listblocks.a65 @@ -0,0 +1,23 @@ + +// tests the html listing feature with blocks that +// contain the same label names, but in different scopes + + *=$1000 + +label1 lda #$00 + + .( +label2 sta $02 + bne label2 + .) + + .( +label2 lda $02 ; again! + bne label2 + .) + +label2 iny + beq label2 + + jmp label1 + diff --git a/xa/tests/listing/listblocks.html b/xa/tests/listing/listblocks.html new file mode 100644 index 0000000..2feabc0 --- /dev/null +++ b/xa/tests/listing/listblocks.html @@ -0,0 +1,24 @@ +(null)
+
+listblocks.a65
+
+
+    5 A:1000                                     *= $1000
+
+    7 A:1000  a9 00                     label1    lda #$00
+
+    9 A:1002                                     .( 
+   10 A:1002  85 02                     label2    sta $02
+   11 A:1004  d0 fc                              bne label2
+   12 A:1006                                     .) 
+
+   14 A:1006                                     .( 
+   15 A:1006  a5 02                     label2    lda $02           ; again!
+   16 A:1008  d0 fc                              bne label2
+   17 A:100a                                     .) 
+
+   19 A:100a  c8                        label2    iny 
+   20 A:100b  f0 fd                              beq label2
+
+   22 A:100d  4c 00 10                           jmp label1
+
diff --git a/xa/tests/listing/listca65.a65 b/xa/tests/listing/listca65.a65 new file mode 100644 index 0000000..98ca0d6 --- /dev/null +++ b/xa/tests/listing/listca65.a65 @@ -0,0 +1,24 @@ + +; tests the html listing feature with blocks that +; contain the same label names, but in different scopes + + .org $1000 + +: lda #$00 + + .scope +: sta $02 +: bne :- + .endscope + + .scope +@label2: lda $02 ; again! + bne @label2 + .endscope + +label2: iny + beq label2 + + beq :--- + jmp :-- + diff --git a/xa/tests/listing/listca65.ca65 b/xa/tests/listing/listca65.ca65 new file mode 100644 index 0000000000000000000000000000000000000000..e0c2101bcf1a03cb281315ebf6385cfd525ba5a8 GIT binary patch literal 18 acmZ3<(8_e--%_Rve@=Y(`{APxlK=o=pbBOH literal 0 HcmV?d00001 diff --git a/xa/tests/listing/listca65.html b/xa/tests/listing/listca65.html new file mode 100644 index 0000000..64bae00 --- /dev/null +++ b/xa/tests/listing/listca65.html @@ -0,0 +1,30 @@ +(null)
+
+listca65.a65
+
+
+    2 A:1000                                    ; tests the html listing feature with blocks that 
+    3 A:1000                                    ; contain the same label names, but in different scopes
+
+    5 A:1000                                     *= $1000
+
+    7 A:1000  a9 00                     :           lda #$00
+
+    9 A:1002                                     .( 
+   10 A:1002  85 02                     :           sta $02
+   11 A:1004  d0 fe                     :           bne :-
+   12 A:1006                                     .) 
+
+   14 A:1006                                     .( 
+   15 A:1006                            @label2   
+   15 A:1006  a5 02                              lda $02              ; again!
+   16 A:1008  d0 fc                              bne @label2
+   17 A:100a                                     .) 
+
+   19 A:100a                            label2    
+   19 A:100a  c8                                 iny 
+   20 A:100b  f0 fd                              beq label2
+
+   22 A:100d  f0 f1                              beq :---
+   23 A:100f  4c 02 10                           jmp :--
+
diff --git a/xa/tests/listing/listca65.o b/xa/tests/listing/listca65.o new file mode 100644 index 0000000000000000000000000000000000000000..4eda2e6a1e6a7817dae4609daa517d4aadcc986a GIT binary patch literal 423 zcmWHo%1h*CU|@&azyL%Hx=>mVO6x;u10Y=nlwStr1DRmJ z#Kh!qXU(k!Rz}9?X<`9lKxwuHpbUo)NSaBIfpH}}$X-SU2-V63vXzkuLS5hnxrOl` zgj&ik43>jX7X)}gygv}?gfI_?_dx_q{e@5;#K4Aqgit=>Aj6oL1VA(gkO|@f1;A{O zLKqw59vB;B9MD{_8jyV;aS-5R;K|7>E=f)_Gt~oP9uPwz%t+7BSkFj6B{45QPdC`v zKfqPjz`($eRj)X+DivMWh}|J4F)202hz&xqIQzS}vIY6OIEFYfI|T=`fEXN6u0j3* Nj_$53exW`-3;>OTHktqc literal 0 HcmV?d00001 From 873ee1c721665edec8a63f590fb60ed4edde7591 Mon Sep 17 00:00:00 2001 From: fachat Date: Mon, 30 Jul 2012 16:24:12 +0200 Subject: [PATCH 18/52] add man page info for HTML listing format --- xa/man/xa.1 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/xa/man/xa.1 b/xa/man/xa.1 index df28951..dac45b2 100644 --- a/xa/man/xa.1 +++ b/xa/man/xa.1 @@ -62,6 +62,10 @@ Set listing filename, default is none. use the special filename .BR \- to print the listing to standard output. .TP +.B \-F html +Set listing format, default is plain. The only other currently supported format is +.BR html +.TP .B \-e filename Set errorlog filename, default is none. .TP From c53468dc87855254ef925ced362fe8db729bea0a Mon Sep 17 00:00:00 2001 From: fachat Date: Mon, 30 Jul 2012 16:27:20 +0200 Subject: [PATCH 19/52] added TODO for listing quirks --- xa/TODO | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/xa/TODO b/xa/TODO index 0944889..97efd47 100644 --- a/xa/TODO +++ b/xa/TODO @@ -8,3 +8,13 @@ o inc a -> ina, dec a -> dea (right now uses bare inc and dec) o VICE label file support o Smarter -X that can cope with non-block-aligned segment sizes + +o The listing feature is not bug-free yet: + - ca65 and other assembler compatibility pseudo-opcodes will be + listed as xa specific ones, not the original in the source + E.g. a CA65 ".scope" will appear as ".(" in the listing + - The assembler has no constant handling, so constants are + resolved at parse time. Thus they appear as their value + in the listing. Only situation now is ".listbytes unlimited", + which will show as ".listbytes 0" in the listing + From e50236d62ba6f8955dde164c08de111f52534317 Mon Sep 17 00:00:00 2001 From: fachat Date: Wed, 1 Aug 2012 13:27:01 +0200 Subject: [PATCH 20/52] Add a new test for ca65 unnamed labels, handling across files and listing them across files --- xa/tests/listing/Makefile | 10 ++++++++-- xa/tests/listing/listca65_2.a65 | 15 +++++++++++++++ xa/tests/listing/listca65_2.ca65 | Bin 0 -> 11 bytes xa/tests/listing/listca65_2.html | 32 +++++++++++++++++++++++++++++++ xa/tests/listing/listca65_2b.a65 | 7 +++++++ 5 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 xa/tests/listing/listca65_2.a65 create mode 100644 xa/tests/listing/listca65_2.ca65 create mode 100644 xa/tests/listing/listca65_2.html create mode 100644 xa/tests/listing/listca65_2b.a65 diff --git a/xa/tests/listing/Makefile b/xa/tests/listing/Makefile index 49e2ec8..cbb69c4 100644 --- a/xa/tests/listing/Makefile +++ b/xa/tests/listing/Makefile @@ -7,7 +7,7 @@ XA=../../xa CA65=ca65 LD65=ld65 -tests: linebreak include1 listblocks listca65 clean +tests: linebreak include1 listblocks listca65 listca65_2 clean include1: include1.a65 @@ -24,10 +24,16 @@ listblocks: listblocks.a65 listca65: listca65.a65 ${XA} -XCA65 -P- -Fhtml listca65.a65 > a.out - #${CA65} $<; ${LD65} -t none -o unnamed2.ca65 unnamed2.o; rm unnamed2.o + #${CA65} $<; ${LD65} -t none -o listca65.ca65 listca65.o; rm listca65.o cmp listca65.html a.out cmp listca65.ca65 a.o65 +listca65_2: listca65_2.a65 + ${XA} -XCA65 -P- -Fhtml listca65_2.a65 > a.out + ${CA65} $<; ${LD65} -t none -o listca65_2.ca65 listca65_2.o; rm listca65_2.o + cmp listca65_2.html a.out + cmp listca65_2.ca65 a.o65 + clean: rm -f a.err a.o65 a.out diff --git a/xa/tests/listing/listca65_2.a65 b/xa/tests/listing/listca65_2.a65 new file mode 100644 index 0000000..28fe1a4 --- /dev/null +++ b/xa/tests/listing/listca65_2.a65 @@ -0,0 +1,15 @@ + +; tests the html listing feature with blocks that +; contain the same label names, but in different scopes + + .org $1000 + +: lda #$00 + + .include "listca65_2b.a65" + +label2: iny + beq label2 + + jmp :- + diff --git a/xa/tests/listing/listca65_2.ca65 b/xa/tests/listing/listca65_2.ca65 new file mode 100644 index 0000000000000000000000000000000000000000..be121928bcad5b8f9f089e44c30cfa0fb9748e3a GIT binary patch literal 11 TcmZ36CeKiFbMzvDh&ow literal 0 HcmV?d00001 diff --git a/xa/tests/listing/listca65_2.html b/xa/tests/listing/listca65_2.html new file mode 100644 index 0000000..50ba70d --- /dev/null +++ b/xa/tests/listing/listca65_2.html @@ -0,0 +1,32 @@ +(null)
+
+listca65_2.a65
+
+
+    2 A:1000                                    ; tests the html listing feature with blocks that 
+    3 A:1000                                    ; contain the same label names, but in different scopes
+
+    5 A:1000                                     *= $1000
+
+    7 A:1000  a9 00                     :           lda #$00
+
+    9 A:1002                                     .include "listca65_2b.a65"
+
+listca65_2b.a65
+
+
+    2 A:1002                                    ; to be included in listca65_2.a65
+    3 A:1002                                    ; to check HTML linkage of unnamed labels across files
+
+    5 A:1002  c8                        :           iny 
+    6 A:1003  d0 fd                              bne :-
+
+listca65_2.a65
+
+
+   11 A:1005                            label2    
+   11 A:1005  c8                                 iny 
+   12 A:1006  f0 fd                              beq label2
+
+   14 A:1008  4c 02 10                           jmp :-
+
diff --git a/xa/tests/listing/listca65_2b.a65 b/xa/tests/listing/listca65_2b.a65 new file mode 100644 index 0000000..109fcb7 --- /dev/null +++ b/xa/tests/listing/listca65_2b.a65 @@ -0,0 +1,7 @@ + + ; to be included in listca65_2.a65 + ; to check HTML linkage of unnamed labels across files + +: iny + bne :- + From 25796d051a6dcef5cc58f91d22069245a56c0692 Mon Sep 17 00:00:00 2001 From: fachat Date: Wed, 15 Aug 2012 03:05:04 +0200 Subject: [PATCH 21/52] add tests for recursive preprocessor defines --- xa/tests/ppdefines/Makefile | 13 +++++++++++++ xa/tests/ppdefines/test1.a65 | 32 ++++++++++++++++++++++++++++++++ xa/tests/ppdefines/test1.o65 | Bin 0 -> 22 bytes 3 files changed, 45 insertions(+) create mode 100644 xa/tests/ppdefines/Makefile create mode 100644 xa/tests/ppdefines/test1.a65 create mode 100644 xa/tests/ppdefines/test1.o65 diff --git a/xa/tests/ppdefines/Makefile b/xa/tests/ppdefines/Makefile new file mode 100644 index 0000000..39d537f --- /dev/null +++ b/xa/tests/ppdefines/Makefile @@ -0,0 +1,13 @@ + +XA=../../xa + +all: test1 clean + +clean: + rm a.o65 + +%:%.a65 + ${XA} $< + cmp a.o65 $@.o65 + + diff --git a/xa/tests/ppdefines/test1.a65 b/xa/tests/ppdefines/test1.a65 new file mode 100644 index 0000000..cb8e30f --- /dev/null +++ b/xa/tests/ppdefines/test1.a65 @@ -0,0 +1,32 @@ + +#define macro1() \ + lda #0 + +#define macro2(a) \ + lda #(a) + +#define macro3(a,b) \ + lda #(a): \ + ldy #(b) + +#define const1 $40 + +#define func1(a) (a) | $20 + + *=$c000 + + macro1() + + macro2(2) + + macro3(2,3) + + lda #(2) | $20 + lda #func1(2) + + macro2(func1(3)) + + macro3(const1, func1(5)) + + macro3(func1(const1), func1(func1(const1))) + diff --git a/xa/tests/ppdefines/test1.o65 b/xa/tests/ppdefines/test1.o65 new file mode 100644 index 0000000000000000000000000000000000000000..74a2827dd56c2f9cc69302808402fddd195bbdfd GIT binary patch literal 22 ccmZ3 Date: Wed, 15 Aug 2012 03:06:45 +0200 Subject: [PATCH 22/52] added 0xHEX and 0OCTAL parsing with -XC compatibility parameter --- xa/man/xa.1 | 5 ++++- xa/src/xa.c | 2 ++ xa/src/xa.h | 1 + xa/src/xah.h | 26 +++++++++++++------------- xa/src/xat.c | 20 +++++++++++++++++--- 5 files changed, 37 insertions(+), 17 deletions(-) diff --git a/xa/man/xa.1 b/xa/man/xa.1 index dac45b2..2ab227d 100644 --- a/xa/man/xa.1 +++ b/xa/man/xa.1 @@ -83,8 +83,11 @@ Add cross-reference list to labellist (requires Enables compatibility settings to become more (not fully!) compatible with other 6502 assemblers. Currently supported are compatibility set "MASM" and "CA65". "MASM" allows colons to appear in comments. This does not affect colon interpretation elsewhere. -"CA65" allows the ":=" label definition (instead of "="), and also the "cheap local labels" using +"CA65" allows the ":=" label definition (instead of "="), It adds the "unnamed labels" and also the +"cheap local labels" using the "@" character. This, however, disables the "@" 24-bit enforcement. +"C" enables the usage of "0xHEX" and "0OCTAL" C-style number encodings. Note that you can combine +compatibility sets e.g. with "-XCA65 -XC". .TP .B \-M Allow colons to appear in comments; for MASM compatibility. This does diff --git a/xa/src/xa.c b/xa/src/xa.c index ba050b0..122248e 100644 --- a/xa/src/xa.c +++ b/xa/src/xa.c @@ -65,6 +65,7 @@ int ncmos, cmosfl, w65816, n65816; /* compatibility flags */ int masm = 0; /* MASM */ int ca65 = 0; /* CA65 */ +int ctypes = 0; /* C compatibility, like "0xab" types */ int nolink = 0; int romable = 0; @@ -1222,6 +1223,7 @@ typedef struct { static compat_set compat_sets[] = { { "MASM", &masm }, { "CA65", &ca65 }, + { "C", &ctypes }, { NULL, NULL } }; diff --git a/xa/src/xa.h b/xa/src/xa.h index fd4d7cf..7cb958c 100644 --- a/xa/src/xa.h +++ b/xa/src/xa.h @@ -27,6 +27,7 @@ extern int noglob; extern int showblk; extern int relmode; extern int crossref; +extern int ctypes; extern char altppchar; extern int tlen, tbase; diff --git a/xa/src/xah.h b/xa/src/xah.h index 3f33fa0..dbedadd 100644 --- a/xa/src/xah.h +++ b/xa/src/xah.h @@ -95,20 +95,20 @@ typedef struct { #define BUFSIZE 4096 /* File-Puffegroesse (wg Festplatte) */ -#define E_OK 0 /* Fehlernummern */ -#define E_SYNTAX -1 /* Syntax Fehler */ -#define E_LABDEF -2 /* Label definiert */ -#define E_NODEF -3 /* Label nicht definiert */ -#define E_LABFULL -4 /* Labeltabelle voll */ -#define E_LABEXP -5 /* Label erwartet */ -#define E_NOMEM -6 /* kein Speicher mehr */ -#define E_ILLCODE -7 /* Illegaler Opcode */ -#define E_ADRESS -8 /* Illegale Adressierung */ +#define E_OK 0 /* No error */ +#define E_SYNTAX -1 /* Syntax error */ +#define E_LABDEF -2 /* Label already defined (duplicate label definition) */ +#define E_NODEF -3 /* Label not defined */ +#define E_LABFULL -4 /* Label table full */ +#define E_LABEXP -5 /* Label expected but not found */ +#define E_NOMEM -6 /* out of memory */ +#define E_ILLCODE -7 /* Illegal Opcode */ +#define E_ADRESS -8 /* Illegal Addressing mode */ #define E_RANGE -9 /* Branch out of range */ -#define E_OVERFLOW -10 /* Ueberlauf */ -#define E_DIV -11 /* Division durch Null */ -#define E_PSOEXP -12 /* Pseudo-Opcode erwartet */ -#define E_BLKOVR -13 /* Block-Stack Uebergelaufen */ +#define E_OVERFLOW -10 /* overflow */ +#define E_DIV -11 /* Division by zero */ +#define E_PSOEXP -12 /* Pseudo-Opcode expected but not found */ +#define E_BLKOVR -13 /* Block-Stack overflow */ #define E_FNF -14 /* File not found (pp) */ #define E_EOF -15 /* End of File */ #define E_BLOCK -16 /* Block inkonsistent */ diff --git a/xa/src/xat.c b/xa/src/xat.c index b250a0e..5093a98 100644 --- a/xa/src/xat.c +++ b/xa/src/xat.c @@ -2130,16 +2130,30 @@ fprintf(stderr, "could not find %s\n", (char *)s+p); } } else - if(s[p]<='9' && s[p]>='0') + if(s[p]<='9' && (s[p]>'0' || (s[p] == '0' && !ctypes))) { tg_dez(s+p,&ll,&v); p+=ll; wval(q,v, 'd'); } else - - /* handle encodings: hex, binary, octal, quoted strings */ + /* handle encodings: hex, binary, octal, quoted strings */ switch(s[p]) { + case '0': + // only gets here when "ctypes" is set, and starts with 0 + // we here check for the C stype "0xHEX" and "0OCTAL" encodings + if ('x' == tolower(s[p+1])) { + // c-style hex + tg_hex(s+p+2, &ll, &v); + p+=2+ll; + wval(q, v, '$'); + } else { + // c-style octal + tg_oct(s+p+1,&ll,&v); + p+=1+ll; + wval(q,v, '&'); + } + break; case '$': tg_hex(s+p+1,&ll,&v); p+=1+ll; From 6ec6887e3d77bd7e07a02e328497942ec85181b1 Mon Sep 17 00:00:00 2001 From: fachat Date: Wed, 15 Aug 2012 03:07:33 +0200 Subject: [PATCH 23/52] fix recursive preprocessor defines (I hope) --- xa/src/xap.c | 419 +++++++++++++++++++++++++++++---------------------- 1 file changed, 242 insertions(+), 177 deletions(-) diff --git a/xa/src/xap.c b/xa/src/xap.c index 29fd0d3..7ffc3e0 100644 --- a/xa/src/xap.c +++ b/xa/src/xap.c @@ -40,7 +40,7 @@ #include "xap.h" /* define this for recursive evaluation output */ -/* #define DEBUG_RECMAC */ +#undef DEBUG_RECMAC char s[MAXLINE]; Datei *filep; @@ -434,78 +434,85 @@ int tcompare(char s[],char *v[], int n) return((i==n)? -1 : i); } -int pp_replace(char *to, char *ti, int a,int b) +static int check_name(char *t, int n) { + + int i=0; + { + char *x=liste[n].search; + while(t[i]==*x++ && t[i]) + i++; + } + + return i == liste[n].s_len; +} + +/** + * this is a break out of the original pp_replace code, as this code + * was basically duplicated for initial and recursive calls. + */ +static int pp_replace_part(char *to, char *t, int n, int sl, int recursive, int *l, int blist) { - char *t=to,c,*x,*y,*mx,*rs; - int i,l,n,sl,d,ld,er=E_OK,hkfl,klfl; - char fti[MAXLINE],fto[MAXLINE]; -/* - int flag=!strncmp(ti,"TOUT",4); - if(flag) printf("flag=%d\n",flag); -*/ - (void)strcpy(t,ti); + int er = E_OK; - if(rlist) - { - while(t[0]!='\0') - { - while(!isalpha(t[0]) && t[0]!='_') - if(t[0]=='\0') - break; /*return(E_OK);*/ - else - { - t++; - ti++; - } - - for(l=0;isalnum(t[l])||t[l]=='_';l++); - ld=l; -/* - if(flag) printf("l=%d,a=%d,t=%s\n",l,a,t); -*/ - if(a<0) - { - n=hashindex[hashcode(t,l)]; - - do - { - sl=liste[n].s_len; - - if(sl && (sl==l)) - { - i=0; - x=liste[n].search; - while(t[i]==*x++ && t[i]) - i++; + // save mem, to restore it when we don't need the pseudo replacements anymore + // Note: in a real version, that should probably be a parameter, and not fiddling + // with global variables... + char *saved_mem = mem; - if(i==sl) - { - rs=liste[n].replace; - + // yes, mark replacement string + char *rs=liste[n].replace; + + // does it have parameters? if(liste[n].p_anz) { + // yes, we have parameters, so we need to pp_replace them + // as well. + char fti[MAXLINE],fto[MAXLINE]; + + // copy replacement into temp buffer (void)strcpy(fti,liste[n].replace); - if(rlist+liste[n].p_anz>=ANZDEF || memfre=ANZDEF || memfre10) + if (++j>10) { + // we ran into 10 recursions deep - that does not look sound, bail out errout(E_ORECMAC); + } } - (void)strcpy(liste[rlist+i].replace, nfto); +#endif + // copy over the replacement string into free memory (using mx as pointer) + (void)strcpy(mx, nfto); + // replace the pointer to the (now obsolete) old replacement with the one we just created + // Note that due to the nature of the (more or less static) memory allocation, this is not + // being freed. Oh well... + liste[blist+i].replace = mx; + mx += strlen(mx)+1; + #ifdef DEBUG_RECMAC printf("FINAL: -%s=%s\n",liste[rlist+i].search,liste[rlist+i].replace); #endif } - if(!er) - er=pp_replace(fto,fti,rlist,rlist+i); + + if(!er) { + // safe-guard our memory allocations + mem = mx; + // only change (of two) from recursive: rlist is 0 there + er=pp_replace(fto,fti,recursive ? 0 : blist,blist+liste[n].p_anz); + } /* if(flag) printf("sl=%d,",sl);*/ sl=(int)((long)y+1L-(long)t); /* if(flag) printf("sl=%d\n",sl);*/ @@ -575,14 +633,18 @@ int pp_replace(char *to, char *ti, int a,int b) /* printf("->%s\n",fto);*/ } } - if(er) + if(er) { + mem = saved_mem; return(er); + } } - d=(int)strlen(rs)-sl; + int d=(int)strlen(rs)-sl; - if(strlen(to)+d>=MAXLINE) + if(strlen(to)+d>=MAXLINE) { + mem = saved_mem; return(E_NOMEM); + } /* if(d<0) @@ -597,129 +659,125 @@ int pp_replace(char *to, char *ti, int a,int b) t[ll+d]=t[ll]; } */ - if(d) - (void)strcpy(t+sl+d,ti+sl); + if(d) { + // d can be positive or negative, so strcpy cannot be used, use memmove instead + (void)memmove(t+sl+d,t+sl, strlen(t) - sl + 1); + } - i=0; + int i=0; + char c; while((c=rs[i])) t[i++]=c; - l=sl+d;/*=0;*/ - break; - } + // other change from recursive. there sl is missing from add + *l=(recursive ? 0 : sl) + d;/*=0;*/ + + mem = saved_mem; + + return (er); +} + +/** + * copy the input string pointed to by ti into + * an output string buffer pointed to by to, replacing all + * preprocessor definitions in the process. + * + * Note: this method is called recursively, with "a" being -1 + * when called from the "outside" respectively in a new context + * (like macro parameters) + * + * The "b" parameter denotes the index in the list from which on + * pseudo replacement entries are being created for replacement + * parameters + * + */ +int pp_replace(char *to, char *ti, int a,int b) +{ + char *t=to; + int l,n,sl,er=E_OK; + int ld; // length of name/token to analyse +/* + int flag=!strncmp(ti,"TOUT",4); + if(flag) printf("flag=%d\n",flag); +*/ + // t points to to, so copy input to output 1:1 + // then below work on the copy in-place + (void)strcpy(t,ti); + + // if there are replacements in the list of replacements + if(rlist) + { + // loop over the whole input + while(t[0]!='\0') + { + // skip over the whitespace + while(!isalpha(t[0]) && t[0]!='_') { + if(t[0]=='\0') + break; /*return(E_OK);*/ + else + { + t++; + ti++; + } + } + + // determine the length of the name + for(l=0;isalnum(t[l])||t[l]=='_';l++); + // store in ld + ld=l; +/* + if(flag) printf("l=%d,a=%d,t=%s\n",l,a,t); +*/ + // the following if() is executed when being called from an + // 'external' context, i.e. not from a recursion + if(a<0) + { + // when called from an external context, not by recursion + + // compute hashcode for the name for the search index entry (liste[n]) + n=hashindex[hashcode(t,l)]; + + // loop over all entries in linked list for hash code (think: hash collisions) + do // while(1); + { + // length of name of pp definition + sl=liste[n].s_len; + + // does pp definition match what we have found? + if(sl && (sl==l) && check_name(t, n)) + { + er = pp_replace_part(to, t, n, sl, 0, &l, b); + break; } if(!n) break; - + + // next index in linked list for given hash code n=liste[n].nextindex; } while(1); } else { + // called when in recursive call + // loop over all the replacement entries from the given b down to 0 + // that allows to replace the parameters first (as they were added at + // the end of the list) for(n=b-1;n>=a;n--) { sl=liste[n].s_len; - if(sl && (sl==l)) + if(sl && (sl==l) && check_name(t, n)) { - i=0; - x=liste[n].search; - while(t[i]==*x++ && t[i]) - i++; - - if(i==sl) - { - rs=liste[n].replace; - if(liste[n].p_anz) - { - (void)strcpy(fti,liste[n].replace); - if(rlist+liste[n].p_anz>=ANZDEF || memfre=MAXLINE) - return(E_NOMEM); -/* - if(d<0) - { - y=t+sl+d; - x=t+sl; - while(*y++=*x++); - } - if(d>0) - { - for(ll=strlen(t);ll>=sl;ll--) - t[ll+d]=t[ll]; - } -*/ - if(d) - (void)strcpy(t+sl+d,ti+sl); - - i=0; - while((c=rs[i])) - t[i++]=c; - l+=d;/*0;*/ - break; - } + er = pp_replace_part(to, t, n, sl, 1, &l, b); + break; } } } + // advance input by length of name ti+=ld; + // advance output by l t+=l; - } - } + } /* end while(t[0] != 0) */ + } /* end if(rlist) */ return(E_OK); } @@ -916,8 +974,15 @@ int pgetline(char *t) er= (er==1) ? E_OK : er ; - if(!er) + if(!er) { +#ifdef DEBUG_RECMAC + printf("<<<: %s\n", in_line); +#endif er=pp_replace(t,in_line,-1,rlist); +#ifdef DEBUG_RECMAC + printf(">>>: %s\n", t); +#endif + } if(!er && nff) er=E_NEWFILE; From 20b1e2cc088ea80e666f32d8a522b9e7e1c5b10c Mon Sep 17 00:00:00 2001 From: fachat Date: Wed, 15 Aug 2012 13:42:58 +0200 Subject: [PATCH 24/52] Fix crazy memory corruption bug caused by listing not interpreting the internal data structures correctly. .dsb and .bin listing is still wrong --- xa/src/xa.c | 17 ++++++++--- xa/src/xal.c | 4 +++ xa/src/xalisting.c | 24 +++++++++++---- xa/src/xap.c | 7 +++-- xa/src/xat.c | 74 +++++++++++++++++++++++++++++++--------------- 5 files changed, 89 insertions(+), 37 deletions(-) diff --git a/xa/src/xa.c b/xa/src/xa.c index 122248e..d2c87bc 100644 --- a/xa/src/xa.c +++ b/xa/src/xa.c @@ -681,6 +681,8 @@ static int pass2(void) l=afile->mn.tmp[afile->mn.tmpe++]; ll=l; + // printf("%p: l=%d first=%02x\n", afile->mn.tmp+afile->mn.tmpe-1, l, 0xff & afile->mn.tmp[afile->mn.tmpe]); + if(!l) { if(afile->mn.tmp[afile->mn.tmpe]==T_LINE) @@ -1041,7 +1043,9 @@ static int x_init(void) static int puttmp(int c) { int er=E_NOMEM; -/*printf("puttmp: afile=%p, tmp=%p, tmpz=%d\n",afile, afile?afile->mn.tmp:0, afile?afile->mn.tmpz:0);*/ + + //printf("puttmp: %02x -> %p \n",0xff & c, afile->mn.tmp+afile->mn.tmpz); + if(afile->mn.tmpzmn.tmp[afile->mn.tmpz++]=c; @@ -1053,14 +1057,19 @@ static int puttmp(int c) static int puttmps(signed char *s, int l) { int i=0,er=E_NOMEM; - + + // printf("puttmps %d bytes from %p to %p:", l, s, afile->mn.tmp+afile->mn.tmpz); + if(afile->mn.tmpz+lmn.tmp[afile->mn.tmpz++]=s[i++]; + while(imn.tmp[afile->mn.tmpz++]=s[i++]; + } er=E_OK; } + // printf("\n"); return(er); } diff --git a/xa/src/xal.c b/xa/src/xal.c index 0c2bebf..b9451a2 100644 --- a/xa/src/xal.c +++ b/xa/src/xal.c @@ -448,6 +448,10 @@ void l_addocc(int n, int *v, int *afl) { /* for the list functionality */ char *l_get_name(int n, label_t *is_cll) { + if (n > afile->la.ltm) { + fprintf(stderr, "Corrupted structures! n=%d, but max=%d\n", n, afile->la.ltm); + exit(1); + } ltp=afile->la.lt+n; *is_cll = ltp->is_cll; return ltp->n; diff --git a/xa/src/xalisting.c b/xa/src/xalisting.c index de8a58b..e689fa8 100644 --- a/xa/src/xalisting.c +++ b/xa/src/xalisting.c @@ -339,15 +339,21 @@ void do_listing(signed char *listing, int listing_len, signed char *bincode, int buf += list_tokens(buf, listing + 3, listing_len - 3); -#ifdef LISTING_DEBUG +#if 1 //def LISTING_DEBUG /* for now only do a hex dump so we see what actually happens */ - i = buf - outline; - if (i<80) buf += list_nchar(buf, ' ', 80-i); + { + char valbuf[32]; + i = buf - outline; + if (i<80) buf += list_nchar(buf, ' ', 80-i); - buf += list_string(buf, " >>"); - for (i = 3; i < listing_len; i++) { + buf += list_string(buf, " >>"); + sprintf(valbuf, "%p", listing+3); + buf += list_string(buf, valbuf); + buf += list_sp(buf); + for (i = 3; i < listing_len; i++) { buf = buf + list_byte(buf, listing[i]); buf = buf + list_sp(buf); + } } #endif buf[0] = 0; @@ -464,7 +470,7 @@ int list_tokens(char *buf, signed char *input, int len) { outp += list_char(buf+outp, ':'); } if (is_cll != UNNAMED) { - outp += list_string(buf+outp, name); + outp += list_string(buf+outp, name == NULL ? "" : name); } if (formatp->end_label != NULL) outp += formatp->end_label(buf+outp); @@ -566,6 +572,12 @@ end: } int list_string(char *buf, char *string) { + if (buf == NULL || string == NULL) { + fprintf(stderr, "NULL pointer: buf=%p, string=%p\n", buf, string); + fflush(stderr); + exit(1); + } + int p = 0; while (string[p] != 0) { buf[p] = string[p]; diff --git a/xa/src/xap.c b/xa/src/xap.c index 7ffc3e0..9fb8cee 100644 --- a/xa/src/xap.c +++ b/xa/src/xap.c @@ -41,6 +41,7 @@ /* define this for recursive evaluation output */ #undef DEBUG_RECMAC +#undef DEBUG_REPLACE char s[MAXLINE]; Datei *filep; @@ -975,11 +976,11 @@ int pgetline(char *t) er= (er==1) ? E_OK : er ; if(!er) { -#ifdef DEBUG_RECMAC - printf("<<<: %s\n", in_line); +#ifdef DEBUG_REPLACE +// printf("<<<: %s\n", in_line); #endif er=pp_replace(t,in_line,-1,rlist); -#ifdef DEBUG_RECMAC +#ifdef DEBUG_REPLACE printf(">>>: %s\n", t); #endif } diff --git a/xa/src/xat.c b/xa/src/xat.c index 5093a98..8a1cd43 100644 --- a/xa/src/xat.c +++ b/xa/src/xat.c @@ -430,6 +430,15 @@ fprintf(stderr, "- p1 %d starting -\n", pc[segment]); } /* copy the buffer */ memcpy(t+tlen, t+6+inp, l-inp); + +#if 0 + printf("t_conv (er=%d, t=%p, tlen=%d, inp=%d):",er, t, tlen, inp); + for(i=0;i1) && (t[inp] Date: Wed, 15 Aug 2012 14:08:13 +0200 Subject: [PATCH 25/52] remove debug output... (oops..) --- xa/src/xalisting.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xa/src/xalisting.c b/xa/src/xalisting.c index e689fa8..39b4331 100644 --- a/xa/src/xalisting.c +++ b/xa/src/xalisting.c @@ -339,7 +339,7 @@ void do_listing(signed char *listing, int listing_len, signed char *bincode, int buf += list_tokens(buf, listing + 3, listing_len - 3); -#if 1 //def LISTING_DEBUG +#ifdef LISTING_DEBUG /* for now only do a hex dump so we see what actually happens */ { char valbuf[32]; From 42310222adb5d9ede859e4387f6da023c7ab5b0f Mon Sep 17 00:00:00 2001 From: fachat Date: Wed, 15 Aug 2012 14:29:17 +0200 Subject: [PATCH 26/52] do not replaces preprocessor tokens/macros in comment part --- xa/src/xap.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/xa/src/xap.c b/xa/src/xap.c index 9fb8cee..c83234f 100644 --- a/xa/src/xap.c +++ b/xa/src/xap.c @@ -708,14 +708,24 @@ int pp_replace(char *to, char *ti, int a,int b) if(rlist) { // loop over the whole input - while(t[0]!='\0') + while(t[0]!='\0' && t[0] != ';') { // skip over the whitespace + char quotefl = 0; while(!isalpha(t[0]) && t[0]!='_') { - if(t[0]=='\0') + if(t[0]=='\0' || (t[0] == ';' && !quotefl)) break; /*return(E_OK);*/ else { + if (quotefl) { + // ignore other quotes within a quote + if (t[0] == quotefl) { + quotefl = 0; + } + } else + if (t[0] == '"' || t[0] == '\'') { + quotefl = t[0]; + } t++; ti++; } @@ -725,9 +735,9 @@ int pp_replace(char *to, char *ti, int a,int b) for(l=0;isalnum(t[l])||t[l]=='_';l++); // store in ld ld=l; -/* - if(flag) printf("l=%d,a=%d,t=%s\n",l,a,t); -*/ + + //printf("l=%d,a=%d,t=%s\n",l,a,t); + // the following if() is executed when being called from an // 'external' context, i.e. not from a recursion if(a<0) From e39d58fc6df391d22ea5bfbc170b6b6bca3de058 Mon Sep 17 00:00:00 2001 From: fachat Date: Wed, 15 Aug 2012 15:24:48 +0200 Subject: [PATCH 27/52] Fix the handling of comments/colons within preprocessor replacements (as they appear there as well). --- xa/src/xa.c | 36 ++++++++++++++++++++++++++---------- xa/src/xap.c | 22 +++++++++++++++++----- xa/src/xat.c | 15 +++++++++++++-- 3 files changed, 56 insertions(+), 17 deletions(-) diff --git a/xa/src/xa.c b/xa/src/xa.c index d2c87bc..e28995d 100644 --- a/xa/src/xa.c +++ b/xa/src/xa.c @@ -92,6 +92,7 @@ static int x_init(void); static int pass1(void); static int pass2(void); static int puttmp(int); +static int puttmpw(int); static int puttmps(signed char *, int); static void chrput(int); static int getline(char *); @@ -457,7 +458,7 @@ int main(int argc,char *argv[]) if(verbose) logout(out); er=pp_open(ifile); - puttmp(0); + puttmpw(0); puttmp(T_FILE); puttmp(0); puttmp(0); @@ -678,7 +679,9 @@ static int pass2(void) while((ner_max==0 || nermn.tmpemn.tmpz) { - l=afile->mn.tmp[afile->mn.tmpe++]; + // get the length of the entry (now two byte - need to handle the sign) + l = afile->mn.tmp[afile->mn.tmpe++]; + l |= afile->mn.tmp[afile->mn.tmpe++] << 8; ll=l; // printf("%p: l=%d first=%02x\n", afile->mn.tmp+afile->mn.tmpe-1, l, 0xff & afile->mn.tmp[afile->mn.tmpe]); @@ -842,14 +845,14 @@ static int pass1(void) { if(er==E_OKDEF) { - if(!(er=puttmp(l))) + if(!(er=puttmpw(l))) er=puttmps(o,l); } else if(er==E_NOLINE) er=E_OK; } else { - if(!(er=puttmp(-l))) + if(!(er=puttmpw(-l))) er=puttmps(o,l); } } @@ -1054,6 +1057,21 @@ static int puttmp(int c) return(er); } +static int puttmpw(int c) +{ + int er=E_NOMEM; + + //printf("puttmp: %02x -> %p \n",0xff & c, afile->mn.tmp+afile->mn.tmpz); + + if(afile->mn.tmpzmn.tmp[afile->mn.tmpz++]= c & 0xff; + afile->mn.tmp[afile->mn.tmpz++]= (c >> 8) & 0xff; + er=E_OK; + } + return(er); +} + static int puttmps(signed char *s, int l) { int i=0,er=E_NOMEM; @@ -1099,20 +1117,18 @@ static int getline(char *s) if(ec==E_NEWLINE) { - puttmp(0); + puttmpw(0); puttmp(T_LINE); - puttmp((filep->fline)&255); - puttmp(((filep->fline)>>8)&255); + puttmpw(filep->fline); ec=E_OK; } else if(ec==E_NEWFILE) { - puttmp(0); + puttmpw(0); puttmp(T_FILE); - puttmp((filep->fline)&255); - puttmp(((filep->fline)>>8)&255); + puttmpw(filep->fline); puttmps((signed char*)&(filep->fname), sizeof(filep->fname)); ec=E_OK; } diff --git a/xa/src/xap.c b/xa/src/xap.c index c83234f..77a296f 100644 --- a/xa/src/xap.c +++ b/xa/src/xap.c @@ -711,12 +711,24 @@ int pp_replace(char *to, char *ti, int a,int b) while(t[0]!='\0' && t[0] != ';') { // skip over the whitespace + // comment handling is NASTY NASTY NASTY + // but I currently don't see another way, as comments and colons + // can (and do) appear in preprocessor replacements char quotefl = 0; - while(!isalpha(t[0]) && t[0]!='_') { - if(t[0]=='\0' || (t[0] == ';' && !quotefl)) + char commentfl = 0; + while((t[0] != 0) && (commentfl || ((!isalpha(t[0]) && t[0]!='_')))) { + if (t[0]=='\0') { break; /*return(E_OK);*/ - else - { + } else + { + if (t[0] == ';' && !quotefl) { + commentfl = 1; + } + if (t[0] == ':' && !quotefl && !ca65 && !masm) { + // note that both ca65 and masm allow colons in comments + // so in these cases we cannot reset the comment handling here + commentfl = 0; + } if (quotefl) { // ignore other quotes within a quote if (t[0] == quotefl) { @@ -728,7 +740,7 @@ int pp_replace(char *to, char *ti, int a,int b) } t++; ti++; - } + } } // determine the length of the name diff --git a/xa/src/xat.c b/xa/src/xat.c index 8a1cd43..33fc984 100644 --- a/xa/src/xat.c +++ b/xa/src/xat.c @@ -23,6 +23,7 @@ /* enable this to turn on (copious) optimization output */ /* #define DEBUG_AM */ #undef LISTING_DEBUG +#undef DEBUG_CONV #include #include @@ -431,7 +432,8 @@ fprintf(stderr, "- p1 %d starting -\n", pc[segment]); /* copy the buffer */ memcpy(t+tlen, t+6+inp, l-inp); -#if 0 +#ifdef DEBUG_CONV + printf("t_conv s:%s\n",s); printf("t_conv (er=%d, t=%p, tlen=%d, inp=%d):",er, t, tlen, inp); for(i=0;i l) + { + // that is corrupt data and should not happen + printf("t_p2_l (ll=%d, t=%p):", *ll, t); + for(int i=0;i Date: Wed, 15 Aug 2012 17:42:05 +0200 Subject: [PATCH 28/52] Allow defining macro parameters with spaces between name, brackets and comma ... --- xa/src/xap.c | 36 ++++++++++++++++++++++++++++------- xa/tests/ppdefines/Makefile | 4 ++-- xa/tests/ppdefines/test1.a65 | 2 +- xa/tests/ppdefines/test1.o65 | Bin 22 -> 22 bytes xa/tests/ppdefines/test2.a65 | 33 ++++++++++++++++++++++++++++++++ xa/tests/ppdefines/test2.o65 | 1 + 6 files changed, 66 insertions(+), 10 deletions(-) create mode 100644 xa/tests/ppdefines/test2.a65 create mode 100644 xa/tests/ppdefines/test2.o65 diff --git a/xa/src/xap.c b/xa/src/xap.c index 77a296f..3a103d3 100644 --- a/xa/src/xap.c +++ b/xa/src/xap.c @@ -355,7 +355,10 @@ int pp_define(char *k) { i++; liste[rl].p_anz++; - for(j=0; t[i+j]!=')' && t[i+j]!=',' && t[i+j]!='\0';j++); + // skip whitespace before parameter name + while(isspace(t[i])) i++; + // find length + for(j=0; (!isspace(t[i+j])) && t[i+j]!=')' && t[i+j]!=',' && t[i+j]!='\0';j++); if(ji=%d, len=%d\n", n, liste[n].search,i, liste[n].s_len); +#endif return i == liste[n].s_len; } @@ -460,6 +468,10 @@ static int pp_replace_part(char *to, char *t, int n, int sl, int recursive, int // with global variables... char *saved_mem = mem; +#ifdef DEBUG_RECMAC + printf("replace part: n=%d, sl=%d, rec=%d, %s\n", n, sl, recursive, t); +#endif + // yes, mark replacement string char *rs=liste[n].replace; @@ -574,7 +586,7 @@ static int pp_replace_part(char *to, char *t, int n, int sl, int recursive, int //int k = 0; // copy over the replacement string into a buffer nfwas - (void)strcpy(nfwas, liste[rlist+i].replace); + (void)strcpy(nfwas, liste[blist+i].replace); if (!er) { // replace the tokens in the parameter, adding possible pseudo params // on top of the liste[] into nfto @@ -625,13 +637,22 @@ static int pp_replace_part(char *to, char *t, int n, int sl, int recursive, int // safe-guard our memory allocations mem = mx; // only change (of two) from recursive: rlist is 0 there +#ifdef DEBUG_RECMAC + printf("replace macro: recursive=%d, blist=%d, -> b=%d\n", recursive, blist, blist+liste[n].p_anz); + printf(" from: %s\n", fti); +#endif er=pp_replace(fto,fti,recursive ? 0 : blist,blist+liste[n].p_anz); +#ifdef DEBUG_RECMAC + printf(" to: %s\n", fto); +#endif } /* if(flag) printf("sl=%d,",sl);*/ sl=(int)((long)y+1L-(long)t); /* if(flag) printf("sl=%d\n",sl);*/ rs=fto; -/* printf("->%s\n",fto);*/ +#ifdef DEBUG_RECMAC + printf("->%s\n",fto); +#endif } } if(er) { @@ -747,8 +768,9 @@ int pp_replace(char *to, char *ti, int a,int b) for(l=0;isalnum(t[l])||t[l]=='_';l++); // store in ld ld=l; - - //printf("l=%d,a=%d,t=%s\n",l,a,t); +#ifdef DEBUG_RECMAC + printf("l=%d,a=%d,b=%d, t=%s\n",l,a, b ,t); +#endif // the following if() is executed when being called from an // 'external' context, i.e. not from a recursion diff --git a/xa/tests/ppdefines/Makefile b/xa/tests/ppdefines/Makefile index 39d537f..2d8bd02 100644 --- a/xa/tests/ppdefines/Makefile +++ b/xa/tests/ppdefines/Makefile @@ -1,13 +1,13 @@ XA=../../xa -all: test1 clean +all: test1 test2 clean clean: rm a.o65 %:%.a65 - ${XA} $< + ${XA} -XC $< cmp a.o65 $@.o65 diff --git a/xa/tests/ppdefines/test1.a65 b/xa/tests/ppdefines/test1.a65 index cb8e30f..67395d0 100644 --- a/xa/tests/ppdefines/test1.a65 +++ b/xa/tests/ppdefines/test1.a65 @@ -14,7 +14,7 @@ #define func1(a) (a) | $20 *=$c000 - + macro1() macro2(2) diff --git a/xa/tests/ppdefines/test1.o65 b/xa/tests/ppdefines/test1.o65 index 74a2827dd56c2f9cc69302808402fddd195bbdfd..449fc69408845bf78c9f68510040dec4cc3ef40e 100644 GIT binary patch literal 22 ccmZ3%7g_80AD)@yZ`_I literal 22 ccmZ3 Date: Fri, 17 Aug 2012 12:24:54 +0200 Subject: [PATCH 29/52] fix sign problem when length of internal line presentation got over 128... --- xa/src/xa.c | 5 ++--- xa/src/xalisting.c | 6 ++++++ xa/src/xalisting.h | 2 ++ xa/src/xat.c | 5 +++-- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/xa/src/xa.c b/xa/src/xa.c index e28995d..49ab4bc 100644 --- a/xa/src/xa.c +++ b/xa/src/xa.c @@ -680,11 +680,11 @@ static int pass2(void) while((ner_max==0 || nermn.tmpemn.tmpz) { // get the length of the entry (now two byte - need to handle the sign) - l = afile->mn.tmp[afile->mn.tmpe++]; + l = 255 & afile->mn.tmp[afile->mn.tmpe++]; l |= afile->mn.tmp[afile->mn.tmpe++] << 8; ll=l; - // printf("%p: l=%d first=%02x\n", afile->mn.tmp+afile->mn.tmpe-1, l, 0xff & afile->mn.tmp[afile->mn.tmpe]); + //printf("%p: l=%d first=%02x\n", afile->mn.tmp+afile->mn.tmpe-1, l, 0xff & afile->mn.tmp[afile->mn.tmpe]); if(!l) { @@ -712,7 +712,6 @@ static int pass2(void) /* t_p2_l() includes the listing call to do_listing() */ er=t_p2_l(afile->mn.tmp+afile->mn.tmpe,&ll,&al); - if(er==E_NOLINE) { } else diff --git a/xa/src/xalisting.c b/xa/src/xalisting.c index 39b4331..f325eeb 100644 --- a/xa/src/xalisting.c +++ b/xa/src/xalisting.c @@ -166,6 +166,12 @@ static formatter_t *formatp = &def_format; /*********************************************************************************************/ +void list_flush() { + if (listfp != NULL) { + fflush(listfp); + } +} + void list_start(const char *formatname) { formatp = &def_format; diff --git a/xa/src/xalisting.h b/xa/src/xalisting.h index 5b14b60..8505047 100644 --- a/xa/src/xalisting.h +++ b/xa/src/xalisting.h @@ -22,6 +22,8 @@ void list_start(char *formatname); //either NULL or "html" void list_end(); +void list_flush(); // debug helper + void list_setfile(FILE *fp); void list_line(int l); /* set line number for the coming listing output */ void list_filename(char *fname);/* set file name for the coming listing output */ diff --git a/xa/src/xat.c b/xa/src/xat.c index 33fc984..2433064 100644 --- a/xa/src/xat.c +++ b/xa/src/xat.c @@ -1013,7 +1013,7 @@ fprintf(stderr, "guessing instruction length is %d\n", bl); /* adjust length by token listing buffer length */ #ifdef DEBUG_CONV - printf("converted: (er=%d, t=%p, ll=%d):",er, t, *ll); + printf("converted: (er=%d, t=%p, ll=%d, tlen=%d):",er, t, *ll, tlen); for(i=0;i<*ll;i++) printf("%02x,",t[i] & 0xff); printf("\n"); @@ -1078,7 +1078,8 @@ int t_p2_l(signed char *t, int *ll, int *al) if (tlen > l) { // that is corrupt data and should not happen - printf("t_p2_l (ll=%d, t=%p):", *ll, t); + list_flush(); + printf("corrupt: t_p2_l (l=%d, tlen=%d, ll=%d, t=%p):", l, tlen, *ll, t); for(int i=0;i Date: Fri, 17 Aug 2012 12:33:22 +0200 Subject: [PATCH 30/52] tests for long lines --- xa/tests/line/Makefile | 6 ++++++ xa/tests/line/test1.a65 | 20 ++++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 xa/tests/line/Makefile create mode 100644 xa/tests/line/test1.a65 diff --git a/xa/tests/line/Makefile b/xa/tests/line/Makefile new file mode 100644 index 0000000..a6acc6b --- /dev/null +++ b/xa/tests/line/Makefile @@ -0,0 +1,6 @@ + +all: test1 + +%:%.a65 + ../../xa $< + diff --git a/xa/tests/line/test1.a65 b/xa/tests/line/test1.a65 new file mode 100644 index 0000000..4b8b416 --- /dev/null +++ b/xa/tests/line/test1.a65 @@ -0,0 +1,20 @@ + +/* + * tests the internal line presentation getting over 128 + */ + +#define MAX_ENDPOINTS 4 + + *=$c000 + +txmax .dsb MAX_ENDPOINTS, 0 ; max transfer length per endpoint +txpos .dsb MAX_ENDPOINTS, 0 ; endpoint buffer position per endpoint, calculated at usbd_start +txlen .dsb MAX_ENDPOINTS, 0 ; endpoint buffer length, set per transaction + +/* + * tests the internal line presentation getting over 256 + */ + + +txpos2 .byt MAX_ENDPOINTS, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; endpoint buffer position per endpoint, calculated at usbd_start and even more comments, but the many values alone use 5 byte per value internally... + From e54c806e73bb94746cd4cd833413002c51952678 Mon Sep 17 00:00:00 2001 From: fachat Date: Fri, 17 Aug 2012 13:50:00 +0200 Subject: [PATCH 31/52] fix double slash comment handling --- xa/src/xap.c | 88 ++++++++++++++++++++++++++++-------- xa/tests/ppdefines/Makefile | 2 +- xa/tests/ppdefines/test3.a65 | 11 +++++ xa/tests/ppdefines/test4.a65 | 13 ++++++ xa/tests/ppdefines/test5.a65 | 33 ++++++++++++++ 5 files changed, 128 insertions(+), 19 deletions(-) create mode 100644 xa/tests/ppdefines/test3.a65 create mode 100644 xa/tests/ppdefines/test4.a65 create mode 100644 xa/tests/ppdefines/test5.a65 diff --git a/xa/src/xap.c b/xa/src/xap.c index 3a103d3..27f7c03 100644 --- a/xa/src/xap.c +++ b/xa/src/xap.c @@ -952,6 +952,51 @@ int icl_open(char *tt) return(0); } +/* + * parses the current line for double-slash comments, + * handling single- and double-quotes appropriately + * shortens the line if a comment is found, returns + * the new line length. + */ +int double_slash_comments(char *line) { + int p = 0; + int qfl = 0; // if set, contains the current quote char (others are then ignored) + char c; + + while (line[p] != 0) { + c = line[p]; + if (c == qfl) { + // always in quote, c==0 not possible due to loop condition + // found matching quote char, so end of quote + qfl = 0; + } else + if ((c == '\'' || c == '"') && !qfl) { + // not in quote, but finding quote char + qfl = c; + } + if (c == '^' && qfl) { + // xa65 escape character in strings (quoted) + if (line[p+1] != 0) { + // skip the next char in test + p++; + } + } + if (c == '/' && !qfl) { + // found '/' outside quote + if (line[p+1] == '/') { + // gotcha + //printf("shorten at %d: %s\n", p, line); + // shorten line + line[p] = 0; + // return new length + return p; + } + } + p++; + } + return p; +} + int pgetline(char *t) { int c,er=E_OK; @@ -963,15 +1008,25 @@ int pgetline(char *t) filep =flist+fsp; do { - c=fgetline(in_line, MAXLINE, &rlen, flist[fsp].filep); - /* continuation lines */ - tlen = rlen; - while(c=='\n' && tlen && in_line[tlen-1]=='\\') { - c=fgetline(in_line + tlen-1, MAXLINE-tlen, &rlen, flist[fsp].filep); - tlen += rlen-1; + int is_continuation = 0; + tlen = 0; // start of current line in in_line[] + do { + c=fgetline(in_line + tlen, MAXLINE, &rlen, flist[fsp].filep); + + /* check for continuation lines */ + is_continuation = ((c == '\n') && (rlen > 0) && (in_line[tlen + rlen - 1]=='\\')); + if (is_continuation) { + // cut off the continuation character + rlen--; + in_line[tlen + rlen] = 0; } - if(in_line[0]=='#' || in_line[0] == altppchar) - { + rlen = double_slash_comments(in_line + tlen); + + tlen += rlen; + } while (is_continuation); + + if(in_line[0]=='#' || in_line[0] == altppchar) + { if (in_line[1]==' ') { /* cpp comment -- pp_comand doesn't handle this right */ er=pp_cpp(in_line+1); @@ -985,10 +1040,10 @@ int pgetline(char *t) } } } - } else + } else er=1; - if(c==EOF) { + if(c==EOF) { if (loopfl && fsp) { char bletch[MAXLINE]; sprintf(bletch, @@ -1005,14 +1060,6 @@ int pgetline(char *t) errout(E_OPENPP); } - /* handle the double-slash comment (like in C++) */ - p = strchr(in_line, '/'); - if (p != NULL) { - if (p[1] == '/') { - *p = 0; /* terminate string */ - } - } - if(!er || loopfl) { in_line[0]='\0'; } @@ -1112,6 +1159,11 @@ int rgetc(FILE *fp) return(c-'\t'?c:' '); } +/** + * Note that the line returned is always zero-terminated, + * the rlen out parameter is just convenience, so that + * a further strlen() can be saved + */ int fgetline(char *t, int len, int *rlen, FILE *fp) { static int c,i; diff --git a/xa/tests/ppdefines/Makefile b/xa/tests/ppdefines/Makefile index 2d8bd02..73b8dde 100644 --- a/xa/tests/ppdefines/Makefile +++ b/xa/tests/ppdefines/Makefile @@ -1,7 +1,7 @@ XA=../../xa -all: test1 test2 clean +all: test1 test2 test3 test4 test5 clean clean: rm a.o65 diff --git a/xa/tests/ppdefines/test3.a65 b/xa/tests/ppdefines/test3.a65 new file mode 100644 index 0000000..6046fc5 --- /dev/null +++ b/xa/tests/ppdefines/test3.a65 @@ -0,0 +1,11 @@ + +#define GD_DEVICE 0x01 // Get device descriptor for Device +#define GD_CONFIGURATION 0x02 // Get device descriptor for Configuration +#define GD_STRING 0x03 // Get device descriptor for String + + *=$c000 + + lda #GD_DEVICE ; test + + lda #GD_CONFIGURATION+$10 + diff --git a/xa/tests/ppdefines/test4.a65 b/xa/tests/ppdefines/test4.a65 new file mode 100644 index 0000000..0d1df86 --- /dev/null +++ b/xa/tests/ppdefines/test4.a65 @@ -0,0 +1,13 @@ + + ; same as test3, only there is a colon in the "//" comment + +#define GD_DEVICE 0x01 // Get device descriptor: Device +#define GD_CONFIGURATION 0x02 // Get device descriptor: Configuration +#define GD_STRING 0x03 // Get device descriptor: String + + *=$c000 + + lda #GD_DEVICE ; test + + lda #GD_CONFIGURATION+$10 + diff --git a/xa/tests/ppdefines/test5.a65 b/xa/tests/ppdefines/test5.a65 new file mode 100644 index 0000000..edfe192 --- /dev/null +++ b/xa/tests/ppdefines/test5.a65 @@ -0,0 +1,33 @@ + + // this tests the double-slash quote in lines with various disturbances... + + lda #1 // test1 + + lda #2/1 // test2 with a constant division + + lda #3*2 // test3 with multi + + lda #4<<1 // test with shift left + lda #4>>1 // test with shift right + + lda #"/" // test with quotes + + lda #'/' // test with single quotes + + .byt "/", "/", '/' // test with multiple quotes + + ; test with comments in quotes + .byt "//" // test with comment in quotes + + ; tests with escaped and quoted quotes + .byt "^"" ; test xa65 specific escape code + .byt "^"" // test + + .byt '"' ; test xa65 specific escape code + .byt '"' // test + + .byt "'" ; test xa65 specific escape code + .byt "'" // test + + .byt '^'' ; test xa65 specific escape code + .byt '^'' // test From fd364f3eef3e158b058bac022a32826dd30c5070 Mon Sep 17 00:00:00 2001 From: fachat Date: Fri, 17 Aug 2012 13:54:02 +0200 Subject: [PATCH 32/52] add missing test case responses --- xa/tests/ppdefines/test3.o65 | 1 + xa/tests/ppdefines/test4.o65 | 1 + xa/tests/ppdefines/test5.o65 | 1 + 3 files changed, 3 insertions(+) create mode 100644 xa/tests/ppdefines/test3.o65 create mode 100644 xa/tests/ppdefines/test4.o65 create mode 100644 xa/tests/ppdefines/test5.o65 diff --git a/xa/tests/ppdefines/test3.o65 b/xa/tests/ppdefines/test3.o65 new file mode 100644 index 0000000..d893461 --- /dev/null +++ b/xa/tests/ppdefines/test3.o65 @@ -0,0 +1 @@ +©© \ No newline at end of file diff --git a/xa/tests/ppdefines/test4.o65 b/xa/tests/ppdefines/test4.o65 new file mode 100644 index 0000000..d893461 --- /dev/null +++ b/xa/tests/ppdefines/test4.o65 @@ -0,0 +1 @@ +©© \ No newline at end of file diff --git a/xa/tests/ppdefines/test5.o65 b/xa/tests/ppdefines/test5.o65 new file mode 100644 index 0000000..1b3ebf8 --- /dev/null +++ b/xa/tests/ppdefines/test5.o65 @@ -0,0 +1 @@ +©©©©©©/©//////""""'''' \ No newline at end of file From ecdf4f78b9742ad4bc85a87dfd01e6da5b0515e9 Mon Sep 17 00:00:00 2001 From: fachat Date: Fri, 17 Aug 2012 14:21:56 +0200 Subject: [PATCH 33/52] new test case hanging xa in an endless loop --- xa/tests/ppdefines/Makefile | 2 +- xa/tests/ppdefines/test6.a65 | 53 ++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 xa/tests/ppdefines/test6.a65 diff --git a/xa/tests/ppdefines/Makefile b/xa/tests/ppdefines/Makefile index 73b8dde..0707010 100644 --- a/xa/tests/ppdefines/Makefile +++ b/xa/tests/ppdefines/Makefile @@ -1,7 +1,7 @@ XA=../../xa -all: test1 test2 test3 test4 test5 clean +all: test1 test2 test3 test4 test5 test6 clean clean: rm a.o65 diff --git a/xa/tests/ppdefines/test6.a65 b/xa/tests/ppdefines/test6.a65 new file mode 100644 index 0000000..6a7fad2 --- /dev/null +++ b/xa/tests/ppdefines/test6.a65 @@ -0,0 +1,53 @@ + +// testing some more complicated defines + +#define spi_enable(mask) \ + lda SPISSRB :\ + and #255-(mask) :\ + sta SPISSRB + +#define spi_disable(mask) \ + lda SPISSRB :\ + ora #(mask) :\ + sta SPISSRB + +#define spi_wra() \ + .( :\ + sta SPIDR :\ +l_ bit SPISR :\ + bpl l_ :\ + lda SPIDR :\ + .) + +#define max3420e_enable() \ + spi_enable(MAX3420E_EnMask) + +#define max3420e_disable() \ + spi_disable(MAX3420E_EnMask) + +#define wreg(reg, val) \ + max3420e_enable() :\ + lda #(reg) | 0x02 :\ + spi_wra() :\ + lda #(val) :\ + spi_wra() :\ + max3420e_disable() + +#define wrac(reg) \ + pha :\ + max3420e_enable() :\ + lda #(reg) | 0x02 :\ + spi_wra() :\ + pla :\ + spi_wra() :\ + max3420e_disable() + +// just the definition of this macro hangs the xa indefinitely... + +#define CLRBIT(reg, val) \ + rreg(reg) :\ + and #255-val :\ + wrac(reg) + + + From a09aa0df401f9fcb6e0eb68941703f8bca928c02 Mon Sep 17 00:00:00 2001 From: fachat Date: Fri, 17 Aug 2012 18:08:00 +0200 Subject: [PATCH 34/52] Fix a one-liner that broke the first pp replacement when it had parameters --- xa/src/xap.c | 13 +++++++++---- xa/tests/ppdefines/Makefile | 2 +- xa/tests/ppdefines/test6.a65 | 8 -------- xa/tests/ppdefines/test6.o65 | 0 xa/tests/ppdefines/test6a.a65 | 28 ++++++++++++++++++++++++++++ xa/tests/ppdefines/test6a.o65 | 0 xa/tests/ppdefines/test6b.a65 | 20 ++++++++++++++++++++ xa/tests/ppdefines/test6b.o65 | 0 xa/tests/ppdefines/test7.a65 | 23 +++++++++++++++++++++++ xa/tests/ppdefines/test7.o65 | 1 + 10 files changed, 82 insertions(+), 13 deletions(-) create mode 100644 xa/tests/ppdefines/test6.o65 create mode 100644 xa/tests/ppdefines/test6a.a65 create mode 100644 xa/tests/ppdefines/test6a.o65 create mode 100644 xa/tests/ppdefines/test6b.a65 create mode 100644 xa/tests/ppdefines/test6b.o65 create mode 100644 xa/tests/ppdefines/test7.a65 create mode 100644 xa/tests/ppdefines/test7.o65 diff --git a/xa/src/xap.c b/xa/src/xap.c index 27f7c03..0fa4a5b 100644 --- a/xa/src/xap.c +++ b/xa/src/xap.c @@ -377,7 +377,7 @@ int pp_define(char *k) i++; t+=i; - pp_replace(h,t,-1,0); + pp_replace(h,t,-1,rlist); t=h; @@ -659,7 +659,7 @@ static int pp_replace_part(char *to, char *t, int n, int sl, int recursive, int mem = saved_mem; return(er); } - } + } // end if(liste[n].p_anz), i.e. if it has parameters int d=(int)strlen(rs)-sl; @@ -688,10 +688,12 @@ static int pp_replace_part(char *to, char *t, int n, int sl, int recursive, int int i=0; char c; - while((c=rs[i])) + while((c=rs[i])) { t[i++]=c; + } // other change from recursive. there sl is missing from add - *l=(recursive ? 0 : sl) + d;/*=0;*/ + //*l=(recursive ? 0 : sl) + d;/*=0;*/ + *l=sl + d;/*=0;*/ mem = saved_mem; @@ -791,6 +793,9 @@ int pp_replace(char *to, char *ti, int a,int b) if(sl && (sl==l) && check_name(t, n)) { er = pp_replace_part(to, t, n, sl, 0, &l, b); + if (er != E_OK) { + return er; + } break; } if(!n) diff --git a/xa/tests/ppdefines/Makefile b/xa/tests/ppdefines/Makefile index 0707010..267711f 100644 --- a/xa/tests/ppdefines/Makefile +++ b/xa/tests/ppdefines/Makefile @@ -1,7 +1,7 @@ XA=../../xa -all: test1 test2 test3 test4 test5 test6 clean +all: test1 test2 test3 test4 test5 test6 test6a test6b test7 clean clean: rm a.o65 diff --git a/xa/tests/ppdefines/test6.a65 b/xa/tests/ppdefines/test6.a65 index 6a7fad2..fbd3721 100644 --- a/xa/tests/ppdefines/test6.a65 +++ b/xa/tests/ppdefines/test6.a65 @@ -25,14 +25,6 @@ l_ bit SPISR :\ #define max3420e_disable() \ spi_disable(MAX3420E_EnMask) -#define wreg(reg, val) \ - max3420e_enable() :\ - lda #(reg) | 0x02 :\ - spi_wra() :\ - lda #(val) :\ - spi_wra() :\ - max3420e_disable() - #define wrac(reg) \ pha :\ max3420e_enable() :\ diff --git a/xa/tests/ppdefines/test6.o65 b/xa/tests/ppdefines/test6.o65 new file mode 100644 index 0000000..e69de29 diff --git a/xa/tests/ppdefines/test6a.a65 b/xa/tests/ppdefines/test6a.a65 new file mode 100644 index 0000000..55c8464 --- /dev/null +++ b/xa/tests/ppdefines/test6a.a65 @@ -0,0 +1,28 @@ + +// testing some more complicated defines + + +#define max3420e_enable() \ + spi_enable(MAX3420E_EnMask) + +#define max3420e_disable() \ + spi_disable(MAX3420E_EnMask) + +#define wrac(reg) \ + pha :\ + max3420e_enable() :\ + lda #(reg) | 0x02 :\ + spi_wra() :\ + pla :\ + spi_wra() :\ + max3420e_disable() + +// just the definition of this macro hangs the xa indefinitely... + +#define CLRBIT(reg, val) \ + rreg(reg) :\ + and #255-val :\ + wrac(reg) + + + diff --git a/xa/tests/ppdefines/test6a.o65 b/xa/tests/ppdefines/test6a.o65 new file mode 100644 index 0000000..e69de29 diff --git a/xa/tests/ppdefines/test6b.a65 b/xa/tests/ppdefines/test6b.a65 new file mode 100644 index 0000000..9d3dea5 --- /dev/null +++ b/xa/tests/ppdefines/test6b.a65 @@ -0,0 +1,20 @@ + +// testing some more complicated defines +// this is the minimum I found to trigger the hang symptom + + +#define max3420e_enable() nop + +#define wrac(reg) \ + max3420e_enable() :\ + lda #(reg) + +// just the definition of this macro hangs the xa indefinitely... + +#define CLRBIT(reg, val) \ + wrac(reg) + + +// *=$c000 +// CLRBIT(1,2) + diff --git a/xa/tests/ppdefines/test6b.o65 b/xa/tests/ppdefines/test6b.o65 new file mode 100644 index 0000000..e69de29 diff --git a/xa/tests/ppdefines/test7.a65 b/xa/tests/ppdefines/test7.a65 new file mode 100644 index 0000000..a9da2ee --- /dev/null +++ b/xa/tests/ppdefines/test7.a65 @@ -0,0 +1,23 @@ + +// due to a bug, the first definition was not behaving correct with the +// parameters during evaluation (which wasn't tested in test6*). +// With max3420e_enable2() first, the code would work, as it +// was not used, with the used max3420e_enable() first it would break. + +#define max3420e_enable() nop + +#define max3420e_enable2() nop + +#define wrac(reg) \ + max3420e_enable() :\ + lda #(reg) + +// just the definition of this macro hangs the xa indefinitely... + +#define CLRBIT(reg, val) \ + wrac(reg) + + + *=$c000 + CLRBIT(1,2) + diff --git a/xa/tests/ppdefines/test7.o65 b/xa/tests/ppdefines/test7.o65 new file mode 100644 index 0000000..043ac56 --- /dev/null +++ b/xa/tests/ppdefines/test7.o65 @@ -0,0 +1 @@ +ê© \ No newline at end of file From 33605e102479f9a222b111ff3ab7f2c72a24dd04 Mon Sep 17 00:00:00 2001 From: "A. Fachat" Date: Wed, 26 Dec 2012 21:50:34 +0100 Subject: [PATCH 35/52] fix unnecessary octal for '0' --- xa/src/xat.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/xa/src/xat.c b/xa/src/xat.c index 2433064..14754c0 100644 --- a/xa/src/xat.c +++ b/xa/src/xat.c @@ -2185,11 +2185,17 @@ fprintf(stderr, "could not find %s\n", (char *)s+p); tg_hex(s+p+2, &ll, &v); p+=2+ll; wval(q, v, '$'); - } else { - // c-style octal + } else + if (isdigit(s[p+1])) { + // c-style octal if digit follows tg_oct(s+p+1,&ll,&v); p+=1+ll; wval(q,v, '&'); + } else { + // else use decimal (0) + tg_dez(s+p,&ll,&v); + p+=ll; + wval(q,v, 'd'); } break; case '$': From 5e89d57ecf99b9d80dd4d6044ea7c8d338064f09 Mon Sep 17 00:00:00 2001 From: "A. Fachat" Date: Sat, 29 Dec 2012 02:45:40 +0100 Subject: [PATCH 36/52] improve reloc65 "-X" option to include bss segment --- xa/man/reloc65.1 | 5 +++-- xa/misc/reloc65.c | 55 +++++++++++++++++++++++++++++++++++++---------- 2 files changed, 47 insertions(+), 13 deletions(-) diff --git a/xa/man/reloc65.1 b/xa/man/reloc65.1 index ba891a9..2229092 100644 --- a/xa/man/reloc65.1 +++ b/xa/man/reloc65.1 @@ -40,8 +40,9 @@ respectively. Not valid for bss or zero. .B \-X Extract text and data segment together from the file instead of writing back the whole -file. Relocating data segment to the end of the text segment -(ignoring the \-xd option) before extracting. +file. Relocating data segment to the end of the text segment and +bss segment to the end of the data segment +(\-xd and \-xb options override the derived address) before extracting. .TP .B \-\-help Show summary of options. diff --git a/xa/misc/reloc65.c b/xa/misc/reloc65.c index 9b528f7..4b57fcf 100644 --- a/xa/misc/reloc65.c +++ b/xa/misc/reloc65.c @@ -74,6 +74,7 @@ void usage(FILE *fp) " -X extracts the file such that text and data\n" " segments are chained, i.e. possibly relocating\n" " the data segment to the end of the text segment\n" + " -v verbose output\n" " --version output version information and exit\n" " --help display this help and exit\n"); } @@ -86,6 +87,7 @@ int main(int argc, char *argv[]) { int tbase = 0, dbase = 0, bbase = 0, zbase = 0; char *outfile = "a.o65"; int extract = 0; + int verbose = 0; if (argc <= 1) { usage(stderr); @@ -106,6 +108,9 @@ int main(int argc, char *argv[]) { if(argv[i][0]=='-') { /* process options */ switch(argv[i][1]) { + case 'v': + verbose = 1; + break; case 'o': if(argv[i][2]) outfile=argv[i]+2; else outfile=argv[++i]; @@ -188,25 +193,53 @@ int main(int argc, char *argv[]) { file.tbase = file.buf[ 9]*256+file.buf[ 8]; file.tlen = file.buf[11]*256+file.buf[10]; - file.tdiff = tflag? tbase - file.tbase : 0; + file.tdiff = tflag ? tbase - file.tbase : 0; + file.dbase = file.buf[13]*256+file.buf[12]; file.dlen = file.buf[15]*256+file.buf[14]; + file.ddiff = dflag ? dbase - file.dbase : 0; if (extract == 3) { if (dflag) { - fprintf(stderr,"reloc65: %s: Warning: data segment address ignored for -X option\n", argv[i]); - } - dbase = file.tbase + file.tdiff + file.tlen; - file.ddiff = dbase - file.dbase; - } else { - file.ddiff = dflag? dbase - file.dbase : 0; + fprintf(stderr,"reloc65: %s: Warning: data segment address overrides -X option\n", argv[i]); + } else { + dbase = file.tbase + file.tdiff + file.tlen; + file.ddiff = dbase - file.dbase; + } } + file.bbase = file.buf[17]*256+file.buf[16]; file.blen = file.buf[19]*256+file.buf[18]; - file.bdiff = bflag? bbase - file.bbase : 0; - file.zbase = file.buf[21]*256+file.buf[20]; - file.zlen = file.buf[23]*256+file.buf[21]; - file.zdiff = zflag? zbase - file.zbase : 0; + file.bdiff = bflag ? bbase - file.bbase : 0; + if (extract == 3) { + if (bflag) { + fprintf(stderr,"reloc65: %s: Warning: bss segment address overrides -X option\n", argv[i]); + } else { + bbase = file.dbase + file.ddiff + file.dlen; + file.bdiff = bbase - file.bbase; + } + } + file.zbase = file.buf[21]*256+file.buf[20]; + file.zlen = file.buf[23]*256+file.buf[22]; + file.zdiff = zflag ? zbase - file.zbase : 0; + + if (verbose) { + printf("Relocating segments to:\n"); + printf("text segment @ $%04x - $%04x, %5d ($%04x) bytes, diff is %5d ($%04x)\n", + file.tbase + file.tdiff, file.tbase + file.tdiff + file.tlen, + file.tlen, file.tlen, file.tdiff, file.tdiff & 0xffff); + printf("data segment @ $%04x - $%04x, %5d ($%04x) bytes, diff is %5d ($%04x)\n", + file.dbase + file.ddiff, file.dbase + file.ddiff + file.dlen, + file.dlen, file.dlen, file.ddiff, file.ddiff & 0xffff); + printf("bss segment @ $%04x - $%04x, %5d ($%04x) bytes, diff is %5d ($%04x)\n", + file.bbase + file.bdiff, file.bbase + file.bdiff + file.blen, + file.blen, file.blen, file.bdiff, file.bdiff & 0xffff); + printf("zero segment @ $%04x - $%04x, %5d ($%04x) bytes, diff is %5d ($%04x)\n", + file.zbase + file.zdiff, file.zbase + file.zdiff + file.zlen, + file.zlen, file.zlen, file.zdiff, file.zdiff & 0xffff); + } + + /* pointer of position in file */ file.segt = file.buf + hlen; file.segd = file.segt + file.tlen; file.utab = file.segd + file.dlen; From 9e09d4fba206f3cfd0dbd9b4b22059ae8ec62547 Mon Sep 17 00:00:00 2001 From: "A. Fachat" Date: Sun, 30 Dec 2012 15:08:03 +0100 Subject: [PATCH 37/52] add "-U" cmd line option --- xa/man/xa.1 | 5 ++++- xa/src/xa.c | 9 +++++++-- xa/src/xa.h | 2 +- xa/src/xaa.c | 2 +- xa/src/xat.c | 2 +- 5 files changed, 14 insertions(+), 6 deletions(-) diff --git a/xa/man/xa.1 b/xa/man/xa.1 index 2ab227d..5a2a480 100644 --- a/xa/man/xa.1 +++ b/xa/man/xa.1 @@ -96,7 +96,10 @@ not affect colon interpretation elsewhere. This option is deprecated. Use instead. .TP .B \-R -Start assembler in relocating mode. +Start assembler in relocating mode, i.e. use segments. +.TP +.B \-U +Do not allow undefined labels in relocating mode. .TP .B \-Llabel Defines diff --git a/xa/src/xa.c b/xa/src/xa.c index 49ab4bc..905f4bc 100644 --- a/xa/src/xa.c +++ b/xa/src/xa.c @@ -56,7 +56,7 @@ #define ANZWARN 13 #define programname "xa" -#define progversion "v2.3.5" +#define progversion "v2.3.5+af" #define authors "Written by Andre Fachat, Jolse Maginnis, David Weinehall and Cameron Kaiser" #define copyright "Copyright (C) 1989-2009 Andre Fachat, Jolse Maginnis, David Weinehall\nand Cameron Kaiser." @@ -73,6 +73,7 @@ int romaddr = 0; int noglob = 0; int showblk = 0; int crossref = 0; +int noundef = 0; // overrides -R acceptance of undefined labels char altppchar; /* local variables */ @@ -270,6 +271,9 @@ int main(int argc,char *argv[]) case 'R': relmode = 1; break; + case 'U': + noundef = 1; + break; case 'D': s = (signed char*)strstr(argv[i]+2,"="); if(s) *s = ' '; @@ -912,7 +916,8 @@ static void usage(int default816, FILE *fp) " -M allow ``:'' to appear in comments for MASM compatibility\n" " -Xcompatset set compatibility flags for other assemblers, known values are:\n" " MASM, CA65\n" - " -R start assembler in relocating mode\n"); + " -R start assembler in relocating mode\n" + " -U do not allow undefined labels in relocating mode\n"); fprintf(fp, " -Llabel defines `label' as absolute, undefined label even when linking\n" " -p replace preprocessor char '#' with custom, e.g. '-p!' replaces it with '!'\n" diff --git a/xa/src/xa.h b/xa/src/xa.h index 7cb958c..40af87b 100644 --- a/xa/src/xa.h +++ b/xa/src/xa.h @@ -22,7 +22,7 @@ #include "xah.h" /* For SEG_MAX */ extern int ncmos, cmosfl, w65816, n65816; -extern int masm, ca65, nolink; +extern int masm, ca65, nolink,noundef; extern int noglob; extern int showblk; extern int relmode; diff --git a/xa/src/xaa.c b/xa/src/xaa.c index e65bd7f..e57f0f1 100644 --- a/xa/src/xaa.c +++ b/xa/src/xaa.c @@ -122,7 +122,7 @@ 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) || (afl==SEG_UNDEFZP))) { + if( (nolink && !noundef) || ((afl==SEG_UNDEF) || (afl==SEG_UNDEFZP))) { er = E_OK; *v = 0; if(afl!=SEG_UNDEFZP) { diff --git a/xa/src/xat.c b/xa/src/xat.c index 14754c0..3750e1b 100644 --- a/xa/src/xat.c +++ b/xa/src/xat.c @@ -2161,7 +2161,7 @@ fprintf(stderr, "could not find %s\n", (char *)s+p); /* if(afl==SEG_ZEROUNDEF) uz++; */ - ud++; + ud++; // number of undefined labels er=E_OK; } p+=ll; From f4d97d6fd65b291ff3a67279ccbaefbb3b72fddc Mon Sep 17 00:00:00 2001 From: "A. Fachat" Date: Fri, 4 Oct 2013 14:10:32 +0200 Subject: [PATCH 38/52] fix incompatibility with system "getline" --- xa/src/xa.c | 6 +++--- xa/src/xalisting.c | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/xa/src/xa.c b/xa/src/xa.c index 905f4bc..40b0e5f 100644 --- a/xa/src/xa.c +++ b/xa/src/xa.c @@ -96,7 +96,7 @@ static int puttmp(int); static int puttmpw(int); static int puttmps(signed char *, int); static void chrput(int); -static int getline(char *); +static int xagetline(char *); static void lineout(void); static long ga_p1(void); static long gm_p1(void); @@ -829,7 +829,7 @@ static int pass1(void) ner=0; /*FIXIT*/ - while(!(er=getline(s))) + while(!(er=xagetline(s))) { er=t_p1((signed char*)s,o,&l,&al); switch(segment) { @@ -1097,7 +1097,7 @@ static int puttmps(signed char *s, int l) static char l[MAXLINE]; -static int getline(char *s) +static int xagetline(char *s) { static int ec; diff --git a/xa/src/xalisting.c b/xa/src/xalisting.c index f325eeb..c60303c 100644 --- a/xa/src/xalisting.c +++ b/xa/src/xalisting.c @@ -581,7 +581,8 @@ int list_string(char *buf, char *string) { if (buf == NULL || string == NULL) { fprintf(stderr, "NULL pointer: buf=%p, string=%p\n", buf, string); fflush(stderr); - exit(1); + //exit(1); + return 0; } int p = 0; From c7477d2f1b1d34b6fd9deab308c0296422f048c7 Mon Sep 17 00:00:00 2001 From: "A. Fachat" Date: Sun, 6 Oct 2013 16:37:28 +0200 Subject: [PATCH 39/52] fix a bug in operand size optimization --- xa/src/xat.c | 13 +++++++++---- xa/tests/README | 1 + xa/tests/relmode/Makefile | 24 ++++++++++++++++++++++++ xa/tests/relmode/mixabsolute.a65 | 18 ++++++++++++++++++ 4 files changed, 52 insertions(+), 4 deletions(-) create mode 100644 xa/tests/relmode/Makefile create mode 100644 xa/tests/relmode/mixabsolute.a65 diff --git a/xa/src/xat.c b/xa/src/xat.c index 3750e1b..4633564 100644 --- a/xa/src/xat.c +++ b/xa/src/xat.c @@ -1691,9 +1691,12 @@ fprintf(stderr, /* terrible KLUDGE!!!! OH NOES!!!1! due to the way this is constructed, you must absolutely always specify @ to get an absolute long or it will absolutely always be optimized down */ - - if(bl && am>16 && - !er && !(vv[0]&0xff0000) && opt[am]>=0) +/* now also checks for negative overflow, resp. not-overflow */ + if(bl + && am>16 + && !er + && (((vv[0]&0xff8000)==0xff8000) || !(vv[0]&0xff0000)) + && opt[am]>=0) if(ct[n][opt[am]]>=0) am=opt[am]; #ifdef DEBUG_AM @@ -1746,8 +1749,10 @@ fprintf(stderr, "byte length is now %d\n", bl); er=E_CMOS; } else { n65816++; - if(!w65816) + if(!w65816) { +fprintf(stderr,"n=%d, am=%d\n", n, am); er=E_65816; + } } } if(am!=0) diff --git a/xa/tests/README b/xa/tests/README index 8ecb6df..a7d08c2 100644 --- a/xa/tests/README +++ b/xa/tests/README @@ -20,6 +20,7 @@ binclude/ Binary include code with some weird casing chppch/ Changing preprocessor characters (-p) charset/ Tests of when charsets should be honoured and when not cc65/ Compatibility tests for ca65 compatibility +relmode/ tests concerning switches between segments and absolute mode Cameron Kaiser, André Fachat diff --git a/xa/tests/relmode/Makefile b/xa/tests/relmode/Makefile new file mode 100644 index 0000000..1b37495 --- /dev/null +++ b/xa/tests/relmode/Makefile @@ -0,0 +1,24 @@ +# +# Makefile for tests +# + +XA=../../xa + +tests: mixabs1 mixabs2 clean + + +mixabs1: mixabsolute.a65 + ${XA} $< + hexdump -C a.o65 > a.hex + cmp mixabs1.out a.hex + +mixabs2: mixabsolute.a65 + ${XA} -R $< + file65 -V a.o65 + reloc65 -bt 40960 -o b.o65 a.o65 + hexdump -C b.o65 > b.hex + cmp mixabs2.out b.hex + +clean: +# rm -f a.err a.o65 a.hex b.o65 b.hex + diff --git a/xa/tests/relmode/mixabsolute.a65 b/xa/tests/relmode/mixabsolute.a65 new file mode 100644 index 0000000..5f01d06 --- /dev/null +++ b/xa/tests/relmode/mixabsolute.a65 @@ -0,0 +1,18 @@ + + .text + +l1 lda l1 + + *=$2000 + +l2 lda l2 + + .data + +l3 .word l3 + + .text + +l4 lda l4 + + From 9cc95b98137f67cbec02da45c0edb10f23d9e237 Mon Sep 17 00:00:00 2001 From: "A. Fachat" Date: Mon, 18 Aug 2014 22:48:22 +0200 Subject: [PATCH 40/52] fix illegal memory access --- xa/src/xalisting.c | 1 + 1 file changed, 1 insertion(+) diff --git a/xa/src/xalisting.c b/xa/src/xalisting.c index c60303c..11955b4 100644 --- a/xa/src/xalisting.c +++ b/xa/src/xalisting.c @@ -449,6 +449,7 @@ int list_tokens(char *buf, signed char *input, int len) { switch(input[inp]) { case T_CAST: outp += list_string(buf+outp, formatp->escape_char(input[inp+1])); + inp++; break; case T_VALUE: /*outp += list_char(buf+outp, 'V');*/ From cad65680e2c3d9bd4bb6318c8c734ddbf38af049 Mon Sep 17 00:00:00 2001 From: "A. Fachat" Date: Mon, 18 Aug 2014 22:56:02 +0200 Subject: [PATCH 41/52] fix double character --- xa/src/xalisting.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xa/src/xalisting.c b/xa/src/xalisting.c index 11955b4..85440c9 100644 --- a/xa/src/xalisting.c +++ b/xa/src/xalisting.c @@ -449,7 +449,7 @@ int list_tokens(char *buf, signed char *input, int len) { switch(input[inp]) { case T_CAST: outp += list_string(buf+outp, formatp->escape_char(input[inp+1])); - inp++; + inp+=2; break; case T_VALUE: /*outp += list_char(buf+outp, 'V');*/ From b4f36e9061bfc041b177f41bec67dbccd845222b Mon Sep 17 00:00:00 2001 From: "A. Fachat" Date: Mon, 18 Aug 2014 23:19:07 +0200 Subject: [PATCH 42/52] first test infrastructure --- xa/src/.gitignore | 2 + xa/tests/Makefile | 4 + xa/tests/adrm/a.o65 | Bin 50 -> 0 bytes xa/tests/adrm/runtest.sh | 302 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 308 insertions(+) create mode 100644 xa/src/.gitignore create mode 100644 xa/tests/Makefile delete mode 100644 xa/tests/adrm/a.o65 create mode 100755 xa/tests/adrm/runtest.sh diff --git a/xa/src/.gitignore b/xa/src/.gitignore new file mode 100644 index 0000000..874c63c --- /dev/null +++ b/xa/src/.gitignore @@ -0,0 +1,2 @@ +*.o + diff --git a/xa/tests/Makefile b/xa/tests/Makefile new file mode 100644 index 0000000..699a340 --- /dev/null +++ b/xa/tests/Makefile @@ -0,0 +1,4 @@ + +tests: + (cd adrm; make tests) + diff --git a/xa/tests/adrm/a.o65 b/xa/tests/adrm/a.o65 deleted file mode 100644 index 218516c921d89e81e10c67e8c7bb4ce449844e2c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 50 vcmZQzX=R1LURDMWN^S3FWnchf=hXHDpGSXU9{ri=qr(!T!@`ho;bH;+WtI?j diff --git a/xa/tests/adrm/runtest.sh b/xa/tests/adrm/runtest.sh new file mode 100755 index 0000000..929afe3 --- /dev/null +++ b/xa/tests/adrm/runtest.sh @@ -0,0 +1,302 @@ +#!/bin/bash + +# run a test script + +#THISDIR=`dirname $0` +THISDIR=`pwd` + +echo "0=$0" +echo "THISDIR=$THISDIR" + +EXCLUDE= +TESTFILES= + +XA=$THISDIR/../../xa + +########################## + +LIST=$NAME.lst + +########################## + +function usage() { + echo "Assemble *.asm test files" + echo " $0 [options] [frs_scripts]" + echo "Options:" + echo " -v verbose log" + echo " -o server log on console" + echo " -d run xa with gdb and set given breakpoint. Can be " + echo " used multiple times" + echo " -k keep all files, even non-log and non-data files in run directory" + echo " -c clean up only non-log and non-data files from run directory," + echo " keep rest (default)" + echo " -C always clean up complete run directory" + echo " -R use given run directory instead of tmp folder (note:" + echo " will not be rmdir'd on -C" + echo " -q will suppress any output except whether test was successful" + echo " -h show this help" +} + +function contains() { + local j + for j in "${@:2}"; do test "$j" == "$1" && return 0; done; + return 1; +} + + +function hexdiff() { + diffres=0 + if ! cmp -b "$1" "$2"; then + tmp1=`mktemp` + tmp2=`mktemp` + + hexdump -C "$1" > $tmp1 + hexdump -C "$2" > $tmp2 + + diff -u $tmp1 $tmp2 + diffres=$? + + rm $tmp1 $tmp2 + fi; + return $diffres +} + +VERBOSE="" +DEBUG="" +CLEAN=1 +QUIET=0 +LOGFILE="" + +TMPDIR=`mktemp -d` +OWNDIR=1 + +while test $# -gt 0; do + case $1 in + -h) + usage + exit 0; + ;; + -o) + LOGFILE="-" + shift; + ;; + -v) + VERBOSE="-v" + shift; + ;; + -d) + if test $# -lt 2; then + echo "Option -d needs the break point name for gdb as parameter" + exit -1; + fi; + DEBUG="$DEBUG $2" + shift 2; + ;; + -k) + CLEAN=0 + shift; + ;; + -c) + CLEAN=1 + shift; + ;; + -C) + CLEAN=2 + shift; + ;; + -q) + QUIET=1 + shift; + ;; + -R) + if test $# -lt 2; then + echo "Option -R needs the directory path as parameter" + exit -1; + fi; + TMPDIR="$2" + OWNDIR=0 + shift 2; + ;; + -?) + echo "Unknown option $1" + usage + exit 1; + ;; + *) + break; + ;; + esac; +done; + +####################### +# test for executables + +ERR=0 +if test ! -e $XA; then + echo "$XA does not exist! Maybe forgot to compile?" + ERR=1 +fi +if [ $ERR -ge 1 ]; then + echo "Aborting!" + exit 1; +fi + + +# scripts to run +if [ "x$*" = "x" ]; then + SCRIPTS=$THISDIR/*${FILTER}*.asm + SCRIPTS=`basename -a $SCRIPTS`; + + TESTSCRIPTS="" + + if test "x$EXCLUDE" != "x"; then + exarr=( $EXCLUDE ) + scrarr=( $SCRIPTS ) + for scr in "${scrarr[@]}"; do + if ! contains "${scr}" "${exarr[@]}"; then + TESTSCRIPTS="$TESTSCRIPTS $scr"; + fi + done; + else + TESTSCRIPTS="$SCRIPTS" + fi; +else + TESTSCRIPTS=""; + + for i in "$@"; do + if test -f "$i".asm ; then + TESTSCRIPTS="$TESTSCRIPTS $i.asm"; + else + TESTSCRIPTS="$TESTSCRIPTS $i"; + fi + done; +fi; + +echo "TESTSCRIPTS=$TESTSCRIPTS" + +######################## +# tmp names +# + +DEBUGFILE="$TMPDIR"/gdb.ex + +######################## +# stdout + +# remember stdout for summary output +exec 5>&1 + +# redirect log when quiet +if test $QUIET -ge 1 ; then + exec 1>$TMPDIR/stdout.log +fi + +######################## +# prepare files +# + +for i in $TESTSCRIPTS; do + cp "$THISDIR/$i" "$TMPDIR" +done; + +######################## +# run scripts +# + +for script in $TESTSCRIPTS; do + + echo "Run script $script" + + + # overwrite test files in each iteration, just in case + for i in $TESTFILES; do + if [ -f ${THISDIR}/${i}.gz ]; then + gunzip -c ${THISDIR}/${i}.gz > ${TMPDIR}/${i} + else + cp ${THISDIR}/${i} ${TMPDIR}/${i} + fi; + done; + + if test "x$DEBUG" = "x"; then + ############################################ + # simply do assemble + + echo "Run assembler:" $XA $VERBOSE $script $TMPDIR + if test "x$LOGFILE" = "x"; then + (cd $TMPDIR; $XA -o a.out -P $script.log $script) + else + (cd $TMPDIR; $XA -o a.out -P $LOGFILE $script) + fi + RESULT=$? + + if test $RESULT -eq 0; then + echo "$script: Ok" >&5 + else + echo "$script: errors: $RESULT" >&5 + fi + + else + echo > $DEBUGFILE; + for i in $DEBUG; do + echo "break $i" >> $DEBUGFILE + done; + gdb -x $DEBUGFILE -ex "run -o a.out -P $LOGFILE $script.asm" $XA + fi; + + #echo "Killing server (pid $SERVERPID)" + #kill -TERM $SERVERPID + + if test "x$COMPAREFILES" != "x"; then + testname=`basename $script .asm` + for i in $COMPAREFILES; do + NAME="${THISDIR}/${i}-${testname}" + if test -f ${NAME}; then + echo "Comparing file ${i} with ${NAME}" + hexdiff ${NAME} $TMPDIR/${i} + if test $? -ne 0; then + echo "$script: File ${i} differs!" >&5 + fi; + fi + if test -f ${NAME}.gz; then + echo "Comparing file ${i} with ${NAME}.gz" + gunzip -c ${NAME}.gz > ${TMPDIR}/shouldbe_${i} + hexdiff ${TMPDIR}/shouldbe_${i} ${TMPDIR}/${i} + if test $? -ne 0; then + echo "$script: File ${i} differs!" >&5 + fi; + rm -f ${TMPDIR}/shouldbe_${i} + fi + done; + fi + + if test $CLEAN -ge 1; then + rm -f $DEBUGFILE; + rm -f $TMPDIR/$script; + fi +done; + +if test $CLEAN -ge 2; then + echo "Cleaning up directory $TMPDIR" + + for script in $TESTSCRIPTS; do + rm -f $TMPDIR/$script.log + done; + + # gzipped test files are unzipped + for i in $TESTFILES; do + rm -f $TMPDIR/$i; + done; + + rm -f $TMPDIR/stdout.log + + # only remove work dir if we own it (see option -R) + if test $OWNDIR -ge 1; then + rmdir $TMPDIR + fi; +else + echo "Find debug info in $TMPDIR" >&5 +fi; + + + + From dfbafeb0b58db59aa0f61d5721d074db1facfb3e Mon Sep 17 00:00:00 2001 From: "A. Fachat" Date: Tue, 19 Aug 2014 17:25:27 +0200 Subject: [PATCH 43/52] Update and fix test suite scripts and first tests --- xa/tests/adrm/Makefile | 5 +++++ xa/tests/adrm/a.out-02 | Bin 0 -> 60 bytes xa/tests/adrm/a.out-816 | Bin 0 -> 50 bytes xa/tests/adrm/a.out-c02 | Bin 0 -> 58 bytes xa/tests/adrm/a.out-zab | Bin 0 -> 47 bytes xa/tests/adrm/a.out-zab2 | Bin 0 -> 46 bytes xa/tests/adrm/a.out-zpa | Bin 0 -> 47 bytes xa/tests/adrm/a.out-zpa2 | Bin 0 -> 46 bytes xa/tests/adrm/bip2.inc | 28 ++++++++++++++++++++++++++++ xa/tests/adrm/runtest.sh | 39 ++++++++++++++++++++++++++++++--------- xa/tests/adrm/zab2.asm | 4 ++++ xa/tests/adrm/zpa2.asm | 4 ++++ 12 files changed, 71 insertions(+), 9 deletions(-) create mode 100644 xa/tests/adrm/Makefile create mode 100644 xa/tests/adrm/a.out-02 create mode 100644 xa/tests/adrm/a.out-816 create mode 100644 xa/tests/adrm/a.out-c02 create mode 100644 xa/tests/adrm/a.out-zab create mode 100644 xa/tests/adrm/a.out-zab2 create mode 100644 xa/tests/adrm/a.out-zpa create mode 100644 xa/tests/adrm/a.out-zpa2 create mode 100644 xa/tests/adrm/bip2.inc create mode 100644 xa/tests/adrm/zab2.asm create mode 100644 xa/tests/adrm/zpa2.asm diff --git a/xa/tests/adrm/Makefile b/xa/tests/adrm/Makefile new file mode 100644 index 0000000..b847663 --- /dev/null +++ b/xa/tests/adrm/Makefile @@ -0,0 +1,5 @@ + +tests: + ./runtest.sh -q -C + + diff --git a/xa/tests/adrm/a.out-02 b/xa/tests/adrm/a.out-02 new file mode 100644 index 0000000000000000000000000000000000000000..f6bd5e1a06534accf1e87b22af020fba4eaf0d06 GIT binary patch literal 60 zcmZQzX=Me$W310um$LS;GV}sbYJ1@t| literal 0 HcmV?d00001 diff --git a/xa/tests/adrm/a.out-816 b/xa/tests/adrm/a.out-816 new file mode 100644 index 0000000000000000000000000000000000000000..218516c921d89e81e10c67e8c7bb4ce449844e2c GIT binary patch literal 50 vcmZQzX=R1LURDMWN^S3FWnchf=hXHDpGSXU9{ri=qr(!T!@`ho;bH;+WtI?j literal 0 HcmV?d00001 diff --git a/xa/tests/adrm/a.out-c02 b/xa/tests/adrm/a.out-c02 new file mode 100644 index 0000000000000000000000000000000000000000..f6b29d110919f49afe2afed85808983600c03e71 GIT binary patch literal 58 zcmZQzX=Me$W310u`&b!zfhe`TZ_dPbtPE1;oSLnA4PD+nsO;gAR(SH?=g}V@6Ba)O Kg@l9)Cldfu>lS_h literal 0 HcmV?d00001 diff --git a/xa/tests/adrm/a.out-zab b/xa/tests/adrm/a.out-zab new file mode 100644 index 0000000000000000000000000000000000000000..357f4d346352c12f5352167b23c8f9a027610a6d GIT binary patch literal 47 zcmV+~0MP#cK&_Pk(EFkdzau~ZodqDu(DtbSg&?T{g(0c`g(9gFg(FM@AWT{wOrRc2 F00GTE5lsL9 literal 0 HcmV?d00001 diff --git a/xa/tests/adrm/a.out-zab2 b/xa/tests/adrm/a.out-zab2 new file mode 100644 index 0000000000000000000000000000000000000000..766f58ca09b20d72307d8dce0cbc34491159bec6 GIT binary patch literal 46 zcmV+}0MY*dK&_Pk(EFkdy&^!J1t7}M_o)DdAgKa{A*ug`BB>LFBTNGzOj;gHpdL&B E0msh~O8@`> literal 0 HcmV?d00001 diff --git a/xa/tests/adrm/a.out-zpa b/xa/tests/adrm/a.out-zpa new file mode 100644 index 0000000000000000000000000000000000000000..b3392207b1a1cdf9a19c73b745acac25c281a6eb GIT binary patch literal 47 zcmV+~0MP#c0Iih((EFkdzaszuodqDu(DtbSg&?T{g(0c`g(9gFg(FM@AWT{wOrRc2 F00Fqa5X}Gp literal 0 HcmV?d00001 diff --git a/xa/tests/adrm/a.out-zpa2 b/xa/tests/adrm/a.out-zpa2 new file mode 100644 index 0000000000000000000000000000000000000000..d7bbeed9b7077ab15e810d7076bdc7e7b21a6778 GIT binary patch literal 46 zcmV+}0MY*d0Iih((EFkdy&?de1t7}M_o)DdAgKa{A*ug`BB>LFBTNGzOj;gHpdL&B E0kh8#%K!iX literal 0 HcmV?d00001 diff --git a/xa/tests/adrm/bip2.inc b/xa/tests/adrm/bip2.inc new file mode 100644 index 0000000..3ad6318 --- /dev/null +++ b/xa/tests/adrm/bip2.inc @@ -0,0 +1,28 @@ +/* + +- tbasic.0.asm: if you make vecwri absolute with !, then the branch gets + generated as if it were NOT absolute. works okay without it (and + gets a warning) + +*/ + +test lda !$0095 + bne test + + ldx #13 +lup0 lda !vecwri,x + sta $2005,x + dex + bne lup0 + lda #$00 + sta $0020 + lda #$02 + sta $0021 + lda #$ff + sta $0022 + lda #$13 + sta $0023 + jmp $2003 + +vectors .byt $4c, $5a, $1e, $4c, $a0, $1e, $4c, $00, $01 +vecwri = vectors - 1 diff --git a/xa/tests/adrm/runtest.sh b/xa/tests/adrm/runtest.sh index 929afe3..ccb8610 100755 --- a/xa/tests/adrm/runtest.sh +++ b/xa/tests/adrm/runtest.sh @@ -8,8 +8,24 @@ THISDIR=`pwd` echo "0=$0" echo "THISDIR=$THISDIR" +declare -A opts +#opts=([816.asm]="-w") +opts[02.asm]="-C" +opts[816.asm]="-w" +opts[zab.asm]="-w" +opts[zpa.asm]="-w" + +#ASMFLAGS=-v +ASMFLAGS= + +# exclude filter from *.asm if no explicit file is given EXCLUDE= -TESTFILES= + +# test files used +TESTFILES="bip.inc bip2.inc" + +# files to compare afterwards, against -