CPU handling in file65, reloc65, and ldo65

This commit is contained in:
Andre Fachat 2023-11-29 13:48:04 +01:00
parent cc03ac80be
commit e51b1e7f41
18 changed files with 260 additions and 38 deletions

View File

@ -47,6 +47,15 @@ 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
"6502" - documented 6502 opcodes only
"NMOS6502" - "6502" plus undocumented opcodes are being used
"65SC02" - extends "6502" with the CMOS opcodes, except BBR/BBS/SMB/RMB
"65C02" - extends "65SC02" with the BBR/BBS/SMB/RMB opcodes
"65CE02" - extends 65C02 with additional CE-specific opcodes
"65816" - i.e. 65816 in 6502 emulation mode; extends "65SC02"(!)
.TP
.B \-\-help
Show summary of options.
.TP

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;
@ -133,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)
@ -189,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);
}
@ -201,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':
@ -271,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++;
@ -305,20 +337,10 @@ int main(int argc, char *argv[]) {
{
int er = 0;
int trgcpu = 0;
const char *modenames[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"
};
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];
@ -340,7 +362,11 @@ int main(int argc, char *argv[]) {
trgmode |= 0x0200;
}
// CPU bits
fcpu = (file->mode & 0x00f0) >> 4;
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;
@ -350,17 +376,26 @@ int main(int argc, char *argv[]) {
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, modenames[fcpu]);
file->fname, fcpu, cpunames[fcpu]);
er = 1;
}
// fall-through
case 0x2: // 65SC02 - CMOS without BBR/BBS/RMB/SMB, compatible with 65816
case 0x5: // 65816 in 6502 emulation mode
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, modenames[fcpu], trgcpu, modenames[trgcpu]);
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;
@ -370,19 +405,19 @@ int main(int argc, char *argv[]) {
// 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, modenames[fcpu], trgcpu, modenames[trgcpu]);
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, modenames[4]);
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, modenames[fcpu], file->fname);
fcpu, cpunames[fcpu], file->fname);
}
break;
}
@ -412,10 +447,15 @@ int main(int argc, char *argv[]) {
}
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);
@ -515,7 +555,7 @@ 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("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",

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

@ -6,8 +6,10 @@ VERBOSE=
XA=../../xa
LDO=../../ldo65
RELOC=../../reloc65
FILE=../../file65
all: test1 test2 test3 test4
all: test1 test2 test3 test4 cpus relocsame overwrite linkup1 linkup2
%.o65: %.a65
${XA} -R -o $@ $<
@ -17,7 +19,6 @@ test1: ${FILES}
${LDO} ${VERBOSE} -o $@.o65 $^
cmp $@.o65 $@.ok
# test with files in order of decreasing align
test2: ${FILES}
${LDO} ${VERBOSE} -o $@.o65 ab256.o65 ab4.o65 ab2.o65 ab1.o65 ad256.o65 ad4.o65 ad2.o65 ad1.o65 at256.o65 at4.o65 at2.o65 at1.o65
@ -35,6 +36,70 @@ test4: ${FILES}
${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
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
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
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
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
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
cpus: c65816 c6502 n6502 c65sc02 c65c02 c65ce02
# prereq for the following
relocsame:
${RELOC} -o $@.o65 c65816-ad4.o65
cmp $@.o65 c65816-ad4.o65
${RELOC} -o $@.o65 c65sc02-at2.o65
cmp $@.o65 c65sc02-at2.o65
overwrite:
# overwrite 65816 with nmos 6502
${RELOC} -C NMOS6502 -o $@-1.o65 c65816-at2.o65
cmp $@-1.o65 n6502-at2.o65
# overwrite 65sc02 with 65c02
${RELOC} -C 65C02 -o $@-2.o65 c65sc02-ad4.o65
cmp $@-2.o65 c65c02-ad4.o65
linkup1:
${LDO} -v -o $@.o65 c6502-ad4.o65 c65c02-at2.o65 c65sc02-ad4.o65
${FILE} $@.o65 > $@.tmp
cmp $@.tmp $@.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
rm -f *.o65 *.tmp

BIN
xa/tests/mode/c6502-ad4.ok Normal file

Binary file not shown.

BIN
xa/tests/mode/c6502-at2.ok Normal file

Binary file not shown.

BIN
xa/tests/mode/c65816-ad4.ok Normal file

Binary file not shown.

BIN
xa/tests/mode/c65816-at2.ok Normal file

Binary file not shown.

BIN
xa/tests/mode/c65c02-ad4.ok Normal file

Binary file not shown.

BIN
xa/tests/mode/c65c02-at2.ok Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

7
xa/tests/mode/linkup1.ok Normal file
View File

@ -0,0 +1,7 @@
linkup1.o65: 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)

BIN
xa/tests/mode/n6502-ad4.ok Normal file

Binary file not shown.

BIN
xa/tests/mode/n6502-at2.ok Normal file

Binary file not shown.