1
0
mirror of https://github.com/fachat/xa65.git synced 2024-06-17 20:29:32 +00:00
This commit is contained in:
Andre Fachat 2023-11-02 10:12:39 +01:00
parent c46dae2105
commit 77471ee3d9
32 changed files with 1328 additions and 149 deletions

View File

@ -399,25 +399,35 @@ xa-2.3.14
xa-2.4.0
* Listing feature.
* Listing feature in plain text or HTML.
* Add -E commandline option to not stop after 20 errors, but show all
of them
of them.
* Introduce -X compatibility set commandline option, to distinguish
between MASM and CA65 compatibility options.
between MASM and CA65 compatibility options; also adds C option for
0x and 0 to specify hex or octal. As a result, -M is now deprecated,
and colons in comments may become the default in a future version.
* Implement CA65 "cheap local labels", ":=" label definitions,
and various pseudo opcodes (.include, .import, .importzp,
.zeropage, .proc (anonymous only), .endproc, .code, .org, .reloc).
* -U option to allow all undefined labels in relocation mode; this
allows exporting them to an o65 file and link at a later time.
allows exporting them to an o65 file and link at a later time (or
specify one at a time with -L).
* Globals may also be specified manually with -g.
* #error allows preprocessor-level assertions.
* .assert allows assembler-level assertions.
* Better fix for segfault with smaller arity macro issue.
* Main Makefile fixes.
* Fixed parallel make in tests, incorporating a patch from Sergei
Trofimovich.
* Some 2.3.x features still allowed with -XXA23, which is obviously
deprecated.
* The quote escape character is now the \ (backslash), except if -XXA23.
* Recursive /* */ comments are no longer allowed, except if -XXA23.
* XA_MAJOR and XA_MINOR predefined macros, except if -XXA23.
* Testsuite expanded.
-- André Fachat <afachat@gmx.de> 13 October, 2023
* Deprecated options (16-bit mvn/mvp argument, -S, -x) finally removed.
If you need this support, you must use 2.3.x.
* Makefile fixes.
* Parallel make disabled for testing (fixes failures, makes output
easier to parse). Parallel make obviously works fine for building.
-- André Fachat <afachat@gmx.de> 13 October, 2023
-- Cameron Kaiser <ckaiser@floodgap.com> XXX

View File

@ -38,8 +38,8 @@ killxa:
xa:
(cd src && LD=${LD} CC="${CC} ${CFLAGS}" ${MAKE})
load:
(cd loader && CC="${CC} ${CFLAGS}" ${MAKE})
#load:
# (cd loader && CC="${CC} ${CFLAGS}" ${MAKE})
uncpk:
(cd misc && CC="${CC} ${CFLAGS}" ${MAKE})
@ -55,7 +55,7 @@ mingw: clean
clean:
(cd src && ${MAKE} clean)
(cd loader && ${MAKE} clean)
#(cd loader && ${MAKE} clean)
(cd misc && ${MAKE} mrproper)
rm -f xa *.exe *.o65 *.s core

View File

@ -40,6 +40,8 @@ Fabian Nunez. For mingw, use
make mingw
(but do it from within MSYS2).
Similarly, Amiga and Atari ST compilation should still also function with
their particular compatible packages.

View File

@ -12,7 +12,7 @@ o The listing feature is not bug-free yet:
E.g. a CA65 ".scope" will appear as ".(" in the listing
- The assembler has no pre-processor handling, so pp constants are
resolved at parse time. Thus they appear as their value
in the listing.
in the listing.
- One situation is ".listbytes unlimited",
which will show as ".listbytes 0" in the listing

4
xa/attic/README Normal file
View File

@ -0,0 +1,4 @@
These are files that have been superseded and may be removed in the future.
loader/ Rewritten as tests/loader/

BIN
xa/attic/loader/rom65.ok Normal file

Binary file not shown.

View File

