release 2.4.1

This commit is contained in:
A. Fachat 2024-03-12 09:25:18 +01:00
parent e95549dfd1
commit 3be092964c
99 changed files with 1129 additions and 114 deletions

View File

@ -438,3 +438,20 @@ xa-2.4.0
-- André Fachat <afachat@gmx.de> and
-- Cameron Kaiser <ckaiser@floodgap.com>, 18 November, 2023
xa 2.4.1
* Allow colon-based unnamed labels to be used separately of CA65 mode
(such as with 65816) with -a. Implies -XMASM.
* Restore ^ syntax for generating control sequences (e.g., "^m^j" evaluates
as 0d 0a) with -k.
* Fix a bug using cheap local labels in expressions.
* Properly tag and match CPU types in o65 objects during relocation and
linking.
* Fix a bug with .align when aligning segments.
* Better validation of arguments to indexed opcodes.
* Testsuite expanded.
-- André Fachat <afachat@gmx.de> and
-- Cameron Kaiser <ckaiser@floodgap.com>, 5 March, 2024

View File

@ -1,12 +1,11 @@
# Unix gcc or DOS go32 cross-compiling gcc
#
VERS = 2.4.0
VERS = 2.4.1
CC = gcc
LD = gcc
# for testing. not to be used; build failures in misc/.
#CFLAGS = -O2 -W -Wall -pedantic -ansi
#CFLAGS = -O2 -g
CFLAGS = -O2
#CFLAGS = -O2 -W -Wall -pedantic -ansi -g
CFLAGS = -O2 -g
LDFLAGS = -lc
# for DOS?

View File

@ -3,7 +3,7 @@ derivatives). xa is a small, fast, portable two-pass assembler that compiles
under most ANSI C compilers. It is distributed under the GNU Public License
(see COPYING).
The current version is 2.4.0, the first new feature release literally in
The current version is 2.4.1, a bug fix for 2.4.0, the first major release in
years. It builds upon the improvements in 2.3.x and its unified 6502/65816
assembler core by adding listing capability, greater flexibility with
relocatable objects, and better cross-compatibility with other popular

View File

@ -1,4 +1,4 @@
.TH FILE65 "1" "18 November 2023"
.TH FILE65 "1" "5 March 2024"
.SH NAME
file65 \- print information for o65 object files
@ -44,7 +44,6 @@ Show version of program.
.SH "SEE ALSO"
.BR ldo65 (1),
.BR printcbm (1),
.BR reloc65 (1),
.BR uncpk (1),
.BR xa (1),
@ -54,7 +53,7 @@ Show version of program.
This manual page was written by David Weinehall <tao@acc.umu.se>
and Cameron Kaiser <ckaiser@floodgap.com>.
Original xa package (C)1989-1997 Andre Fachat. Additional changes
(C)1989-2023 Andre Fachat, Jolse Maginnis, David Weinehall and
(C)1989-2024 Andre Fachat, Jolse Maginnis, David Weinehall and
Cameron Kaiser. The current maintainer is Cameron Kaiser.
.SH WEBSITE

View File

@ -1,4 +1,4 @@
.TH LDO65 "1" "18 November 2023"
.TH LDO65 "1" "5 March 2024"
.SH NAME
ldo65 \- linker for o65 object files
@ -57,7 +57,6 @@ Show version of program.
.SH "SEE ALSO"
.BR file65 (1),
.BR printcbm (1),
.BR reloc65 (1),
.BR uncpk (1),
.BR dxa (1),
@ -67,7 +66,7 @@ Show version of program.
This manual page was written by David Weinehall <tao@acc.umu.se>
and Cameron Kaiser <ckaiser@floodgap.com>.
Original xa package (C)1989-1997 Andre Fachat. Additional changes
(C)1989-2023 Andre Fachat, Jolse Maginnis, David Weinehall and
(C)1989-2024 Andre Fachat, Jolse Maginnis, David Weinehall and
Cameron Kaiser. The current maintainer is Cameron Kaiser.
.SH WEBSITE

View File

@ -40,7 +40,7 @@ Show version of program.
.SH AUTHOR
This manual page was written by David Weinehall <tao@acc.umu.se>.
Original xa package (C)1989-1997 Andre Fachat. Additional changes
(C)1989-2023 Andre Fachat, Jolse Maginnis, David Weinehall and
(C)1989-2024 Andre Fachat, Jolse Maginnis, David Weinehall and
Cameron Kaiser. The current maintainer is Cameron Kaiser.
.SH WEBSITE

View File

@ -1,4 +1,4 @@
.TH RELOC65 "1" "18 November 2023"
.TH RELOC65 "1" "5 March 2024"
.SH NAME
reloc65 \- relocator for o65 object files
@ -47,6 +47,43 @@ 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 \-C cputype
Define a new CPU type for the output file. Available values are:
.IP
.B 6502
- documented 6502 opcodes only
.IP
.B NMOS6502
-
.B 6502
plus undocumented opcodes
.IP
.B 65SC02
- extends
.B 6502
with CMOS opcodes, except for
.BR BBR / BBS / SMB
and
.B RMB
.IP
.B 65C02
- extends
.B 65SC02
with the
.BR BBR / BBS / SMB
and
.B RMB
opcodes
.IP
.B 65CE02
- extends
.B 65C02
with additional CE-specific opcodes
.IP
.B 65816
- 65816 in 6502 emulation mode; extends
.B 65SC02
.TP
.B \-\-help
Show summary of options.
.TP
@ -56,7 +93,6 @@ Show version of program.
.SH "SEE ALSO"
.BR file65 (1),
.BR ldo65 (1),
.BR printcbm (1),
.BR uncpk (1),
.BR dxa (1),
.BR xa (1)
@ -65,7 +101,7 @@ Show version of program.
This manual page was written by David Weinehall <tao@acc.umu.se>
and Cameron Kaiser <ckaiser@floodgap.com>.
Original xa package (C)1989-1997 Andre Fachat. Additional changes
(C)1989-2023 Andre Fachat, Jolse Maginnis, David Weinehall and
(C)1989-2024 Andre Fachat, Jolse Maginnis, David Weinehall and
Cameron Kaiser. The current maintainer is Cameron Kaiser.
.SH WEBSITE

View File

@ -1,4 +1,4 @@
.TH UNCPK "1" "18 November 2023"
.TH UNCPK "1" "5 March 2024"
.SH NAME
uncpk \- manage c64 cpk archives
@ -61,7 +61,6 @@ List contents of archive
.SH "SEE ALSO"
.BR file65 (1),
.BR ldo65 (1),
.BR printcbm (1),
.BR reloc65 (1),
.BR dxa (1),
.BR xa (1)
@ -70,7 +69,7 @@ List contents of archive
This manual page was written by David Weinehall <tao@acc.umu.se>
and Cameron Kaiser <ckaiser@floodgap.com>.
Original xa package (C)1989-1997 Andre Fachat. Additional changes
(C)1989-2023 Andre Fachat, Jolse Maginnis, David Weinehall and
(C)1989-2024 Andre Fachat, Jolse Maginnis, David Weinehall and
Cameron Kaiser. The current maintainer is Cameron Kaiser.
.SH WEBSITE

View File

