1
0
mirror of https://github.com/fachat/xa65.git synced 2024-06-26 08:29:29 +00:00

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)
This commit is contained in:
Andre Fachat 2011-12-16 23:30:15 +01:00
parent f28af4a917
commit eae097c73a
13 changed files with 228 additions and 33 deletions

View File

@ -295,3 +295,19 @@ xa-2.3.5
* Documentation updated.
-- Cameron Kaiser <ckaiser@floodgap.com> 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 <afachat@gmx.de> 25 June, 2011

View File

@ -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 <tao@acc.umu.se>,
Andre Fachat <fachat@web.de>
and Cameron Kaiser <ckaiser@floodgap.com>.
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

View File

@ -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"

View File

@ -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) {

View File

@ -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;

View File

@ -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)

View File

@ -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);

View File

@ -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*);

View File

@ -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);

View File

@ -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);
}

View File

@ -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);

View File

@ -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;

View File

@ -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<k && !er) {
binfname[j++] = t[i++];
if (j > 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;