@ -13,9 +13,12 @@ prints file information for files in the o65 object format.
.SH OPTIONS
.TP
.B \-V
.B \-v
Print undefined and global labels.
.TP
.B \-vv
Print undefined and global labels, and relocation tables.
.TP
.B \-P
Print the segment end addresses (suitable for the
.BR xa (1)

View File

@ -9,7 +9,7 @@ ldo65 \- linker for o65 object files
.SH DESCRIPTION
.B ldo65
is a linker for files in the `o65' object format, formerly
is a linker for files in the o65 object format, formerly
.B ld65
but renamed to avoid conflicts with the
.B cc65
@ -32,9 +32,23 @@ man page for an explanation.
Set output filename. The default is
.BR a.o65 \&.
.TP
.B \-L name
Allow label
.B name
to remain undefined, even after linking.
This option may be specified multiple times for multiple labels.
.TP
.B \-U
Allow any label to remain undefined, even after linking.
.TP
.B \-G
Suppress writing of globals.
.TP
.B \-g name
Only export global
.BR name .
This option may be specified multiple times for multiple globals.
.TP
.B \-\-help
Show summary of options.
.TP

View File

@ -19,6 +19,9 @@ object format.
Set output filename. The default is
.BR a.o65 \&.
.TP
.B \-v
Verbose output.
.TP
.B \-b? addr
Relocate segment
.B ?

View File

@ -49,19 +49,21 @@ use the special filename
to output to standard output.
.TP
.B \-P filename
Set listing filename, default is none. use the special filename
Set listing filename. The 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
.B \-F format
Set listing format; default is
.BR plain .
The only other currently supported format is
.BR html .
.TP
.B \-e filename
Set errorlog filename, default is none.
Set errorlog filename; default is none.
.TP
.B \-l filename
Set labellist filename, default is none. This is the symbol table and can
Set labellist filename; default is none. This is the symbol table and can
be used by disassemblers such as
.BR dxa (1)
to reconstruct source.
@ -71,20 +73,63 @@ 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 "="), 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".
Enables compatibility settings to become more (not fully!) compatible with other 6502 assemblers and codebases.
Currently supported are compatibility sets
.BR MASM ,
.BR CA65
and
.BR C ,
with
.B XA23
available as a deprecated option for codebases relying on compatibility with
the previous version of
.BR xa .
Multiple compatibility sets may be specified and combined, e.g.,
.B \-XMASM
.BR \-XXA23 .
.IP
.B \-XMASM
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.
.IP
.B \-XCA65
adds syntactic features more compatible with
.BR ca65 (1).
It permits
.B :=
for defining labels (instead of plain
.BR = ),
and adds support for unnamed labels and "cheap" local labels using the
.B @
character, but disables its other meaning for 24-bit mode (see
.B ASSEMBLER
.BR SYNTAX ).
.IP
.B \-XC
enables the usage of
.B 0xHEX
and
.B 0OCTAL
C-style number encodings.
.IP
.B \-XXA23
restores partial compatibility with
.B xa
2.3.x. In particular, it uses
.B ^
for quote escapes instead of 2.4's
.BR \e ,
allows nested multi-line comments, and disables all predefined
.B xa
preprocessor macros. This option is inherently deprecated and may be removed
in the next 2.x or 3.x release.
.TP
.B \-M
Allow colons to appear in comments; for MASM compatibility. This does
not affect colon interpretation elsewhere. This option is deprecated. Use
.BR -X
instead.
This option is deprecated; use
.B \-XMASM
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 \-R
Start assembler in relocating mode, i.e. use segments.
@ -148,27 +193,12 @@ Characters may need to be quoted for your shell (example:
).
.TP
.B \-\-help
Show summary of options.
Show summary of options
.RB ( -?
is a synonym).
.TP
.B \-\-version
Show version of program.
.LP
The following options are
.BR deprecated
and will be removed in 2.4 and later versions:
.TP
.B \-x
Use old filename behaviour (overrides
.BR \-o ,
.B \-e
and
.BR \-l ).
.TP
.B \-S
Allow preprocessor substitution within strings (this is now disallowed
for better
.BR cpp (1)
compatibility).
.SH ASSEMBLER SYNTAX
@ -204,9 +234,15 @@ decimal value
.TP
.B $234
hexadecimal value
.RB ( 0x234
accepted with
.BR -XC )
.TP
.B &123
octal
.RB ( 0123
accepted with
.BR -XC )
.TP
.B %010110
binary
@ -248,7 +284,14 @@ statements such as
.IP
.B * = $c000
.LP
which sets the program counter to decimal location 49152. With the exception
which sets the program counter to decimal location 49152. If
.B \-XCA65
is specified, you can also use
.B :=
as well as
.BR = .
.LP
With the exception
of the program counter, labels cannot be assigned multiple times. To explicitly
declare redefinition of a label, place a - (dash) before it, e.g.,
.IP
@ -263,6 +306,52 @@ for block instructions). A label may also be hard-specified with the
.B \-L
command line option.
.LP
If
.B \-XCA65
is specified, "cheap" local labels may be used and/or redefined, marked by the
.B @
prefix. Additionally, 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
documentation),
.LP
: lda (ptr1),y ; #1
.BR
cmp (ptr2),y
.BR
bne :+ ; -> #2
.BR
tax
.BR
beq :+++ ; -> #4
.BR
iny
.BR
bne :- ; -> #1
.BR
inc ptr1+1
.BR
inc ptr2+1
.BR
bne :- ; -> #1
.BR
.BR
: bcs :+ ; #2 -> #3
.BR
ldx #$FF
.BR
rts
.BR
.BR
: ldx #$01 ; #3
.BR
: rts ; #4
.LP
Redefining a label does not change previously assembled code that used the
earlier value. Therefore, because the program counter is a special type of
label, changing the program counter to a lower value does not reorder code
@ -335,10 +424,14 @@ less than or equal to (7)
less than (7)
.TP
.B =
equal to (6)
equal to (6);
.B ==
also accepted
.TP
.B <> ><
does not equal (6)
does not equal (6);
.B !=
also accepted
.TP
.B &
bitwise AND (5)
@ -389,7 +482,8 @@ 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, must not specify the CA65 compatibility).
command-line option, must not specify
.BR \-XCA65 ).
.B This is required to specify any
.B 24-bit quantity!
.TP
@ -449,8 +543,9 @@ comments, such that
.B ; a comment:lda #0
.LP
is understood as a comment followed by an opcode. To defeat this, use the
.B \-M
command line option to allow colons within comments. This does not apply to
.B \-XMASM
compatibility mode to allow colons within comments; this may become the
default in a future version. Colon statement separation does not apply to
.B /* */
and
.B //
@ -546,19 +641,22 @@ 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.
.B \&.)
is equivalent to
.B .block
or
.B .proc
. The latter is similar to the ca65 pseudo-opcode, but only anonymous blocks
are supported.
.IP
.B \.block
is accepted as a synonym for
.BR \&.) ,
as well as
.B \.proc
(but you cannot specify an explicit scope name as in
.BR ca65 ;
only anonymous blocks are supported).
.TP
.B \&.)
Closes a block. This is equivalent to
Closes a block.
.B .bend
or
.B .endproc
are accepted as synonyms.
.
.TP
.B \.as \.al \.xs \.xl
@ -587,14 +685,44 @@ 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 \.assert expression,"message"
Evaluates
.B expression
and if it is false (i.e., evaluates to zero), prints
.B message
as a fatal error, terminating assembly immediately.
For example, a block of assembly code
that creates high ROM might have
.IP
\&.assert *<$fffa, "hit vectors"
.IP
to ensure that assembled code does not leak into the 6502 high vectors. If
the preceding code is too long, the assertion will be false, and the
condition will be detected in a controlled fashion. Any operation may be
used as part of the expression, including logical comparisons such as
.BR = ,
.BR == ,
.BR < ,
.BR <= ,
.BR > ,
.BR >= ,
.B !=
and
.BR <> .
.TP
.B \.include "filename"
Includes another file in place of the pseudo-op, as if the preprocessor had
done so with an
.B #include
directive (see
.BR PREPROCESSOR ).
.LP
The following pseudo-ops apply primarily to relocatable .o65 objects.
The following pseudo-ops apply primarily to relocatable
.B .o65
objects.
A full discussion of the relocatable format is beyond the
scope of this manpage, as it is currently a format in flux. Documentation
scope of this manpage. Documentation
on the proposed v1.2 format is in
.B doc/fileformat.txt
within the
@ -602,16 +730,32 @@ within the
installation directory.
.TP
.B .text .data .bss .zero
These pseudo-ops switch between the different segments, .text being the actual
code section, .data being the data segment, .bss being uninitialized label
space for allocation and .zero being uninitialized zero page space for
allocation. In .bss and .zero, only labels are evaluated. These pseudo-ops
These pseudo-ops switch between the different segments,
.B .text
being the actual code section,
.B .data
being the data segment,
.B .bss
being uninitialized label space for allocation and
.B .zero
being uninitialized zero page space for allocation. In
.B .bss
and
.BR .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".
For
.B ca65
compatibility, this is currently mapped to
.BR .text .
.TP
.B .zeropage
For CA65 compatibility this is currently mapped to ".zero".
For
.B ca65
compatibility, this is currently mapped to
.BR .zero .
.TP
.B .align value
Aligns the current segment to a byte boundary (2, 4 or 256) as specified by
@ -620,7 +764,7 @@ value
(and places it in the header when relative mode is enabled). Other values
generate an error.
.TP
.B .fopt type,value1,value2,value3,...
.B .fopt type, value1, value2, value3, ...
Acts like
.B .byt/.asc
except that the values are embedded into the object file as file options.
@ -633,14 +777,14 @@ 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
the link stage, like the
.B -L
command line parameter
command line parameter.
.TP
.B .importzp label1, label2, label3, ...
Similar to
.B .import
only it imports zeropage labels (i.e. byte values)
Analogous to
.BR .import ,
except that it only imports zeropage labels (i.e., byte values).
.SH PREPROCESSOR
@ -724,8 +868,19 @@ may interpret too early until the file actually gets to
.B xa
itself for processing.
.LP
The following preprocessor directives are supported.
The following predefined macros are supported, except if
.B \-XXA23
is specified:
.TP
.B XA_MAJOR
The current major version of
.BR xa .
.TP
.B XA_MINOR
The current minor version of
.BR xa .
.LP
The following preprocessor directives are supported:
.TP
.B #include """filename"""
Inserts the contents of file
@ -750,6 +905,9 @@ Computes the value of expression
.B expression
and prints it into the errorlog file.
.TP
.B #error message
Displays the message as an error and terminates assembly.
.TP
.B #define DEFINE text
Equates macro
.B DEFINE
@ -979,8 +1137,8 @@ and
use two eight bit parameters, the only instructions in the entire
instruction set to do so. Older versions of
.B xa
took a single 16-bit absolute value. Since 2.3.7, the standard syntax is
now accepted and the old syntax is deprecated (a warning will be generated).
took a single 16-bit absolute value. As of 2.4.0, this old syntax is
no longer accepted.
.LP
Forward-defined labels -- that is, labels that are defined after the current
instruction is processed -- cannot be optimized into zero
@ -1014,20 +1172,6 @@ be prepended with the
prefix. Otherwise, the assembler will attempt to optimize to 16 bits, which
may be undesirable.
.SH "IMMINENT DEPRECATION"
The following options and modes will be
.B REMOVED
in 2.4 and later versions of
.BR xa :
.LP
.B \-x
.LP
.B \-S
.LP
the original
.B mvn $xxxx
syntax
.SH "SEE ALSO"
.BR file65 (1),
.BR ldo65 (1),

View File

@ -124,7 +124,6 @@ file65 file;
unsigned char cmp[] = { 1, 0, 'o', '6', '5' };
unsigned char hdr[26] = { 1, 0, 'o', '6', '5', 0 };
int verbose = 0;
void usage(FILE *fp)
{
@ -140,7 +139,6 @@ void usage(FILE *fp)
" -U accept any undef'd labels after linking\n"
" -L<name> accept specific given undef'd labels after linking\n"
" -g<name> only export the globals defined with (multiple) -g options\n"
" -v verbose output\n"
" --version output version information and exit\n"
" --help display this help and exit\n",
programname);
@ -188,13 +186,6 @@ int main(int argc, char *argv[]) {
while(i<argc && argv[i][0]=='-') {
/* process options */
switch(argv[i][1]) {
case 'v':
j=1;
while (argv[i][j]=='v') {
verbose++;
j++;
}
break;
case 'G':
noglob=1;
break;
@ -304,19 +295,6 @@ printf("tbase=%04x+len=%04x->%04x, file->tbase=%04x, f.tlen=%04x -> tdiff=%04x\n
printf("zbase=%04x+len=%04x->%04x, file->zbase=%04x, f.zlen=%04x -> zdiff=%04x\n",
zbase, tzlen, (zbase + tzlen), file->zbase, file->zlen, file->zdiff);
*/
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",
file->zbase, file->zbase + file->zdiff, file->zdiff, file->zlen);
}
/* update globals (for result file) */
ttlen += file->tlen;
tdlen += file->dlen;
@ -699,21 +677,17 @@ int len_reloc_seg(unsigned char *buf, int ri) {
unsigned char *reloc_globals(unsigned char *buf, file65 *fp) {
int n, old, new, seg;
char *name;
n = buf[0] + 256*buf[1];
buf +=2;
while(n) {
name = buf;
/*printf("relocating %s, ", buf);*/
while(*(buf++));
seg = *buf & 0x07;
seg = *buf;
old = buf[1] + 256*buf[2];
new = old + reldiff(seg);
if (verbose > 1) {
printf("%s:%s: old=%04x, seg=%d, rel=%04x, new=%04x\n",
fp->fname, name, old, seg, reldiff(seg), new);
}
/*printf("old=%04x, seg=%d, rel=%04x, new=%04x\n", old, seg, reldiff(seg), new);*/
buf[1] = new & 255;
buf[2] = (new>>8) & 255;
buf +=3;

View File

@ -707,9 +707,6 @@ int ll_pdef(char *t)
return(E_NODEF);
}
/*
* Write out the list of global labels in an o65 file
*/
int l_write(FILE *fp)
{
int i, afl, n=0;
@ -719,39 +716,25 @@ int l_write(FILE *fp)
fputc(0, fp);
return 0;
}
// calculate number of global labels
for (i=0;i<afile->la.lti;i++) {
ltp=afile->la.lt+i;
if((!ltp->blk) && (ltp->fl==1)) {
n++;
}
}
// write number of globals to file
fputc(n&255, fp);
fputc((n>>8)&255, fp);
// iterate over labels and write out label
for (i=0;i<afile->la.lti;i++)
{
ltp=afile->la.lt+i;
if((!ltp->blk) && (ltp->fl==1)) {
// write global name
fprintf(fp, "%s",ltp->n);
fputc(0,fp);
// segment byte
afl = ltp->afl;
// hack to switch undef and abs flag from internal to file format
// if asolute of undefined (< SEG_TEXT, i.e. 0 or 1)
// then invert bit 0 (0 = absolute)
if( (afl & (A_FMASK>>8)) < SEG_TEXT) {
afl^=1;
}
// remove residue flags, only write out real segment number
// according to o65 file format definition
afl = afl & (A_FMASK >> 8);
/* hack to switch undef and abs flag from internal to file format */
/*printf("label %s, afl=%04x, A_FMASK>>8=%04x\n", ltp->n, afl, A_FMASK>>8);*/
if( (afl & (A_FMASK>>8)) < SEG_TEXT) afl^=1;
fputc(afl,fp);
// value
fputc(ltp->val&255, fp);
fputc((ltp->val>>8)&255, fp);
}

View File

@ -38,6 +38,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"
listing/ Test of listing feature
op816/ Regression test for '816 opcodes (thanks Alessandro Gatti)
branch/ Branch range test
masmcom/ Another test for -M that generates totally valid code
@ -49,6 +50,8 @@ alxl/ Various '816 width tests (includes Samuel Falvo's test)
pparity/ Tests of preprocessor macro arity (with Emil Johansson's test)
recucom/ Recursive comments test
aserror/ Tests of .assert and #error syntax/function
loader/ Old ../loader tests, moved into test suite proper
reset_segment/ Verifies conditions under which a segment is reset
Cameron Kaiser, André Fachat

19
xa/tests/loader/Makefile Normal file
View File

@ -0,0 +1,19 @@
all: loader example test2 rom65
clean:
rm -f loader test2 example a.o65 rom65
loader: loader.a65 file.def
../../xa loader.a65 -o loader
example: test.a
../../xa -R test.a -o example
test2: test2.a
../../xa test2.a -o test2
rom65: test.a
# ugly!
( cd .. && ../mkrom.sh -O "-G" -S "-bd 1234" -R loader/rom65 loader/test.a loader/test.a )
../hextool -cmp=rom65.ok < rom65

8
xa/tests/loader/README Normal file
View File

@ -0,0 +1,8 @@
In this directory you find two test files, i.e. test.a and test2.a for
xa. test.a is assembled into the file "example", which is loaded by the
relocator "loader", when started on a C64. Don't try to execute this
file, it's just for testing.

BIN
xa/tests/loader/ex2 Normal file

Binary file not shown.

BIN
xa/tests/loader/example2 Normal file

Binary file not shown.

36
xa/tests/loader/file.def Normal file
View File

@ -0,0 +1,36 @@
/* These definitions are without the two leading version/marker bytes,
* length is without options
*/
#define HDR_MAGIC 0
#define HDR_VERSION 3
#define HDR_MODE 4
#define HDR_TBASE 6
#define HDR_TLEN 8
#define HDR_DBASE 10
#define HDR_DLEN 12
#define HDR_BBASE 14
#define HDR_BLEN 16
#define HDR_ZBASE 18
#define HDR_ZLEN 20
#define HDR_STACKLEN 22
#define HDR_LEN 24
#define A_ADR $80
#define A_HIGH $40 /* or'd with the low byte */
#define A_LOW $20
#define A_MASK $e0 /* reloc type mask */
#define A_FMASK $0f /* segment type mask */
#define SEG_UNDEF 0
#define SEG_ABS 1
#define SEG_TEXT 2
#define SEG_DATA 3
#define SEG_BSS 4
#define SEG_ZERO 5
#define FM_OBJ %00010000
#define FM_SIZE %00100000
#define FM_RELOC %01000000
#define FM_CPU %10000000

909
xa/tests/loader/loader.a65 Normal file
View File

@ -0,0 +1,909 @@
/**************************************************************************
*
* Loader for 6502 relocatable binary format
*
* The loader supports 16 bit o65 version 1 files without undefined
* references. Also it doesn't like pagewise relocation and 65816
* code, because there are different/additional relocation entries.
*
* The support routines, that have to be changed are at the end of the
* file. The stuff in this file is in absolute format (well, you have to
* bootstrap from something :-)
* The support routines for the file handling are for the operating system
* OS/A65, as of version 1.3.10b. The first part of the file (wrapped in
* "#ifdef C64") shows how to use it with a C64, for example.
*
* The subroutine 'loader' is called with a file descriptor, that has a
* meaning for the support routines, in the X register.
* The file must already be open. Also binit must have been called before.
* The loader doesn't close the file.
*
* Support routines are:
* binit a = hi byte start address memory to handle,
* x = hi byte length of memory to handle
* balloc a/y = length of block -> x = memory descriptor
* bfree x = memory block descriptor to free
* getbadr x = memory descriptor -> a/y address of memory block
*
* zalloc a = length of needed zeropage block. returns a=address
* zfree a = address of block to free
*
* fgetc x = file descriptor, returns read byte (c=0) or error (c=1)
* The error is passed through; fgetc blocks if no data
* available
* fgetb x = filedescriptor, a/y = address of block descriptor,
* i.e. a word start address and a word length of block.
* returns (c=0) or error in accu (c=1).
*
**************************************************************************/
/**************************************************************************
* This part is a binding for a C64
* to show how it works
*/
#define C64
#ifdef C64
sysmem =$033c
syszp =$57
.word $0801
*=$801
.word nextl
.word 10
.byt $9e, "2080",0
nextl .word 0
.dsb 2080-*, 0
c64load .(
lda #>PRGEND+255
ldx #>$A000-PRGEND
jsr binit ; init memory handling
lda #7
ldx #<fname
ldy #>fname
jsr $ffbd ; setfnpar
lda #2
ldx #11
ldy #0
jsr $ffba ; setfpar
jsr $ffc0 ; open
bcs end
ldx #2
jsr $ffc6 ; chkin
bcs end
jsr loader ; don't care about x, chkin did it
php
pha
jsr $ffcc ; clrch
lda #2
jsr $ffc3 ; close
pla
plp
end rts
fname ;.asc "example",0
.byt $45, $58, $41, $4d, $50, $4c, $45, 0
.)
fgetc .(
jsr $ffcf
php
pha
bcc carry
lda #"C"
jsr $ffd2
pla
pha
carry
jsr hexout
lda #$20
jsr $ffd2
pla
plp
rts
.)
hexout .(
pha
lsr
lsr
lsr
lsr
jsr nibout
pla
nibout and #$0f
clc
adc #$30
cmp #$3a
bcc ok
adc #$41-$3a-1
ok jmp $ffd2
.)
zalloc .(
cmp #$80 ; save from $90 upward = OS, below is only basic
bcs end
lda #$10
end rts
.)
zfree .(
clc
rts
.)
#endif
/**************************************************************************
* Here is the real loader code
*/
#include "file.def"
#define E_NOMEM <-40
#define E_FVERSION <-41
loader .(
p1 =syszp
p2 =syszp+2
-syszp +=4
tmp =sysmem
file =sysmem+1
-sysmem +=2
header =sysmem
-sysmem +=HDR_LEN
textb =sysmem ; memory block ID
texta =sysmem+1 ; address of block
textl =sysmem+3 ; address of block
textd =sysmem+5 ; difference to assemble address
-sysmem +=7
datab =sysmem
dataa =sysmem+1
datal =sysmem+3
datad =sysmem+5
-sysmem +=7
bssb =sysmem
bssa =sysmem+1
bssd =sysmem+3
-sysmem +=5
zeroa =sysmem
zerod =sysmem+1
-sysmem +=3
stx file
jsr fgetc
bcs end
sta tmp
jsr fgetc
bcs end
tay
lda tmp
cpy #0
bne rt
cmp #1
beq load
rt lda #E_FVERSION ; ok, but not this version
end sec
rts
load .(
lda #<header
sta p1
lda #>header
sta p1+1
lda #<HDR_LEN
sta p1+2
lda #>HDR_LEN
sta p1+3
ldx file
lda #<p1
ldy #>p1
jsr fgetb
bcs end
; header loaded, check magic and version
lda header+HDR_MAGIC
cmp #$6f
bne end
lda header+HDR_MAGIC+1
cmp #"6"
bne end
lda header+HDR_MAGIC+2
cmp #"5"
bne end
lda header+HDR_VERSION
cmp #0
bne end
lda header+HDR_MODE+1
and #%11110000
bne end
; now allocate buffers
lda header+HDR_TLEN
ldy header+HDR_TLEN+1
sta textl
sty textl+1
jsr balloc
stx textb
bcs no_text2
jsr getbadr
sta texta
sty texta+1
sec
sbc header+HDR_TBASE
sta textd
tya
sbc header+HDR_TBASE+1
sta textd+1
lda header+HDR_DLEN
ldy header+HDR_DLEN+1
sta datal
sty datal+1
jsr balloc
stx datab
bcs no_data2
no_text2 bcs no_text1
jsr getbadr
sta dataa
sty dataa+1
sec
sbc header+HDR_DBASE
sta datad
tya
sbc header+HDR_DBASE+1
sta datad+1
lda header+HDR_BLEN
ldy header+HDR_BLEN+1
jsr balloc
stx bssb
bcs no_bss
no_text1 bcs no_text
no_data2 bcs no_data
jsr getbadr
sta bssa
sty bssa+1
sec
sbc header+HDR_BBASE
sta bssd
tya
sbc header+HDR_BBASE+1
sta bssd+1
lda header+HDR_ZLEN
jsr zalloc
bcs no_zero
sta zeroa
sec
sbc header+HDR_ZBASE
sta zerod
lda #0
sta zerod+1
jmp do_load
&no_file lda zeroa
jsr zfree
no_zero ldx bssb
jsr bfree
no_bss ldx datab
jsr bfree
no_data ldx textb
jsr bfree
no_text rts
do_load ; load options (i.e. ignore them now)
jsr fgetc
bcs no_file
cmp #0
beq load_text
tay
dey
optl jsr fgetc
bcs no_file
dey
bne optl
beq do_load
load_text ; load text segment
ldx file
lda #<texta
ldy #>texta
jsr fgetb
bcs no_file
ldx file
lda #<dataa
ldy #>dataa
jsr fgetb
bcs no_file
; check number of undefined references
ldx file
jsr fgetc
&no_file2 bcs no_file
cmp #0
bne no_file ; we have some -> not handled
ldx file
jsr fgetc
bcs no_file
cmp #0
bne no_file
; ok, text segments loaded, now relocate
lda texta
sec
sbc #1
sta p1
lda texta+1
sbc #0
sta p1+1
jsr trel
lda dataa
sec
sbc #1
sta p1
lda dataa+1
sbc #0
sta p1+1
jsr trel
lda texta ; return start of text segment
ldy texta+1
clc
rts
.)
trel .(
ldx file
jsr fgetc
no_file1 bcs no_file2
cmp #0
beq reloc_rts
cmp #255
bne t1
lda #254
clc
adc p1
sta p1
bcc trel
inc p1+1
jmp trel
t1 clc
adc p1
sta p1
bcc t1a
inc p1+1
t1a ; p1 is the relocation address
ldx file
jsr fgetc
bcs no_file1
tay
and #A_MASK
sta tmp
tya
and #A_FMASK
jsr getreldiff
ldy tmp
cpy #A_ADR
bne t2
ldy #0
clc
adc (p1),y
sta (p1),y
iny
txa
adc (p1),y
sta (p1),y
jmp trel
t2
cpy #A_LOW
bne t3
ldy #0
clc
adc (p1),y
sta (p1),y
jmp trel
t3
cpy #A_HIGH
bne trel
sta p2
stx p2+1
ldx file
jsr fgetc
clc
adc p2 ; just get the carry bit
ldy #0
lda p2+1 ; relocate high byte
adc (p1),y
sta (p1),y
jmp trel
reloc_rts
clc
rts
.)
getreldiff .( ; comparing with SEG_UNDEF would give a way
; to get label value here for undefined refs
cmp #SEG_TEXT
bne notext
lda textd
ldx textd+1
rts
notext cmp #SEG_DATA
bne nodata
lda datad
ldx datad+1
rts
nodata cmp #SEG_BSS
bne nobss
lda bssd
ldx bssd+1
rts
nobss cmp #SEG_ZERO
bne nozero
lda zerod
ldx zerod+1
nozero rts
.)
.)
/**************************************************************************
* Here come the support routines
*
* first is a simple and basic implementation of fgetb, just using fgetc
*/
fgetb .(
p =syszp
-syszp +=2
file =sysmem
l =sysmem+1
-sysmem +=3
stx file ; x=file, a=zp-adr of address, y=zp-adr of len
sta p
sty p+1
ldy #3
lda (p),y
sta l+1
dey
lda (p),y
sta l
dey
lda (p),y
pha
dey
lda (p),y
sta p
pla
sta p+1
loop ldx file
jsr fgetc ; this is a simple implementation
bcs end
ldy #0
sta (p),y
inc p
bne l0
inc p+1
l0
lda l
bne l1
dec l+1
l1 dec l
lda l
ora l+1
bne loop
clc
end
rts
.)
/**************************************************************************
* support for memory allocation
*
* These routines are taken from a preliminary SLIP implementation, as of
* OS/A65 version 1.3.10b
*/
#define MAXSLOT 8
/**********************************************************************/
/* New memory management for IP buffers */
/* exports */
/* binit */
/* balloc, bfree, btrunc, bsplit, brealloc */
/* getbadr, getblen */
#define MINBUF 8
#define MINMASK %11111000
.(
slotladr =sysmem
slothadr =sysmem+MAXSLOT
slotllen =sysmem+MAXSLOT*2
slothlen =sysmem+MAXSLOT*3
-sysmem +=MAXSLOT*4
flist =sysmem
slot =sysmem+2
-sysmem +=3
p =syszp
p2 =syszp+2
p3 =syszp+4
p4 =syszp+6
-syszp +=8
/* init memory management */
&binit .(
sta p+1 ; hi byte startadress buffer
stx p2+1 ; hi byte length of buffer
lda #0
tay
l0 sta slotladr,y
sta slothadr,y
iny
cpy #MAXSLOT
bcc l0
sta p
tay
sta (p),y
iny
sta (p),y
iny
sta (p),y
iny
lda p2+1
sta (p),y
lda p
sta flist
lda p+1
sta flist+1
clc
rts
.)
/* a/y = size of buffer to be allocated -> x buffer-ID */
&balloc .(
/* walk along freelist, and take first matching buffer
length is made a multiple of 8 (for freelist connectors */
pha
jsr getbslot
pla
bcc gotslot
lda #E_NOMEM
rts
gotslot
stx slot
adc #MINBUF-1
and #MINMASK
sta slotllen,x
tya
adc #0
sta slothlen,x
lda #0
sta p2
sta p2+1
lda flist
sta p
lda flist+1
sta p+1
l0
ldy #2
lda (p),y
sec
sbc slotllen,x
sta p3
iny
lda (p),y
sbc slothlen,x
sta p3+1
bcs found
lda p
sta p2
lda p+1
sta p2+1
ldy #1
lda (p2),y
sta p+1
dey
lda (p2),y
sta p
ora p+1
bne l0
oops lda #E_NOMEM
sec
rts
found
/* ok, we found a free buffer: p points to the buffer, p2 to the
previous one. p3 is the length of the free buffer minus the
needed size. If the buffer is longer than needed, create a
new free buffer, then link new buffer to freelist */
lda p /* save buffer address */
sta slotladr,x
lda p+1
sta slothadr,x
lda p3 /* check length */
ora p3+1
beq nocreate
lda p /* get address of new free buffer */
clc
adc slotllen,x
sta p4
lda p+1
adc slothlen,x
sta p4+1
ldy #0 /* copy next pointer */
lda (p),y
sta (p4),y
iny
lda (p),y
sta (p4),y
iny /* set new length */
lda slotllen,x
sta (p),y
lda p3
sta (p4),y
iny
lda slothlen,x
sta (p),y
lda p3+1
sta (p4),y
lda p4
sta p
lda p4+1
sta p+1
nocreate
lda p2
ora p2+1
beq freestart
ldy #0
lda p
sta (p2),y
iny
lda p+1
sta (p2),y
clc
bcc geta
freestart
lda p
sta flist
lda p+1
sta flist+1
clc
geta
lda slotladr,x
ldy slothadr,x
rts
.)
/* free buffer (ID=xr) */
&bfree .(
lda slothadr,x
sta p3+1
lda slotladr,x
sta p3
ora p3+1
beq end2
ldy #2
lda slotllen,x
sta (p3),y
iny
lda slothlen,x
sta (p3),y
lda #0
sta slothadr,x
sta slotladr,x
lda flist
ora flist+1
bne ok /* no free buffer so far? */
lda p3
sta flist
lda p3+1
sta flist+1
ldy #0
tya
sta (p3),y
iny
sta (p3),y
end2 clc
rts
ok
lda #0
sta p2
sta p2+1
lda flist
sta p
lda flist+1
sta p+1
/* we have to find the place where to put the buffer in the
ordered free list. Then we have to check if we can merge
free buffers */
loop
lda p3+1
cmp p+1
bcc found
bne next
lda p3
cmp p
bcc found
next
lda p
sta p2
lda p+1
sta p2+1
ldy #0
lda (p2),y
sta p
iny
lda (p2),y
sta p+1
ora p
bne loop
beq found
end
clc
rts
found /* p2 is the buffer before the one to be freed, p the one behind.
p3 is the buffer to be inserted */
lda p2
ora p2+1
bne fok
; insert before the first free buffer so far
ldy #0
lda flist
sta (p3),y
iny
lda flist+1
sta (p3),y
lda p3
sta flist
ldy p3+1
sty flist+1
jsr bmerge
clc
rts
fok ; insert to list
ldy #1
lda p+1 ;lda (p2),y
sta (p3),y
dey
lda p ;lda (p2),y
sta (p3),y
lda p3
sta (p2),y
iny
lda p3+1
sta (p2),y
lda p3
ldy p3+1
jsr bmerge
lda p2
ldy p2+1
jsr bmerge
clc
rts
.)
/* get adress of buffer */
&getbadr .(
lda slotladr,x
ldy slothadr,x
clc
rts
.)
/* get length of buffer */
&getblen .(
lda slotllen,x
ldy slothlen,x
clc
rts
.)
/* get free buffer-ID slot */
getbslot .(
ldx #0
l0
clc
lda slotladr,x
ora slothadr,x
beq found
inx
cpx #MAXSLOT
bcc l0
found
rts
.)
/* check if two buffers (i.e. a/y plus following) can be merged */
bmerge .(
sta p
sty p+1
ldy #2
clc
lda (p),y
adc p
sta p3
iny
lda (p),y
adc p+1
sta p3+1
ldy #0
lda (p),y
cmp p3
bne nomerge
iny
lda (p),y
cmp p3+1
bne nomerge
merge
ldy #2
clc
lda (p3),y
adc (p),y
sta (p),y
iny
lda (p3),y
adc (p),y
sta (p),y
ldy #0
lda (p3),y
sta (p),y
iny
lda (p3),y
sta (p),y
nomerge
clc
rts
.)
.)
PRGEND

BIN
xa/tests/loader/rom65.ok Normal file

Binary file not shown.

36
xa/tests/loader/test.a Normal file
View File

@ -0,0 +1,36 @@
.fopt 1, "filename"
.(
.text
&absv = 4
lda #>test+4
bne test
*=$8000 ;*
lda <test
lo bvc lo
*=
test
lda (0),y
jmp (test)
.word *
.data
+bla
.word test
.byt <test-8, >test-8
.)
.text
nop
; .fopt 1, "filename"
lda bsslab
lda zerolab
lda #absv*2
.bss
bsslab
.dsb 20,1
.zero
zerolab
.dsb 20

28
xa/tests/loader/test2.a Normal file
View File

@ -0,0 +1,28 @@
*=$8000
.(
; .text
lda #>test+4
bne test
;*=*
lda <test
;*=
test
lda (0),y
jmp (test)
; .data
+bla
.word test
.byt <test-1, >test-1
.)
; .text
nop
lda bsslab
lda zerolab
; .bss
bsslab
.dsb 20,1
; .zero
zerolab
.dsb 20

3
xa/tests/loader/test3.a Normal file
View File

@ -0,0 +1,3 @@
lda #label
lab2