@ -1,4 +1,4 @@
.TH XA "1" "18 November 2023"
.TH XA "1" "5 March 2024"
.SH NAME
xa \- 6502/R65C02/65816 cross-assembler
@ -117,13 +117,22 @@ restores partial compatibility with
.B xa
2.3.x. In particular, it uses
.B ^
for quote escapes instead of 2.4's
for generating control characters, disables escaped characters with
.BR \e ,
allows nested multi-line comments, and disables all predefined
.B xa
preprocessor macros. This option is inherently deprecated and may be removed
preprocessor macros. Although some portions of this option remain
supported syntax, the option itself is inherently deprecated and may be removed
in the next 2.x or 3.x release.
.TP
.B \-a
Support
.BR ca65 (1)-style
unnamed labels using colons, but not the remainder of the other supported
.BR ca65 (1)
features. This allows their use with 65816 mode, for example. Implies
.BR -XMASM .
.TP
.B \-M
This option is deprecated and will be removed in a future version; use
.B \-XMASM
@ -131,6 +140,14 @@ instead. Allows colons to appear in comments for MASM compatibility. This does
not affect colon interpretation elsewhere, and may become the default in a
future version.
.TP
.B \-k
Allow the carat
.RB ( ^ )
to mask a character with $1f/31. This can be used as a shorthand for
control characters, such as
.B "^m^j"
becoming a carriage return followed by a linefeed.
.TP
.B \-R
Start assembler in relocating mode, i.e. use segments.
.TP
@ -323,14 +340,14 @@ and
.LP
If
.B \-XCA65
is specified, "cheap" local labels may be used, marked by the
.B @
prefix. Additionally, unnamed labels may be specified with
or
.B \-a
is specified, "unnamed" labels may be specified with
.B :
(i.e., no label, just a colon); branches may then reference these unnamed
labels with a colon and plus signs for forward branching or minus signs
for backward branching. For example (from the
.B ca65
.BR ca65 (1)
documentation),
.LP
: lda (ptr1),y ; #1
@ -367,6 +384,14 @@ documentation),
.BR
: rts ; #4
.LP
Additionally, in
.B \-XCA65
mode, "cheap" local labels may be used, marked by the
.B @
prefix. These temporary labels exist only between two regular labels and
automatically go out of scope with the next regular label. This allows,
with reasonable care, reuse of common label names like "loop."
.LP
For those instructions where the accumulator is the implied argument (such as
.B asl
and
@ -1175,7 +1200,6 @@ indexed, branching and so on.
.SH "SEE ALSO"
.BR file65 (1),
.BR ldo65 (1),
.BR printcbm (1),
.BR reloc65 (1),
.BR uncpk (1),
.BR dxa (1)
@ -1185,7 +1209,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-2023 Andre Fachat, Jolse Maginnis, David Weinehall,
(C)1989-2024 Andre Fachat, Jolse Maginnis, David Weinehall,
Cameron Kaiser. The official maintainer is Cameron Kaiser.
.SH OVER 30 YEARS OF XA

View File

@ -37,6 +37,36 @@
#define author "Written by Andre Fachat"
#define copyright "Copyright (C) 1997-2002 Andre Fachat."
/* o65 file format mode bits */
#define FM_OBJ 0x1000
#define FM_SIZE 0x2000
#define FM_RELOC 0x4000
#define FM_CPU 0x8000
#define FM_CPU2 0x00f0
#define FM_CPU2_6502 0x0000
#define FM_CPU2_65C02 0x0010
#define FM_CPU2_65SC02 0x0020
#define FM_CPU2_65CE02 0x0030
#define FM_CPU2_NMOS 0x0040
#define FM_CPU2_65816E 0x0050
const char *cpunames[16] = {
"6502",
"65C02",
"65SC02",
"65CE02",
"NMOS6502",
"65816",
NULL, NULL,
"6809", NULL, // 1000 -
"Z80", NULL, NULL, // 1010 -
"8086", // 1101 -
"80286", // 1110 -
NULL
};
int read_options(FILE *fp);
int print_labels(FILE *fp, int offset);
@ -81,7 +111,7 @@ int main(int argc, char *argv[]) {
i = 1;
if (strstr(argv[i], "--help") || strstr(argv[i], "-?")) {
if (strstr(argv[i], "--help") || strstr(argv[i], "-?") || strstr(argv[i], "-h")) {
usage(stdout);
exit(0);
}
@ -114,7 +144,7 @@ int main(int argc, char *argv[]) {
xapar = 1;
break;
default:
fprintf(stderr,"%s: %s unknown option\n",programname,argv[i]);
fprintf(stderr,"%s: %s unknown option, use '-h' for help\n",programname,argv[i]);
break;
}
} else {
@ -127,11 +157,12 @@ int main(int argc, char *argv[]) {
printf("%s: o65 version %d %s file\n", argv[i], hdr[5],
hdr[7]&0x10 ? "object" : "executable");
printf(" mode: %04x =",mode );
printf("%s%s%s%s%s\n",
(mode & 0x1000)?"[object]":"[executable]",
(mode & 0x2000)?"[32bit]":"[16bit]",
(mode & 0x4000)?"[page relocation]":"[byte relocation]",
(mode & 0x8000)?"[CPU 65816]":"[CPU 6502]",
printf("[%s][%sbit][%s relocation][CPU %s][CPU2 %s]%s\n",
(mode & 0x1000)?"object":"executable",
(mode & 0x2000)?"32":"16",
(mode & 0x4000)?"page":"byte",
(mode & 0x8000)?"65816":"6502",
cpunames[(mode & FM_CPU2) >> 4],
aligntxt[mode & 3]);
}
if(mode & 0x2000) {

View File

@ -54,6 +54,22 @@ The process of linking works as follows:
*/
/* o65 file format mode bits */
#define FM_OBJ 0x1000
#define FM_SIZE 0x2000
#define FM_RELOC 0x4000
#define FM_CPU 0x8000
#define FM_CPU2 0x00f0
#define FM_CPU2_6502 0x0000
#define FM_CPU2_65C02 0x0010
#define FM_CPU2_65SC02 0x0020
#define FM_CPU2_65CE02 0x0030
#define FM_CPU2_NMOS 0x0040
#define FM_CPU2_65816E 0x0050
typedef struct {
char *name;
int len;
@ -67,12 +83,21 @@ typedef struct {
size_t fsize; /* length of file */
unsigned char *buf; /* file content */
int mode; /* mode value */
int align; /* align value */
int tbase; /* header: text base */
int tlen; /* text length */
int talign; /* insert to get correct alignment */
int dbase; /* data base */
int dlen; /* data length */
int dalign; /* insert to get correct alignment */
int bbase; /* bss base */
int blen; /* bss length */
int balign; /* insert to get correct alignment */
int zbase; /* zero base */
int zlen; /* zero length */
@ -124,6 +149,21 @@ file65 file;
unsigned char cmp[] = { 1, 0, 'o', '6', '5' };
unsigned char hdr[26] = { 1, 0, 'o', '6', '5', 0 };
const char *cpunames[16] = {
"documented 6502",
"65C02 (CMOS with BBR/BBS/RMB/SMB)",
"65SC02 (CMOS without BBR/BBS/RMB/SMB)",
"65CE02",
"6502 with undocumented opcodes",
"65816 in 6502 emulation mode",
"n/a", "n/a",
"6809?", "n/a", // 1000 -
"Z80?", "n/a", "n/a", // 1010 -
"8086?", // 1101 -
"80286?", // 1110 -
"n/a"
};
int verbose = 0;
void usage(FILE *fp)
@ -150,6 +190,7 @@ int main(int argc, char *argv[]) {
int noglob=0;
int undefok=0;
int i = 1;
// default output segment addresses, overwritten by cmdline params
int tbase = 0x0400, dbase = 0x1000, bbase = 0x4000, zbase = 0x0002;
int ttlen, tdlen, tblen, tzlen, routtlen, routdlen, tro, dro;
int lasttaddr, lastdaddr;
@ -158,8 +199,11 @@ int main(int argc, char *argv[]) {
int j, jm;
file65 *file, **fp = NULL;
FILE *fd;
int nundef = 0; // counter/index in list of remaining undef'd labels
int nundef = 0; // counter/index in list of remaining undef'd labels
int maxalign; // maximum alignment over all files
char *alignfname; // (first) file that requires that alignment
int trgmode = 0; // mode for the output file
char alignbuf[256]; // to efficiently write align fillers
char *arg;
char **defined = NULL;
@ -176,7 +220,7 @@ int main(int argc, char *argv[]) {
exit(1);
}
if (strstr(argv[1], "--help") || strstr(argv[1], "-?")) {
if (strstr(argv[1], "--help") || strstr(argv[1], "-?") || strstr(argv[1], "-h")) {
usage(stdout);
exit(0);
}
@ -188,6 +232,7 @@ int main(int argc, char *argv[]) {
/* read options */
while(i<argc && argv[i][0]=='-') {
arg = NULL;
/* process options */
switch(argv[i][1]) {
case 'v':
@ -258,7 +303,7 @@ int main(int argc, char *argv[]) {
}
break;
default:
fprintf(stderr,"file65: %s unknown option, use '-?' for help\n",argv[i]);
fprintf(stderr,"file65: %s unknown option, use '-h for help\n",argv[i]);
break;
}
i++;
@ -282,6 +327,154 @@ int main(int argc, char *argv[]) {
i++;
}
// -------------------------------------------------------------------------
// compute target file mode value
// compute target mode and max align value
trgmode = 0;
maxalign = 0;
alignfname = "<none>";
{
int er = 0;
int trgcpu = 0;
if (verbose) {
printf("Starting CPU type calculation with mode %s (%d) ...\n",
cpunames[trgcpu], trgcpu);
}
for(i=0;i<j;i++) {
int fcpu;
file = fp[i];
if (file->align > maxalign) {
maxalign = file->align;
alignfname = file->fname;
}
if (file->mode & 0x8000) {
// 65816
trgmode |= 0x8000;
if (trgcpu == 4) {
fprintf(stderr, "Error: file '%s' in 65816 CPU mode is incompatible with previous NMOS undocumented opcodes CPU mode\n",
file->fname);
er = 1;
}
}
if (file->mode & 0x0200) {
// zero out bss
trgmode |= 0x0200;
}
// CPU bits
fcpu = (file->mode & FM_CPU2) >> 4;
if (verbose) {
printf("Matching file %s with CPU %s (%d) to target %s (%d) ...\n",
file->fname, cpunames[fcpu], fcpu, cpunames[trgcpu], trgcpu);
}
switch (fcpu) {
case 0x0: // bare minimum documented 6502 is just fine
break;
case 0x1: // 65C02 - CMOS with BBR/BBS/RMB/SMB, incompatible with 65816
case 0x3: // 65CE02 - CMOS with BBR/... and add'l opcodes, incompatible w/ 65816
if (trgmode & 0x8000 || trgcpu == 5) {
fprintf(stderr, "Error: file '%s' in CPU mode %d (%s) "
"is incompatible with previous 65816 CPU mode\n",
file->fname, fcpu, cpunames[fcpu]);
er = 1;
}
// fall-through
case 0x2: // 65SC02 - CMOS without BBR/BBS/RMB/SMB, compatible with 65816
if (trgcpu == 4) {
// is incompatible with nmos6502 with undocumented opcodes
fprintf(stderr, "Error: file '%s' in CPU mode %d (%s) "
"is incompatible with previous files with mode %d (%s)\n",
file->fname, fcpu, cpunames[fcpu], trgcpu, cpunames[trgcpu]);
er = 1;
}
break;
case 0x5: // 65816 in 6502 emulation mode
if (trgcpu == 1 || trgcpu == 3) {
// 65C02 and 65CE02 are incompatible with nmos6502 with undocumented opcodes
fprintf(stderr, "Error: file '%s' in CPU mode %d (%s) is "
"incompatible with previous files with mode %d (%s)\n",
file->fname, fcpu, cpunames[fcpu], trgcpu, cpunames[trgcpu]);
er = 1;
}
break;
case 0x4: // NMOS 6502 with undocumented opcodes
if (trgcpu == 1 || trgcpu == 2 || trgcpu == 3 || trgcpu == 5) {
// is incompatible with nmos6502 with undocumented opcodes
fprintf(stderr, "Error: file '%s' in CPU mode %d (%s) is "
"incompatible with previous files with mode %d (%s)\n",
file->fname, fcpu, cpunames[fcpu], trgcpu, cpunames[trgcpu]);
er = 1;
}
if (trgmode & 0x8000) {
fprintf(stderr, "Error: file '%s' in mode %d (%s) is incompatible with previous 65816 CPU mode\n",
file->fname, 4, cpunames[4]);
er = 1;
}
break;
default:
if (fcpu > 5) {
printf("Warning: unknown CPU mode %d (%s) detected in file %s\n",
fcpu, cpunames[fcpu], file->fname);
}
break;
}
// setting the new mode
switch (fcpu) {
case 0x0: // compatible with everything, no change
break;
case 0x3: // 65CE02 -> supersedes 6502, 65SC02, and 65C02
if (trgcpu == 1) {
// 65C02
trgcpu = fcpu;
}
// fall-through
case 0x5: // 65816 in 6502 emu mode, supersedes documented NMOS and 65SC02
case 0x1: // CMOS w/ BBR.. -> supersedes documented NMOS and 65SC02
if (trgcpu == 2) {
// 65SC02
trgcpu = fcpu;
}
// fall-through
case 0x2: // 65SC02 -> supersedes only NMOS 6502
case 0x4: // NMOS 6502 w/ undocumented opcodes
default:
if (trgcpu == 0) {
// NMOS 6502
trgcpu = fcpu;
}
break;
}
if (verbose && !er) {
printf("... to new target %s (%d)\n",
cpunames[trgcpu], trgcpu);
}
}
if (er) {
exit(1);
}
trgmode |= trgcpu << 4;
}
if (maxalign) {
printf("Info: Alignment at %d-boundaries required\n", maxalign + 1);
}
switch (maxalign) {
case 0:
break;
case 1:
trgmode |= 1;
break;
case 3:
trgmode |= 2;
break;
case 255:
trgmode |= 3;
break;
}
// -------------------------------------------------------------------------
// step 2 - calculate new segment base addresses per file, by
// concatenating the segments per type
@ -290,10 +483,64 @@ int main(int argc, char *argv[]) {
/* set total length to zero */
ttlen = tdlen = tblen = tzlen = 0;
// then check start addresses
file = fp[0];
if (file->align != 0) {
int er = 0;
if (tbase & file->align) {
fprintf(stderr, "Error: text segment start address ($%04x) "
"not aligned as required by first file (at %d bytes)\n",
tbase, file->align + 1);
er = 1;
}
if (dbase & file->align) {
fprintf(stderr, "Error: data segment start address ($%04x) "
"not aligned as required by first file (at %d bytes)\n",
dbase, file->align + 1);
er = 1;
}
if (bbase & file->align) {
fprintf(stderr, "Error: bss segment start address ($%04x) "
"not aligned as required (by first file at %d bytes)\n",
bbase, file->align + 1);
er = 1;
}
if (er) {
exit(1);
}
}
/* find new addresses for the files and read globals */
for(i=0;i<j;i++) {
file = fp[i];
/* compute align fillers */
file->talign = 0;
file->dalign = 0;
file->balign = 0;
// filler only needed if align not zero ...
if (file->align) {
// ... and respective segment not empty
if (file->tlen) {
//file->talign = file->align + 1 - ((tbase + ttlen) & file->align);
file->talign = ( -((tbase + ttlen) & file->align) ) & file->align;
}
if (file->dlen) {
//file->dalign = file->align + 1 - ((dbase + tdlen) & file->align);
file->dalign = ( -((dbase + tdlen) & file->align) ) & file->align;
}
if (file->blen) {
//file->balign = file->align + 1 - ((bbase + tblen) & file->align);
file->balign = ( -((bbase + tblen) & file->align) ) & file->align;
}
}
/* insert align fillers */
ttlen += file->talign;
tdlen += file->dalign;
tblen += file->balign;
/* compute relocation differences */
file->tdiff = ((tbase + ttlen) - file->tbase);
file->ddiff = ((dbase + tdlen) - file->dbase);
@ -308,14 +555,14 @@ printf("zbase=%04x+len=%04x->%04x, file->zbase=%04x, f.zlen=%04x -> zdiff=%04x\n
*/
if (verbose > 0) {
printf("Relocating file: %s\n", file->fname);
printf(" text: from %04x to %04x (diff is %04x, length is %04x)\n",
file->tbase, file->tbase + file->tdiff, file->tdiff, file->tlen);
printf(" data: from %04x to %04x (diff is %04x, length is %04x)\n",
file->dbase, file->dbase + file->ddiff, file->ddiff, file->dlen);
printf(" bss: from %04x to %04x (diff is %04x, length is %04x)\n",
file->bbase, file->bbase + file->bdiff, file->bdiff, file->blen);
printf(" zero: from %02x to %02x (diff is %02x, length is %02x)\n",
printf("Relocating file: %s [CPU %s]\n", file->fname, cpunames[((file->mode & FM_CPU2) >> 4) & 0x0f]);
printf(" text: align fill %04x, relocate from %04x to %04x (diff is %04x, length is %04x)\n",
file->talign, file->tbase, file->tbase + file->tdiff, file->tdiff, file->tlen);
printf(" data: align fill %04x, relocate from %04x to %04x (diff is %04x, length is %04x)\n",
file->dalign, file->dbase, file->dbase + file->ddiff, file->ddiff, file->dlen);
printf(" bss: align fill %04x, relocate from %04x to %04x (diff is %04x, length is %04x)\n",
file->balign, file->bbase, file->bbase + file->bdiff, file->bdiff, file->blen);
printf(" zero: relocate from %02x to %02x (diff is %02x, length is %02x)\n",
file->zbase, file->zbase + file->zdiff, file->zdiff, file->zlen);
}
@ -326,6 +573,31 @@ printf("zbase=%04x+len=%04x->%04x, file->zbase=%04x, f.zlen=%04x -> zdiff=%04x\n
tzlen += file->zlen;
}
// validate various situations.
if (maxalign != 0) {
int er = 0;
if (tbase & maxalign) {
fprintf(stderr, "Error: text segment start address ($%04x) "
"not aligned as first required by file %s (at %d bytes)\n",
tbase, alignfname, maxalign + 1);
er = 1;
}
if (dbase & maxalign) {
fprintf(stderr, "Error: data segment start address ($%04x) "
"not aligned as first required by file %s (at %d bytes)\n",
dbase, alignfname, maxalign + 1);
er = 1;
}
if (bbase & maxalign) {
fprintf(stderr, "Error: bss segment start address ($%04x) "
"not aligned as first required (by file %s (at %d bytes)\n",
bbase, alignfname, maxalign + 1);
er = 1;
}
if (er) {
exit(1);
}
}
// validate various situations.
{
int er = 0;
@ -471,7 +743,7 @@ printf("zbase=%04x+len=%04x->%04x, file->zbase=%04x, f.zlen=%04x -> zdiff=%04x\n
//
// prepare header
hdr[ 6] = 0; hdr[ 7] = 0;
hdr[ 6] = trgmode & 255; hdr[ 7] = (trgmode>>8)& 255;
hdr[ 8] = tbase & 255; hdr[ 9] = (tbase>>8) & 255;
hdr[10] = ttlen & 255; hdr[11] = (ttlen >>8)& 255;
hdr[12] = dbase & 255; hdr[13] = (dbase>>8) & 255;
@ -499,13 +771,22 @@ printf("zbase=%04x+len=%04x->%04x, file->zbase=%04x, f.zlen=%04x -> zdiff=%04x\n
}
fputc(0,fd);
// align filler is NOP, just in case
memset(alignbuf, 0xea, sizeof(alignbuf));
// write text segment
for(i=0;i<j;i++) {
if (fp[i]->talign) {
fwrite(alignbuf, 1, fp[i]->talign, fd);
}
fwrite(fp[i]->buf + fp[i]->tpos, 1, fp[i]->tlen, fd);
}
// write data segment
for(i=0;i<j;i++) {
if (fp[i]->dalign) {
fwrite(alignbuf, 1, fp[i]->dalign, fd);
}
fwrite(fp[i]->buf + fp[i]->dpos, 1, fp[i]->dlen, fd);
}
@ -732,6 +1013,7 @@ file65 *load_file(char *fname) {
struct stat fs;
FILE *fp;
int mode, hlen;
int align;
size_t n;
file=malloc(sizeof(file65));
@ -743,7 +1025,10 @@ file65 *load_file(char *fname) {
/*printf("load_file(%s)\n",fname);*/
file->fname=fname;
stat(fname, &fs);
if(stat(fname, &fs) < 0) {
perror("while opening file: stat");
exit(1);
}
file->fsize=fs.st_size;
file->buf=malloc(file->fsize);
if(!file->buf) {
@ -757,6 +1042,7 @@ file65 *load_file(char *fname) {
fclose(fp);
if((n>=file->fsize) && (!memcmp(file->buf, cmp, 5))) {
mode=file->buf[7]*256+file->buf[6];
file->mode = mode;
if(mode & 0x2000) {
fprintf(stderr,"file65: %s: 32 bit size not supported\n", fname);
free(file->buf); free(file); file=NULL;
@ -766,14 +1052,38 @@ file65 *load_file(char *fname) {
fname);
free(file->buf); free(file); file=NULL;
} else {
align = mode & 3;
switch(align) {
case 0:
align = 0;
break;
case 1:
// word align
align = 1;
break;
case 2:
// long align
align = 3;
break;
case 3:
// page align
align = 255;
break;
}
file->align = align;
hlen = BUF+read_options(file->buf+BUF);
file->tbase = file->buf[ 9]*256+file->buf[ 8];
file->tlen = file->buf[11]*256+file->buf[10];
file->talign= 0;
file->dbase = file->buf[13]*256+file->buf[12];
file->dlen = file->buf[15]*256+file->buf[14];
file->dalign= 0;
file->bbase = file->buf[17]*256+file->buf[16];
file->blen = file->buf[19]*256+file->buf[18];
file->balign= 0;
file->zbase = file->buf[21]*256+file->buf[20];
file->zlen = file->buf[23]*256+file->buf[22];

View File

@ -34,6 +34,21 @@
#define author "Written by Andre Fachat"
#define copyright "Copyright (C) 1997-2002 Andre Fachat."
/* o65 file format mode bits */
#define FM_OBJ 0x1000
#define FM_SIZE 0x2000
#define FM_RELOC 0x4000
#define FM_CPU 0x8000
#define FM_CPU2 0x00f0
#define FM_CPU2_6502 0x0000
#define FM_CPU2_65C02 0x0010
#define FM_CPU2_65SC02 0x0020
#define FM_CPU2_65CE02 0x0030
#define FM_CPU2_NMOS 0x0040
#define FM_CPU2_65816E 0x0050
typedef struct {
char *fname;
size_t fsize;
@ -74,13 +89,32 @@ 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"
" -C <CPU> Set the o65 CPU flags in the output for the following CPUs:\n"
" 6502, 65SC02, 65C02, 65CE02, 65816, NMOS6502\n"
" (for details see the man page)\n"
" -v verbose output\n"
" --version output version information and exit\n"
" --help display this help and exit\n");
}
const char *cpunames[16] = {
"6502",
"65C02",
"65SC02",
"65CE02",
"NMOS6502",
"65816",
NULL, NULL,
"6809", NULL, // 1000 -
"Z80", NULL, NULL, // 1010 -
"8086", // 1101 -
"80286", // 1110 -
NULL
};
int main(int argc, char *argv[]) {
int i = 1, mode, hlen;
int j;
size_t n;
FILE *fp;
int tflag = 0, dflag = 0, bflag = 0, zflag = 0;
@ -89,13 +123,15 @@ int main(int argc, char *argv[]) {
char *outfile = "a.o65";
int extract = 0;
int verbose = 0;
int trgcpu = -1; // output file target CPU flag (-1 = do not change)
char *arg; // temporary argument pointer
if (argc <= 1) {
usage(stderr);
exit(1);
}
if (strstr(argv[1], "--help") || strstr(argv[1], "-?")) {
if (strstr(argv[1], "--help") || strstr(argv[1], "-?") || strstr(argv[1], "-h")) {
usage(stdout);
exit(0);
}
@ -106,6 +142,7 @@ int main(int argc, char *argv[]) {
}
while(i<argc) {
arg = NULL;
if(argv[i][0]=='-') {
/* process options */
switch(argv[i][1]) {
@ -166,8 +203,27 @@ int main(int argc, char *argv[]) {
break;
}
break;
case 'C':
if(argv[i][2]) arg=argv[i]+2;
else if(i + 1 < argc) arg=argv[++i];
if (arg == NULL) {
printf("Missing CPU parameter to -C - ignored\n");
break;
}
for(j = 0; j < 16; j++) {
if (cpunames[j] != NULL && !strcmp(arg, cpunames[j])) {
break;
}
}
if (j == 16) {
printf("Unknown CPU identifier '%s' for -C - ignored\n",
arg);
} else {
trgcpu = j;
}
break;
default:
fprintf(stderr,"%s: %s unknown option, use '-?' for help\n",programname,argv[i]);
fprintf(stderr,"%s: %s unknown option, use '-h' for help\n",programname,argv[i]);
break;
}
} else {
@ -177,7 +233,7 @@ int main(int argc, char *argv[]) {
file.fsize=fs.st_size;
file.buf=malloc(file.fsize);
if(!file.buf) {
fprintf(stderr,"Oops, no more memory!\n");
fprintf(stderr,"Oops, no more memory! (%d)\n", file.fsize);
exit(1);
}
printf("reloc65: read file %s -> %s\n",argv[i],outfile);
@ -187,12 +243,26 @@ int main(int argc, char *argv[]) {
fclose(fp);
if((n>=file.fsize) && (!memcmp(file.buf, cmp, 5))) {
mode=file.buf[7]*256+file.buf[6];
if(mode & 0x2000) {
if(mode & FM_SIZE) {
fprintf(stderr,"reloc65: %s: 32 bit size not supported\n", argv[i]);
} else
if(mode & 0x4000) {
if(mode & FM_RELOC) {
fprintf(stderr,"reloc65: %s: pagewise relocation not supported\n", argv[i]);
} else {
if (trgcpu >= 0) {
// change CPU flags
mode &= ~FM_CPU;
mode &= ~FM_CPU2;
mode |= (trgcpu << 4);
if (trgcpu == 5) {
// this trgcpu is actually 65816 in emulation mode
// unsure if we should do an own cmdline option
mode |= FM_CPU; // 65816 native
}
}
file.buf[6] = mode & 0xff;
file.buf[7] = (mode >> 8) & 0xff;
hlen = BUF+read_options(file.buf+BUF);
file.tbase = file.buf[ 9]*256+file.buf[ 8];

View File

@ -58,7 +58,7 @@
#define programname "xa"
/* progversion now in xa.h */
#define authors "Written by Andre Fachat, Jolse Maginnis, David Weinehall and Cameron Kaiser"
#define copyright "Copyright (C) 1989-2023 Andre Fachat, Jolse Maginnis, David Weinehall\nand Cameron Kaiser."
#define copyright "Copyright (C) 1989-2024 Andre Fachat, Jolse Maginnis, David Weinehall\nand Cameron Kaiser."
/* exported globals */
int ncmos, cmosfl, w65816, n65816;
@ -66,6 +66,7 @@ int ncmos, cmosfl, w65816, n65816;
/* compatibility flags */
int masm = 0; /* MASM */
int ca65 = 0; /* CA65 */
int collab = 0; /* allow colon relative labels even without ca65 mode */
int xa23 = 0; /* ^ and recursive comments, disable \ escape */
int ctypes = 0; /* C compatibility, like "0xab" types */
int nolink = 0;
@ -74,6 +75,7 @@ int romaddr = 0;
int noglob = 0;
int showblk = 0;
int crossref = 0;
int mask = 0;
int undefok = 0; // -R only accepts -Llabels; with -U all undef'd labels are ok in -R mode
char altppchar;
@ -140,12 +142,20 @@ int main(int argc,char *argv[])
char old_o[MAXLINE];
tim1=time(NULL);
ncmos=0;
n65816=0;
// note: unfortunately we do no full distinction between 65C02 and 65816.
// The conflict is in the column 7 and column f opcodes, where the 65C02
// has the BBR/BBS/SMB/RMB opcodes, but the 65816 has its own.
// Also, we potentially could support the 65SC02, which is the 65C02, but
// without the conflicting BBR/BBS/SMB/RMB opcodes.
// This, however, is a TODO for a later version.
cmosfl=1;
//fmode = FM_CPU2_65C02;
w65816=0; /* default: 6502 only */
ncmos=0; // counter for CMOS opcodes used
n65816=0; // counter for 65816-specific opcodes used
altppchar = '#' ; /* i.e., NO alternate char */
if((tmpp = strrchr(argv[0],'/'))) {
@ -205,6 +215,15 @@ int main(int argc,char *argv[])
while(i<argc) {
if(argv[i][0]=='-') {
switch(argv[i][1]) {
case 'a':
if (ca65) {
collab=0; /* paranoia */
fprintf(stderr, "Warning: -a not needed with -XCA65\n");
} else collab=1;
break;
case 'k':
mask = 1;
break;
case 'E':
ner_max = 0;
break;
@ -218,7 +237,7 @@ int main(int argc,char *argv[])
}
if (argv[i][2] == '#')
fprintf(stderr,
"using -p# is evidence of stupidity\n");
"using -p# is not necessary, '#' is the default\n");
altppchar = argv[i][2];
if (argv[i][3] != '\0')
fprintf(stderr,
@ -239,6 +258,10 @@ int main(int argc,char *argv[])
if (set_compat(name) < 0) {
fprintf(stderr, "Compatibility set '%s' unknown - ignoring! (check case?)\n", name);
}
if (collab && ca65) {
collab=0;
fprintf(stderr, "Warning: -a not needed with -XCA65\n");
}
}
break;
case 'O': /* output charset */
@ -299,12 +322,29 @@ int main(int argc,char *argv[])
break;
case 'C':
cmosfl = 0;
fmode &= ~FM_CPU2; // fall back to standard 6502
// breaks existing tests (compare with pre-assembled files)
//if (w65816) {
// fmode |= FM_CPU2_65816E;
//}
break;
case 'W':
w65816 = 0;
fmode &= ~FM_CPU;
fmode &= ~FM_CPU2;
// breaks existing tests (compare with pre-assembled files)
//if (cmosfl) {
// fmode |= FM_CPU2_65C02;
//}
break;
case 'w':
// note: we do not disable cmos here, as opcode tables note CMOS for
// opcodes common to both, CMOS and 65816 as well.
w65816 = 1;
fmode &= ~FM_CPU2;
// breaks existing tests (compare with pre-assembled files)
//fmode |= FM_CPU; // 65816 bit
//fmode |= FM_CPU2_65816E;// 6502 in 65816 emu, to manage opcode compatibility in ldo65
break;
case 'B':
showblk = 1;
@ -510,10 +550,6 @@ int main(int argc,char *argv[])
sprintf(out,"Warning: bss segment ($%04x) start address doesn't align to %d!\n", bbase, align);
logout(out);
}
if(zbase & (align-1)) {
sprintf(out,"Warning: zero segment ($%04x) start address doesn't align to %d!\n", zbase, align);
logout(out);
}
if (n65816>0)
fmode |= 0x8000;
switch(align) {
@ -612,32 +648,6 @@ int h_length(void) {
return 26+o_length();
}
#if 0
/* write header for relocatable output format */
int h_write(FILE *fp, int tbase, int tlen, int dbase, int dlen,
int bbase, int blen, int zbase, int zlen) {
fputc(1, fp); /* version byte */
fputc(0, fp); /* hi address 0 -> no C64 */
fputc("o", fp);
fputc("6", fp);
fputc("5", fp);
fputc(0, fp); /* format version */
fputw(mode, fp); /* file mode */
fputw(tbase,fp); /* text base */
fputw(tlen,fp); /* text length */
fputw(dbase,fp); /* data base */
fputw(dlen,fp); /* data length */
fputw(bbase,fp); /* bss base */
fputw(blen,fp); /* bss length */
fputw(zbase,fp); /* zerop base */
fputw(zlen,fp); /* zerop length */
o_write(fp);
return 0;
}
#endif
static int setfext(char *s, char *ext)
{
@ -665,11 +675,6 @@ static int setfext(char *s, char *ext)
return(0);
}
/*
static char *tmp;
static unsigned long tmpz;
static unsigned long tmpe;
*/
static long ga_p1(void)
{
@ -932,6 +937,8 @@ static void usage(int default816, FILE *fp)
" (deprecated: prefer -XMASM)\n"
" -Xcompatset set compatibility flags for other assemblers, known values are:\n"
" C, MASM, CA65, XA23 (deprecated: for better 2.3 compatibility)\n"
" -a Allow ca65-style unnamed labels with colons, implies -XMASM\n"
" -k Allow carat to mask character value with 31/$1f\n"
" -R start assembler in relocating mode\n"
" -U allow all undefined labels in relocating mode\n");
fprintf(fp,
@ -1169,10 +1176,12 @@ static int xa_getline(char *s)
we have ca65 compatibility, we ignore the colon */
// also check for ":+" and ":-"
if (((!startofline) && l[i]!='=' && l[i]!='+' && l[i]!='-') || !ca65 || comcom) {
//#error gotta get collab into this test
//if (((!startofline) && l[i]!='=' && l[i]!='+' && l[i]!='-') || !ca65 || comcom) {
if (((!startofline) && l[i]!='=' && l[i]!='+' && l[i]!='-') || !(ca65 || collab) || 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)) {
if(!comcom || !(masm || ca65 || collab)) {
/* 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... */

View File

@ -23,11 +23,11 @@
#define progmajor "2"
#define progminor "4"
#define progpatch "0"
#define progpatch "1"
#define progversion progmajor "." progminor "." progpatch
extern int ncmos, cmosfl, w65816, n65816;
extern int masm, ca65, xa23, nolink, undefok;
extern int masm, ca65, xa23, nolink, undefok, collab, mask;
extern int noglob;
extern int showblk;
extern int relmode;

View File

@ -39,4 +39,6 @@
t[i++] = f & 255; \
} while (0)
#define wval_len 5 /* number of bytes stored in wval() call */
#endif /* __XA65_XAD_H__ */

View File

@ -192,11 +192,22 @@ typedef struct {
#define A_LONG 0xc000
/* o65 file format mode bits */
#define FM_OBJ 0x1000
#define FM_SIZE 0x2000
#define FM_RELOC 0x4000
#define FM_CPU 0x8000
#define FM_CPU2 0x00f0
#define FM_CPU2_6502 0x0000
#define FM_CPU2_65C02 0x0010
#define FM_CPU2_65SC02 0x0020
#define FM_CPU2_65CE02 0x0030
#define FM_CPU2_NMOS 0x0040
#define FM_CPU2_65816E 0x0050
/* segment definitions */
#define SEG_ABS 0
#define SEG_UNDEF 1
#define SEG_TEXT 2

View File

@ -278,8 +278,8 @@ int l_def(char *s, int *l, int *x, int *f)
cll_clear();
}
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]);
if((!isalpha(s[i])) && (s[i]!='_') && !((ca65 || collab) && ((cll_fl == UNNAMED) || isdigit(s[i])) ) ) {
//printf("SYNTAX ca65=%d collab=%d cll_fl=%d, i=%d, s[i]=%02x (%c)\n", ca65, collab, cll_fl, i, s[i], s[i]);
er=E_SYNTAX;
} else
{
@ -653,7 +653,7 @@ int ll_search(char *s, int *n, xalabel_t cll_fl) /* search Label in Tab
{
for (k=0;(k<j)&&(ltp->n[k]==s[k]);k++);
if (cll_fl == CHEAP) {
if ( (j == k) && cll_fl == CHEAP) {
if (ltp->blk == cll_getcur()) {
er=E_OK;
break;

View File

@ -834,12 +834,12 @@ printf("reloc: er=%d, l=%d, segment=%d, pc[%d]=%04x, pc[abs(%d)]=%04x, pc[text(%
t[0]=Kdsb;
i=1;
bl=tmp=(tmp - (pc[segment] & (tmp-1))) & (tmp-1);
wval(i,tmp, 0);
wval(i,tmp, 0); // 5 byte
t[i++]=',';
tmp2= 0xea;
wval(i,tmp2, 0); /* nop opcode */
wval(i,tmp2, 0); /* nop opcode, another 5 byte */
t[i++]=T_END;
*ll=9;
*ll=wval_len * 2 + 3; //13; //9;
er=E_OKDEF;
} else {
*ll=0; /* ignore if aligned right */
@ -1324,7 +1324,7 @@ int t_p2(signed char *t, int *ll, int fl, int *al)
} else {
er = E_SYNTAX;
}
/* get filename.
/* get error string.
the tokenizer can either see it as a multichar string ... */
if (!er) {
int k;
@ -1344,7 +1344,7 @@ int t_p2(signed char *t, int *ll, int fl, int *al)
have been caught by the above) */
} else
if(!(er=a_term(t+i,&c,&l,pc[segment],&afl,&label,1))) {
if (!result) fprintf(stderr, "%c", c);
if (!result) fprintf(stderr, "Assertion failed: %c", c);
i += l;
}
}
@ -1838,7 +1838,10 @@ fprintf(stderr, "Kdsb E_DSB %i\n", j);
if(tolower(t[inp])=='s')
sy=12;
else
if(tolower(t[inp])=='x')
sy=5;
else
er=E_SYNTAX;
} else
er=E_SYNTAX;
}
@ -1965,7 +1968,9 @@ fprintf(stderr, "byte length is now %d, am=%d, er=%d\n", bl, am, er);
} else {
n65816++;
if(!w65816) {
fprintf(stderr,"n=%d, am=%d\n", n, am);
#ifdef DEBUG_AM
fprintf(stderr,"not 65816 n=%d, am=%d\n", n, am);
#endif
er=E_65816;
}
}
@ -2335,7 +2340,7 @@ static int t_conv(signed char *s, signed char *t, int *l, int pc, int *nk,
} else
/* maybe it's a label
Note that for ca65 cheap local labels, we check for "@" */
if(isalpha(s[p]) || s[p]=='_' || ((s[p]==':' || s[p]=='@') && ca65))
if(isalpha(s[p]) || s[p]=='_' || (s[p]==':' && collab) || ((s[p]==':' || s[p]=='@') && ca65))
{
int p2 = 0;
@ -2770,7 +2775,7 @@ fprintf(stderr, "tg_asc token = %i\n", n);
if (!n || n == Kbin || n == Kaasc) {
t[j++]=s[i];
/* XXX 2.4 implement option for ^ for backwards compatibility */
} else if(ca65 || !xa23 || s[i]!='^') { /* no escape code "^" - TODO: does ca65 has an escape code */
} else if(ca65 || (!xa23 && !mask) || 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];

View File

@ -44,6 +44,7 @@ relmode/ tests concerning switches between segments and absolute mode
mvnmvp/ Test MVN MVP unusual addressing mode ('816)
dos51/ Regression test, label scoping, "real world code"
cpktest/ Regression test, label listing, "real world code"
usb65/ Unusual macro and scoping, "real world code"
listing/ Test of listing feature
op816/ Regression test for '816 opcodes (thanks Alessandro Gatti)
branch/ Branch range test

100
xa/tests/align/Makefile Normal file
View File

@ -0,0 +1,100 @@
XA=../../xa
default: all
all: t01 t02 t03 t11 t12 t13 t21 t22 t23 t31 t32 t33 t41 t42 t43
# BSD only has suffix rules
.SUFFIXES: .o65 .hex .a65
#%.o65: %.s
.a65.o65:
${XA} -R -c -o $@ $?
#%.hex: %.o65
.o65.hex:
../hextool $? > $@
###############################################
# text segment correctly aligned
t01: t01.o65
../hextool -cmp=$@.ok $@.o65
t02: t02.o65
../hextool -cmp=$@.ok $@.o65
t03: t03.o65
../hextool -cmp=$@.ok $@.o65
###############################################
# data segment correctly aligned
t11: t11.o65
../hextool -cmp=$@.ok $@.o65
t12: t12.o65
../hextool -cmp=$@.ok $@.o65
t13: t13.o65
../hextool -cmp=$@.ok $@.o65
###############################################
# text segment incorrectly aligned
t21: t01.a65
${XA} -R -c -bt 1025 -o $@.o65 $? 2> $@.msg
../hextool -cmp=$@.mok $@.msg
../hextool -cmp=$@.ok $@.o65
t22: t02.a65
${XA} -R -c -bt 1025 -o $@.o65 $? 2> $@.msg
../hextool -cmp=$@.mok $@.msg
../hextool -cmp=$@.ok $@.o65
t23: t03.a65
${XA} -R -c -bt 1025 -o $@.o65 $? 2> $@.msg
../hextool -cmp=$@.mok $@.msg
../hextool -cmp=$@.ok $@.o65
###############################################
# text segment correctly aligned, but data segment not (even if empty)
t31: t01.a65
${XA} -R -c -bd 1025 -o $@.o65 $? 2> $@.msg
../hextool -cmp=$@.mok $@.msg
../hextool -cmp=$@.ok $@.o65
t32: t02.a65
${XA} -R -c -bd 1025 -o $@.o65 $? 2> $@.msg
../hextool -cmp=$@.mok $@.msg
../hextool -cmp=$@.ok $@.o65
t33: t03.a65
${XA} -R -c -bd 1025 -o $@.o65 $? 2> $@.msg
../hextool -cmp=$@.mok $@.msg
../hextool -cmp=$@.ok $@.o65
###############################################
# data segment incorrectly aligned
t41: t11.a65
${XA} -R -c -bd 1025 -o $@.o65 $? 2> $@.msg
../hextool -cmp=$@.mok $@.msg
../hextool -cmp=$@.ok $@.o65
t42: t12.a65
${XA} -R -c -bd 1025 -o $@.o65 $? 2> $@.msg
../hextool -cmp=$@.mok $@.msg
../hextool -cmp=$@.ok $@.o65
t43: t13.a65
${XA} -R -c -bd 1025 -o $@.o65 $? 2> $@.msg
../hextool -cmp=$@.mok $@.msg
../hextool -cmp=$@.ok $@.o65
clean:
rm -f *.o65 *.hex

10
xa/tests/align/t01.a65 Normal file
View File

@ -0,0 +1,10 @@
.text
tay
.align 2
tay

BIN
xa/tests/align/t01.ok Normal file

Binary file not shown.

10
xa/tests/align/t02.a65 Normal file
View File

@ -0,0 +1,10 @@
.text
tay
.align 4
tay

BIN
xa/tests/align/t02.ok Normal file

Binary file not shown.

10
xa/tests/align/t03.a65 Normal file
View File

@ -0,0 +1,10 @@
.text
tay
.align 256
tay

BIN
xa/tests/align/t03.ok Normal file

Binary file not shown.

10
xa/tests/align/t11.a65 Normal file
View File

@ -0,0 +1,10 @@
.data
tay
.align 2
tay

BIN
xa/tests/align/t11.ok Normal file

Binary file not shown.

10
xa/tests/align/t12.a65 Normal file
View File

@ -0,0 +1,10 @@
.data
tay
.align 4
tay

BIN
xa/tests/align/t12.ok Normal file

Binary file not shown.

10
xa/tests/align/t13.a65 Normal file
View File

@ -0,0 +1,10 @@
.data
tay
.align 256
tay

BIN
xa/tests/align/t13.ok Normal file

Binary file not shown.

1
xa/tests/align/t21.mok Normal file
View File

@ -0,0 +1 @@
Warning: text segment ($0401) start address doesn't align to 2!

1
xa/tests/align/t21.msg Normal file
View File

@ -0,0 +1 @@
Warning: text segment ($0401) start address doesn't align to 2!

BIN
xa/tests/align/t21.ok Normal file

Binary file not shown.

1
xa/tests/align/t22.mok Normal file
View File

@ -0,0 +1 @@
Warning: text segment ($0401) start address doesn't align to 4!

1
xa/tests/align/t22.msg Normal file
View File

@ -0,0 +1 @@
Warning: text segment ($0401) start address doesn't align to 4!

BIN
xa/tests/align/t22.ok Normal file

Binary file not shown.

1
xa/tests/align/t23.mok Normal file
View File

@ -0,0 +1 @@
Warning: text segment ($0401) start address doesn't align to 256!

1
xa/tests/align/t23.msg Normal file
View File

@ -0,0 +1 @@
Warning: text segment ($0401) start address doesn't align to 256!

BIN
xa/tests/align/t23.ok Normal file

Binary file not shown.

1
xa/tests/align/t31.mok Normal file
View File

@ -0,0 +1 @@
Warning: data segment ($0401) start address doesn't align to 2!

1
xa/tests/align/t31.msg Normal file
View File

@ -0,0 +1 @@
Warning: data segment ($0401) start address doesn't align to 2!

BIN
xa/tests/align/t31.ok Normal file

Binary file not shown.

1
xa/tests/align/t32.mok Normal file
View File

@ -0,0 +1 @@
Warning: data segment ($0401) start address doesn't align to 4!

1
xa/tests/align/t32.msg Normal file
View File

@ -0,0 +1 @@
Warning: data segment ($0401) start address doesn't align to 4!

BIN
xa/tests/align/t32.ok Normal file

Binary file not shown.

1
xa/tests/align/t33.mok Normal file
View File

@ -0,0 +1 @@
Warning: data segment ($0401) start address doesn't align to 256!

1
xa/tests/align/t33.msg Normal file
View File

@ -0,0 +1 @@
Warning: data segment ($0401) start address doesn't align to 256!

BIN
xa/tests/align/t33.ok Normal file

Binary file not shown.

1
xa/tests/align/t41.mok Normal file
View File

@ -0,0 +1 @@
Warning: data segment ($0401) start address doesn't align to 2!

1
xa/tests/align/t41.msg Normal file
View File

@ -0,0 +1 @@
Warning: data segment ($0401) start address doesn't align to 2!

BIN
xa/tests/align/t41.ok Normal file

Binary file not shown.

1
xa/tests/align/t42.mok Normal file
View File

@ -0,0 +1 @@
Warning: data segment ($0401) start address doesn't align to 4!

1
xa/tests/align/t42.msg Normal file
View File

@ -0,0 +1 @@
Warning: data segment ($0401) start address doesn't align to 4!

BIN
xa/tests/align/t42.ok Normal file

Binary file not shown.

1
xa/tests/align/t43.mok Normal file
View File

@ -0,0 +1 @@
Warning: data segment ($0401) start address doesn't align to 256!

1
xa/tests/align/t43.msg Normal file
View File

@ -0,0 +1 @@
Warning: data segment ($0401) start address doesn't align to 256!

BIN
xa/tests/align/t43.ok Normal file

Binary file not shown.

View File

@ -6,7 +6,7 @@ XA=../../xa
CA65=ca65
LD65=ld65
OBJS=unnamed1 unnamed2 escape2
OBJS=unnamed1 unnamed2 escape1 escape2 lll
# escape1 test only relevant if xa23 mode is on
#tests: unnamed1 unnamed2 escape1 escape2 clean
@ -18,15 +18,23 @@ unnamed1: unnamed1.a65
#${CA65} unnamed1.a65; ${LD65} -t none -o unnamed1.ca65 unnamed1.o; rm unnamed1.o
${XA} -XCA65 unnamed1.a65 -o $@
../hextool -cmp=unnamed1.ca65 < $@
${XA} -a unnamed1.a65 -o $@
../hextool -cmp=unnamed1.ca65 < $@
unnamed2: unnamed2.a65
#${CA65} unnamed2.a65; ${LD65} -t none -o unnamed2.ca65 unnamed2.o; rm unnamed2.o
${XA} -XCA65 unnamed2.a65 -o $@ 2>a.err || true
../hextool -cmp=unnamed2.ca65 < $@
${XA} -a unnamed2.a65 -o $@ 2>a.err || true
../hextool -cmp=unnamed2.ca65 < $@
# add -XXA23 to actually test this
escape1: escape1.a65
${XA} escape1.a65 -o $@
# shouldn't work by default
${XA} escape1.a65 -o $@ || exit 0 && exit 1
${XA} -XXA23 escape1.a65 -o $@
../hextool -cmp=escape1.out < $@
${XA} -k escape1.a65 -o $@
../hextool -cmp=escape1.out < $@
escape2: escape2.a65
@ -34,6 +42,15 @@ escape2: escape2.a65
${XA} -XCA65 escape2.a65 -o $@ 2>a.err || true
../hextool -cmp=escape2.ca65 < $@
lll: lll.a65
# shouldn't work
${XA} lll.a65 -o $@ || exit 0 && exit 1
${XA} -a lll.a65 -o $@ || exit 0 && exit 1
${XA} -w lll.a65 -o $@ || exit 0 && exit 1
# should work
${XA} -XCA65 lll.a65 -o $@
../hextool -cmp=lll.out < $@
clean:
rm -f *.err a.o65 $(OBJS)

View File

@ -2,5 +2,6 @@
*=$1000
lda #"^^"
.asc "^m^j"

View File

@ -1 +1 @@
ゥ^
ゥ^

28
xa/tests/ca65/lll.a65 Normal file
View File

@ -0,0 +1,28 @@
; As extracted from https://codebase64.org/doku.php?id=base:256_bytes_tune_player
* = $326
@musicdata:
; errs
@Voc0start:
.byte $00
.byte <(@Voc0komp-@musicdata)
; errs
@Voc1start:
.byte $40
.byte <(@Voc1melody-@musicdata)
; errs
@Voc2start:
;-
;-
.byte $50
@Voc2loop:
.byte $60
.byte <(@Voc2loop-@musicdata)
; errs
@Voc0komp:
.byte $10
.byte <(@Voc0start-@musicdata)
@Voc1melody:
.byte $20
.byte <(@Voc1start-@musicdata)

BIN
xa/tests/ca65/lll.out Normal file

Binary file not shown.

14
xa/tests/cll/Makefile Normal file
View File

@ -0,0 +1,14 @@
XA=../../xa
all: test1.o65
.SUFFIXES: .a65 .o65
.a65.o65:
${XA} -XCA65 -o $@ $>
clean:
rm -f *.o65
rm -f test1

30
xa/tests/cll/test1.a65 Normal file
View File

@ -0,0 +1,30 @@
; As extracted from https://codebase64.org/doku.php?id=base:256_bytes_tune_player
.org $326
foo:
@musicdata:
; errs
@Voc0start:
.byte $00
; .byte <(@Voc0komp-@musicdata)
; errs
@Voc1start:
.byte $40
.byte <(@Voc1melody-@musicdata)
; errs
@Voc2start:
;-
;-
.byte $50
@Voc2loop:
.byte $60
.byte <(@Voc2loop-@musicdata)
; errs
@Voc0komp:
.byte $10
.byte <(@Voc0start-@musicdata)
@Voc1melody:
.byte $20
.byte <(@Voc1start-@musicdata)

View File

@ -0,0 +1,6 @@
:
lda @$123456
beq :+
bne :-
:
sta @$654321

View File

@ -0,0 +1 @@
¯V4ðÐø<C390>!Ce

View File

@ -1,13 +1,21 @@
default:
# this should fail.
../../xa scomcom.asm || exit 0 && exit 1
../../xa -a 816com.asm || exit 0 && exit 1
../../xa -w 816com.asm || exit 0 && exit 1
# it did fail. these should now all succeed.
../../xa -M scomcom.asm
../../xa -XMASM scomcom.asm
../hextool -cmp=scomcomm.ok < a.o65
../../xa -a scomcom.asm
../hextool -cmp=scomcomm.ok < a.o65
../../xa comcom.asm
../hextool -cmp=comcom.ok < a.o65
../../xa -M comcom.asm
../../xa -XMASM comcom.asm
../hextool -cmp=comcomm.ok < a.o65
../../xa -a comcom.asm
../hextool -cmp=comcomm.ok < a.o65
../../xa -a -w 816com.asm
../hextool -cmp=816com.ok < a.o65
clean:
rm -f a.o65

View File

@ -1,6 +1,6 @@
default:
# compile with masm mode on.
../../xa -M -o test.o test.s
../../xa -XMASM -o test.o test.s
../hextool -cmp=okmasm < test.o
# compile without
../../xa -o test.o test.s

149
xa/tests/mode/Makefile Normal file
View File

@ -0,0 +1,149 @@
FILES=at1.o65 at2.o65 at4.o65 at256.o65 ad1.o65 ad2.o65 ad4.o65 ad256.o65 ab1.o65 ab2.o65 ab4.o65 ab256.o65
VERBOSE=
#VERBOSE=-v
XA=../../xa
LDO=../../ldo65
RELOC=../../reloc65
FILE=../../file65
all: test1.o65 test2.o65 test3.o65 test4 cpus relocsame overwrite linkup1.tmp linkup2
.SUFFIXES: .a65 .o65
.a65.o65:
${XA} -R -o $@ $?
# test with files in order of increasing align
test1.o65: ${FILES}
${LDO} ${VERBOSE} -o $@ ${FILES}
../hextool -cmp=$@.ok $@
# test with files in order of decreasing align
test2.o65: ${FILES}
${LDO} ${VERBOSE} -o $@ ab256.o65 ab4.o65 ab2.o65 ab1.o65 ad256.o65 ad4.o65 ad2.o65 ad1.o65 at256.o65 at4.o65 at2.o65 at1.o65
../hextool -cmp=$@.ok $@
# test with files in order of increasing align, not starting at align=1
test3.o65: ${FILES}
${LDO} ${VERBOSE} -o $@ ab2.o65 at2.o65 ad2.o65 ab4.o65 at4.o65 ad4.o65 ad256.o65 at256.o65 ab256.o65
../hextool -cmp=$@.ok $@
# test with files in order of increasing align, with non-aligned segment addresses
test4: ${FILES}
${LDO} ${VERBOSE} -bt 1025 -bd 1025 -o $@.o65 ab2.o65 at2.o65 ad2.o65 ab4.o65 at4.o65 ad4.o65 ad256.o65 at256.o65 ab256.o65 || exit 0 && exit 1
${LDO} ${VERBOSE} -bt 1026 -bd 1026 -o $@.o65 ab2.o65 at2.o65 ad2.o65 ab4.o65 at4.o65 ad4.o65 ad256.o65 at256.o65 ab256.o65 || exit 0 && exit 1
${LDO} ${VERBOSE} -bt 1027 -bd 1027 -o $@.o65 ab2.o65 at2.o65 ad2.o65 ab4.o65 at4.o65 ad4.o65 ad256.o65 at256.o65 ab256.o65 || exit 0 && exit 1
${LDO} ${VERBOSE} -bt 1028 -bd 1028 -o $@.o65 ab2.o65 at2.o65 ad2.o65 ab4.o65 at4.o65 ad4.o65 ad256.o65 at256.o65 ab256.o65 || exit 0 && exit 1
#c6502: at2.o65 ad4.o65
# for i in $^; do ${RELOC} -C 6502 -o $@-$$i $$i; done
# cmp $@-at2.o65 $@-at2.ok
# cmp $@-ad4.o65 $@-ad4.ok
c6502: c6502-at2.o65 c6502-ad4.o65
c6502-at2.o65: at2.o65
${RELOC} -C 6502 -o $@ $?
../hextool -cmp=$@.ok $@
c6502-ad4.o65: ad4.o65
${RELOC} -C 6502 -o $@ $?
../hextool -cmp=$@.ok $@
#c65c02: at2.o65 ad4.o65
# for i in $^; do ${RELOC} -C 65C02 -o $@-$$i $$i; done
# cmp $@-at2.o65 $@-at2.ok
# cmp $@-ad4.o65 $@-ad4.ok
c65c02: c65c02-at2.o65 c65c02-ad4.o65
c65c02-at2.o65: at2.o65
${RELOC} -C 65C02 -o $@ $?
../hextool -cmp=$@.ok $@
c65c02-ad4.o65: ad4.o65
${RELOC} -C 65C02 -o $@ $?
../hextool -cmp=$@.ok $@
#c65ce02: at2.o65 ad4.o65
# for i in $^; do ${RELOC} -C 65CE02 -o $@-$$i $$i; done
# cmp $@-at2.o65 $@-at2.ok
# cmp $@-ad4.o65 $@-ad4.ok
c65ce02: c65ce02-at2.o65 c65ce02-ad4.o65
c65ce02-at2.o65: at2.o65
${RELOC} -C 65CE02 -o $@ $?
../hextool -cmp=$@.ok $@
c65ce02-ad4.o65: ad4.o65
${RELOC} -C 65CE02 -o $@ $?
../hextool -cmp=$@.ok $@
#c65sc02: at2.o65 ad4.o65
# for i in $^; do ${RELOC} -C 65SC02 -o $@-$$i $$i; done
# cmp $@-at2.o65 $@-at2.ok
# cmp $@-ad4.o65 $@-ad4.ok
c65sc02: c65sc02-at2.o65 c65sc02-ad4.o65
c65sc02-at2.o65: at2.o65
${RELOC} -C 65SC02 -o $@ $?
../hextool -cmp=$@.ok $@
c65sc02-ad4.o65: ad4.o65
${RELOC} -C 65SC02 -o $@ $?
../hextool -cmp=$@.ok $@
#c65816: at2.o65 ad4.o65
# for i in $^; do ${RELOC} -C 65816 -o $@-$$i $$i; done
# cmp $@-at2.o65 $@-at2.ok
# cmp $@-ad4.o65 $@-ad4.ok
c65816: c65816-at2.o65 c65816-ad4.o65
c65816-at2.o65: at2.o65
${RELOC} -C 65816 -o $@ $?
../hextool -cmp=$@.ok $@
c65816-ad4.o65: ad4.o65
${RELOC} -C 65816 -o $@ $?
../hextool -cmp=$@.ok $@
#n6502: at2.o65 ad4.o65
# for i in $^; do ${RELOC} -C NMOS6502 -o $@-$$i $$i; done
# cmp $@-at2.o65 $@-at2.ok
# cmp $@-ad4.o65 $@-ad4.ok
n6502: n6502-at2.o65 n6502-ad4.o65
n6502-at2.o65: at2.o65
${RELOC} -C NMOS6502 -o $@ $?
../hextool -cmp=$@.ok $@
n6502-ad4.o65: ad4.o65
${RELOC} -C NMOS6502 -o $@ $?
../hextool -cmp=$@.ok $@
cpus: c65816 c6502 n6502 c65sc02 c65c02 c65ce02
# prereq for the following
relocsame: cpus
${RELOC} -o $@.o65 c65816-ad4.o65
../hextool -cmp=c65816-ad4.o65 $@.o65
${RELOC} -o $@.o65 c65sc02-at2.o65
../hextool -cmp=c65sc02-at2.o65 $@.o65
overwrite: cpus
# overwrite 65816 with nmos 6502
${RELOC} -C NMOS6502 -o $@-1.o65 c65816-at2.o65
../hextool -cmp=n6502-at2.o65 $@-1.o65
# overwrite 65sc02 with 65c02
${RELOC} -C 65C02 -o $@-2.o65 c65sc02-ad4.o65
../hextool -cmp=c65c02-ad4.o65 $@-2.o65
linkup1.tmp: cpus
${LDO} -v -o $@.tmp c6502-ad4.o65 c65c02-at2.o65 c65sc02-ad4.o65
${FILE} $@.tmp > $@
../hextool -cmp=$@.ok $@
linkup2:
# incompatible links
${LDO} ${VERBOSE} -o $@.o65 c6502-ad4.o65 c65c02-at2.o65 c65816-ad4.o65 || exit 0 && exit 1
${LDO} ${VERBOSE} -o $@.o65 c6502-ad4.o65 c65ce02-at2.o65 c65816-ad4.o65 || exit 0 && exit 1
${LDO} ${VERBOSE} -o $@.o65 c6502-ad4.o65 c65816-at2.o65 c65c02-ad4.o65 || exit 0 && exit 1
${LDO} ${VERBOSE} -o $@.o65 c6502-ad4.o65 c65816-at2.o65 c65ce02-ad4.o65 || exit 0 && exit 1
${LDO} ${VERBOSE} -o $@.o65 c65816-at2.o65 c65ce02-ad4.o65 c65c02-at2.o65 || exit 0 && exit 1
${LDO} ${VERBOSE} -o $@.o65 n6502-at2.o65 c65ce02-ad4.o65 || exit 0 && exit 1
${LDO} ${VERBOSE} -o $@.o65 n6502-at2.o65 c65c02-ad4.o65 || exit 0 && exit 1
${LDO} ${VERBOSE} -o $@.o65 n6502-at2.o65 c65sc02-ad4.o65 || exit 0 && exit 1
${LDO} ${VERBOSE} -o $@.o65 n6502-at2.o65 c65816-ad4.o65 || exit 0 && exit 1
clean:
rm -f *.o65 *.tmp

6
xa/tests/mode/ab1.a65 Normal file
View File

@ -0,0 +1,6 @@
.align 1
.bss
.byt 0

6
xa/tests/mode/ab2.a65 Normal file
View File

@ -0,0 +1,6 @@
.align 2
.bss
.byt 0

6
xa/tests/mode/ab256.a65 Normal file
View File

@ -0,0 +1,6 @@
.align 256
.bss
.byt 0

6
xa/tests/mode/ab4.a65 Normal file
View File

@ -0,0 +1,6 @@
.align 4
.bss
.byt 0

6
xa/tests/mode/ad1.a65 Normal file
View File

@ -0,0 +1,6 @@
.align 1
.data
.byt 0

6
xa/tests/mode/ad2.a65 Normal file
View File

@ -0,0 +1,6 @@
.align 2
.data
.byt 0

6
xa/tests/mode/ad256.a65 Normal file
View File

@ -0,0 +1,6 @@
.align 256
.data
.byt 0

6
xa/tests/mode/ad4.a65 Normal file
View File

@ -0,0 +1,6 @@
.align 4
.data
.byt 0

4
xa/tests/mode/at1.a65 Normal file
View File

@ -0,0 +1,4 @@
.align 1
iny

4
xa/tests/mode/at2.a65 Normal file
View File

@ -0,0 +1,4 @@
.align 2
iny

4
xa/tests/mode/at256.a65 Normal file
View File

@ -0,0 +1,4 @@
.align 256
iny

4
xa/tests/mode/at4.a65 Normal file
View File

@ -0,0 +1,4 @@
.align 4
iny

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,7 @@
linkup1.tmp.tmp: o65 version 0 executable file
mode: 0012 =[executable][16bit][byte relocation][CPU 6502][CPU2 65C02][align 4]
text segment @ $0400 - $0401 [$0001 bytes]
data segment @ $1000 - $1005 [$0005 bytes]
bss segment @ $4000 - $4000 [$0000 bytes]
zero segment @ $0002 - $0002 [$0000 bytes]
stack size $0000 bytes (i.e. unknown)

Binary file not shown.

Binary file not shown.

BIN
xa/tests/mode/test1.o65.ok Normal file

Binary file not shown.

BIN
xa/tests/mode/test2.o65.ok Normal file

Binary file not shown.

BIN
xa/tests/mode/test3.o65.ok Normal file

Binary file not shown.