mirror of
https://github.com/fachat/xa65.git
synced 2024-06-01 22:41:32 +00:00
Compare commits
12 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
3be092964c | ||
|
e95549dfd1 | ||
|
0cfdf82384 | ||
|
b5c1e9b902 | ||
|
5d66d3a11a | ||
|
eff641bcff | ||
|
8becb7ecea | ||
|
4b54dd031e | ||
|
a98b3770ee | ||
|
c1fb2af9c2 | ||
|
1006018d26 | ||
|
13b4cf53d9 |
5
README
5
README
|
@ -5,11 +5,10 @@ xa65 is a 6502 cross assembler, running on Unix (and Unix-alikes), and producing
|
|||
|
||||
xa65 was originally authored by me, André Fachat, but currently and still xa65 is maintained by Cameron Kaiser at http://www.floodgap.com/retrotech/xa/ .
|
||||
|
||||
Due to current time constraints Cameron can not do any updates, so I decided to create this repository to publish my (beta) version that implements a long outstanding feature: assembler listings...
|
||||
|
||||
In this experimental repository, I am mirroring Cameron's releases and I am working on fixes and changes that I may want to submit to Cameron.
|
||||
|
||||
These are the directories:
|
||||
|
||||
xa - contains the main source. The master branch is the stable version (currently 2.3.5)
|
||||
xa - contains the main source. The master branch is the stable version
|
||||
|
||||
|
||||
|
|
151
xa/ChangeLog
151
xa/ChangeLog
|
@ -304,3 +304,154 @@ xa-2.3.6
|
|||
* Fixed message offsets.
|
||||
|
||||
-- Cameron Kaiser <ckaiser@floodgap.com> 11 July 2014
|
||||
|
||||
xa-2.3.7
|
||||
|
||||
* Fixed buffer overflow and test failure with gcc 4.9 (thanks Adam Sampson).
|
||||
* mvn and mvp now use the standard syntax (thanks Alessandro Gatti).
|
||||
* Copyright message is no longer put in the error log to simplify testing.
|
||||
* Makefile properly triggers a relink for testing or source changes.
|
||||
* Spurious messages quelled.
|
||||
* Documentation updated.
|
||||
* Testsuite expanded.
|
||||
|
||||
-- Cameron Kaiser <ckaiser@floodgap.com> 29 December 2014
|
||||
|
||||
xa-2.3.8
|
||||
|
||||
* Fixed issue with colons in string literals being treated as separators
|
||||
(thanks Simon Rowe).
|
||||
* Testsuite expanded.
|
||||
|
||||
-- Cameron Kaiser <ckaiser@floodgap.com> 29 June 2017
|
||||
|
||||
xa-2.3.9
|
||||
|
||||
* Fixed issue on Windows and DOS systems with the .bin pseudo-op (thanks
|
||||
Bago Zonde).
|
||||
* Documentation updated.
|
||||
* Testsuite expanded.
|
||||
* For the thirty year anniversary of xa, we're changing the name to xxxa.
|
||||
(Just kidding.)
|
||||
|
||||
-- Cameron Kaiser <ckaiser@floodgap.com> 31 January 2019
|
||||
|
||||
xa-2.3.10
|
||||
|
||||
* Three fixes, all from Andre:
|
||||
- Don't crash if a useless segment is referenced outside of relocating
|
||||
mode (thanks Laszlo Barath for the report).
|
||||
- Don't substitute within strings, for better cpp compatibility (thanks
|
||||
Glenn Holmer for the report). I added the -S option for backwards
|
||||
compatibility for the old behaviour; it will be removed in 2.4 and later.
|
||||
- Fix underflow issue if a variable is late-bound (with -L) when that
|
||||
variable is used in computations with negative offsets.
|
||||
* Deprecated options will be removed in 2.4 and everything is warned.
|
||||
* Documentation updated.
|
||||
* Testsuite expanded.
|
||||
|
||||
-- Cameron Kaiser <ckaiser@floodgap.com> 9 November 2019
|
||||
|
||||
xa-2.3.11
|
||||
|
||||
* Compilation fix for gcc 10 (thanks Dan Horak).
|
||||
* Allow pointer arithmetic in relocating mode within the same segment, since
|
||||
the result is segmentless (thanks Andre for the report).
|
||||
* .dsb with negative quantities shouldn't work (thanks Andre for the report).
|
||||
* Stop a divide-by-zero floating point exception (thanks Frederic Cambus).
|
||||
* Testsuite expanded.
|
||||
|
||||
-- Cameron Kaiser <ckaiser@floodgap.com> 4 May 2020
|
||||
|
||||
xa-2.3.12
|
||||
|
||||
* Regression fix for address size validation in 65816 mode (thanks Sam
|
||||
Falvo; we had a pending fix for this but I like his test case).
|
||||
* Testsuite expanded.
|
||||
|
||||
-- Cameron Kaiser <ckaiser@floodgap.com> 26 November 2021
|
||||
|
||||
xa-2.3.13
|
||||
|
||||
* Fix // and /* */ in quoted strings. Incredible no one ever hit this
|
||||
before (thanks ZornsLemma).
|
||||
* Segfault fixes for file65, reloc65 and xa. Remember, kids, if you ever
|
||||
run xa as root all kittens will die. Please save the kittens (thanks
|
||||
Stephen Kitt).
|
||||
* Just compare to null in the preprocessor (thanks Bas Wassink).
|
||||
* Testsuite expanded.
|
||||
|
||||
-- Cameron Kaiser <ckaiser@floodgap.com> 25 March 2022
|
||||
|
||||
xa-2.3.14
|
||||
|
||||
* Fix a segfault when a recursive macro has a smaller arity than the
|
||||
macro it references (thanks Emil Johansson for the report).
|
||||
* Fix for recursive comments, which was a regression from 2.3.13 (note:
|
||||
this may be reexamined for 2.4), and some improvements to the comment
|
||||
parser to fix more edge cases. (Andre)
|
||||
* Now you can just do 'make test TESTS=test,test,test' instead of running
|
||||
./tests/harness with specific options. ('make test' by itself of course
|
||||
still works fine to run the whole suite.)
|
||||
* Testsuite expanded.
|
||||
|
||||
-- Cameron Kaiser <ckaiser@floodgap.com> 7 February 2023
|
||||
|
||||
xa-2.4.0
|
||||
|
||||
* Listing feature in plain text or HTML, along with .listbytes to control
|
||||
how hex bytes get listed in the output.
|
||||
* Add -E commandline option to not stop after 20 errors, but show all
|
||||
of them.
|
||||
* Introduce -X compatibility set commandline option, to distinguish
|
||||
between MASM and CA65 compatibility options; 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 (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.
|
||||
* Added a test case that failed in 2.3.14 from Tom Hargreaves.
|
||||
* 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 greatly expanded.
|
||||
* The old loader/ testsuite and doc/ archive are now in attic/, which is
|
||||
the repository for old unsupported components. It may be purged in a
|
||||
future version.
|
||||
* -M is now deprecated (use -XMASM), just in case you forgot.
|
||||
* printcbm(1) is now deprecated (use VICE petcat, it does a lot more).
|
||||
* Previously deprecated options (16-bit mvn/mvp argument, -S, -x) finally
|
||||
removed. If you need this support, you must use 2.3.x.
|
||||
|
||||
-- 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
|
||||
|
||||
|
||||
|
|
36
xa/Makefile
36
xa/Makefile
|
@ -1,10 +1,11 @@
|
|||
# Unix gcc or DOS go32 cross-compiling gcc
|
||||
#
|
||||
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
|
||||
#CFLAGS = -O2 -W -Wall -pedantic -ansi -g
|
||||
CFLAGS = -O2 -g
|
||||
LDFLAGS = -lc
|
||||
|
||||
# for DOS?
|
||||
|
@ -26,13 +27,18 @@ DOCDIR = $(DESTDIR)/share/doc
|
|||
MKDIR = mkdir -p
|
||||
INSTALL = install
|
||||
|
||||
all: xa uncpk
|
||||
TESTS=ALL
|
||||
|
||||
all: killxa xa uncpk
|
||||
|
||||
killxa:
|
||||
rm -f xa
|
||||
|
||||
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})
|
||||
|
@ -48,11 +54,11 @@ mingw: clean
|
|||
|
||||
clean:
|
||||
(cd src && ${MAKE} clean)
|
||||
(cd loader && ${MAKE} clean)
|
||||
#(cd loader && ${MAKE} clean)
|
||||
(cd misc && ${MAKE} mrproper)
|
||||
rm -f xa *.exe *.o65
|
||||
rm -f xa *.exe *.o65 *.s core
|
||||
|
||||
install: xa uncpk
|
||||
install: all
|
||||
$(MKDIR) $(BINDIR)
|
||||
$(MKDIR) $(MANDIR)
|
||||
$(INSTALL) xa reloc65 ldo65 file65 printcbm uncpk $(BINDIR)
|
||||
|
@ -60,8 +66,14 @@ install: xa uncpk
|
|||
#$(MKDIR) $(DOCDIR)/xa65
|
||||
|
||||
dist: clean
|
||||
#cd .. ; tar cvf xa-2.3.6A.tar xa-2.3.6 ; gzip xa-2.3.6A.tar
|
||||
cd .. ; tar cvf xa-2.3.6.tar xa-2.3.6 ; gzip xa-2.3.6.tar
|
||||
cd .. ; tar cvf xa-$(VERS).tar xa-$(VERS) ; gzip xa-$(VERS).tar
|
||||
|
||||
test:
|
||||
cd tests && ./harness -make="$(MAKE)" -cc="$(CC)" -cflags="$(CFLAGS)"
|
||||
# no prereqs to force parallel make to play nice
|
||||
test:
|
||||
rm -rf xa
|
||||
$(MAKE) xa
|
||||
$(MAKE) uncpk
|
||||
cd tests && ./harness \
|
||||
-tests="$(TESTS)" \
|
||||
-cc="$(CC)" -cflags="$(CFLAGS)" \
|
||||
-make="$(MAKE)" -makeflags="$(MAKEFLAGS)"
|
||||
|
|
|
@ -3,23 +3,32 @@ 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.3.4, which implements multiple improvements on
|
||||
2.3.2, a bug fix to the 2.3.0 version. 2.3.0 itself features many
|
||||
compatibility improvements and new man-based documentation. It also completed
|
||||
the merge of the 65816 and 6502/R65C02 versions and thus the current xa can
|
||||
generate code for all targets now.
|
||||
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
|
||||
cross-assemblers (notably ca65) because once you use xa, you'll want to keep
|
||||
on using it. :)
|
||||
|
||||
Certain long-deprecated options and non-standard syntaxes have also been
|
||||
removed in this release, so it is possible some very old code may not
|
||||
assemble without errors. These changes have been a long time coming and we
|
||||
gave lots of warnings, so if you require these features and cannot change
|
||||
your code to work without them, you must use xa 2.3.14. Fortunately, most
|
||||
code should continue to work just fine and the test suite is even bigger to
|
||||
catch these sorts of regressions.
|
||||
|
||||
To install on a generic Unixy thing, you should be able to just type
|
||||
|
||||
% make # to build the executable, and if it works ...
|
||||
% make test # if you have Perl, make and prerequisites, otherwise
|
||||
% make install # to install man pages and binaries into the system
|
||||
|
||||
This will create xa along with its various support utilities. Try assembling
|
||||
the cpk depacker in examples/ as a test. xa also comes with uncpk (a program
|
||||
for generating cpk archives) and printcbm (a program for listing Commodore
|
||||
BASIC test) and file65, ldo65 and reloc65 for displaying, linking and
|
||||
relocating o65 files in Andre's relocatable format (see doc/fileformats.txt).
|
||||
The loader/ directory also has goodies for managing relocatable binaries.
|
||||
BASIC test, now deprecated as of 2.4) and file65, ldo65 and reloc65 for
|
||||
displaying, linking and relocating o65 files in Andre's relocatable format.
|
||||
|
||||
Don't forget the man pages in man/. Install these into your MANPATH at your
|
||||
leisure, or read them with nroff -man (and/or groff -man).
|
||||
|
@ -38,6 +47,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.
|
||||
|
||||
|
|
16
xa/TODO
16
xa/TODO
|
@ -1,10 +1,18 @@
|
|||
o nm65 that prints labels from o65 files
|
||||
|
||||
o `-L' option for ldo65, such that globals can be suppressed,
|
||||
but KERNEL can be kept
|
||||
|
||||
o inc a -> ina, dec a -> dea (right now uses bare inc and dec)
|
||||
|
||||
o VICE label file support
|
||||
|
||||
o Smarter -X that can cope with non-block-aligned segment sizes
|
||||
o Smarter -X that can cope with non-block-aligned segment sizes (in reloc65)
|
||||
|
||||
o The listing feature is not bug-free yet:
|
||||
- ca65 and other assembler compatibility pseudo-opcodes will be
|
||||
listed as xa specific ones, not the original in the source
|
||||
E.g. a CA65 ".scope" will appear as ".(" in the listing
|
||||
- The assembler has no pre-processor handling, so pp constants are
|
||||
resolved at parse time. Thus they appear as their value
|
||||
in the listing.
|
||||
- One situation is ".listbytes unlimited",
|
||||
which will show as ".listbytes 0" in the listing
|
||||
|
||||
|
|
6
xa/attic/README
Normal file
6
xa/attic/README
Normal file
|
@ -0,0 +1,6 @@
|
|||
These are files that have been superseded and may be removed in the future.
|
||||
|
||||
loader/ Rewritten as tests/loader/
|
||||
doc/ Replaced by man/
|
||||
(for o65, see http://www.6502.org/users/andre/o65/ )
|
||||
|
19
xa/attic/loader/Makefile.test
Normal file
19
xa/attic/loader/Makefile.test
Normal 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!
|
||||
# don't run if this system doesn't have bash
|
||||
test -f /bin/bash || exit 0 && ( cd .. && ../mkrom.sh -O "-G" -S "-bd 1234" -R loader/rom65 loader/test.a loader/test.a ) && ( ../hextool -cmp=rom65.ok < rom65 )
|
||||
|
BIN
xa/attic/loader/rom65.ok
Normal file
BIN
xa/attic/loader/rom65.ok
Normal file
Binary file not shown.
|
@ -1,3 +1,3 @@
|
|||
Also look at ../doc/ for previous documentation files and the Change log.
|
||||
Also look at ../attic/doc/ for previous documentation files.
|
||||
|
||||
Cameron Kaiser
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.TH FILE65 "1" "11 April 2006"
|
||||
.TH FILE65 "1" "5 March 2024"
|
||||
|
||||
.SH NAME
|
||||
file65 \- print information for o65 object files
|
||||
|
@ -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)
|
||||
|
@ -41,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),
|
||||
|
@ -51,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-2006 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
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.TH LDO65 "1" "11 April 2006"
|
||||
.TH LDO65 "1" "5 March 2024"
|
||||
|
||||
.SH NAME
|
||||
ldo65 \- linker for o65 object files
|
||||
|
@ -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
|
||||
|
@ -43,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),
|
||||
|
@ -53,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-2006 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
|
||||
|
|
|
@ -1,7 +1,17 @@
|
|||
.TH PRINTCBM "1" "11 April 2006"
|
||||
.TH PRINTCBM "1" "DEPRECATED"
|
||||
|
||||
.SH NAME
|
||||
printcbm \- list a Commodore BASIC file
|
||||
printcbm \- list a Commodore BASIC file (DEPRECATED)
|
||||
|
||||
.SH NOTICE
|
||||
As of
|
||||
.B xa
|
||||
2.4,
|
||||
.B printcbm
|
||||
is deprecated and will be removed in a future version. Please consider
|
||||
migrating your usage to VICE
|
||||
.BR petcat(1) ,
|
||||
which has many more options.
|
||||
|
||||
.SH SYNOPSIS
|
||||
.B printcbm
|
||||
|
@ -30,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-2006 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
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.TH RELOC65 "1" "11 April 2006"
|
||||
.TH RELOC65 "1" "5 March 2024"
|
||||
|
||||
.SH NAME
|
||||
reloc65 \- relocator for o65 object files
|
||||
|
@ -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 ?
|
||||
|
@ -40,8 +43,46 @@ respectively. Not valid for bss or zero.
|
|||
.B \-X
|
||||
Extract text and data segment together
|
||||
from the file instead of writing back the whole
|
||||
file. Relocating data segment to the end of the text segment
|
||||
(ignoring the \-xd option) before extracting.
|
||||
file. Relocating data segment to the end of the text segment and
|
||||
bss segment to the end of the data segment
|
||||
(\-xd and \-xb options override the derived address) before extracting.
|
||||
.TP
|
||||
.B \-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.
|
||||
|
@ -52,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)
|
||||
|
@ -61,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-2006 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
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.TH UNCPK "1" "11 April 2006"
|
||||
.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-2006 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
|
||||
|
|
522
xa/man/xa.1
522
xa/man/xa.1
|
@ -1,4 +1,4 @@
|
|||
.TH XA "1" "7 February 2009"
|
||||
.TH XA "1" "5 March 2024"
|
||||
|
||||
.SH NAME
|
||||
xa \- 6502/R65C02/65816 cross-assembler
|
||||
|
@ -10,8 +10,7 @@ xa \- 6502/R65C02/65816 cross-assembler
|
|||
.SH DESCRIPTION
|
||||
.B xa
|
||||
is a multi-pass cross-assembler for the 8-bit processors in the 6502 series
|
||||
(such as
|
||||
the 6502, 65C02, 6504, 6507,
|
||||
(such as the 6502, 65C02, 6504, 6507,
|
||||
6510, 7501, 8500, 8501 and 8502), the Rockwell R65C02, and
|
||||
the 16-bit 65816 processor. For a description of syntax, see
|
||||
.B ASSEMBLER SYNTAX
|
||||
|
@ -19,19 +18,14 @@ further in this manual page.
|
|||
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B \-E
|
||||
Do not stop after 20 errors, but show all errors.
|
||||
.TP
|
||||
.B \-v
|
||||
Verbose output.
|
||||
.TP
|
||||
.B \-x
|
||||
Use old filename behaviour (overrides
|
||||
.BR \-o ,
|
||||
.B \-e
|
||||
and
|
||||
.BR \-l ).
|
||||
This option is now deprecated.
|
||||
.TP
|
||||
.B \-C
|
||||
No CMOS opcodes (default is to allow R65C02 opcodes)
|
||||
No CMOS opcodes (default is to allow R65C02 opcodes).
|
||||
.TP
|
||||
.B \-W
|
||||
No 65816 opcodes (default).
|
||||
|
@ -54,11 +48,22 @@ use the special filename
|
|||
.BR \-
|
||||
to output to standard output.
|
||||
.TP
|
||||
.B \-P filename
|
||||
Set listing filename. The default is none; use the special filename
|
||||
.BR \-
|
||||
to print the listing to standard output.
|
||||
.TP
|
||||
.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.
|
||||
|
@ -67,12 +72,87 @@ to reconstruct source.
|
|||
Add cross-reference list to labellist (requires
|
||||
.BR \-l ).
|
||||
.TP
|
||||
.B \-Xcompatset
|
||||
Enables compatibility settings to become more (not fully!) compatible with other 6502 assemblers 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 generating control characters, disables escaped characters with
|
||||
.BR \e ,
|
||||
allows nested multi-line comments, and disables all predefined
|
||||
.B xa
|
||||
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
|
||||
Allow colons to appear in comments; for MASM compatibility. This does
|
||||
not affect colon interpretation elsewhere.
|
||||
This option is deprecated and will be removed in a future version; 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 \-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.
|
||||
Start assembler in relocating mode, i.e. use segments.
|
||||
.TP
|
||||
.B \-U
|
||||
Do not allow undefined labels in relocating mode.
|
||||
.TP
|
||||
.B \-Llabel
|
||||
Defines
|
||||
|
@ -130,7 +210,9 @@ 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.
|
||||
|
@ -169,9 +251,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
|
||||
|
@ -213,7 +301,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
|
||||
|
@ -228,6 +323,75 @@ for block instructions). A label may also be hard-specified with the
|
|||
.B \-L
|
||||
command line option.
|
||||
.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
|
||||
assembled previously and changing it to a higher value does not issue
|
||||
padding to put subsequent code at the new location. This is intentional
|
||||
behaviour to facilitate generating relocatable and position-independent code,
|
||||
but can differ from other assemblers which use this behaviour for
|
||||
linking. However, it is possible to use pseudo-ops to simulate other
|
||||
assemblers' behaviour and use
|
||||
.B xa
|
||||
as a linker; see
|
||||
.B PSEUDO-OPS
|
||||
and
|
||||
.BR LINKING .
|
||||
.LP
|
||||
If
|
||||
.B \-XCA65
|
||||
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
|
||||
.BR ca65 (1)
|
||||
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
|
||||
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
|
||||
|
@ -238,7 +402,7 @@ and
|
|||
on R65C02; etc.), the idiom of explicitly specifying the accumulator with
|
||||
.B a
|
||||
is unnecessary as the proper form will be selected if there is no explicit
|
||||
argument. In fact, for consistency with label handing, if there is a label
|
||||
argument. In fact, for consistency with label handling, if there is a label
|
||||
named
|
||||
.BR a ,
|
||||
this will actually generate code referencing that label as a memory
|
||||
|
@ -275,7 +439,7 @@ shift right (8)
|
|||
.B >= =>
|
||||
greater than or equal to (7)
|
||||
.TP
|
||||
.B <
|
||||
.B >
|
||||
greater than (7)
|
||||
.TP
|
||||
.B <= =<
|
||||
|
@ -285,10 +449,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)
|
||||
|
@ -337,11 +505,10 @@ or zero page value, do not attempt to optimize to a zero page argument
|
|||
for those opcodes that support it (i.e., keep as 16 bit word)
|
||||
.TP
|
||||
.B @
|
||||
render as 24-bit quantity for 65816 (must specify
|
||||
render as 24-bit quantity for 65816, even if smaller than 24 bits (must specify
|
||||
.B \-w
|
||||
command-line option).
|
||||
.B This is required to specify any
|
||||
.B 24-bit quantity!
|
||||
command-line option, must not specify
|
||||
.BR \-XCA65 )
|
||||
.TP
|
||||
.B `
|
||||
force further optimization, even if the length of the instruction cannot
|
||||
|
@ -399,8 +566,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 //
|
||||
|
@ -441,7 +609,7 @@ and
|
|||
are synonymous, so you can mix things such as
|
||||
.B .byt $43, 22, """a character string"""
|
||||
and get the expected result. The string is subject to the current character
|
||||
set, but the remaining bytes are inserted wtihout modification.
|
||||
set, but the remaining bytes are inserted without modification.
|
||||
.TP
|
||||
.B .aasc """text1""","text2",...
|
||||
Specifies a character string that is
|
||||
|
@ -464,22 +632,29 @@ repetitions of
|
|||
will be inserted into the assembled object. For example,
|
||||
.B .dsb 5,$10
|
||||
will insert five bytes, each being 16 decimal, into the object. The arguments
|
||||
may be expressions.
|
||||
may be expressions. If only a single argument is provided, then the argument
|
||||
is treated as a number of null bytes to insert. See
|
||||
.B LINKING
|
||||
for how to use this pseudo-op to link multiple objects.
|
||||
.TP
|
||||
.B .bin offset,length,"filename"
|
||||
Inlines a binary file without further interpretation specified by
|
||||
.B filename
|
||||
from offset
|
||||
.B offset
|
||||
to length
|
||||
.BR length .
|
||||
(relative to the beginning of the file)
|
||||
for
|
||||
.B length
|
||||
bytes.
|
||||
This allows you to insert data such as a previously assembled object file
|
||||
or an image or other binary data structure, inlined directly into this
|
||||
file's object. If
|
||||
.B length
|
||||
is zero, then the length of
|
||||
.BR filename ,
|
||||
minus the offset, is used instead. The arguments may be expressions.
|
||||
minus the offset, is used instead. The arguments may be expressions. See
|
||||
.B LINKING
|
||||
for how to use this pseudo-op to link multiple objects.
|
||||
.TP
|
||||
.B \&.(
|
||||
Opens a new block for scoping. Within a block, all labels defined are local to
|
||||
|
@ -491,10 +666,23 @@ a block, precede the label with
|
|||
or precede it with
|
||||
.B &
|
||||
to declare it within the previous level only (or globally if you are only
|
||||
one level deep). Sixteen levels of scoping are permitted.
|
||||
one level deep). Sixteen levels of scoping are permitted.
|
||||
.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.
|
||||
.B .bend
|
||||
or
|
||||
.B .endproc
|
||||
are accepted as synonyms.
|
||||
.TP
|
||||
.B \.as \.al \.xs \.xl
|
||||
Only relevant in 65816 mode (with the
|
||||
|
@ -521,31 +709,98 @@ and
|
|||
generate errors if
|
||||
.B \-w
|
||||
is not specified.
|
||||
.TP
|
||||
.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 ),
|
||||
but at the assembler
|
||||
phase after preprocessing has already occurred.
|
||||
|
||||
.LP
|
||||
The following pseudo-ops apply primarily to relocatable .o65 objects.
|
||||
The following pseudo-op applies to listing mode.
|
||||
.TP
|
||||
.B \.listbytes number
|
||||
In the listing output, sets the maximum number of hex bytes to be printed
|
||||
in the listing for pseudo-ops like
|
||||
.BR .byt ,
|
||||
by default 8. The special argument
|
||||
.B unlimited
|
||||
sets no upper limit. If listing mode is disabled, this pseudo-op has no
|
||||
observable effect.
|
||||
|
||||
.LP
|
||||
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
|
||||
on the proposed v1.2 format is in
|
||||
.B doc/fileformat.txt
|
||||
within the
|
||||
.B xa
|
||||
installation directory.
|
||||
scope of this manpage; see
|
||||
.B http://www.6502.org/users/andre/o65/
|
||||
for the most current specification.
|
||||
.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
|
||||
are valid in relative and absolute modes.
|
||||
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 relocating and absolute modes.
|
||||
.TP
|
||||
.B .code
|
||||
For
|
||||
.B ca65
|
||||
compatibility, this is currently mapped to
|
||||
.BR .text .
|
||||
.TP
|
||||
.B .zeropage
|
||||
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
|
||||
.B
|
||||
value
|
||||
(and places it in the header when relative mode is enabled). Other values
|
||||
(and places it in the header when relocating 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.
|
||||
|
@ -555,6 +810,17 @@ is used to specify the file option being referenced. A table of these options
|
|||
is in the relocatable o65 file format description. The remainder of the options
|
||||
are interpreted as values to insert. Any number of values may be specified,
|
||||
and may also be strings.
|
||||
.TP
|
||||
.B .import label1, label2, label3, ...
|
||||
Defines the given labels as global labels which are imported and resolved during
|
||||
the link stage, like the
|
||||
.B -L
|
||||
command line parameter.
|
||||
.TP
|
||||
.B .importzp label1, label2, label3, ...
|
||||
Analogous to
|
||||
.BR .import ,
|
||||
except that it only imports zeropage labels (i.e., byte values).
|
||||
|
||||
.SH PREPROCESSOR
|
||||
|
||||
|
@ -638,8 +904,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
|
||||
|
@ -664,6 +941,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
|
||||
|
@ -697,12 +977,6 @@ satisfied, then the source code between the directive and its terminating
|
|||
.B #endif
|
||||
are expunged and not assembled. Up to fifteen levels of nesting are supported.
|
||||
.TP
|
||||
.B #endif
|
||||
Closes a conditional block.
|
||||
.TP
|
||||
.B #else
|
||||
Implements alternate path for a conditional block.
|
||||
.TP
|
||||
.B #ifdef DEFINE
|
||||
True only if macro
|
||||
.B DEFINE
|
||||
|
@ -733,6 +1007,12 @@ is defined
|
|||
.I and
|
||||
assigned with a value.
|
||||
.I This works on labels, not macros!
|
||||
.TP
|
||||
.B #else
|
||||
Implements alternate path for a conditional block.
|
||||
.TP
|
||||
.B #endif
|
||||
Closes a conditional block.
|
||||
.LP
|
||||
Unclosed conditional blocks at the end of included files generate warnings;
|
||||
unclosed conditional blocks at the end of assembly generate an error.
|
||||
|
@ -757,6 +1037,107 @@ you might use something like this in your library's code:
|
|||
.br
|
||||
.B #endif
|
||||
|
||||
.SH LINKING
|
||||
|
||||
.B xa
|
||||
is oriented towards generating sequential binaries. Code is strictly
|
||||
emitted in order even if the program counter is set to a lower location
|
||||
than previously assembled code, and padding is not automatically emitted
|
||||
if the program counter is set to a higher location. Changing the program
|
||||
location only changes new labels for code that is subsequently emitted;
|
||||
previous emitted code remains unchanged. Fortunately, for many object files
|
||||
these conventions have no effect on their generation.
|
||||
.LP
|
||||
However, some applications may require generating an object file built
|
||||
from several previously generated components, and/or submodules which
|
||||
may need to be present at specific memory locations. With a minor amount of
|
||||
additional specification, it is possible to use
|
||||
.B xa
|
||||
for this purpose as well.
|
||||
.LP
|
||||
The first means of doing so uses the o65 format to make relocatable objects
|
||||
that in turn can be linked by
|
||||
.BR ldo65 (1)
|
||||
(q.v.).
|
||||
.LP
|
||||
The second means involves either assembled code, or insertion of
|
||||
previously built object or data files with
|
||||
.BR .bin ,
|
||||
using
|
||||
.B .dsb
|
||||
pseudo-ops with computed expression arguments to insert any necessary padding
|
||||
between them, in the sequential order they are to reside in memory. Consider
|
||||
this example:
|
||||
.LP
|
||||
|
||||
.br
|
||||
.word $1000
|
||||
.br
|
||||
* = $1000
|
||||
.br
|
||||
|
||||
.br
|
||||
; this is your code at $1000
|
||||
.br
|
||||
part1 rts
|
||||
.br
|
||||
; this label marks the end of code
|
||||
.br
|
||||
endofpart1
|
||||
.br
|
||||
|
||||
.br
|
||||
; DON'T PUT A NEW .word HERE!
|
||||
.br
|
||||
* = $2000
|
||||
.br
|
||||
.dsb (*-endofpart1), 0
|
||||
.br
|
||||
; yes, set it again
|
||||
.br
|
||||
* = $2000
|
||||
.br
|
||||
|
||||
.br
|
||||
; this is your code at $2000
|
||||
.br
|
||||
part2 rts
|
||||
.br
|
||||
.LP
|
||||
This example, written for Commodore microcomputers using a 16-bit starting
|
||||
address, has two "modules" in it: one block of code at $1000 (4096),
|
||||
indicated by the code between labels
|
||||
.B part1
|
||||
and
|
||||
.BR endofpart1 ,
|
||||
and a second block at $2000 (8192) starting at label
|
||||
.BR part2 .
|
||||
.LP
|
||||
The padding is computed by the
|
||||
.B .dsb
|
||||
pseudo-op between the two modules. Note that the program counter is set
|
||||
to the new address and then a computed expression inserts the proper number
|
||||
of fill bytes from the end of the assembled code in part 1 up to the new
|
||||
program counter address. Since this itself advances the program counter,
|
||||
the program counter is reset again, and assembly continues.
|
||||
.LP
|
||||
When the object this source file generates is loaded, there will be an
|
||||
.B rts
|
||||
instruction at address 4096 and another at address 8192, with null bytes
|
||||
between them.
|
||||
.LP
|
||||
Should one of these areas need to contain a pre-built file, instead of
|
||||
assembly code, simply use a
|
||||
.B .bin
|
||||
pseudo-op to load whatever portions of the file are required into the
|
||||
output. The computation of addresses and number of necessary fill bytes
|
||||
is done in the same fashion.
|
||||
.LP
|
||||
Although this example used the program counter itself to compute the
|
||||
difference between addresses, you can use any label for this purpose,
|
||||
keeping in mind that only the program counter determines where relative
|
||||
addresses within assembled code are resolved.
|
||||
|
||||
.SH ENVIRONMENT
|
||||
|
||||
.B xa
|
||||
|
@ -785,6 +1166,16 @@ and
|
|||
.B dec
|
||||
instructions respectively.
|
||||
.LP
|
||||
The 65816 instructions
|
||||
.B mvn
|
||||
and
|
||||
.B mvp
|
||||
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. 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
|
||||
page instructions even if the label does end up being defined as a zero page
|
||||
|
@ -805,22 +1196,10 @@ Indiscriminately forcing the issue can be fraught with peril, however, and
|
|||
is not recommended; to discourage this, the assembler will complain about its
|
||||
use in addressing mode situations where no ambiguity exists, such as indirect
|
||||
indexed, branching and so on.
|
||||
.LP
|
||||
Also, as a further consequence of the way optimization is managed, we repeat
|
||||
that
|
||||
.B all
|
||||
24-bit quantities and labels that reference a 24-bit quantity in 65816 mode,
|
||||
anteriorly declared or otherwise,
|
||||
.B MUST
|
||||
be prepended with the
|
||||
.B @
|
||||
prefix. Otherwise, the assembler will attempt to optimize to 16 bits, which
|
||||
may be undesirable.
|
||||
|
||||
.SH "SEE ALSO"
|
||||
.BR file65 (1),
|
||||
.BR ldo65 (1),
|
||||
.BR printcbm (1),
|
||||
.BR reloc65 (1),
|
||||
.BR uncpk (1),
|
||||
.BR dxa (1)
|
||||
|
@ -830,8 +1209,11 @@ This manual page was written by David Weinehall <tao@acc.umu.se>,
|
|||
Andre Fachat <fachat@web.de>
|
||||
and Cameron Kaiser <ckaiser@floodgap.com>.
|
||||
Original xa package (C)1989-1997 Andre Fachat. Additional changes
|
||||
(C)1989-2009 Andre Fachat, Jolse Maginnis, David Weinehall,
|
||||
(C)1989-2024 Andre Fachat, Jolse Maginnis, David Weinehall,
|
||||
Cameron Kaiser. The official maintainer is Cameron Kaiser.
|
||||
|
||||
.SH OVER 30 YEARS OF XA
|
||||
Yay us?
|
||||
|
||||
.SH WEBSITE
|
||||
http://www.floodgap.com/retrotech/xa/
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
XCBMLIB = ..
|
||||
|
||||
# -Wall -ansi et al. cause compile problems.
|
||||
CFLAGS = -O2
|
||||
CFLAGS = -O2 -g
|
||||
|
||||
LIBS = #-lncurses -ltermcap -lm
|
||||
|
||||
|
|
120
xa/misc/file65.c
120
xa/misc/file65.c
|
@ -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);
|
||||
|
||||
|
@ -48,6 +78,8 @@ int rompar = 0;
|
|||
int romoff = 0;
|
||||
int labels = 0;
|
||||
|
||||
int verbose = 0;
|
||||
|
||||
void usage(FILE *fp)
|
||||
{
|
||||
fprintf(fp,
|
||||
|
@ -62,13 +94,14 @@ void usage(FILE *fp)
|
|||
" in the same ROM. Add offset to start address.\n"
|
||||
" -A offset same as `-a', but only print the start address of the next\n"
|
||||
" file in the ROM\n"
|
||||
" -V print undefined and global labels\n"
|
||||
" -v print undefined and global labels\n"
|
||||
" -vv print undefined and global labels, and relocation tables\n"
|
||||
" --version output version information and exit\n"
|
||||
" --help display this help and exit\n");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int i = 1, n, mode, hlen;
|
||||
int i, j, n, mode, hlen;
|
||||
FILE *fp;
|
||||
char *aligntxt[4]= {"[align 1]","[align 2]","[align 4]","[align 256]"};
|
||||
if(argc<=1) {
|
||||
|
@ -76,12 +109,14 @@ int main(int argc, char *argv[]) {
|
|||
exit(1);
|
||||
}
|
||||
|
||||
if (strstr(argv[1], "--help")) {
|
||||
i = 1;
|
||||
|
||||
if (strstr(argv[i], "--help") || strstr(argv[i], "-?") || strstr(argv[i], "-h")) {
|
||||
usage(stdout);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (strstr(argv[1], "--version")) {
|
||||
if (strstr(argv[i], "--version")) {
|
||||
version(programname, progversion, author, copyright);
|
||||
exit(0);
|
||||
}
|
||||
|
@ -90,24 +125,26 @@ int main(int argc, char *argv[]) {
|
|||
if(argv[i][0]=='-') {
|
||||
/* process options */
|
||||
switch(argv[i][1]) {
|
||||
case 'V':
|
||||
labels = 1;
|
||||
break;
|
||||
case 'v':
|
||||
printf("file65: Version 0.2\n");
|
||||
j = 1;
|
||||
while (argv[i][j] == 'v') {
|
||||
verbose ++;
|
||||
j++;
|
||||
}
|
||||
break;
|
||||
case 'a':
|
||||
case 'A':
|
||||
rompar = 1;
|
||||
if(argv[i][1]=='A') rompar++;
|
||||
if(argv[i][2]) romoff = atoi(argv[i]+2);
|
||||
else romoff = atoi(argv[++i]);
|
||||
else if(i + 1 < argc) romoff = atoi(argv[++i]);
|
||||
else fprintf(stderr,"%s: missing offset\n",programname);
|
||||
break;
|
||||
case 'P':
|
||||
xapar = 1;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,"file65: %s unknown option\n",argv[i]);
|
||||
fprintf(stderr,"%s: %s unknown option, use '-h' for help\n",programname,argv[i]);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
|
@ -120,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) {
|
||||
|
@ -141,7 +179,7 @@ int main(int argc, char *argv[]) {
|
|||
printf(" zero segment @ $%04x - $%04x [$%04x bytes]\n", hdr[21]*256+hdr[20], hdr[21]*256+hdr[20]+hdr[23]*256+hdr[22], hdr[23]*256+hdr[22]);
|
||||
printf(" stack size $%04x bytes %s\n", hdr[25]*256+hdr[24],
|
||||
(hdr[25]*256+hdr[24])==0?"(i.e. unknown)":"");
|
||||
if(labels) {
|
||||
if(verbose) {
|
||||
read_options(fp);
|
||||
print_labels(fp, hdr[11]*256+hdr[10] + hdr[15]*256+hdr[14]);
|
||||
}
|
||||
|
@ -230,13 +268,13 @@ void print_option(unsigned char *buf, int len) {
|
|||
}
|
||||
|
||||
int read_options(FILE *fp) {
|
||||
int c, l=0;
|
||||
int c, d, l=0;
|
||||
unsigned char tb[256];
|
||||
|
||||
c=fgetc(fp); l++;
|
||||
while(c && c!=EOF) {
|
||||
c&=255;
|
||||
fread(tb, 1, c-1, fp);
|
||||
d = fread(tb, 1, c-1, fp);
|
||||
if(labels) print_option(tb, c);
|
||||
l+=c;
|
||||
c=fgetc(fp);
|
||||
|
@ -246,11 +284,17 @@ int read_options(FILE *fp) {
|
|||
|
||||
int print_labels(FILE *fp, int offset) {
|
||||
int i, nud, c, seg, off;
|
||||
const char *segments[] = { "undef", "abs", "text", "data", "bss", "zero" };
|
||||
const char *reltype[] = { "-", "LOW", "HIGH", "-", "WORD", "SEG", "SEGADDR" };
|
||||
|
||||
/*
|
||||
printf("print_labels:offset=%d\n",offset);
|
||||
*/
|
||||
fseek(fp, offset, SEEK_CUR);
|
||||
|
||||
// -----------------------------------------------------------
|
||||
// print undefined labels
|
||||
|
||||
nud = (fgetc(fp) & 0xff);
|
||||
nud += ((fgetc(fp) << 8) & 0xff00);
|
||||
|
||||
|
@ -268,25 +312,59 @@ printf("print_labels:offset=%d\n",offset);
|
|||
printf("\n");
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// skip relocation tables
|
||||
|
||||
// two tables, one for text one for data
|
||||
for(i=0;i<2;i++) {
|
||||
unsigned char lowbyte;
|
||||
unsigned short index;
|
||||
unsigned short offset = 0;
|
||||
|
||||
if (verbose > 1) {
|
||||
printf("Relocation table for %s:\n", i ? "text":"data");
|
||||
}
|
||||
|
||||
c=fgetc(fp);
|
||||
while(c && c!=EOF) {
|
||||
c&= 0xff;
|
||||
while(c == 255 && c!= EOF) {
|
||||
offset += 254;
|
||||
c=fgetc(fp);
|
||||
if(c==EOF) break;
|
||||
c&= 0xff;
|
||||
}
|
||||
if(c==EOF) break;
|
||||
offset += c;
|
||||
|
||||
c=fgetc(fp);
|
||||
if( (c & 0xe0) == 0x40 ) fgetc(fp);
|
||||
if( (c & 0x07) == 0 ) { fgetc(fp); fgetc(fp); }
|
||||
|
||||
if( (c & 0xe0) == 0x40 ) {
|
||||
lowbyte = fgetc(fp);
|
||||
}
|
||||
if( (c & 0x07) == 0 ) {
|
||||
index = fgetc(fp) & 0xff;
|
||||
index += (fgetc(fp) & 0xff) << 8;
|
||||
}
|
||||
if (verbose > 1) {
|
||||
printf("\t%d:%s(%s (%d)", offset, reltype[ (c>>5) & 0xf], segments[c & 0x07], (c&0x07));
|
||||
if ( (c & 0xe0) == 0x40) {
|
||||
printf(", %02x", lowbyte);
|
||||
}
|
||||
if ( (c & 0x07) == 0) {
|
||||
printf(", %04x", index);
|
||||
}
|
||||
printf(")");
|
||||
}
|
||||
c=fgetc(fp);
|
||||
}
|
||||
if (verbose > 1) {
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// print global labels
|
||||
nud = (fgetc(fp) & 0xff);
|
||||
nud += ((fgetc(fp) << 8) & 0xff00);
|
||||
printf("Global Labels: %d\n", nud);
|
||||
|
|
1082
xa/misc/ldo65.c
1082
xa/misc/ldo65.c
File diff suppressed because it is too large
Load Diff
|
@ -46,6 +46,8 @@ void usage(FILE *fp)
|
|||
fprintf(fp,
|
||||
"Usage: %s [OPTION]... [FILE]...\n"
|
||||
"List CBM BASIC programs\n"
|
||||
"This tool is deprecated as of xa 2.4 and will be removed in a future version.\n"
|
||||
"Please consider migrating to VICE petcat, which has many more options.\n"
|
||||
"\n"
|
||||
" --version output version information and exit\n"
|
||||
" --help display this help and exit\n",
|
||||
|
@ -62,7 +64,7 @@ int main(int argc, char *argv[])
|
|||
exit(1);
|
||||
}
|
||||
|
||||
if (strstr(argv[1], "--help")) {
|
||||
if (strstr(argv[1], "--help") || strstr(argv[1], "-?")) {
|
||||
usage(stdout);
|
||||
exit(0);
|
||||
}
|
||||
|
|
|
@ -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,25 +89,49 @@ 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;
|
||||
int tbase = 0, dbase = 0, bbase = 0, zbase = 0;
|
||||
int *base;
|
||||
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")) {
|
||||
if (strstr(argv[1], "--help") || strstr(argv[1], "-?") || strstr(argv[1], "-h")) {
|
||||
usage(stdout);
|
||||
exit(0);
|
||||
}
|
||||
|
@ -103,42 +142,49 @@ int main(int argc, char *argv[]) {
|
|||
}
|
||||
|
||||
while(i<argc) {
|
||||
arg = NULL;
|
||||
if(argv[i][0]=='-') {
|
||||
/* process options */
|
||||
switch(argv[i][1]) {
|
||||
case 'v':
|
||||
verbose = 1;
|
||||
break;
|
||||
case 'o':
|
||||
if(argv[i][2]) outfile=argv[i]+2;
|
||||
else outfile=argv[++i];
|
||||
else if(i + 1 < argc) outfile=argv[++i];
|
||||
else fprintf(stderr,"%s: missing output file\n",programname);
|
||||
break;
|
||||
case 'X':
|
||||
extract=3;
|
||||
break;
|
||||
case 'b':
|
||||
base=NULL;
|
||||
switch(argv[i][2]) {
|
||||
case 't':
|
||||
tflag= 1;
|
||||
if(argv[i][3]) tbase = atoi(argv[i]+3);
|
||||
else tbase = atoi(argv[++i]);
|
||||
base=&tbase;
|
||||
break;
|
||||
case 'd':
|
||||
dflag= 1;
|
||||
if(argv[i][3]) dbase = atoi(argv[i]+3);
|
||||
else dbase = atoi(argv[++i]);
|
||||
base=&dbase;
|
||||
break;
|
||||
case 'b':
|
||||
bflag= 1;
|
||||
if(argv[i][3]) bbase = atoi(argv[i]+3);
|
||||
else bbase = atoi(argv[++i]);
|
||||
base=&bbase;
|
||||
break;
|
||||
case 'z':
|
||||
zflag= 1;
|
||||
if(argv[i][3]) zbase = atoi(argv[i]+3);
|
||||
else zbase = atoi(argv[++i]);
|
||||
base=&zbase;
|
||||
break;
|
||||
default:
|
||||
printf("Unknown segment type '%c' - ignored!\n", argv[i][2]);
|
||||
break;
|
||||
}
|
||||
if (base != NULL) {
|
||||
if(argv[i][3]) *base = atoi(argv[i]+3);
|
||||
else if(i + 1 < argc) *base = atoi(argv[++i]);
|
||||
else fprintf(stderr,"%s: missing address\n",programname);
|
||||
}
|
||||
break;
|
||||
case 'x': /* extract segment */
|
||||
switch(argv[i][2]) {
|
||||
|
@ -157,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,"reloc65: %s unknown option, use '-?' for help\n",argv[i]);
|
||||
fprintf(stderr,"%s: %s unknown option, use '-h' for help\n",programname,argv[i]);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
|
@ -168,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);
|
||||
|
@ -178,35 +243,77 @@ 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];
|
||||
file.tlen = file.buf[11]*256+file.buf[10];
|
||||
file.tdiff = tflag? tbase - file.tbase : 0;
|
||||
file.tdiff = tflag ? tbase - file.tbase : 0;
|
||||
|
||||
file.dbase = file.buf[13]*256+file.buf[12];
|
||||
file.dlen = file.buf[15]*256+file.buf[14];
|
||||
file.ddiff = dflag ? dbase - file.dbase : 0;
|
||||
if (extract == 3) {
|
||||
if (dflag) {
|
||||
fprintf(stderr,"reloc65: %s: Warning: data segment address ignored for -X option\n", argv[i]);
|
||||
}
|
||||
dbase = file.tbase + file.tdiff + file.tlen;
|
||||
file.ddiff = dbase - file.dbase;
|
||||
} else {
|
||||
file.ddiff = dflag? dbase - file.dbase : 0;
|
||||
fprintf(stderr,"reloc65: %s: Warning: data segment address overrides -X option\n", argv[i]);
|
||||
} else {
|
||||
dbase = file.tbase + file.tdiff + file.tlen;
|
||||
file.ddiff = dbase - file.dbase;
|
||||
}
|
||||
}
|
||||
|
||||
file.bbase = file.buf[17]*256+file.buf[16];
|
||||
file.blen = file.buf[19]*256+file.buf[18];
|
||||
file.bdiff = bflag? bbase - file.bbase : 0;
|
||||
file.zbase = file.buf[21]*256+file.buf[20];
|
||||
file.zlen = file.buf[23]*256+file.buf[21];
|
||||
file.zdiff = zflag? zbase - file.zbase : 0;
|
||||
file.bdiff = bflag ? bbase - file.bbase : 0;
|
||||
if (extract == 3) {
|
||||
if (bflag) {
|
||||
fprintf(stderr,"reloc65: %s: Warning: bss segment address overrides -X option\n", argv[i]);
|
||||
} else {
|
||||
bbase = file.dbase + file.ddiff + file.dlen;
|
||||
file.bdiff = bbase - file.bbase;
|
||||
}
|
||||
}
|
||||
|
||||
file.zbase = file.buf[21]*256+file.buf[20];
|
||||
file.zlen = file.buf[23]*256+file.buf[22];
|
||||
file.zdiff = zflag ? zbase - file.zbase : 0;
|
||||
|
||||
if (verbose) {
|
||||
printf("Relocating segments to:\n");
|
||||
printf("text segment @ $%04x - $%04x, %5d ($%04x) bytes, diff is %5d ($%04x)\n",
|
||||
file.tbase + file.tdiff, file.tbase + file.tdiff + file.tlen,
|
||||
file.tlen, file.tlen, file.tdiff, file.tdiff & 0xffff);
|
||||
printf("data segment @ $%04x - $%04x, %5d ($%04x) bytes, diff is %5d ($%04x)\n",
|
||||
file.dbase + file.ddiff, file.dbase + file.ddiff + file.dlen,
|
||||
file.dlen, file.dlen, file.ddiff, file.ddiff & 0xffff);
|
||||
printf("bss segment @ $%04x - $%04x, %5d ($%04x) bytes, diff is %5d ($%04x)\n",
|
||||
file.bbase + file.bdiff, file.bbase + file.bdiff + file.blen,
|
||||
file.blen, file.blen, file.bdiff, file.bdiff & 0xffff);
|
||||
printf("zero segment @ $%04x - $%04x, %5d ($%04x) bytes, diff is %5d ($%04x)\n",
|
||||
file.zbase + file.zdiff, file.zbase + file.zdiff + file.zlen,
|
||||
file.zlen, file.zlen, file.zdiff, file.zdiff & 0xffff);
|
||||
}
|
||||
|
||||
/* pointer of position in file */
|
||||
file.segt = file.buf + hlen;
|
||||
file.segd = file.segt + file.tlen;
|
||||
file.utab = file.segd + file.dlen;
|
||||
|
|
|
@ -65,7 +65,7 @@ int main(int argc, char *argv[])
|
|||
exit(1);
|
||||
}
|
||||
|
||||
if (strstr(argv[1], "--help")) {
|
||||
if (strstr(argv[1], "--help") || strstr(argv[1], "-?")) {
|
||||
usage(stdout);
|
||||
exit(0);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
OBJ = xa.o xaa.o xal.o xap.o xat.o xar.o xar2.o xao.o xau.o xam.o xacharset.o
|
||||
OBJ = xa.o xaa.o xal.o xap.o xat.o xar.o xar2.o xao.o xau.o xam.o xacharset.o xalisting.o
|
||||
|
||||
#CFLAGS=-W -Wall -pedantic -ansi #-g
|
||||
#CFLAGS=-W -Wall -pedantic -ansi -g
|
||||
#CFLAGS=-W -Wall -ansi -O2
|
||||
#CFLAGS=-g -std=c11 -D_GNU_SOURCE
|
||||
#LD = ${CC}
|
||||
#LDFLAGS = "-lc"
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#ifndef __XA65_VERSION_H__
|
||||
#define __XA65_VERSION_H__
|
||||
|
||||
void version(const char *programname, const char *progversion,
|
||||
void version(const char *programname, const char *version,
|
||||
const char *authors, const char *copyright)
|
||||
{
|
||||
fprintf(stdout,
|
||||
|
@ -31,7 +31,7 @@ void version(const char *programname, const char *progversion,
|
|||
"copying conditions. There is NO\n"
|
||||
"warranty; not even for MERCHANTABILIY or "
|
||||
"FITNESS FOR A PARTICULAR PURPOSE.\n",
|
||||
programname, progversion, authors, copyright);
|
||||
programname, version, authors, copyright);
|
||||
}
|
||||
|
||||
#endif /* __XA65_VERSION_H__ */
|
||||
|
|
591
xa/src/xa.c
591
xa/src/xa.c
|
@ -45,6 +45,7 @@
|
|||
#include "xar.h"
|
||||
#include "xat.h"
|
||||
#include "xacharset.h"
|
||||
#include "xalisting.h"
|
||||
|
||||
#include "version.h"
|
||||
|
||||
|
@ -55,26 +56,36 @@
|
|||
#define ANZWARN 13
|
||||
|
||||
#define programname "xa"
|
||||
#define progversion "v2.3.6"
|
||||
/* progversion now in xa.h */
|
||||
#define authors "Written by Andre Fachat, Jolse Maginnis, David Weinehall and Cameron Kaiser"
|
||||
#define copyright "Copyright (C) 1989-2014 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;
|
||||
int masm = 0;
|
||||
|
||||
/* 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;
|
||||
int romable = 0;
|
||||
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;
|
||||
|
||||
/* local variables */
|
||||
|
||||
static char out[MAXLINE];
|
||||
static time_t tim1, tim2;
|
||||
static FILE *fpout, *fperr, *fplab;
|
||||
static FILE *fpout, *fperr, *fplab, *fplist;
|
||||
static int ner = 0;
|
||||
static int ner_max = 20;
|
||||
|
||||
static int align = 1;
|
||||
|
||||
|
@ -85,12 +96,14 @@ static int x_init(void);
|
|||
static int pass1(void);
|
||||
static int pass2(void);
|
||||
static int puttmp(int);
|
||||
static int puttmpw(int);
|
||||
static int puttmps(signed char *, int);
|
||||
static void chrput(int);
|
||||
static int xa_getline(char *);
|
||||
static void lineout(void);
|
||||
static long ga_p1(void);
|
||||
static long gm_p1(void);
|
||||
static int set_compat(char *compat_name);
|
||||
|
||||
/* text */
|
||||
int memode,xmode;
|
||||
|
@ -110,16 +123,18 @@ int main(int argc,char *argv[])
|
|||
signed char *s=NULL;
|
||||
char *tmpp;
|
||||
|
||||
char *listformat = NULL;
|
||||
|
||||
int mifiles = 5;
|
||||
int nifiles = 0;
|
||||
int verbose = 0;
|
||||
int oldfile = 0;
|
||||
int no_link = 0;
|
||||
|
||||
char **ifiles;
|
||||
char *ofile;
|
||||
char *efile;
|
||||
char *lfile;
|
||||
char *printfile; /* print listing to this file */
|
||||
char *ofile; /* output file */
|
||||
char *efile; /* error listing goes there */
|
||||
char *lfile; /* labels go here */
|
||||
char *ifile;
|
||||
|
||||
char old_e[MAXLINE];
|
||||
|
@ -127,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],'/'))) {
|
||||
|
@ -160,7 +183,7 @@ int main(int argc,char *argv[])
|
|||
exit(1);
|
||||
}
|
||||
|
||||
if (strstr(argv[1], "--help")) {
|
||||
if (strstr(argv[1], "--help") || strstr(argv[1], "-?")) {
|
||||
usage(w65816, stdout);
|
||||
exit(0);
|
||||
}
|
||||
|
@ -173,6 +196,7 @@ int main(int argc,char *argv[])
|
|||
ofile="a.o65";
|
||||
efile=NULL;
|
||||
lfile=NULL;
|
||||
printfile=NULL;
|
||||
|
||||
if(pp_init()) {
|
||||
logout("fatal: pp: no memory!");
|
||||
|
@ -191,6 +215,18 @@ 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;
|
||||
case 'p':
|
||||
/* intentionally not allowing an argument to follow with a
|
||||
space to avoid - being seen as the alternate
|
||||
|
@ -201,16 +237,17 @@ 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,
|
||||
"warning: extra characters to -p ignored\n");
|
||||
break;
|
||||
case 'M':
|
||||
fprintf(stderr, "Warning: -M is deprecated (use -XMASM) and will be removed in a future version\n");
|
||||
masm = 1; /* MASM compatibility mode */
|
||||
break;
|
||||
case 'O': /* output charset */
|
||||
case 'X': /* compatibility across assemblers... */
|
||||
{
|
||||
char *name = NULL;
|
||||
if (argv[i][2] == 0) {
|
||||
|
@ -218,6 +255,27 @@ int main(int argc,char *argv[])
|
|||
} else {
|
||||
name = argv[i]+2;
|
||||
}
|
||||
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 */
|
||||
{
|
||||
char *name = NULL;
|
||||
if (argv[i][2] == 0) {
|
||||
if (i + 1 < argc) name = argv[++i];
|
||||
else {
|
||||
fprintf(stderr, "-O requires an argument\n");
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
name = argv[i]+2;
|
||||
}
|
||||
if (set_charset(name) < 0) {
|
||||
fprintf(stderr, "Output charset name '%s' unknown - ignoring! (check case?)\n", name);
|
||||
}
|
||||
|
@ -226,7 +284,13 @@ int main(int argc,char *argv[])
|
|||
case 'A': /* make text segment start so that text relocation
|
||||
is not necessary when _file_ starts at adr */
|
||||
romable = 2;
|
||||
if(argv[i][2]==0) romaddr = atoi(argv[++i]);
|
||||
if(argv[i][2]==0) {
|
||||
if (i + 1 < argc) romaddr = atoi(argv[++i]);
|
||||
else {
|
||||
fprintf(stderr, "-A requires an argument\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
else romaddr = atoi(argv[i]+2);
|
||||
break;
|
||||
case 'G':
|
||||
|
@ -241,6 +305,9 @@ int main(int argc,char *argv[])
|
|||
case 'R':
|
||||
relmode = 1;
|
||||
break;
|
||||
case 'U':
|
||||
undefok = 1;
|
||||
break;
|
||||
case 'D':
|
||||
s = (signed char*)strstr(argv[i]+2,"=");
|
||||
if(s) *s = ' ';
|
||||
|
@ -255,44 +322,87 @@ 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;
|
||||
break;
|
||||
case 'x': /* old filename behaviour */
|
||||
oldfile = 1;
|
||||
fprintf(stderr, "Warning: -x is now deprecated and may disappear in future versions!\n");
|
||||
break;
|
||||
case 'I':
|
||||
if(argv[i][2]==0) {
|
||||
reg_include(argv[++i]);
|
||||
if (i + 1 < argc) reg_include(argv[++i]);
|
||||
else {
|
||||
fprintf(stderr, "-I requires an argument\n");
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
reg_include(argv[i]+2);
|
||||
}
|
||||
break;
|
||||
case 'P':
|
||||
if(argv[i][2]==0) {
|
||||
printfile=argv[++i];
|
||||
} else {
|
||||
printfile=argv[i]+2;
|
||||
}
|
||||
break;
|
||||
case 'F':
|
||||
if (argv[i][2]==0) {
|
||||
listformat = argv[++i];
|
||||
} else {
|
||||
listformat = argv[i]+2;
|
||||
}
|
||||
break;
|
||||
case 'o':
|
||||
if(argv[i][2]==0) {
|
||||
ofile=argv[++i];
|
||||
if (i + 1 < argc) ofile=argv[++i];
|
||||
else {
|
||||
fprintf(stderr, "-o requires an argument\n");
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
ofile=argv[i]+2;
|
||||
}
|
||||
break;
|
||||
case 'l':
|
||||
if(argv[i][2]==0) {
|
||||
lfile=argv[++i];
|
||||
if (i + 1 < argc) lfile=argv[++i];
|
||||
else {
|
||||
fprintf(stderr, "-l requires an argument\n");
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
lfile=argv[i]+2;
|
||||
}
|
||||
break;
|
||||
case 'e':
|
||||
if(argv[i][2]==0) {
|
||||
efile=argv[++i];
|
||||
if (i + 1 < argc) efile=argv[++i];
|
||||
else {
|
||||
fprintf(stderr, "-e requires an argument\n");
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
efile=argv[i]+2;
|
||||
}
|
||||
|
@ -346,16 +456,14 @@ int main(int argc,char *argv[])
|
|||
exit(0);
|
||||
}
|
||||
|
||||
if(oldfile) {
|
||||
strcpy(old_e, ifiles[0]);
|
||||
strcpy(old_o, ifiles[0]);
|
||||
strcpy(old_l, ifiles[0]);
|
||||
if(verbose) fprintf(stderr, "%s\n",copyright);
|
||||
|
||||
if(setfext(old_e,".err")==0) efile = old_e;
|
||||
if(setfext(old_o,".obj")==0) ofile = old_o;
|
||||
if(setfext(old_l,".lab")==0) lfile = old_l;
|
||||
if (printfile!=NULL && !strcmp(printfile, "-")) {
|
||||
printfile=NULL;
|
||||
fplist = stdout;
|
||||
} else {
|
||||
fplist= printfile ? xfopen(printfile,"w") : NULL;
|
||||
}
|
||||
|
||||
fplab= lfile ? xfopen(lfile,"w") : NULL;
|
||||
fperr= efile ? xfopen(efile,"w") : NULL;
|
||||
if(!strcmp(ofile,"-")) {
|
||||
|
@ -381,9 +489,11 @@ int main(int argc,char *argv[])
|
|||
{
|
||||
if(!x_init())
|
||||
{
|
||||
if(fperr) fprintf(fperr,"%s\n",copyright);
|
||||
/* if(fperr) fprintf(fperr,"%s\n",copyright); */
|
||||
if(verbose) logout(ctime(&tim1));
|
||||
|
||||
list_setfile(fplist);
|
||||
|
||||
/* Pass 1 */
|
||||
|
||||
pc[SEG_ABS]= 0; /* abs addressing */
|
||||
|
@ -393,6 +503,8 @@ int main(int argc,char *argv[])
|
|||
r_mode(RMODE_RELOC);
|
||||
segment = SEG_TEXT;
|
||||
} else {
|
||||
/* prime old_segment in r_mode with SEG_TEXT */
|
||||
segment = SEG_ABS;
|
||||
r_mode(RMODE_ABS);
|
||||
}
|
||||
|
||||
|
@ -406,7 +518,7 @@ int main(int argc,char *argv[])
|
|||
if(verbose) logout(out);
|
||||
|
||||
er=pp_open(ifile);
|
||||
puttmp(0);
|
||||
puttmpw(0);
|
||||
puttmp(T_FILE);
|
||||
puttmp(0);
|
||||
puttmp(0);
|
||||
|
@ -438,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) {
|
||||
|
@ -459,15 +567,21 @@ int main(int argc,char *argv[])
|
|||
{
|
||||
if(verbose) logout("xAss65: Pass 2:\n");
|
||||
|
||||
list_start(listformat);
|
||||
|
||||
seg_pass2();
|
||||
|
||||
if(!relmode) {
|
||||
r_mode(RMODE_ABS);
|
||||
if(relmode) {
|
||||
r_mode(RMODE_RELOC);
|
||||
segment = SEG_TEXT;
|
||||
} else {
|
||||
r_mode(RMODE_RELOC);
|
||||
segment = SEG_TEXT;
|
||||
/* prime old_segment in r_mode with SEG_TEXT */
|
||||
segment = SEG_ABS;
|
||||
r_mode(RMODE_ABS);
|
||||
}
|
||||
er=pass2();
|
||||
|
||||
list_end();
|
||||
}
|
||||
|
||||
if(fplab) printllist(fplab);
|
||||
|
@ -476,9 +590,10 @@ int main(int argc,char *argv[])
|
|||
|
||||
if((!er) && relmode) seg_end(fpout); /* write reloc/label info */
|
||||
|
||||
if(fplist && fplist!=stdout) fclose(fplist);
|
||||
if(fperr) fclose(fperr);
|
||||
if(fplab) fclose(fplab);
|
||||
if(fpout) fclose(fpout);
|
||||
if(fpout && fpout!=stdout) fclose(fpout);
|
||||
|
||||
} else {
|
||||
logout("fatal: x: no memory!\n");
|
||||
|
@ -500,7 +615,12 @@ int main(int argc,char *argv[])
|
|||
|
||||
if(ner || er)
|
||||
{
|
||||
if (ner_max > 0) {
|
||||
fprintf(stderr, "Break after %d error%c\n",ner,ner?'s':0);
|
||||
} else {
|
||||
/* ner_max==0, i.e. show all errors */
|
||||
fprintf(stderr, "End after %d error%c\n",ner,ner?'s':0);
|
||||
}
|
||||
/*unlink();*/
|
||||
if(ofile) {
|
||||
unlink(ofile);
|
||||
|
@ -528,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)
|
||||
{
|
||||
|
@ -581,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)
|
||||
{
|
||||
|
@ -615,39 +704,41 @@ static int pass2(void)
|
|||
filep=&datei;
|
||||
afile->mn.tmpe=0L;
|
||||
|
||||
while(ner<20 && afile->mn.tmpe<afile->mn.tmpz)
|
||||
while((ner_max==0 || ner<ner_max) && afile->mn.tmpe<afile->mn.tmpz)
|
||||
{
|
||||
l=afile->mn.tmp[afile->mn.tmpe++];
|
||||
// get the length of the entry (now two byte - need to handle the sign)
|
||||
l = 255 & afile->mn.tmp[afile->mn.tmpe++];
|
||||
l |= afile->mn.tmp[afile->mn.tmpe++] << 8;
|
||||
ll=l;
|
||||
|
||||
//printf("%p: l=%d first=%02x\n", afile->mn.tmp+afile->mn.tmpe-1, l, 0xff & afile->mn.tmp[afile->mn.tmpe]);
|
||||
|
||||
if(!l)
|
||||
{
|
||||
if(afile->mn.tmp[afile->mn.tmpe]==T_LINE)
|
||||
{
|
||||
datei.fline=(afile->mn.tmp[afile->mn.tmpe+1]&255)+(afile->mn.tmp[afile->mn.tmpe+2]<<8);
|
||||
afile->mn.tmpe+=3;
|
||||
list_line(datei.fline); /* set line number of next listing output */
|
||||
} else
|
||||
if(afile->mn.tmp[afile->mn.tmpe]==T_FILE)
|
||||
{
|
||||
// copy the current line number from the current file descriptor
|
||||
datei.fline=(afile->mn.tmp[afile->mn.tmpe+1]&255)+(afile->mn.tmp[afile->mn.tmpe+2]<<8);
|
||||
|
||||
// copy the pointer to the file name in the current file descriptor
|
||||
// Note: the filename in the current file descriptor is separately malloc'd and
|
||||
// thus save to store the pointer
|
||||
memcpy(&datei.fname, afile->mn.tmp+afile->mn.tmpe+3, sizeof(datei.fname));
|
||||
afile->mn.tmpe+=3+sizeof(datei.fname);
|
||||
/*
|
||||
datei.fname = malloc(strlen((char*) afile->mn.tmp+afile->mn.tmpe+3)+1);
|
||||
if(!datei.fname) {
|
||||
fprintf(stderr,"Oops, no more memory\n");
|
||||
exit(1);
|
||||
}
|
||||
strcpy(datei.fname,(char*) afile->mn.tmp+afile->mn.tmpe+3);
|
||||
afile->mn.tmpe+=3+strlen(datei.fname);
|
||||
*/
|
||||
|
||||
list_filename(datei.fname); /* set file name of next listing output */
|
||||
}
|
||||
} else
|
||||
{
|
||||
/* do not attempt address mode optimization on pass 2 */
|
||||
er=t_p2(afile->mn.tmp+afile->mn.tmpe,&ll,1,&al);
|
||||
|
||||
|
||||
/* t_p2_l() includes the listing call to do_listing() */
|
||||
er=t_p2_l(afile->mn.tmp+afile->mn.tmpe,&ll,&al);
|
||||
if(er==E_NOLINE)
|
||||
{
|
||||
} else
|
||||
|
@ -717,7 +808,7 @@ fprintf(stderr, "offset = %i length = %i fstart = %i flen = %i charo = %c\n",
|
|||
fprintf(stderr, "fnam = %s\n", binfnam);
|
||||
*/
|
||||
/* primitive insurance */
|
||||
if (!(foo = fopen(binfnam, "r"))) {
|
||||
if (!(foo = fopen(binfnam, "rb"))) {
|
||||
errout(E_FNF);
|
||||
ner++;
|
||||
} else {
|
||||
|
@ -752,16 +843,14 @@ fprintf(stderr, "offset = %i length = %i fstart = %i flen = %i charo = %c\n",
|
|||
|
||||
static int pass1(void)
|
||||
{
|
||||
signed char o[MAXLINE];
|
||||
int l,er,temp_er,al;
|
||||
signed char o[2*MAXLINE]; /* doubled for token listing */
|
||||
int l,er,al;
|
||||
|
||||
memode=0;
|
||||
xmode=0;
|
||||
tlen=0;
|
||||
ner=0;
|
||||
|
||||
temp_er = 0;
|
||||
|
||||
/*FIXIT*/
|
||||
while(!(er=xa_getline(s)))
|
||||
{
|
||||
|
@ -774,7 +863,7 @@ static int pass1(void)
|
|||
case SEG_ZERO: zlen += al; break;
|
||||
}
|
||||
|
||||
/*printf(": er= %d, l=%d, tmpz=%d\n",er,l,tmpz); */
|
||||
//printf(": er= %d, l=%d\n",er,l);
|
||||
|
||||
if(l)
|
||||
{
|
||||
|
@ -782,14 +871,14 @@ static int pass1(void)
|
|||
{
|
||||
if(er==E_OKDEF)
|
||||
{
|
||||
if(!(er=puttmp(l)))
|
||||
if(!(er=puttmpw(l)))
|
||||
er=puttmps(o,l);
|
||||
} else
|
||||
if(er==E_NOLINE)
|
||||
er=E_OK;
|
||||
} else
|
||||
{
|
||||
if(!(er=puttmp(-l)))
|
||||
if(!(er=puttmpw(-l)))
|
||||
er=puttmps(o,l);
|
||||
}
|
||||
}
|
||||
|
@ -804,7 +893,6 @@ static int pass1(void)
|
|||
}
|
||||
|
||||
if(er!=E_EOF) {
|
||||
fprintf(stderr, "foul through\n");
|
||||
errout(er);
|
||||
}
|
||||
|
||||
|
@ -827,8 +915,7 @@ static void usage(int default816, FILE *fp)
|
|||
programname);
|
||||
fprintf(fp,
|
||||
" -v verbose output\n"
|
||||
" -x old filename behaviour (overrides `-o', `-e', `-l')\n"
|
||||
" This is deprecated and may disappear in future versions!\n"
|
||||
" -E do not break after 20 errors, but show all\n"
|
||||
" -C no CMOS-opcodes\n"
|
||||
" -W no 65816-opcodes%s\n"
|
||||
" -w allow 65816-opcodes%s\n",
|
||||
|
@ -842,11 +929,21 @@ static void usage(int default816, FILE *fp)
|
|||
fprintf(fp,
|
||||
" -e filename sets errorlog filename, default is none\n"
|
||||
" -l filename sets labellist filename, default is none\n"
|
||||
" -P filename sets filename for listing, default is none, '-' is stdout\n"
|
||||
" -F format sets format for listing, default is plain, 'html' is current only other\n"
|
||||
" supported format\n"
|
||||
" -r adds crossreference list to labellist (if `-l' given)\n"
|
||||
" -M allow ``:'' to appear in comments for MASM compatibility\n"
|
||||
" -R start assembler in relocating mode\n");
|
||||
" (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,
|
||||
" -Llabel defines `label' as absolute, undefined label even when linking\n"
|
||||
" -p<c> replace preprocessor char '#' with custom, e.g. '-p!' replaces it with '!'\n"
|
||||
" -b? addr set segment base address to integer value addr\n"
|
||||
" `?' stands for t(ext), d(ata), b(ss) and z(ero) segment\n"
|
||||
" (address can be given more than once, last one is used)\n");
|
||||
|
@ -856,105 +953,95 @@ static void usage(int default816, FILE *fp)
|
|||
" Other segments must be specified with `-b?'\n"
|
||||
" -G suppress list of exported globals\n");
|
||||
fprintf(fp,
|
||||
" -p? set preprocessor character to ?, default is #\n"
|
||||
" -DDEF=TEXT defines a preprocessor replacement\n"
|
||||
" -Ocharset set output charset (PETSCII or ASCII), case-sensitive\n"
|
||||
" -Ocharset set output charset (PETSCII, ASCII, etc.), case-sensitive\n"
|
||||
" -Idir add directory `dir' to include path (before XAINPUT)\n"
|
||||
" --version output version information and exit\n"
|
||||
" --help display this help and exit\n");
|
||||
}
|
||||
|
||||
/*
|
||||
static char *ertxt[] = { "Syntax","Label definiert",
|
||||
"Label nicht definiert","Labeltabelle voll",
|
||||
"Label erwartet","Speicher voll","Illegaler Opcode",
|
||||
"Falsche Adressierungsart","Branch ausserhalb des Bereichs",
|
||||
"Ueberlauf","Division durch Null","Pseudo-Opcode erwartet",
|
||||
"Block-Stack-Ueberlauf","Datei nicht gefunden",
|
||||
"End of File","Block-Struktur nicht abgeschlossen",
|
||||
"NoBlk","NoKey","NoLine","OKDef","DSB","NewLine",
|
||||
"NewFile","CMOS-Befehl","pp:Falsche Anzahl Parameter" };
|
||||
*/
|
||||
static char *ertxt[] = {
|
||||
"Syntax",
|
||||
"Label already defined",
|
||||
"Label not defined",
|
||||
"Label table full",
|
||||
"Label expected",
|
||||
"Out of memory",
|
||||
"Illegal opcode",
|
||||
"Wrong addressing mode",
|
||||
"Branch out of range",
|
||||
"Overflow",
|
||||
"Division by zero",
|
||||
"Pseudo-opcode expected",
|
||||
"Block stack overflow",
|
||||
"File not found",
|
||||
"End of file",
|
||||
"Unmatched block close",
|
||||
"NoBlk",
|
||||
"NoKey",
|
||||
"NoLine",
|
||||
"OKDef",
|
||||
"DSB",
|
||||
"NewLine",
|
||||
"NewFile",
|
||||
"CMOS instruction used with -C",
|
||||
"pp:Wrong parameter count",
|
||||
"Illegal pointer arithmetic",
|
||||
"Illegal segment",
|
||||
"File header option too long",
|
||||
"File option not at file start (when ROM-able)",
|
||||
"Illegal align value",
|
||||
"65816 mode used/required",
|
||||
"Exceeded recursion limit for label evaluation",
|
||||
"Unresolved preprocessor directive at end of file",
|
||||
"Data underflow",
|
||||
"Illegal quantity",
|
||||
".bin",
|
||||
"Syntax", // E_SYNTAX =-1
|
||||
"Label already defined", // E_LABDEF =-2
|
||||
"Label not defined", // E_NODEF =-3
|
||||
"Label table full", // E_LABFULL =-4
|
||||
"Label expected", // E_LABEXP =-5
|
||||
"Out of memory", // E_NOMEM =-6
|
||||
"Illegal opcode", // E_ILLCODE =-7
|
||||
"Wrong addressing mode", // E_ADRESS =-8
|
||||
"Branch out of range", // E_RANGE =-9
|
||||
"Overflow", // E_OVERFLOW =-10
|
||||
"Division by zero", // E_DIV =-11
|
||||
"Pseudo-opcode expected", // E_PSOEXP =-12
|
||||
"Block stack overflow", // E_BLKOVR =-13
|
||||
"File not found", // E_FNF =-14
|
||||
"End of file", // E_EOF =-15
|
||||
"Unmatched block close", // E_BLOCK =-16
|
||||
"NoBlk", // E_NOBLK =-17
|
||||
"NoKey", // E_NOKEY =-18
|
||||
"NoLine", // E_NOLINE =-19
|
||||
"OKDef", // E_OKDEF =-20
|
||||
"DSB", // E_DSB =-21
|
||||
"NewLine", // E_NEWLINE =-22
|
||||
"NewFile", // E_NEWFILE =-23
|
||||
"CMOS instruction used with -C", // E_DMOS =-24
|
||||
"pp:Wrong parameter count", // E_ANZPAR =-25
|
||||
"Illegal pointer arithmetic (-26)", // E_ILLPOINTER =-26
|
||||
"Illegal segment", // E_ILLSEGMENT =-27
|
||||
"File header option too long", // E_OPTLEN =-28
|
||||
"File option not at file start (when ROM-able)", // E_ROMOPT =-29
|
||||
"Illegal align value", // E_ILLALIGN =-30
|
||||
"65816 mode used/required", // E_65816 =-31
|
||||
"Exceeded recursion limit for label evaluation", // E_ORECMAC =-32
|
||||
"Unresolved preprocessor directive at end of file", // E_OPENPP =-33
|
||||
"Data underflow", // E_OUTOFDATA =-34
|
||||
"Illegal quantity", // E_ILLQUANT =-35
|
||||
".bin", // E_BIN =-36
|
||||
"#error directive", // E_UERROR =-37
|
||||
"Assertion", // E_AERROR =-38
|
||||
"DSB has negative length", // E_NEGDSBLEN =-39
|
||||
/* placeholders for future fatal errors */
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // -40
|
||||
"", // -41
|
||||
"", // -42
|
||||
"", // -43
|
||||
"", // -44
|
||||
"", // -45
|
||||
"", // -46
|
||||
"", // -47
|
||||
"", // -48
|
||||
"", // -49
|
||||
"", // -50
|
||||
"", // -51
|
||||
"", // -52
|
||||
"", // -53
|
||||
"", // -54
|
||||
"", // -55
|
||||
"", // -56
|
||||
"", // -57
|
||||
"", // -58
|
||||
"", // -59
|
||||
"", // -60
|
||||
"", // -61
|
||||
"", // -62
|
||||
"", // -63
|
||||
"", // -64 (was missing...)
|
||||
/* warnings */
|
||||
"Cutting word relocation in byte value",
|
||||
"Byte relocation in word value",
|
||||
"Illegal pointer arithmetic",
|
||||
"Address access to low or high byte pointer",
|
||||
"High byte access to low byte pointer",
|
||||
"Low byte access to high byte pointer",
|
||||
"Can't optimize forward-defined label; using absolute addressing",
|
||||
"Open preprocessor directive at end of file (intentional?)",
|
||||
"Included binary data exceeds 64KB",
|
||||
"Included binary data exceeds 16MB",
|
||||
"Cutting word relocation in byte value", // W_ADRRELOC =-65
|
||||
"Byte relocation in word value", // W_BYTERELOC =-66
|
||||
"Illegal pointer arithmetic (-66)", // E_WPOINTER =-67
|
||||
"Address access to low or high byte pointer", // W_ADDRACC =-68
|
||||
"High byte access to low byte pointer", // W_HIGHACC =-69
|
||||
"Low byte access to high byte pointer", // W_LOWACC =-70
|
||||
"Can't optimize forward-defined label; using absolute addressing", // W_FORLAB =-71
|
||||
"Open preprocessor directive at end of file (intentional?)", // W_OPENPP =-72
|
||||
"Included binary data exceeds 64KB", // W_OVER64K =-73
|
||||
"Included binary data exceeds 16MB", // W_OVER16M =-74
|
||||
"Subtracting pointer from constant not supported in -R mode", // W_SUBTRACT =-75
|
||||
/* more placeholders */
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"", // -76
|
||||
"", // -77
|
||||
|
||||
};
|
||||
|
||||
|
@ -977,7 +1064,9 @@ static int x_init(void)
|
|||
static int puttmp(int c)
|
||||
{
|
||||
int er=E_NOMEM;
|
||||
/*printf("puttmp: afile=%p, tmp=%p, tmpz=%d\n",afile, afile?afile->mn.tmp:0, afile?afile->mn.tmpz:0);*/
|
||||
|
||||
//printf("puttmp: %02x -> %p \n",0xff & c, afile->mn.tmp+afile->mn.tmpz);
|
||||
|
||||
if(afile->mn.tmpz<TMPMEM)
|
||||
{
|
||||
afile->mn.tmp[afile->mn.tmpz++]=c;
|
||||
|
@ -986,17 +1075,37 @@ static int puttmp(int c)
|
|||
return(er);
|
||||
}
|
||||
|
||||
static int puttmpw(int c)
|
||||
{
|
||||
int er=E_NOMEM;
|
||||
|
||||
//printf("puttmp: %02x -> %p \n",0xff & c, afile->mn.tmp+afile->mn.tmpz);
|
||||
|
||||
if(afile->mn.tmpz<TMPMEM-1)
|
||||
{
|
||||
afile->mn.tmp[afile->mn.tmpz++]= c & 0xff;
|
||||
afile->mn.tmp[afile->mn.tmpz++]= (c >> 8) & 0xff;
|
||||
er=E_OK;
|
||||
}
|
||||
return(er);
|
||||
}
|
||||
|
||||
static int puttmps(signed char *s, int l)
|
||||
{
|
||||
int i=0,er=E_NOMEM;
|
||||
|
||||
|
||||
// printf("puttmps %d bytes from %p to %p:", l, s, afile->mn.tmp+afile->mn.tmpz);
|
||||
|
||||
if(afile->mn.tmpz+l<TMPMEM)
|
||||
{
|
||||
while(i<l)
|
||||
afile->mn.tmp[afile->mn.tmpz++]=s[i++];
|
||||
while(i<l) {
|
||||
//printf(" %02x", 0xff & s[i]);
|
||||
afile->mn.tmp[afile->mn.tmpz++]=s[i++];
|
||||
}
|
||||
|
||||
er=E_OK;
|
||||
}
|
||||
// printf("\n");
|
||||
return(er);
|
||||
}
|
||||
|
||||
|
@ -1026,25 +1135,19 @@ static int xa_getline(char *s)
|
|||
|
||||
if(ec==E_NEWLINE)
|
||||
{
|
||||
puttmp(0);
|
||||
puttmpw(0);
|
||||
puttmp(T_LINE);
|
||||
puttmp((filep->fline)&255);
|
||||
puttmp(((filep->fline)>>8)&255);
|
||||
ec=E_OK;
|
||||
puttmpw(filep->fline);
|
||||
ec=E_OK;
|
||||
|
||||
}
|
||||
else
|
||||
if(ec==E_NEWFILE)
|
||||
{
|
||||
puttmp(0);
|
||||
puttmpw(0);
|
||||
puttmp(T_FILE);
|
||||
puttmp((filep->fline)&255);
|
||||
puttmp(((filep->fline)>>8)&255);
|
||||
puttmpw(filep->fline);
|
||||
puttmps((signed char*)&(filep->fname), sizeof(filep->fname));
|
||||
/*
|
||||
puttmps((signed char*)filep->fname,
|
||||
1+(int)strlen(filep->fname));
|
||||
*/
|
||||
ec=E_OK;
|
||||
}
|
||||
} while(!ec && l[i]=='\0');
|
||||
|
@ -1053,26 +1156,52 @@ static int xa_getline(char *s)
|
|||
gl=0;
|
||||
if(!ec || ec==E_EOF)
|
||||
{
|
||||
int startofline = 1;
|
||||
do {
|
||||
c=s[j]=l[i++];
|
||||
|
||||
if (c=='\"')
|
||||
if (!(hkfl&2) && c=='\"')
|
||||
hkfl^=1;
|
||||
if (c==';' && !hkfl)
|
||||
if (!comcom && !(hkfl&1) && c=='\'')
|
||||
hkfl^=2;
|
||||
if (c==';' && !hkfl) {
|
||||
comcom = 1;
|
||||
if (c=='\0')
|
||||
break; /* hkfl = comcom = 0 */
|
||||
if (c==':' && !hkfl && (!comcom || !masm)) {
|
||||
gl=1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (c=='\0') {
|
||||
// end of line
|
||||
break; /* hkfl = comcom = 0 */
|
||||
}
|
||||
if (c==':' && !hkfl) {
|
||||
/* if the next char is a "=" - so that we have a ":=" - and we
|
||||
we have ca65 compatibility, we ignore the colon */
|
||||
// also check for ":+" and ":-"
|
||||
|
||||
//#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 || 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... */
|
||||
gl=1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!isspace(c)) {
|
||||
startofline = 0;
|
||||
}
|
||||
j++;
|
||||
} while (c!='\0' && j<MAXLINE-1 && i<MAXLINE-1);
|
||||
|
||||
s[j]='\0';
|
||||
} else
|
||||
s[0]='\0';
|
||||
|
||||
#if 0
|
||||
printf("got line: %s\n", s);
|
||||
#endif
|
||||
return(ec);
|
||||
}
|
||||
|
||||
|
@ -1092,8 +1221,8 @@ static void lineout(void)
|
|||
|
||||
void errout(int er)
|
||||
{
|
||||
if (er<-ANZERR || er>-1) {
|
||||
if(er>=-(ANZERR+ANZWARN) && er < -ANZERR) {
|
||||
if (er<=-ANZERR || er>-1) {
|
||||
if(er>=-(ANZERR+ANZWARN) && er <= -ANZERR) {
|
||||
sprintf(out,"%s:line %d: %04x: Warning - %s\n",
|
||||
filep->fname, filep->fline, pc[segment], ertxt[(-er)-1]);
|
||||
} else {
|
||||
|
@ -1129,3 +1258,37 @@ void logout(char *s)
|
|||
fprintf(fperr,"%s",s);
|
||||
}
|
||||
|
||||
/*****************************************************************/
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
int *flag;
|
||||
} compat_set;
|
||||
|
||||
static compat_set compat_sets[] = {
|
||||
{ "MASM", &masm },
|
||||
{ "CA65", &ca65 },
|
||||
{ "C", &ctypes },
|
||||
{ "XA23", &xa23 },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
int set_compat(char *compat_name) {
|
||||
int i = 0;
|
||||
while (compat_sets[i].name != NULL) {
|
||||
if (strcmp(compat_sets[i].name, compat_name) == 0) {
|
||||
/* set appropriate compatibility flag */
|
||||
(*compat_sets[i].flag) = 1;
|
||||
|
||||
/* warn on old versions of xa */
|
||||
if (xa23) fprintf(stderr,
|
||||
"Warning: -XXA23 is explicitly deprecated\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -21,12 +21,18 @@
|
|||
|
||||
#include "xah.h" /* For SEG_MAX */
|
||||
|
||||
#define progmajor "2"
|
||||
#define progminor "4"
|
||||
#define progpatch "1"
|
||||
#define progversion progmajor "." progminor "." progpatch
|
||||
|
||||
extern int ncmos, cmosfl, w65816, n65816;
|
||||
extern int masm, nolink;
|
||||
extern int masm, ca65, xa23, nolink, undefok, collab, mask;
|
||||
extern int noglob;
|
||||
extern int showblk;
|
||||
extern int relmode;
|
||||
extern int crossref;
|
||||
extern int ctypes;
|
||||
extern char altppchar;
|
||||
|
||||
extern int tlen, tbase;
|
||||
|
|
92
xa/src/xaa.c
92
xa/src/xaa.c
|
@ -32,7 +32,7 @@
|
|||
|
||||
static int pr[]= { P_START,P_ADD,P_ADD,P_MULT,P_MULT,P_SHIFT,P_SHIFT,P_CMP,
|
||||
P_CMP,P_EQU,P_CMP,P_CMP,P_EQU,P_AND,P_XOR,P_OR,
|
||||
P_LAND,P_LOR };
|
||||
P_LAND,P_LOR,P_EQU,P_START };
|
||||
|
||||
static int pp,pcc;
|
||||
static int fundef;
|
||||
|
@ -77,7 +77,8 @@ int a_term(signed char *s, int *v, int *l, int xpc, int *pfl, int *label, int f)
|
|||
if(afl) *pfl=A_HIGH | ((afl<<8) & A_FMASK) | (*v & 255);
|
||||
*v=(*v>>8)&255;
|
||||
}
|
||||
else {
|
||||
else
|
||||
if(s[pp]!=T_END) {
|
||||
er=ag_term(s,P_START,v,&afl, label);
|
||||
bfl = afl & (A_MASK>>8);
|
||||
if(bfl && (bfl != (A_ADR>>8)) ) {
|
||||
|
@ -85,10 +86,12 @@ int a_term(signed char *s, int *v, int *l, int xpc, int *pfl, int *label, int f)
|
|||
errout(W_ADDRACC);
|
||||
}
|
||||
if(afl) *pfl = A_ADR | ((afl<<8) & A_FMASK);
|
||||
} else {
|
||||
er = E_SYNTAX;
|
||||
}
|
||||
|
||||
*l=pp;
|
||||
/* printf("a_term: afl->%04x *pfl=%04x, (pc=%04x)\n",afl,*pfl, xpc); */
|
||||
//fprintf(stderr, "a_term: nolink=%d, noundef=%d ->er=%d; l=%d, pp=%d, afl->%04x *pfl=%04x, (pc=%04x)\n",nolink, noundef ,er, *l, pp, afl,*pfl, xpc);
|
||||
return(er);
|
||||
}
|
||||
|
||||
|
@ -98,13 +101,28 @@ static int ag_term(signed char *s, int p, int *v, int *nafl, int *label)
|
|||
|
||||
afl = 0;
|
||||
|
||||
/*printf("ag_term(%02x %02x %02x %02x %02x %02x\n",s[0],s[1],s[2],s[3],s[4],s[5]);*/
|
||||
//fprintf(stderr, "ag_term(%02x %02x %02x %02x %02x %02x\n",s[0],s[1],s[2],s[3],s[4],s[5]);
|
||||
|
||||
while(s[pp]=='-')
|
||||
{
|
||||
pp++;
|
||||
mf=-mf;
|
||||
}
|
||||
|
||||
#if(0) /* NYI: this is hacked into .assert for now */
|
||||
if(s[pp]==18) /* logical not */
|
||||
{
|
||||
pp++;
|
||||
if(!(er=ag_term(s,P_START,v,&afl,label)))
|
||||
{
|
||||
if(s[pp]!=')')
|
||||
er=E_SYNTAX;
|
||||
else
|
||||
pp++;
|
||||
}
|
||||
*v = !(*v);
|
||||
} else
|
||||
#endif
|
||||
if(s[pp]=='(')
|
||||
{
|
||||
pp++;
|
||||
|
@ -119,32 +137,44 @@ static int ag_term(signed char *s, int p, int *v, int *nafl, int *label)
|
|||
if(s[pp]==T_LABEL)
|
||||
{
|
||||
er=l_get(cval(s+pp+1),v, &afl);
|
||||
/* printf("label: er=%d, seg=%d, afl=%d, nolink=%d, fundef=%d\n",
|
||||
er, segment, afl, nolink, fundef); */
|
||||
|
||||
/*
|
||||
printf("label: er=%d, seg=%d, afl=%d, nolink=%d, fundef=%d\n",
|
||||
er, segment, afl, nolink, fundef);
|
||||
*/
|
||||
if(er==E_NODEF && segment != SEG_ABS && fundef ) {
|
||||
if( nolink || (afl==SEG_UNDEF)) {
|
||||
if( nolink || ((afl==SEG_UNDEF) || (afl==SEG_UNDEFZP))) {
|
||||
er = E_OK;
|
||||
*v = 0;
|
||||
afl = SEG_UNDEF;
|
||||
if(afl!=SEG_UNDEFZP) {
|
||||
afl = SEG_UNDEF;
|
||||
}
|
||||
*label = cval(s+pp+1);
|
||||
}
|
||||
}
|
||||
pp+=3;
|
||||
}
|
||||
else
|
||||
if(s[pp]==T_VALUE)
|
||||
if(s[pp]==T_VALUE || s[pp] == T_CAST)
|
||||
{
|
||||
while (s[pp] == T_CAST) {
|
||||
pp+=2;
|
||||
}
|
||||
*v=lval(s+pp+1);
|
||||
pp+=4;
|
||||
/* printf("value: v=%04x\n",*v); */
|
||||
pp+=5;
|
||||
/*
|
||||
printf("value: v=%04x\n",*v);
|
||||
*/
|
||||
}
|
||||
else
|
||||
if(s[pp]==T_POINTER)
|
||||
{
|
||||
afl = s[pp+1];
|
||||
*v=cval(s+pp+2);
|
||||
pp+=4;
|
||||
/* printf("pointer: v=%04x, afl=%04x\n",*v,afl); */
|
||||
pp+=6;
|
||||
/*
|
||||
printf("pointer: v=%04x, afl=%04x\n",*v,afl);
|
||||
*/
|
||||
}
|
||||
else
|
||||
if(s[pp]=='*')
|
||||
|
@ -152,15 +182,16 @@ static int ag_term(signed char *s, int p, int *v, int *nafl, int *label)
|
|||
*v=pcc;
|
||||
pp++;
|
||||
afl = segment;
|
||||
}
|
||||
}
|
||||
else {
|
||||
er=E_SYNTAX;
|
||||
}
|
||||
|
||||
*v *= mf;
|
||||
|
||||
while(!er && s[pp]!=')' && s[pp]!=']' && s[pp]!=',' && s[pp]!=T_END)
|
||||
while(!er && s[pp]!=')' && s[pp]!=']' && s[pp]!=',' && s[pp]!=T_END && s[pp]!=T_COMMENT)
|
||||
{
|
||||
//fprintf(stderr, "ag_term while: s[pp=%d]=%02x\n", pp, s[pp]);
|
||||
er=get_op(s,&o);
|
||||
|
||||
if(!er && pr[o]>p)
|
||||
|
@ -169,18 +200,25 @@ static int ag_term(signed char *s, int p, int *v, int *nafl, int *label)
|
|||
if(!(er=ag_term(s,pr[o],&w, nafl, label)))
|
||||
{
|
||||
if(afl || *nafl) { /* check pointer arithmetic */
|
||||
if((afl == *nafl) && (afl!=SEG_UNDEF) && o==2) {
|
||||
afl = 0; /* substract two pointers */
|
||||
if((afl == *nafl) && (afl!=SEG_UNDEFZP) && (afl!=SEG_UNDEF) && o==2) {
|
||||
afl = 0; /* subtract two pointers */
|
||||
} else
|
||||
if(((afl && !*nafl) || (*nafl && !afl)) && o==1) {
|
||||
afl=(afl | *nafl); /* add constant to pointer */
|
||||
} else
|
||||
if((afl && !*nafl) && o==2) {
|
||||
afl=(afl | *nafl); /* substract constant from pointer */
|
||||
afl=(afl | *nafl); /* subtract constant from pointer */
|
||||
} else {
|
||||
if(segment!=SEG_ABS) {
|
||||
if((!afl && *nafl) && o==2) {
|
||||
/* subtract pointer from constant */
|
||||
errout(W_SUBTRACT);
|
||||
}
|
||||
/* allow math in the same segment */
|
||||
if(segment!=SEG_ABS && segment != afl) {
|
||||
if(!dsb_len) {
|
||||
er=E_ILLPOINTER;
|
||||
/*printf("ILLPOINTER=dsb_len=%d,segment=%d\n",dsb_len, segment);*/
|
||||
/* e.g. adding two pointers, adding two undefined values */
|
||||
er=E_ILLSEGMENT;
|
||||
}
|
||||
}
|
||||
afl=0;
|
||||
|
@ -202,10 +240,18 @@ static int get_op(signed char *s, int *o)
|
|||
|
||||
*o=s[pp];
|
||||
|
||||
if(*o<1 || *o>17)
|
||||
if(*o<1 || *o>17) {
|
||||
/*
|
||||
printf("*o=%d, pp=%d, s=%s\n", *o, pp, s);
|
||||
for (int i=0; i< 10; i++) {
|
||||
printf(" %02x", s[i]);
|
||||
}
|
||||
printf("\n");
|
||||
*/
|
||||
er=E_SYNTAX;
|
||||
else
|
||||
} else {
|
||||
er=E_OK;
|
||||
}
|
||||
|
||||
return(er);
|
||||
}
|
||||
|
@ -224,7 +270,7 @@ static int do_op(int *w,int w2,int o)
|
|||
*w *=w2;
|
||||
break;
|
||||
case 4:
|
||||
if (w!=0)
|
||||
if (w2!=0)
|
||||
*w /=w2;
|
||||
else
|
||||
er =E_DIV;
|
||||
|
|
|
@ -31,11 +31,14 @@
|
|||
|
||||
#define cval(s) 256 * ((s)[1] & 255) + ((s)[0]&255)
|
||||
#define lval(s) 65536 * ((s)[2] & 255) + 256 * ((s)[1] & 255) + ((s)[0] & 255)
|
||||
#define wval(i, v) do { \
|
||||
#define wval(i, v, f) do { \
|
||||
t[i++] = T_VALUE; \
|
||||
t[i++] = v & 255; \
|
||||
t[i++] = (v >> 8) & 255; \
|
||||
t[i++] = (v >> 16) & 255; \
|
||||
t[i++] = f & 255; \
|
||||
} while (0)
|
||||
|
||||
#define wval_len 5 /* number of bytes stored in wval() call */
|
||||
|
||||
#endif /* __XA65_XAD_H__ */
|
||||
|
|
111
xa/src/xah.h
111
xa/src/xah.h
|
@ -20,15 +20,29 @@
|
|||
#ifndef __XA65_XAH_H__
|
||||
#define __XA65_XAH_H__
|
||||
|
||||
#define ANZLAB 5000 /* mal 14 -> Byte */
|
||||
/*
|
||||
* Note: the computations to get the number of bytes necessary to allocate are
|
||||
* a historic remnant of the Atari ST (the original platform) not being able to efficiently allocate small chunks
|
||||
* of memory so I had to allocate a large chunk myself and manage the tables myself.
|
||||
* This has changed and some parts of xa65 are modified to just do a malloc() now.
|
||||
* These fixed numbers should actually go away. AF 20110623
|
||||
*/
|
||||
#define ANZLAB 5000 /* multiplied by sizeof(Labtab) -> Byte */
|
||||
#define LABMEM 40000L
|
||||
#define MAXLAB 32
|
||||
#define MAXBLK 16
|
||||
#define MAXFILE 7
|
||||
#define MAXLINE 2048
|
||||
#define MAXPP 40000L
|
||||
#define ANZDEF 2340 /* mal 14 -> Byte, ANZDEF * 14 < 32768 */
|
||||
#define TMPMEM 200000L /* Zwischenspeicher von Pass1 nach Pass 2 */
|
||||
#define ANZDEF 2340 /* multiplied by sizeof(List) -> Byte, ANZDEF * 20 < 32768 */
|
||||
#define TMPMEM 2000000L /* temporary memory buffer from Pass1 to Pass 2 (includes all source, thus enlarged) */
|
||||
|
||||
typedef enum {
|
||||
STD = 0,
|
||||
CHEAP = 1,
|
||||
UNNAMED = 2,
|
||||
UNNAMED_DEF = 3
|
||||
} xalabel_t;
|
||||
|
||||
typedef struct LabOcc {
|
||||
struct LabOcc *next;
|
||||
|
@ -36,17 +50,29 @@ typedef struct LabOcc {
|
|||
char *fname;
|
||||
} LabOcc;
|
||||
|
||||
/**
|
||||
* struct that defines a label, after it has been parsed
|
||||
*/
|
||||
typedef struct {
|
||||
int blk;
|
||||
int origblk; // only for fl=3
|
||||
int val;
|
||||
int len;
|
||||
int fl; /* 0 = label value not valid/known,
|
||||
* 1 = label value known
|
||||
* 2 = label value not known, external global label (imported on link)
|
||||
* 3 = label value not known, temporarily on external global label list (for -U)
|
||||
*/
|
||||
int afl; /* 0 = no address (no relocation), 1 = address label */
|
||||
int nextindex;
|
||||
xalabel_t is_cll; /* 0 is normal label, 1 is cheap local label (used for listing) */
|
||||
char *n;
|
||||
struct LabOcc *occlist;
|
||||
// within a block, make a linked list for the unnamed label counting
|
||||
// use indexes, as the label table can be re-alloced (so pointers change)
|
||||
// -1 is the "undef'd" end of list
|
||||
int blknext;
|
||||
int blkprev;
|
||||
} Labtab;
|
||||
|
||||
typedef struct {
|
||||
|
@ -71,20 +97,20 @@ typedef struct {
|
|||
|
||||
#define BUFSIZE 4096 /* File-Puffegroesse (wg Festplatte) */
|
||||
|
||||
#define E_OK 0 /* Fehlernummern */
|
||||
#define E_SYNTAX -1 /* Syntax Fehler */
|
||||
#define E_LABDEF -2 /* Label definiert */
|
||||
#define E_NODEF -3 /* Label nicht definiert */
|
||||
#define E_LABFULL -4 /* Labeltabelle voll */
|
||||
#define E_LABEXP -5 /* Label erwartet */
|
||||
#define E_NOMEM -6 /* kein Speicher mehr */
|
||||
#define E_ILLCODE -7 /* Illegaler Opcode */
|
||||
#define E_ADRESS -8 /* Illegale Adressierung */
|
||||
#define E_OK 0 /* No error */
|
||||
#define E_SYNTAX -1 /* Syntax error */
|
||||
#define E_LABDEF -2 /* Label already defined (duplicate label definition) */
|
||||
#define E_NODEF -3 /* Label not defined */
|
||||
#define E_LABFULL -4 /* Label table full */
|
||||
#define E_LABEXP -5 /* Label expected but not found */
|
||||
#define E_NOMEM -6 /* out of memory */
|
||||
#define E_ILLCODE -7 /* Illegal Opcode */
|
||||
#define E_ADRESS -8 /* Illegal Addressing mode */
|
||||
#define E_RANGE -9 /* Branch out of range */
|
||||
#define E_OVERFLOW -10 /* Ueberlauf */
|
||||
#define E_DIV -11 /* Division durch Null */
|
||||
#define E_PSOEXP -12 /* Pseudo-Opcode erwartet */
|
||||
#define E_BLKOVR -13 /* Block-Stack Uebergelaufen */
|
||||
#define E_OVERFLOW -10 /* overflow */
|
||||
#define E_DIV -11 /* Division by zero */
|
||||
#define E_PSOEXP -12 /* Pseudo-Opcode expected but not found */
|
||||
#define E_BLKOVR -13 /* Block-Stack overflow */
|
||||
#define E_FNF -14 /* File not found (pp) */
|
||||
#define E_EOF -15 /* End of File */
|
||||
#define E_BLOCK -16 /* Block inkonsistent */
|
||||
|
@ -112,7 +138,10 @@ typedef struct {
|
|||
#define E_OUTOFDATA -34 /* out of data */
|
||||
#define E_ILLQUANT -35 /* generic illegal quantity error */
|
||||
#define E_BIN -36 /* okdef */
|
||||
/* errors thru 64 are placeholders */
|
||||
#define E_UERROR -37 /* #error */
|
||||
#define E_AERROR -38 /* .assert failed */
|
||||
#define E_NEGDSBLEN -39 /* .dsb has negative length */
|
||||
/* errors thru 64 are placeholders available for use */
|
||||
|
||||
#define W_ADRRELOC -65 /* word relocation in byte value */
|
||||
#define W_BYTRELOC -66 /* byte relocation in word value */
|
||||
|
@ -124,20 +153,28 @@ typedef struct {
|
|||
#define W_OPENPP -72 /* warning about open preprocessor directive */
|
||||
#define W_OVER64K -73 /* included binary over 64K in 6502 mode */
|
||||
#define W_OVER16M -74 /* included binary over 16M in 65816 mode */
|
||||
/* warnings 75-77 are placeholders */
|
||||
#define W_SUBTRACT -75 /* subtract a segment pointer from a constant - not supported in -R mode */
|
||||
/* warnings 75-77 are placeholders available for use */
|
||||
|
||||
#define T_VALUE -1
|
||||
#define T_LABEL -2
|
||||
#define T_OP -3
|
||||
#define T_END -4
|
||||
#define T_LINE -5
|
||||
#define T_FILE -6
|
||||
#define T_POINTER -7
|
||||
/* Meta-values for the token list. Note must not overlap with the
|
||||
* K* definitions in xat.c, which have outgrown the positive numbers
|
||||
* and are now growing up from -128 ... */
|
||||
#define T_VALUE -1 /* following is a 24 bit value in the token list */
|
||||
#define T_LABEL -2 /* referring to a label, following the token is the 16bit label number */
|
||||
#define T_OP -3 /* label oriented operation; following is the label number (16bit), plus the operation char (e.g. '+') */
|
||||
#define T_END -4 /* end of line marker */
|
||||
#define T_LINE -5 /* new line indicator; following is the 16 bit line number */
|
||||
#define T_FILE -6 /* new file indicator; following is the 16 bit line number, then the file name (zero-term) */
|
||||
#define T_POINTER -7 /* ??? */
|
||||
#define T_COMMENT -8 /* unused */
|
||||
#define T_DEFINE -9 /* define a label; inserted at conversion and discarded in pass1, only used in listing output */
|
||||
#define T_LISTING -10 /* meta token, inserted after conversion before pass1, used after pass2 to create listing */
|
||||
#define T_CAST -11 /* token inserted for a cast */
|
||||
|
||||
#define P_START 0 /* Prioritaeten fuer Arithmetik */
|
||||
#define P_LOR 1 /* Von zwei Operationen wird immer */
|
||||
#define P_LAND 2 /* die mit der hoeheren Prioritaet */
|
||||
#define P_OR 3 /* zuerst ausgefuehrt */
|
||||
#define P_START 0 /* arithmetic operation priorities */
|
||||
#define P_LOR 1 /* of any two operations, the one with */
|
||||
#define P_LAND 2 /* the higher priority will be done first */
|
||||
#define P_OR 3
|
||||
#define P_XOR 4
|
||||
#define P_AND 5
|
||||
#define P_EQU 6
|
||||
|
@ -155,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
|
||||
|
@ -168,6 +216,8 @@ typedef struct {
|
|||
#define SEG_ZERO 5
|
||||
#define SEG_MAX 6
|
||||
|
||||
#define SEG_UNDEFZP 7 /* is being mapped to UNDEF */
|
||||
|
||||
typedef struct Fopt {
|
||||
signed char *text; /* text after pass1 */
|
||||
int len;
|
||||
|
@ -188,8 +238,11 @@ typedef struct File {
|
|||
int base[SEG_MAX];
|
||||
int len[SEG_MAX];
|
||||
struct {
|
||||
// temporary memory between pass1 and pass2
|
||||
signed char *tmp;
|
||||
// write pointer
|
||||
unsigned long tmpz;
|
||||
// read pointer
|
||||
unsigned long tmpe;
|
||||
} mn;
|
||||
struct {
|
||||
|
|
544
xa/src/xal.c
544
xa/src/xal.c
|
@ -48,46 +48,24 @@ static int b_fget(int*,int);
|
|||
static int b_ltest(int,int);
|
||||
static int b_get(int*);
|
||||
static int b_test(int);
|
||||
static int ll_def(char *s, int *n, int b);
|
||||
static int ll_def(char *s, int *n, int b, xalabel_t ltype);
|
||||
static int b_link(int);
|
||||
|
||||
/* local variables */
|
||||
static int b_new(void);
|
||||
|
||||
/*
|
||||
static int hashindex[256];
|
||||
static Labtab *lt = NULL;
|
||||
static int lti = 0;
|
||||
static int ltm = 0;
|
||||
*/
|
||||
static void cll_init();
|
||||
static int cll_get();
|
||||
static void cll_clear();
|
||||
static int cll_getcur();
|
||||
|
||||
/*
|
||||
static char *ln;
|
||||
static unsigned long lni;
|
||||
static long sl;
|
||||
*/
|
||||
|
||||
static Labtab *ltp;
|
||||
|
||||
int l_init(void)
|
||||
{
|
||||
cll_init();
|
||||
//unn_init();
|
||||
return 0;
|
||||
#if 0
|
||||
int er;
|
||||
|
||||
for(er=0;er<256;er++)
|
||||
hashindex[er]=0;
|
||||
|
||||
/*sl=(long)sizeof(Labtab);*/
|
||||
|
||||
/* if(!(er=m_alloc((long)(sizeof(Labtab)*ANZLAB),(char**)<)))
|
||||
er=m_alloc((long)LABMEM,&ln);*/
|
||||
|
||||
er=m_alloc((long)(sizeof(Labtab)*ANZLAB),(char**)<);
|
||||
|
||||
lti=0;
|
||||
/* lni=0L;*/
|
||||
|
||||
return(er);
|
||||
#endif
|
||||
}
|
||||
|
||||
int ga_lab(void)
|
||||
|
@ -139,86 +117,221 @@ FILE *fp;
|
|||
}
|
||||
}
|
||||
|
||||
/**********************************************************************************
|
||||
* cheap local labels
|
||||
*/
|
||||
|
||||
static int cll_current = 0; /* the current cheap local labels block */
|
||||
|
||||
/**
|
||||
* init the cheap local labels
|
||||
*/
|
||||
void cll_init() {
|
||||
cll_current = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the block number for a new cheap local label block
|
||||
*/
|
||||
int cll_get() {
|
||||
if (cll_current == 0) {
|
||||
cll_current = b_new();
|
||||
}
|
||||
return cll_current;
|
||||
}
|
||||
|
||||
/**
|
||||
* clear the local labels
|
||||
*/
|
||||
void cll_clear() {
|
||||
cll_current = 0;
|
||||
}
|
||||
|
||||
int cll_getcur() {
|
||||
return cll_current;
|
||||
}
|
||||
|
||||
/**********************************************************************************/
|
||||
|
||||
/**
|
||||
* define a global label (from the "-L" command line parameter)
|
||||
*/
|
||||
int lg_set(char *s ) {
|
||||
int n, er;
|
||||
|
||||
er = ll_search(s,&n);
|
||||
er = ll_search(s,&n, STD);
|
||||
|
||||
if(er==E_OK) {
|
||||
fprintf(stderr,"Warning: global label doubly defined!\n");
|
||||
} else {
|
||||
if(!(er=ll_def(s,&n,0))) {
|
||||
ltp=afile->la.lt+n;
|
||||
ltp->fl=2;
|
||||
ltp->afl=SEG_UNDEF;
|
||||
}
|
||||
if(!(er=ll_def(s,&n,0, STD))) {
|
||||
return lg_import(n);
|
||||
}
|
||||
}
|
||||
return er;
|
||||
}
|
||||
|
||||
/**
|
||||
* define a global label (from the .import pseudo opcode))
|
||||
* "s" is a pointer to the first label character, end is at \0
|
||||
* or at non-alphanumeric/_ char
|
||||
*/
|
||||
int lg_import(int n) {
|
||||
int er=E_OK;
|
||||
|
||||
ltp=afile->la.lt+n;
|
||||
ltp->fl=2;
|
||||
ltp->afl=SEG_UNDEF;
|
||||
|
||||
return er;
|
||||
}
|
||||
|
||||
/*
|
||||
* re-define a previously undef'd label as globally undefined
|
||||
* (for -U option)
|
||||
*/
|
||||
int lg_toglobal(char *s ) {
|
||||
int n, er;
|
||||
|
||||
//printf("lg_toglobal(%s)\n", s);
|
||||
er = ll_search(s,&n, STD);
|
||||
|
||||
if(er==E_OK && ltp->fl != 3) {
|
||||
// fonnd, but not yet set as global undef'd label
|
||||
ltp=afile->la.lt+n;
|
||||
ltp->fl=3;
|
||||
ltp->afl=SEG_UNDEF;
|
||||
ltp->origblk=ltp->blk;
|
||||
ltp->blk=0;
|
||||
}
|
||||
return er;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* define a global zeropage label (from the .importzp pseudo opcode))
|
||||
* "s" is a pointer to the first label character, end is at \0
|
||||
* or at non-alphanumeric/_ char
|
||||
*/
|
||||
int lg_importzp(int n) {
|
||||
int er=E_OK;
|
||||
|
||||
ltp=afile->la.lt+n;
|
||||
ltp->fl=2;
|
||||
ltp->afl=SEG_UNDEFZP;
|
||||
|
||||
return er;
|
||||
}
|
||||
|
||||
/**********************************************************************************/
|
||||
|
||||
int l_def(char *s, int *l, int *x, int *f)
|
||||
{
|
||||
int n,er,b,i=0;
|
||||
xalabel_t cll_fl;
|
||||
|
||||
*f=0;
|
||||
b=0;
|
||||
n=0;
|
||||
*f=0; /* flag (given as param) that the label is to be re-defined and the
|
||||
"label defined error" is to be skipped */
|
||||
b=0; /* block level on block stack, resp. block number */
|
||||
n=0; /* flag, when set, b is absolute block number and not being translated */
|
||||
cll_fl=STD; /* when 0, clear the cheap local label block */
|
||||
|
||||
if(s[0]==':') {
|
||||
// ca65 unnamed label
|
||||
i++;
|
||||
//n++; /* block number b is absolute */
|
||||
//b=unn_get(); /* current (possibly newly allocated) unnamed label block */
|
||||
cll_fl = UNNAMED; // keep the cheap local label block
|
||||
} else
|
||||
if(s[0]=='-')
|
||||
{
|
||||
*f+=1;
|
||||
*f+=1; /* label is being redefined */
|
||||
i++;
|
||||
} else
|
||||
if(s[0]=='@')
|
||||
{
|
||||
i++;
|
||||
n++; /* block number b is absolute */
|
||||
b=cll_get(); /* current (possibly newly allocated) cheap label block */
|
||||
cll_fl=CHEAP; /* do not clear the cll block again... */
|
||||
} else
|
||||
if(s[0]=='+')
|
||||
{
|
||||
i++;
|
||||
n++;
|
||||
b=0;
|
||||
n++; /* block number b is absolute */
|
||||
b=0; /* global block number */
|
||||
}
|
||||
while(s[i]=='&')
|
||||
{
|
||||
n=0;
|
||||
if (n) b=0; /* reset block number */
|
||||
n=0; /* block number is relative */
|
||||
i++;
|
||||
b++;
|
||||
b++; /* one (more) level up the block stack */
|
||||
}
|
||||
if(!n)
|
||||
if(!n) {
|
||||
/* translate from block stack level to absolute block number */
|
||||
b_fget(&b,b);
|
||||
}
|
||||
|
||||
if(cll_fl == STD) {
|
||||
/* clear cheap local labels */
|
||||
cll_clear();
|
||||
}
|
||||
|
||||
if(!isalpha(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
|
||||
} else
|
||||
{
|
||||
er=ll_search(s+i,&n);
|
||||
er = E_NODEF;
|
||||
if (cll_fl != UNNAMED) {
|
||||
er=ll_search(s+i,&n, cll_fl);
|
||||
}
|
||||
|
||||
if(er==E_OK)
|
||||
{
|
||||
//printf("l_def OK: cll_fl=%d, i=%d, s=%s\n", cll_fl, i, s);
|
||||
/* we actually found an existing label in the same scope */
|
||||
ltp=afile->la.lt+n;
|
||||
|
||||
if(*f)
|
||||
{
|
||||
/* redefinition of label */
|
||||
*l=ltp->len+i;
|
||||
} else
|
||||
if(ltp->fl==0)
|
||||
if(ltp->fl == 0)
|
||||
{
|
||||
/* label has not been defined yet, (e.g. pass1 forward ref), so we try to set it. */
|
||||
*l=ltp->len+i;
|
||||
if(b_ltest(ltp->blk,b))
|
||||
er=E_LABDEF;
|
||||
else
|
||||
ltp->blk=b;
|
||||
|
||||
} else
|
||||
if(ltp->fl == 3)
|
||||
{
|
||||
/* label has been defined as -U undef'd label so far - we need to check */
|
||||
*l=ltp->len+i;
|
||||
if(b_ltest(ltp->origblk,b))
|
||||
er=E_LABDEF;
|
||||
else
|
||||
ltp->blk=b;
|
||||
|
||||
} else
|
||||
er=E_LABDEF;
|
||||
} else
|
||||
if(er==E_NODEF)
|
||||
{
|
||||
if(!(er=ll_def(s+i,&n,b))) /* ll_def(...,*f) */
|
||||
|
||||
if(!(er=ll_def(s+i,&n,b, cll_fl) )) /* store the label in the table of labels */
|
||||
{
|
||||
ltp=afile->la.lt+n;
|
||||
*l=ltp->len+i;
|
||||
ltp->fl=0;
|
||||
ltp->is_cll=cll_fl;
|
||||
}
|
||||
//printf("l_def NODEF: n=%d, s=%s\n", n, ltp->n);
|
||||
}
|
||||
|
||||
*x=n;
|
||||
|
@ -229,15 +342,31 @@ int l_def(char *s, int *l, int *x, int *f)
|
|||
int l_search(char *s, int *l, int *x, int *v, int *afl)
|
||||
{
|
||||
int n,er,b;
|
||||
xalabel_t cll_fl;
|
||||
|
||||
*afl=0;
|
||||
|
||||
er=ll_search(s,&n);
|
||||
/*printf("l_search: lab=%s(l=%d), afl=%d, er=%d, n=%d\n",s,*l, *afl,er,n);*/
|
||||
/* check cheap local label */
|
||||
cll_fl=STD;
|
||||
if (s[0]=='@') {
|
||||
cll_fl=CHEAP;
|
||||
s++;
|
||||
} else
|
||||
if (s[0]==':') {
|
||||
cll_fl = UNNAMED_DEF;
|
||||
s++;
|
||||
}
|
||||
|
||||
er = E_NODEF;
|
||||
if (cll_fl != UNNAMED_DEF) {
|
||||
er=ll_search(s,&n, cll_fl);
|
||||
}
|
||||
|
||||
//printf("l_search: lab=%s(afl=%d, er=%d, cll_fl=%d, cll_cur=%d)\n",s,*afl,er, cll_fl, cll_getcur());
|
||||
if(er==E_OK)
|
||||
{
|
||||
ltp=afile->la.lt+n;
|
||||
*l=ltp->len;
|
||||
*l=ltp->len + ((cll_fl == STD) ? 0 : 1);
|
||||
if(ltp->fl == 1)
|
||||
{
|
||||
l_get(n,v,afl);/* *v=lt[n].val;*/
|
||||
|
@ -251,12 +380,22 @@ int l_search(char *s, int *l, int *x, int *v, int *afl)
|
|||
}
|
||||
else
|
||||
{
|
||||
b_get(&b);
|
||||
er=ll_def(s,x,b); /* ll_def(...,*v); */
|
||||
if(cll_fl == CHEAP) {
|
||||
b=cll_get();
|
||||
} else
|
||||
if(cll_fl == UNNAMED_DEF) {
|
||||
b_get(&b); // b=unn_get();
|
||||
} else {
|
||||
b_get(&b);
|
||||
}
|
||||
|
||||
er=ll_def(s,x,b, cll_fl); /* ll_def(...,*v); */
|
||||
|
||||
ltp=afile->la.lt+(*x);
|
||||
|
||||
*l=ltp->len;
|
||||
ltp->is_cll = cll_fl;
|
||||
|
||||
*l=ltp->len + ((cll_fl == STD) ? 0 : 1);
|
||||
//*l=ltp->len + cll_fl;
|
||||
|
||||
if(!er)
|
||||
{
|
||||
|
@ -303,11 +442,87 @@ void l_addocc(int n, int *v, int *afl) {
|
|||
}
|
||||
}
|
||||
|
||||
/* for the list functionality */
|
||||
char *l_get_name(int n, xalabel_t *is_cll) {
|
||||
if (n > afile->la.ltm) {
|
||||
fprintf(stderr, "Corrupted structures! n=%d, but max=%d\n", n, afile->la.ltm);
|
||||
exit(1);
|
||||
}
|
||||
ltp=afile->la.lt+n;
|
||||
*is_cll = ltp->is_cll;
|
||||
return ltp->n;
|
||||
}
|
||||
|
||||
// works on the static(!) ltp "label table pointer"
|
||||
// also returns the actual index in the table of the current ltp
|
||||
static int resolve_unnamed() {
|
||||
// need to count up/down in the linkd label list for the block
|
||||
char *namep = ltp->n;
|
||||
int nextp = -1;
|
||||
//printf("::: unnamed_def: %s, n=%d\n", namep, n);
|
||||
while ((*namep == '+') || (*namep == '-')) {
|
||||
char c = *namep;
|
||||
nextp = -1;
|
||||
if (c == '+') {
|
||||
nextp = ltp->blknext;
|
||||
} else
|
||||
if (c == '-') {
|
||||
nextp = ltp->blkprev;
|
||||
}
|
||||
//printf("::: nextp=%d\n", nextp);
|
||||
if (nextp == -1) {
|
||||
return -1; // E_NODEF
|
||||
}
|
||||
ltp = afile->la.lt+nextp;
|
||||
//printf("::: leads to: %s, nextp=%d\n", ltp->n, nextp);
|
||||
if (ltp->is_cll == UNNAMED) {
|
||||
namep++;
|
||||
}
|
||||
}
|
||||
return nextp;
|
||||
}
|
||||
|
||||
/* for the listing, esp. html links; returns a pointer to a static buffer, available till next call */
|
||||
char *l_get_unique_name(int n) {
|
||||
static char buf[MAXLINE];
|
||||
ltp=afile->la.lt+n;
|
||||
|
||||
if (ltp->is_cll == CHEAP || ltp->is_cll == STD) {
|
||||
sprintf(buf, "%d%c%s", ltp->blk,
|
||||
(ltp->is_cll == CHEAP) ? 'C' : '_',
|
||||
ltp->n);
|
||||
} else
|
||||
if (ltp->is_cll == UNNAMED) {
|
||||
// definition of unnamed label - name is NULL
|
||||
// so use the actual index
|
||||
sprintf(buf, "%dU%d", ltp->blk, n);
|
||||
} else
|
||||
if (ltp->is_cll == UNNAMED_DEF) {
|
||||
// we actually need to find the correct label from the "+" and "-"
|
||||
// in the name
|
||||
int tmp = resolve_unnamed();
|
||||
if (tmp >= 0) {
|
||||
sprintf(buf, "%dU%d", ltp->blk, tmp);
|
||||
} else {
|
||||
sprintf(buf, "__%d", tmp);
|
||||
}
|
||||
} else {
|
||||
buf[0] = 0; // no value
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
int l_get(int n, int *v, int *afl)
|
||||
{
|
||||
if(crossref) l_addocc(n,v,afl);
|
||||
|
||||
ltp=afile->la.lt+n;
|
||||
ltp = afile->la.lt+n;
|
||||
|
||||
if (ltp->is_cll == UNNAMED_DEF) {
|
||||
int tmp = resolve_unnamed();
|
||||
if (tmp == -1) return E_NODEF;
|
||||
// now ltp is set to the actual label
|
||||
}
|
||||
(*v)=ltp->val;
|
||||
lz=ltp->n;
|
||||
*afl = ltp->afl;
|
||||
|
@ -321,7 +536,8 @@ void l_set(int n, int v, int afl)
|
|||
ltp->val = v;
|
||||
ltp->fl = 1;
|
||||
ltp->afl = afl;
|
||||
/*printf("l_set('%s'(%d), v=$%04x, afl=%d\n",ltp->n, n, v, afl);*/
|
||||
|
||||
//printf("l_set('%s'(%d), v=$%04x, afl=%d\n",ltp->n, n, v, afl);
|
||||
}
|
||||
|
||||
static void ll_exblk(int a, int b)
|
||||
|
@ -335,19 +551,23 @@ static void ll_exblk(int a, int b)
|
|||
}
|
||||
}
|
||||
|
||||
static int ll_def(char *s, int *n, int b) /* definiert naechstes Label nr->n */
|
||||
/* defines next label, returns new label number in out param n */
|
||||
static int ll_def(char *s, int *n, int b, xalabel_t ltype)
|
||||
{
|
||||
int j=0,er=E_NOMEM,hash;
|
||||
char *s2;
|
||||
char *s2 = NULL;
|
||||
|
||||
/*printf("ll_def: s=%s\n",s); */
|
||||
//printf("ll_def: s=%s, ltype=%d, no_name=%d\n",s, ltype, no_name);
|
||||
|
||||
// label table for the file ...
|
||||
if(!afile->la.lt) {
|
||||
// ... does not exist yet, so malloc it
|
||||
afile->la.lti = 0;
|
||||
afile->la.ltm = 1000;
|
||||
afile->la.lt = malloc(afile->la.ltm * sizeof(Labtab));
|
||||
}
|
||||
if(afile->la.lti>=afile->la.ltm) {
|
||||
// ... or is at its capacity limit, so realloc it
|
||||
afile->la.ltm *= 1.5;
|
||||
afile->la.lt = realloc(afile->la.lt, afile->la.ltm * sizeof(Labtab));
|
||||
}
|
||||
|
@ -355,54 +575,66 @@ static int ll_def(char *s, int *n, int b) /* definiert naechstes Label
|
|||
fprintf(stderr, "Oops: no memory!\n");
|
||||
exit(1);
|
||||
}
|
||||
#if 0
|
||||
if((lti<ANZLAB) /*&&(lni<(long)(LABMEM-MAXLAB))*/)
|
||||
{
|
||||
#endif
|
||||
ltp=afile->la.lt+afile->la.lti;
|
||||
/*
|
||||
s2=ltp->n=ln+lni;
|
||||
|
||||
while((j<MAXLAB-1) && (s[j]!='\0') && (isalnum(s[j]) || s[j]=='_'))
|
||||
{
|
||||
s2[j]=s[j];
|
||||
j++;
|
||||
}
|
||||
*/
|
||||
while((s[j]!='\0') && (isalnum(s[j]) || (s[j]=='_'))) j++;
|
||||
s2 = malloc(j+1);
|
||||
if(!s2) {
|
||||
// current pointer in label table
|
||||
ltp = afile->la.lt + afile->la.lti;
|
||||
|
||||
if (ltype != UNNAMED) {
|
||||
// alloc space and copy over name
|
||||
if (ltype == UNNAMED_DEF) {
|
||||
// unnamed lables are like ":--" or ":+" with variable length
|
||||
while((s[j]!='\0') && (s[j]=='+' || s[j]=='-')) j++;
|
||||
} else {
|
||||
// standard (and cheap) labels are normal text
|
||||
while((s[j]!='\0') && (isalnum(s[j]) || (s[j]=='_'))) j++;
|
||||
}
|
||||
s2 = malloc(j+1);
|
||||
if(!s2) {
|
||||
fprintf(stderr,"Oops: no memory!\n");
|
||||
exit(1);
|
||||
}
|
||||
strncpy(s2,s,j);
|
||||
s2[j]=0;
|
||||
}
|
||||
strncpy(s2,s,j);
|
||||
s2[j]=0;
|
||||
/*
|
||||
if(j<MAXLAB)
|
||||
{
|
||||
*/
|
||||
|
||||
// init new entry in label table
|
||||
er=E_OK;
|
||||
ltp->len=j;
|
||||
ltp->n = s2;
|
||||
ltp->blk=b;
|
||||
ltp->len=j; // length of label
|
||||
ltp->n = s2; // name of label (char*)
|
||||
ltp->blk=b; // block number
|
||||
ltp->fl=0;
|
||||
ltp->afl=0;
|
||||
ltp->occlist=NULL;
|
||||
hash=hashcode(s,j);
|
||||
ltp->nextindex=afile->la.hashindex[hash];
|
||||
afile->la.hashindex[hash]=afile->la.lti;
|
||||
*n=afile->la.lti;
|
||||
afile->la.lti++;
|
||||
/* lni+=j+1;*/
|
||||
/* }
|
||||
}
|
||||
*/
|
||||
/*printf("ll_def return: %d\n",er);*/
|
||||
ltp->is_cll=ltype; // STD, CHEAP, or UNNAMED label
|
||||
ltp->occlist=NULL;
|
||||
hash=hashcode(s,j); // compute hashcode
|
||||
ltp->nextindex=afile->la.hashindex[hash]; // and link in before last entry with same hashcode
|
||||
afile->la.hashindex[hash]=afile->la.lti; // set as start of list for that hashcode
|
||||
|
||||
// TODO: does not work across files!
|
||||
ltp->blknext = -1; // no next block
|
||||
ltp->blkprev = b_link( afile->la.lti ); // previous block, linked within block
|
||||
|
||||
if (ltp->blkprev != -1) {
|
||||
ltp = afile->la.lt + ltp->blkprev;
|
||||
ltp->blknext = afile->la.lti;
|
||||
}
|
||||
|
||||
*n=afile->la.lti; // return the list index for that file in the out parameter n
|
||||
afile->la.lti++; // increase last index in lable table
|
||||
|
||||
return(er);
|
||||
}
|
||||
|
||||
|
||||
int ll_search(char *s, int *n) /* search Label in Tabelle ,nr->n */
|
||||
/**
|
||||
* search a label name in the label table. Return the label number
|
||||
* in "n". Finds only labels that are in a block that is in the current
|
||||
* set of blocks (in the block stack)
|
||||
*
|
||||
* If cll_fl is set, the label is also searched in the local cheap label scope
|
||||
*
|
||||
* Do not define the label (as is done in l_search()!)
|
||||
*/
|
||||
int ll_search(char *s, int *n, xalabel_t cll_fl) /* search Label in Tabelle ,nr->n */
|
||||
{
|
||||
int i,j=0,k,er=E_NODEF,hash;
|
||||
|
||||
|
@ -411,7 +643,6 @@ int ll_search(char *s, int *n) /* search Label in Tabelle ,nr->n */
|
|||
hash=hashcode(s,j);
|
||||
i=afile->la.hashindex[hash];
|
||||
|
||||
/*printf("search?\n");*/
|
||||
if(i>=afile->la.ltm) return E_NODEF;
|
||||
|
||||
do
|
||||
|
@ -422,11 +653,25 @@ int ll_search(char *s, int *n) /* search Label in Tabelle ,nr->n */
|
|||
{
|
||||
for (k=0;(k<j)&&(ltp->n[k]==s[k]);k++);
|
||||
|
||||
if((j==k)&&(!b_test(ltp->blk)))
|
||||
{
|
||||
er=E_OK;
|
||||
break;
|
||||
}
|
||||
if ( (j == k) && cll_fl == CHEAP) {
|
||||
if (ltp->blk == cll_getcur()) {
|
||||
er=E_OK;
|
||||
break;
|
||||
}
|
||||
} else
|
||||
if (cll_fl == UNNAMED) {
|
||||
// TODO
|
||||
} else {
|
||||
//printf("ll_search:match labels %s with %p (%s) from block %d, block check is %d\n", s, ltp, ltp->n, ltp->blk, b_test(ltp->blk));
|
||||
/* check if the found label is in any of the blocks in the
|
||||
current block stack */
|
||||
if((j==k)&&(!b_test(ltp->blk)))
|
||||
{
|
||||
/* ok, label found and it is reachable (its block nr is in the current block stack */
|
||||
er=E_OK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!i)
|
||||
|
@ -444,6 +689,8 @@ int ll_search(char *s, int *n) /* search Label in Tabelle ,nr->n */
|
|||
getchar();
|
||||
}
|
||||
#endif
|
||||
//printf("l_search(%s) returns er=%d, n=%d\n", s, er, *n);
|
||||
|
||||
return(er);
|
||||
}
|
||||
|
||||
|
@ -451,7 +698,7 @@ int ll_pdef(char *t)
|
|||
{
|
||||
int n;
|
||||
|
||||
if(ll_search(t,&n)==E_OK)
|
||||
if(ll_search(t,&n, STD)==E_OK)
|
||||
{
|
||||
ltp=afile->la.lt+n;
|
||||
if(ltp->fl)
|
||||
|
@ -460,6 +707,9 @@ 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;
|
||||
|
@ -469,25 +719,39 @@ 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 */
|
||||
/*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;
|
||||
// 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);
|
||||
fputc(afl,fp);
|
||||
|
||||
// value
|
||||
fputc(ltp->val&255, fp);
|
||||
fputc((ltp->val>>8)&255, fp);
|
||||
}
|
||||
|
@ -496,19 +760,39 @@ int l_write(FILE *fp)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int bt[MAXBLK];
|
||||
static int blk;
|
||||
static int bi;
|
||||
/*******************************************************************************************
|
||||
* block management code. Here the ".(" and ".)" blocks are maintained.
|
||||
*
|
||||
* Blocks are numbered uniquely, every time a new block is opened, the "blk" variable
|
||||
* is increased and its number used as block number.
|
||||
*
|
||||
* The currently open blocks are maintained in a stack (bt[]). The lowest entry is the outermost
|
||||
* block number, adding block numbers as blocks are opened. When a block is closed,
|
||||
* the block stack is shortened again (bi has the length of the block stack)
|
||||
*
|
||||
* Methods exist to open new blocks, close a block, and do some checks, e.g. whether
|
||||
* a specific block number is contained in the current block stack.
|
||||
*/
|
||||
static int bt[MAXBLK]; /* block stack */
|
||||
static int labind; /* last allocated label, -1 none yet alloc'd - used for linking to find unnamed labels */
|
||||
static int bi; /* length of the block stack (minus 1, i.e. bi[bi] has the innermost block) */
|
||||
static int blk; /* current block number for allocation */
|
||||
|
||||
int b_init(void)
|
||||
{
|
||||
blk =0;
|
||||
bi =0;
|
||||
bt[bi]=blk;
|
||||
labind=-1;
|
||||
|
||||
return(E_OK);
|
||||
}
|
||||
|
||||
int b_new(void)
|
||||
{
|
||||
return ++blk;
|
||||
}
|
||||
|
||||
int b_depth(void)
|
||||
{
|
||||
return bi;
|
||||
|
@ -519,19 +803,26 @@ int ga_blk(void)
|
|||
return(blk);
|
||||
}
|
||||
|
||||
/**
|
||||
* open a new block scope
|
||||
*/
|
||||
int b_open(void)
|
||||
{
|
||||
int er=E_BLKOVR;
|
||||
|
||||
if(bi<MAXBLK-1)
|
||||
{
|
||||
bt[++bi]=++blk;
|
||||
bi++;
|
||||
bt[bi]=b_new();
|
||||
|
||||
er=E_OK;
|
||||
}
|
||||
return(er);
|
||||
}
|
||||
|
||||
/**
|
||||
* close a block scope
|
||||
*/
|
||||
int b_close(void)
|
||||
{
|
||||
|
||||
|
@ -542,10 +833,14 @@ int b_close(void)
|
|||
} else {
|
||||
return E_BLOCK;
|
||||
}
|
||||
|
||||
cll_clear();
|
||||
//unn_clear();
|
||||
return(E_OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* get the block number of the current innermost block
|
||||
*/
|
||||
static int b_get(int *n)
|
||||
{
|
||||
*n=bt[bi];
|
||||
|
@ -553,6 +848,9 @@ static int b_get(int *n)
|
|||
return(E_OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the block number of the block "i" levels up in the current block stack
|
||||
*/
|
||||
static int b_fget(int *n, int i)
|
||||
{
|
||||
if((bi-i)>=0)
|
||||
|
@ -562,6 +860,10 @@ static int b_fget(int *n, int i)
|
|||
return(E_OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* tests whether the given block number n is in the current stack of
|
||||
* current block numbers bt[]
|
||||
*/
|
||||
static int b_test(int n)
|
||||
{
|
||||
int i=bi;
|
||||
|
@ -572,6 +874,9 @@ static int b_test(int n)
|
|||
return( i+1 ? E_OK : E_NOBLK );
|
||||
}
|
||||
|
||||
/**
|
||||
* tests whether the given block number "a" is in the
|
||||
*/
|
||||
static int b_ltest(int a, int b) /* testet ob bt^-1(b) in intervall [0,bt^-1(a)] */
|
||||
{
|
||||
int i=0,er=E_OK;
|
||||
|
@ -593,3 +898,10 @@ static int b_ltest(int a, int b) /* testet ob bt^-1(b) in intervall [0,bt^-1(
|
|||
return(er);
|
||||
}
|
||||
|
||||
int b_link(int newlab) {
|
||||
int tmp = labind;
|
||||
//printf("b_link: old was %d, set to %d\n", tmp, newlab);
|
||||
labind = newlab;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
|
13
xa/src/xal.h
13
xa/src/xal.h
|
@ -21,8 +21,13 @@
|
|||
|
||||
#include <stdio.h> /* for FILE */
|
||||
|
||||
/* nasty stuff - "lz" is exported from xal.c so xa.c can print the name
|
||||
* of the label that was last searched for in the error message that the
|
||||
* label was not found...
|
||||
*/
|
||||
extern char *lz;
|
||||
|
||||
|
||||
int l_init(void);
|
||||
int ga_lab(void);
|
||||
int gm_lab(void);
|
||||
|
@ -30,6 +35,10 @@ long gm_labm(void);
|
|||
long ga_labm(void);
|
||||
|
||||
int lg_set(char *);
|
||||
int lg_import(int);
|
||||
int lg_importzp(int);
|
||||
// used to re-define undef'd labels as global for -U option
|
||||
int lg_toglobal(char *);
|
||||
|
||||
int b_init(void);
|
||||
int b_depth(void);
|
||||
|
@ -40,9 +49,11 @@ int ga_blk(void);
|
|||
int l_def(char *s, int* l, int *x, int *f);
|
||||
int l_search(char *s, int *l, int *x, int *v, int *afl);
|
||||
void l_set(int n, int v, int afl);
|
||||
char* l_get_name(int n, xalabel_t *is_cll);
|
||||
char* l_get_unique_name(int n);
|
||||
int l_get(int n, int *v, int *afl);
|
||||
int l_vget(int n, int *v, char **s);
|
||||
int ll_search(char *s, int *n);
|
||||
int ll_search(char *s, int *n, xalabel_t labeltype);
|
||||
int ll_pdef(char *t);
|
||||
|
||||
int b_open(void);
|
||||
|
|
750
xa/src/xalisting.c
Normal file
750
xa/src/xalisting.c
Normal file
|
@ -0,0 +1,750 @@
|
|||
/* xa65 - 65xx/65816 cross-assembler and utility suite
|
||||
*
|
||||
* Copyright (C) 1989-1997 André Fachat (a.fachat@physik.tu-chemnitz.de)
|
||||
* maintained by Cameron Kaiser
|
||||
*
|
||||
* Assembler listing
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/* enable this to turn on (copious) optimization output */
|
||||
/* #define DEBUG_AM */
|
||||
#undef LISTING_DEBUG
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "xah.h"
|
||||
#include "xal.h"
|
||||
#include "xat.h"
|
||||
|
||||
|
||||
/*********************************************************************************************/
|
||||
/* this is the listing code
|
||||
*
|
||||
* Unfortunately this code has to go here (for now), as this file is the only one
|
||||
* where we have access to the tables that allow to convert the tokens back to
|
||||
* a listing
|
||||
*/
|
||||
|
||||
static FILE *listfp = NULL;
|
||||
static int list_lineno = 1; /* current line number */
|
||||
static int list_last_lineno = 0; /* current line number */
|
||||
static char *list_filenamep = NULL; /* current file name pointer */
|
||||
|
||||
static int list_numbytes = 8;
|
||||
|
||||
static int list_string(char *buf, char *string);
|
||||
static int list_tokens(char *buf, signed char *input, int len);
|
||||
static int list_value(char *buf, int val, signed char format);
|
||||
static int list_nchar(char *buf, signed char c, int n);
|
||||
static int list_char(char *buf, signed char c);
|
||||
static int list_sp(char *buf);
|
||||
static int list_word(char *buf, int outword);
|
||||
static int list_word_f(char *buf, int outword, signed char format);
|
||||
static int list_byte(char *buf, int outbyte);
|
||||
static int list_byte_f(char *buf, int outbyte, signed char format);
|
||||
static int list_nibble_f(char *buf, int outnib, signed char format);
|
||||
|
||||
/*********************************************************************************************/
|
||||
|
||||
// formatter
|
||||
typedef struct {
|
||||
void (*start_listing)(char *name);
|
||||
void (*start_line)();
|
||||
int (*set_anchor)(char *buf, char *name); // returns number of bytes added to buf
|
||||
int (*start_label)(char *buf, char *name); // returns number of bytes added to buf
|
||||
int (*end_label)(char *buf);
|
||||
void (*end_line)();
|
||||
void (*end_listing)();
|
||||
char* (*escape)(char *toescape); // returns pointer to static buffer, valid until next call
|
||||
char* (*escape_char)(char toescape); // returns pointer to static buffer, valid until next call
|
||||
} formatter_t;
|
||||
|
||||
static char *def_escape(char *toescape) {
|
||||
return toescape;
|
||||
}
|
||||
|
||||
static char *def_escape_char(char toescape) {
|
||||
static char buf[2];
|
||||
buf[0] = toescape;
|
||||
buf[1] = 0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
static formatter_t def_format = {
|
||||
NULL, NULL, NULL, NULL,
|
||||
NULL, NULL, NULL,
|
||||
def_escape, def_escape_char
|
||||
};
|
||||
|
||||
static void html_start_listing(char *name) {
|
||||
// really short version for now
|
||||
fprintf(listfp, "<html><head><title>%s</title></head><body><pre>\n",
|
||||
(name == NULL) ? "(null)" : name);
|
||||
}
|
||||
|
||||
static int html_set_anchor(char *buf, char *name) {
|
||||
sprintf(buf, "<a name=\"%s\"> </a>", name);
|
||||
return strlen(buf);
|
||||
}
|
||||
|
||||
static int html_start_label(char *buf, char *name) {
|
||||
sprintf(buf, "<a href=\"#%s\">", name);
|
||||
return strlen(buf);
|
||||
}
|
||||
|
||||
static int html_end_label(char *buf) {
|
||||
sprintf(buf, "</a>");
|
||||
return strlen(buf);
|
||||
}
|
||||
|
||||
static void html_end_listing() {
|
||||
fprintf(listfp, "</pre></body></html>\n");
|
||||
}
|
||||
|
||||
static char *html_escape(char *toescape) {
|
||||
static char buf[MAXLINE];
|
||||
|
||||
char *p = toescape;
|
||||
char *q = buf;
|
||||
|
||||
while (*p != 0) {
|
||||
if (*p == '<') {
|
||||
strcpy(q, "<");
|
||||
q+=4;
|
||||
p++;
|
||||
} else
|
||||
if (*p == '&') {
|
||||
strcpy(q, "&");
|
||||
q+=5;
|
||||
p++;
|
||||
} else
|
||||
if (*p == '>') {
|
||||
strcpy(q, ">");
|
||||
q+=4;
|
||||
p++;
|
||||
} else {
|
||||
*q = *p;
|
||||
q++;
|
||||
p++;
|
||||
}
|
||||
}
|
||||
*q = 0; // string terminator
|
||||
return buf;
|
||||
}
|
||||
|
||||
static char *html_escape_char(char toescape) {
|
||||
static char buf[2];
|
||||
|
||||
buf[0] = toescape;
|
||||
buf[1] = 0;
|
||||
|
||||
return html_escape(buf);
|
||||
}
|
||||
|
||||
static formatter_t html_format = {
|
||||
html_start_listing,
|
||||
NULL,
|
||||
html_set_anchor,
|
||||
html_start_label,
|
||||
html_end_label,
|
||||
NULL,
|
||||
html_end_listing,
|
||||
html_escape, html_escape_char
|
||||
};
|
||||
|
||||
static formatter_t *formatp = &def_format;
|
||||
|
||||
/*********************************************************************************************/
|
||||
|
||||
void list_flush() {
|
||||
if (listfp != NULL) {
|
||||
fflush(listfp);
|
||||
}
|
||||
}
|
||||
|
||||
void list_start(const char *formatname) {
|
||||
formatp = &def_format;
|
||||
|
||||
if (formatname != NULL && strcmp("html", formatname) == 0) {
|
||||
formatp = &html_format;
|
||||
}
|
||||
|
||||
if (listfp != NULL) {
|
||||
if (formatp->start_listing != NULL) formatp->start_listing(list_filenamep);
|
||||
}
|
||||
}
|
||||
|
||||
void list_end() {
|
||||
if (listfp != NULL) {
|
||||
if (formatp->end_listing != NULL) formatp->end_listing();
|
||||
}
|
||||
}
|
||||
|
||||
// set number of bytes per line displayed as hex
|
||||
void list_setbytes(int number_of_bytes_per_line) {
|
||||
list_numbytes = number_of_bytes_per_line;
|
||||
}
|
||||
|
||||
/* set line number for the coming listing output */
|
||||
void list_line(int l) {
|
||||
list_lineno = l;
|
||||
}
|
||||
|
||||
/* set file name for the coming listing output */
|
||||
void list_filename(char *fname) {
|
||||
if (list_filenamep == NULL || (fname != NULL && strcmp(fname, list_filenamep) != 0)) {
|
||||
list_filenamep = fname;
|
||||
list_lineno = 1;
|
||||
list_last_lineno = 0;
|
||||
|
||||
/* Hack */
|
||||
if (listfp != NULL) {
|
||||
fprintf(listfp, "\n%s\n\n", fname);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* set the output file descriptor where to write the listing
|
||||
*/
|
||||
void list_setfile(FILE *fp) {
|
||||
listfp = fp;
|
||||
}
|
||||
|
||||
char *list_preamble(char *buf, int lineno, int seg, int pc) {
|
||||
int i;
|
||||
char c;
|
||||
|
||||
/* line number in file */
|
||||
snprintf(buf, 10, "% 5d", lineno);
|
||||
i = strlen(buf);
|
||||
buf += i;
|
||||
buf += list_char(buf, ' ');
|
||||
|
||||
c = '?';
|
||||
/* preamble <segment>':'<address>' ' */
|
||||
switch(seg) {
|
||||
case SEG_ABS: c='A'; break;
|
||||
case SEG_TEXT: c='T'; break;
|
||||
case SEG_BSS: c='B'; break;
|
||||
case SEG_DATA: c='D'; break;
|
||||
case SEG_UNDEF: c='U'; break;
|
||||
case SEG_ZERO: c='Z'; break;
|
||||
}
|
||||
buf = buf + list_char(buf, c);
|
||||
buf = buf + list_char(buf, ':');
|
||||
buf = buf + list_word(buf, pc);
|
||||
buf = buf + list_nchar(buf, ' ', 2);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* listing/listing_len give the buffer address and length respectively that contains
|
||||
* the token as they are produced by the tokenizer.
|
||||
* bincode/bincode_len give the buffer address and length that contain the binary code
|
||||
* that is produced from the token listing
|
||||
*
|
||||
* Note that both lengths may be zero
|
||||
*/
|
||||
void do_listing(signed char *listing, int listing_len, signed char *bincode, int bincode_len) {
|
||||
int i, n_hexb, num_last_line, tmp, overflow;
|
||||
|
||||
char outline[MAXLINE];
|
||||
char *buf = outline;
|
||||
|
||||
int lst_seg = listing[0];
|
||||
int lst_pc = (listing[2]<<8) | (listing[1] & 255);
|
||||
|
||||
/* no output file (not even stdout) */
|
||||
if (listfp == NULL) return;
|
||||
|
||||
|
||||
/*printf("do_listing: listing=%p (%d), bincode=%p (%d)\n", listing, listing_len, bincode, bincode_len);*/
|
||||
|
||||
if (bincode_len < 0) bincode_len = -bincode_len;
|
||||
|
||||
/* do we need a separation line? */
|
||||
if (list_lineno > list_last_lineno+1) {
|
||||
/* yes */
|
||||
/*fprintf(listfp, "line=%d, last=%d\n", list_lineno, list_last_lineno);*/
|
||||
fprintf(listfp, "\n");
|
||||
}
|
||||
list_last_lineno = list_lineno;
|
||||
|
||||
// could be extended to include the preamble...
|
||||
if (formatp->start_line != NULL) formatp->start_line();
|
||||
|
||||
buf = list_preamble(buf, list_lineno, lst_seg, lst_pc);
|
||||
|
||||
// check if we have labels, so we can adjust the max printable number of
|
||||
// bytes in the last line
|
||||
num_last_line = 11;
|
||||
tmp = listing[3] & 255;
|
||||
if (tmp == (T_DEFINE & 255)) {
|
||||
// we have label definition
|
||||
num_last_line = 8;
|
||||
}
|
||||
overflow = 0;
|
||||
|
||||
/* binary output (up to 8 byte. If more than 8 byte, print 7 plus "..." */
|
||||
n_hexb = bincode_len;
|
||||
if (list_numbytes != 0 && n_hexb >= list_numbytes) {
|
||||
n_hexb = list_numbytes-1;
|
||||
overflow = 1;
|
||||
}
|
||||
for (i = 0; i < n_hexb; i++) {
|
||||
buf = buf + list_byte(buf, bincode[i]);
|
||||
buf = buf + list_sp(buf);
|
||||
if ( (i%16) == 15) {
|
||||
// make a break
|
||||
buf[0] = 0;
|
||||
fprintf(listfp, "%s\n", outline);
|
||||
if (formatp->end_line != NULL) formatp->end_line();
|
||||
if (formatp->start_line != NULL) formatp->start_line();
|
||||
buf = outline;
|
||||
buf = list_preamble(buf, list_lineno, lst_seg, lst_pc + i + 1);
|
||||
}
|
||||
}
|
||||
if (overflow) {
|
||||
// are we at the last byte?
|
||||
if (n_hexb + 1 == bincode_len) {
|
||||
// just print the last byte
|
||||
buf = buf + list_byte(buf, bincode[i]);
|
||||
buf = buf + list_sp(buf);
|
||||
} else {
|
||||
// display "..."
|
||||
buf = buf + list_nchar(buf, '.', 3);
|
||||
}
|
||||
n_hexb++;
|
||||
}
|
||||
i = n_hexb % 16;
|
||||
if (i > num_last_line) {
|
||||
// make a break (Note: with original PC, as now the assembler text follows
|
||||
buf[0] = 0;
|
||||
fprintf(listfp, "%s\n", outline);
|
||||
if (formatp->end_line != NULL) formatp->end_line();
|
||||
if (formatp->start_line != NULL) formatp->start_line();
|
||||
buf = outline;
|
||||
buf = list_preamble(buf, list_lineno, lst_seg, lst_pc);
|
||||
i = 0;
|
||||
}
|
||||
i = num_last_line - i;
|
||||
buf = buf + list_nchar(buf, ' ', i * 3);
|
||||
|
||||
buf = buf + list_sp(buf);
|
||||
|
||||
buf += list_tokens(buf, listing + 3, listing_len - 3);
|
||||
|
||||
#ifdef LISTING_DEBUG
|
||||
/* for now only do a hex dump so we see what actually happens */
|
||||
{
|
||||
char valbuf[32];
|
||||
i = buf - outline;
|
||||
if (i<80) buf += list_nchar(buf, ' ', 80-i);
|
||||
|
||||
buf += list_string(buf, " >>");
|
||||
sprintf(valbuf, "%p", listing+3);
|
||||
buf += list_string(buf, valbuf);
|
||||
buf += list_sp(buf);
|
||||
for (i = 3; i < listing_len; i++) {
|
||||
buf = buf + list_byte(buf, listing[i]);
|
||||
buf = buf + list_sp(buf);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
buf[0] = 0;
|
||||
|
||||
fprintf(listfp, "%s\n", outline);
|
||||
|
||||
if (formatp->end_line != NULL) formatp->end_line();
|
||||
}
|
||||
|
||||
int list_tokens(char *buf, signed char *input, int len) {
|
||||
int outp = 0;
|
||||
int inp = 0;
|
||||
int tmp;
|
||||
char *name;
|
||||
signed char c;
|
||||
xalabel_t is_cll;
|
||||
int tabval, operator;
|
||||
signed char format;
|
||||
|
||||
if (inp >= len) return 0;
|
||||
|
||||
tmp = input[inp] & 255;
|
||||
|
||||
tabval = 0;
|
||||
if (tmp == (T_DEFINE & 255)) {
|
||||
while (inp < len && tmp == (T_DEFINE & 255)) {
|
||||
tmp = ((input[inp+2]&255)<<8) | (input[inp+1]&255);
|
||||
/*printf("define: len=%d, inp=%d, tmp=%d\n", len, inp, tmp);*/
|
||||
name=l_get_name(tmp, &is_cll);
|
||||
|
||||
// duplicate anchor names?
|
||||
if (formatp->set_anchor != NULL) {
|
||||
outp += formatp->set_anchor(buf+outp, l_get_unique_name(tmp));
|
||||
}
|
||||
|
||||
if (is_cll == CHEAP) {
|
||||
outp += list_char(buf+outp, '@');
|
||||
} else
|
||||
if (is_cll == UNNAMED_DEF || is_cll == UNNAMED) {
|
||||
outp += list_char(buf+outp, ':');
|
||||
}
|
||||
if (is_cll != UNNAMED) {
|
||||
tmp = list_string(buf+outp, name);
|
||||
tabval += tmp + 1 + is_cll;
|
||||
outp += tmp;
|
||||
}
|
||||
outp += list_char(buf+outp, ' ');
|
||||
inp += 3;
|
||||
tmp = input[inp] & 255;
|
||||
}
|
||||
if (tabval < 10) {
|
||||
outp += list_nchar(buf+outp, ' ', 10-tabval);
|
||||
}
|
||||
} else {
|
||||
if (tmp >= 0 && tmp < number_of_valid_tokens) {
|
||||
outp += list_string(buf+outp, " ");
|
||||
}
|
||||
}
|
||||
|
||||
if (tmp >= 0 && tmp < number_of_valid_tokens) {
|
||||
/* assembler keyword */
|
||||
/*printf("tmp=%d, kt[tmp]=%p\n", tmp, kt[tmp]);*/
|
||||
if (kt[tmp] != NULL) {
|
||||
outp += list_string(buf+outp, kt[tmp]);
|
||||
}
|
||||
outp += list_sp(buf + outp);
|
||||
inp += 1;
|
||||
#if 0
|
||||
if (tmp == Kinclude) {
|
||||
/* just another exception from the rule... */
|
||||
/* next char is terminator (", ') then the length and then the file name */
|
||||
char term = input[inp];
|
||||
int len = input[inp+1] & 255;
|
||||
outp += list_char(buf+outp, term);
|
||||
for (tmp = 2; tmp < len+2; tmp++) {
|
||||
outp += list_char(buf+outp, input[inp+tmp]);
|
||||
}
|
||||
outp += list_char(buf+outp, term);
|
||||
inp += len + 2;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
operator = 0;
|
||||
while (inp < len) {
|
||||
|
||||
switch(input[inp]) {
|
||||
case T_CAST:
|
||||
outp += list_string(buf+outp, formatp->escape_char(input[inp+1]));
|
||||
inp+=2;
|
||||
break;
|
||||
case T_VALUE:
|
||||
/*outp += list_char(buf+outp, 'V');*/
|
||||
/* 24 bit value */
|
||||
tmp = ((input[inp+3]&255)<<16) | ((input[inp+2]&255)<<8) | (input[inp+1]&255);
|
||||
format = input[inp+4];
|
||||
outp += list_value(buf+outp, tmp, format);
|
||||
inp += 5;
|
||||
operator = 1; /* check if arithmetic operator follows */
|
||||
break;
|
||||
case T_LABEL:
|
||||
/*outp += list_char(buf+outp, 'L');*/
|
||||
/* 16 bit label number */
|
||||
tmp = ((input[inp+2]&255)<<8) | (input[inp+1]&255);
|
||||
name=l_get_name(tmp, &is_cll);
|
||||
|
||||
// duplicate label name
|
||||
if (formatp->start_label != NULL) {
|
||||
outp += formatp->start_label(buf+outp, l_get_unique_name(tmp));
|
||||
}
|
||||
if (is_cll == CHEAP) {
|
||||
outp += list_char(buf+outp, '@');
|
||||
} else
|
||||
if (is_cll == UNNAMED || is_cll == UNNAMED_DEF) {
|
||||
outp += list_char(buf+outp, ':');
|
||||
}
|
||||
if (is_cll != UNNAMED) {
|
||||
outp += list_string(buf+outp, name == NULL ? "<null>" : name);
|
||||
}
|
||||
|
||||
if (formatp->end_label != NULL) outp += formatp->end_label(buf+outp);
|
||||
|
||||
inp += 3;
|
||||
operator = 1; /* check if arithmetic operator follows */
|
||||
break;
|
||||
case T_OP:
|
||||
/* label arithmetic operation; inp[3] is operation like '=' or '+' */
|
||||
tmp = ((input[inp+2]&255)<<8) | (input[inp+1]&255);
|
||||
name=l_get_name(tmp, &is_cll);
|
||||
if (input[inp+3] == '=') {
|
||||
// label definition
|
||||
if (formatp->set_anchor != NULL) {
|
||||
outp += formatp->set_anchor(buf+outp, l_get_unique_name(tmp));
|
||||
}
|
||||
}
|
||||
if (is_cll) outp += list_char(buf+outp, '@');
|
||||
outp += list_string(buf+outp, name);
|
||||
outp += list_char(buf+outp, input[inp+3]);
|
||||
inp += 4;
|
||||
|
||||
break;
|
||||
case T_END:
|
||||
/* end of operation */
|
||||
/*outp += list_string(buf+outp, ";");*/
|
||||
inp += 1;
|
||||
goto end;
|
||||
break;
|
||||
case T_COMMENT:
|
||||
if (inp > 0 && inp < 20) {
|
||||
outp += list_nchar(buf+outp, ' ', 20-inp);
|
||||
}
|
||||
tmp = ((input[inp+2]&255)<<8) | (input[inp+1]&255);
|
||||
outp += list_char(buf+outp, ';');
|
||||
outp += list_string(buf+outp, (char*)input+inp+3);
|
||||
inp += tmp + 3;
|
||||
break;
|
||||
case T_LINE:
|
||||
case T_FILE:
|
||||
/* those two are meta-tokens, evaluated outside the t_p2 call,
|
||||
* they result in calls to list_line(), list_filename() */
|
||||
break;
|
||||
case T_POINTER:
|
||||
/* what is this? It's actually resolved during token conversion */
|
||||
tmp = ((input[inp+5]&255)<<8) | (input[inp+4]&255);
|
||||
name=l_get_name(tmp, &is_cll);
|
||||
if (formatp->start_label != NULL) {
|
||||
outp += formatp->start_label(buf+outp, l_get_unique_name(tmp));
|
||||
}
|
||||
if (is_cll) outp += list_char(buf+outp, '@');
|
||||
outp += list_string(buf+outp, name);
|
||||
|
||||
if (formatp->end_label != NULL) outp += formatp->end_label(buf+outp);
|
||||
/*
|
||||
outp += list_byte(buf+outp, input[inp+1]);
|
||||
outp += list_char(buf+outp, '#');
|
||||
tmp = ((input[inp+3]&255)<<8) | (input[inp+2]&255);
|
||||
outp += list_value(buf+outp, tmp);
|
||||
*/
|
||||
inp += 6;
|
||||
operator = 1; /* check if arithmetic operator follows */
|
||||
break;
|
||||
case '"': {
|
||||
int i, len;
|
||||
|
||||
// string display
|
||||
inp++;
|
||||
outp += list_char(buf+outp, '"');
|
||||
len = input[inp] & 0xff;
|
||||
for (i = 0; i < len; i++) {
|
||||
inp++;
|
||||
outp += list_char(buf+outp, input[inp]);
|
||||
}
|
||||
inp++;
|
||||
outp += list_char(buf+outp, '"');
|
||||
break;
|
||||
}
|
||||
case '*': {
|
||||
// If '*' appears as operand, it is the PC. We need to switch to operator then
|
||||
inp++;
|
||||
outp += list_char(buf+outp, '*');
|
||||
operator = 1;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
c = input[inp];
|
||||
if (c > 31) {
|
||||
outp += list_string(buf+outp, formatp->escape_char(input[inp]));
|
||||
} else {
|
||||
outp += list_char(buf+outp, '\'');
|
||||
outp += list_byte(buf+outp, input[inp]);
|
||||
}
|
||||
inp += 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (operator && inp < len) {
|
||||
signed char op = input[inp];
|
||||
if (op > 0 && op <= 20) { // sizeof(arith_ops)
|
||||
outp += list_string(buf+outp, formatp->escape(arith_ops[op]));
|
||||
inp += 1;
|
||||
operator = 0;
|
||||
}
|
||||
// note: falls through for closing brackets which are where an operator would normally be.
|
||||
// closing bracket is then printed in upper (operand) part in default case before
|
||||
// another operator is expected after the bracket
|
||||
}
|
||||
}
|
||||
end:
|
||||
return outp;
|
||||
}
|
||||
|
||||
int list_string(char *buf, char *string) {
|
||||
int p = 0;
|
||||
|
||||
if (buf == NULL || string == NULL) {
|
||||
fprintf(stderr, "NULL pointer: buf=%p, string=%p\n", buf, string);
|
||||
fflush(stderr);
|
||||
//exit(1);
|
||||
return 0;
|
||||
}
|
||||
while (string[p] != 0) {
|
||||
buf[p] = string[p];
|
||||
p++;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
int list_value(char *buf, int val, signed char format) {
|
||||
int p = 0;
|
||||
char valbuf[32];
|
||||
|
||||
switch (format) {
|
||||
case '$':
|
||||
p += list_char(buf + p, '$');
|
||||
if (val & (255<<16)) {
|
||||
p += list_byte(buf+p, val>>16);
|
||||
p += list_word(buf+p, val);
|
||||
} else
|
||||
if (val & (255<<8)) {
|
||||
p += list_word(buf+p, val);
|
||||
} else {
|
||||
p += list_byte(buf+p, val);
|
||||
}
|
||||
break;
|
||||
case '%':
|
||||
p += list_char(buf + p, '%');
|
||||
if (val & (255<<16)) {
|
||||
p += list_byte_f(buf+p, val>>16,'%');
|
||||
p += list_word_f(buf+p, val,'%');
|
||||
} else
|
||||
if (val & (255<<8)) {
|
||||
p += list_word_f(buf+p, val,'%');
|
||||
} else {
|
||||
p += list_byte_f(buf+p, val,'%');
|
||||
}
|
||||
break;
|
||||
case '&':
|
||||
snprintf(valbuf, 32, "%o",val);
|
||||
p+= list_char(buf+p, '&');
|
||||
p+= list_string(buf+p, valbuf);
|
||||
break;
|
||||
case 'd':
|
||||
snprintf(valbuf, 32, "%d",val);
|
||||
p+= list_string(buf+p, valbuf);
|
||||
break;
|
||||
case '\'':
|
||||
case '"':
|
||||
p+= list_char(buf+p, format);
|
||||
p+= list_char(buf+p, val);
|
||||
p+= list_char(buf+p, format);
|
||||
break;
|
||||
default:
|
||||
/* hex format as fallback */
|
||||
p += list_char(buf + p, '$');
|
||||
if (val & (255<<16)) {
|
||||
p += list_byte(buf+p, val>>16);
|
||||
p += list_word(buf+p, val);
|
||||
} else
|
||||
if (val & (255<<8)) {
|
||||
p += list_word(buf+p, val);
|
||||
} else {
|
||||
p += list_byte(buf+p, val);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
int list_nchar(char *buf, signed char c, int n) {
|
||||
int i;
|
||||
for (i = 0; i < n; i++) {
|
||||
buf[i]=c;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
int list_char(char *buf, signed char c) {
|
||||
buf[0] = c;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int list_sp(char *buf) {
|
||||
buf[0] = ' ';
|
||||
return 1;
|
||||
}
|
||||
|
||||
int list_word(char *buf, int outword) {
|
||||
return list_word_f(buf, outword, '$');
|
||||
}
|
||||
|
||||
int list_word_f(char *buf, int outword, signed char format) {
|
||||
int p = 0;
|
||||
p+= list_byte_f(buf+p, outword >> 8, format);
|
||||
p+= list_byte_f(buf+p, outword, format);
|
||||
return p;
|
||||
}
|
||||
|
||||
int list_byte(char *buf, int outbyte) {
|
||||
return list_byte_f(buf, outbyte, '$');
|
||||
}
|
||||
|
||||
int list_byte_f(char *buf, int outbyte, signed char format) {
|
||||
int p = 0;
|
||||
p+= list_nibble_f(buf+p, (outbyte >> 4), format);
|
||||
p+= list_nibble_f(buf+p, outbyte, format);
|
||||
return p;
|
||||
}
|
||||
|
||||
int list_nibble_f(char *buf, int outnib, signed char format) {
|
||||
int p = 0;
|
||||
outnib = outnib & 0xf;
|
||||
switch(format) {
|
||||
case '$':
|
||||
if (outnib < 10) {
|
||||
buf[p]='0'+outnib;
|
||||
} else {
|
||||
buf[p]='a'-10+outnib;
|
||||
}
|
||||
p++;
|
||||
break;
|
||||
case '%':
|
||||
buf[p++] = (outnib&8)?'1':'0';
|
||||
buf[p++] = (outnib&4)?'1':'0';
|
||||
buf[p++] = (outnib&2)?'1':'0';
|
||||
buf[p++] = (outnib&1)?'1':'0';
|
||||
break;
|
||||
default:
|
||||
/* hex as default */
|
||||
if (outnib < 10) {
|
||||
buf[p]='0'+outnib;
|
||||
} else {
|
||||
buf[p]='a'-10+outnib;
|
||||
}
|
||||
p++;
|
||||
break;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
|
34
xa/src/xalisting.h
Normal file
34
xa/src/xalisting.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
/* xa65 - 65xx/65816 cross-assembler and utility suite
|
||||
*
|
||||
* Copyright (C) 1989-1997 André Fachat (a.fachat@physik.tu-chemnitz.de)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
#ifndef __XA65_XALISTING_H__
|
||||
#define __XA65_XALISTING_H__
|
||||
|
||||
void list_start(char *formatname); //either NULL or "html"
|
||||
void list_end();
|
||||
|
||||
void list_flush(); // debug helper
|
||||
|
||||
void list_setfile(FILE *fp);
|
||||
void list_line(int l); /* set line number for the coming listing output */
|
||||
void list_filename(char *fname);/* set file name for the coming listing output */
|
||||
|
||||
// list a single line/token set
|
||||
void do_listing(signed char *listing, int listing_len, signed char *bincode, int bincode_len);
|
||||
|
||||
#endif /* __XA65_XALISTING_H__ */
|
|
@ -53,10 +53,13 @@ FILE *xfopen(const char *fn,const char *mode)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
// copy to xname by replacing windows backslashes with the proper DIRCHAR
|
||||
for(i=0;i<l+1;i++) {
|
||||
xname[i]=((fn[i]=='\\')?DIRCHAR:fn[i]);
|
||||
}
|
||||
|
||||
//printf("name=%s, xname=%s, mode=%s\n",fn,xname, mode);
|
||||
|
||||
if(mode[0]=='r')
|
||||
{
|
||||
if((file=fopen(fn,mode))==NULL
|
||||
|
@ -68,7 +71,6 @@ FILE *xfopen(const char *fn,const char *mode)
|
|||
strcpy(n2,n);
|
||||
strcat(n2,xname);
|
||||
strcat(n,fn);
|
||||
/* printf("name=%s,n2=%s,mode=%s\n",n,n2,mode); */
|
||||
file=fopen(n,mode);
|
||||
if(!file) file=fopen(n2,mode);
|
||||
}
|
||||
|
@ -87,7 +89,6 @@ FILE *xfopen(const char *fn,const char *mode)
|
|||
strcpy(n2,n);
|
||||
strcat(n2,xname);
|
||||
strcat(n,fn);
|
||||
/* printf("name=%s,n2=%s,mode=%s\n",n,n2,mode); */
|
||||
file=fopen(n,mode);
|
||||
if(!file) file=fopen(n2,mode);
|
||||
}
|
||||
|
|
|
@ -66,7 +66,7 @@ void o_write(FILE *fp) {
|
|||
l=afile->fo.olist[i].len;
|
||||
t=afile->fo.olist[i].text;
|
||||
/* do not optimize */
|
||||
t_p2(t, &l, 1, &afl);
|
||||
t_p2_l(t, &l, &afl);
|
||||
|
||||
if(l>254) {
|
||||
errout(E_OPTLEN);
|
||||
|
|
790
xa/src/xap.c
790
xa/src/xap.c
File diff suppressed because it is too large
Load Diff
|
@ -30,12 +30,15 @@ void pp_end(void);
|
|||
int pgetline(char *t);
|
||||
Datei *pp_getidat(void);
|
||||
|
||||
/* needed for .include pseudo opcode */
|
||||
int icl_open(char*);
|
||||
|
||||
int ga_pp(void);
|
||||
int gm_pp(void);
|
||||
long gm_ppm(void);
|
||||
long ga_ppm(void);
|
||||
|
||||
Datei *filep;
|
||||
char s[MAXLINE];
|
||||
extern Datei *filep;
|
||||
extern char s[MAXLINE];
|
||||
|
||||
#endif /* __XA65_XAP_H__ */
|
||||
|
|
30
xa/src/xar.c
30
xa/src/xar.c
|
@ -30,22 +30,30 @@
|
|||
#include "xao.h"
|
||||
#include "xau.h"
|
||||
|
||||
#undef DEBUG_RELOC
|
||||
|
||||
File *afile = NULL;
|
||||
|
||||
int rmode = RMODE_RELOC;
|
||||
|
||||
/*
|
||||
int r_set(int pc, int afl, int l) {
|
||||
/*printf("set relocation @$%04x, l=%d, afl=%04x, segment=%d\n",pc, l, afl,segment);*/
|
||||
if(segment==SEG_TEXT) return rt_set(pc,afl,l,0);
|
||||
if(segment==SEG_DATA) return rd_set(pc,afl,l,0);
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
|
||||
int u_set(int pc, int afl, int label, int l) {
|
||||
/*printf("set relocation @$%04x, l=%d, afl=%04x, segment=%d, label=%d\n",
|
||||
pc, l, afl,segment, label);*/
|
||||
if((afl & A_FMASK) == (SEG_UNDEF<<8))
|
||||
#ifdef DEBUG_RELOC
|
||||
printf("set relocation @$%04x, l=%d, afl=%04x, segment=%d, label=%d\n",
|
||||
pc, l, afl,segment, label);
|
||||
#endif
|
||||
if(((afl & A_FMASK) == (SEG_UNDEF<<8))
|
||||
|| ((afl & A_FMASK) == (SEG_UNDEFZP<<8))
|
||||
) {
|
||||
label = u_label(label); /* set label as undefined */
|
||||
}
|
||||
if(segment==SEG_TEXT) return rt_set(pc,afl,l,label);
|
||||
if(segment==SEG_DATA) return rd_set(pc,afl,l,label);
|
||||
return 0;
|
||||
|
@ -77,7 +85,9 @@ int rt_set(int pc, int afl, int l, int lab) {
|
|||
/*printf("Warning: byte relocation in word value at PC=$%04x!\n",pc);*/
|
||||
}
|
||||
if(l==1 && ((afl&A_MASK)==A_ADR)) {
|
||||
if((afl & A_FMASK) != (SEG_ZERO<<8)) {
|
||||
if(((afl & A_FMASK) != (SEG_ZERO<<8))
|
||||
&& ((afl & A_FMASK) != (SEG_UNDEFZP<<8))
|
||||
) {
|
||||
/*printf("afl=%04x\n",afl);*/
|
||||
errout(W_ADRRELOC);
|
||||
}
|
||||
|
@ -147,10 +157,16 @@ int rt_write(FILE *fp, int pc) {
|
|||
}
|
||||
fputc(pc2-pc, fp);
|
||||
pc=pc2;
|
||||
fputc((afl>>8)&255, fp);
|
||||
if((afile->rt.rlist[p].afl&A_FMASK)==(SEG_UNDEF<<8)) {
|
||||
if((afile->rt.rlist[p].afl&A_FMASK)==(SEG_UNDEFZP<<8)) {
|
||||
fputc( (((afl & ~A_FMASK)>>8)&255)|SEG_UNDEF, fp);
|
||||
fputc(afile->rt.rlist[p].lab & 255, fp);
|
||||
fputc((afile->rt.rlist[p].lab>>8) & 255, fp);
|
||||
} else {
|
||||
fputc( (afl>>8)&255, fp);
|
||||
if((afile->rt.rlist[p].afl&A_FMASK)==(SEG_UNDEF<<8)) {
|
||||
fputc(afile->rt.rlist[p].lab & 255, fp);
|
||||
fputc((afile->rt.rlist[p].lab>>8) & 255, fp);
|
||||
}
|
||||
}
|
||||
if((afl&A_MASK)==A_HIGH) fputc(afl&255,fp);
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
extern File *alloc_file(void);
|
||||
|
||||
/* jumps to r[td]_set, depending on segment */
|
||||
int r_set(int pc, int reloc, int len);
|
||||
/*int r_set(int pc, int reloc, int len);*/
|
||||
int u_set(int pc, int reloc, int label, int len);
|
||||
|
||||
int rt_set(int pc, int reloc, int len, int label);
|
||||
|
|
|
@ -111,11 +111,17 @@ int rd_write(FILE *fp, int pc) {
|
|||
}
|
||||
fputc(pc2-pc, fp);
|
||||
pc=pc2;
|
||||
fputc((afl>>8)&255, fp);
|
||||
if((afile->rd.rlist[p].afl&A_FMASK)==(SEG_UNDEF<<8)) {
|
||||
if((afile->rd.rlist[p].afl&A_FMASK)==(SEG_UNDEFZP<<8)) {
|
||||
fputc((((afl & ~A_FMASK)>>8)&255)|SEG_UNDEF, fp);
|
||||
fputc(afile->rd.rlist[p].lab & 255, fp);
|
||||
fputc((afile->rd.rlist[p].lab>>8) & 255, fp);
|
||||
} else {
|
||||
fputc((afl>>8)&255, fp);
|
||||
if(((afile->rd.rlist[p].afl&A_FMASK)==(SEG_UNDEF<<8))) {
|
||||
fputc(afile->rd.rlist[p].lab & 255, fp);
|
||||
fputc((afile->rd.rlist[p].lab>>8) & 255, fp);
|
||||
}
|
||||
}
|
||||
}
|
||||
if((afl&A_MASK)==A_HIGH) fputc(afl&255,fp);
|
||||
}
|
||||
p=afile->rd.rlist[p].next;
|
||||
|
|
1121
xa/src/xat.c
1121
xa/src/xat.c
File diff suppressed because it is too large
Load Diff
|
@ -22,7 +22,11 @@
|
|||
extern int dsb_len;
|
||||
|
||||
int t_p1(signed char *s, signed char *t, int *ll, int *al);
|
||||
int t_p2(signed char *t, int *ll, int fl, int *al);
|
||||
int t_p2_l(signed char *t, int *ll, int *al);
|
||||
int b_term(char *s, int *v, int *l, int pc);
|
||||
|
||||
extern char *kt[]; // table of key words, needed for listing
|
||||
extern char *arith_ops[]; // table of arithmetic operators, needed for listing
|
||||
extern int number_of_valid_tokens; // as it says, in the "kt" table
|
||||
|
||||
#endif /* __XA65_XAT_H__ */
|
||||
|
|
12
xa/src/xau.c
12
xa/src/xau.c
|
@ -1,6 +1,6 @@
|
|||
/* xa65 - 65xx/65816 cross-assembler and utility suite
|
||||
*
|
||||
* Copyright (C) 1989-1997 André Fachat (a.fachat@physik.tu-chemnitz.de)
|
||||
* Copyright (C) 1989-1997 André Fachat (fachat@web.de)
|
||||
*
|
||||
* Undefined label tracking module (also see xal.c)
|
||||
*
|
||||
|
@ -27,15 +27,13 @@
|
|||
#include "xah.h"
|
||||
#include "xal.h"
|
||||
|
||||
/*
|
||||
static int *ulist = NULL;
|
||||
static int un = 0;
|
||||
static int um = 0;
|
||||
*/
|
||||
#undef DEBUG_UNDEF
|
||||
|
||||
int u_label(int labnr) {
|
||||
int i;
|
||||
/*printf("u_label: %d\n",labnr);*/
|
||||
#ifdef DEBUG_UNDEF
|
||||
printf("u_label: %d\n",labnr);
|
||||
#endif
|
||||
if(!afile->ud.ulist) {
|
||||
afile->ud.ulist = malloc(200*sizeof(int));
|
||||
if(afile->ud.ulist) afile->ud.um=200;
|
||||
|
|
|
@ -1,21 +1,31 @@
|
|||
This is a directory of test suites for complex or pathological cases that
|
||||
have been repaired (?) in the current version. It is primarily for internal
|
||||
testing, but is here for your interest.
|
||||
testing, but is here for your interest. It requires a reasonably compatible
|
||||
`make` and Perl.
|
||||
|
||||
Starting with 2.3.6, you should not normally need to run these directly
|
||||
unless 'make test' fails. If you do, use harness:
|
||||
You can run specific tests from the main source directory with
|
||||
|
||||
make test TESTS=test,test,test,...
|
||||
|
||||
or, if `make test` doesn't work right on your system, you can run the Perl
|
||||
harness directly:
|
||||
|
||||
./harness -cc=... -cflags=... -make=... -tests=testdir,testdir,testdir,...
|
||||
|
||||
If -tests is omitted, all tests are run.
|
||||
|
||||
Don't run the makefiles directly, if they exist; they may not work properly.
|
||||
If a Makefile is not present, then the test harness assembles "test.s" and
|
||||
compares it with "ok".
|
||||
|
||||
adrm/ Addressing mode test (especially the optimizer and quantity
|
||||
prefixes)
|
||||
nonl/ Patryk's no-new-line-on-last-line cases ;)
|
||||
fordef/ Optimizer warnings for forward defined labels
|
||||
relocmode/ Tests to prevent use of irrational segments if relocating
|
||||
mde isn't on
|
||||
relocundef/ Tests for the detection of undefined references during a
|
||||
reloc65 export.
|
||||
reloc65 export
|
||||
ldoreloc/ Test case for the relocation table reading of ldo when undef'd
|
||||
refs are involved
|
||||
comcom/ Comments-with-comments-with-commands-etc. for testing -M
|
||||
|
@ -23,10 +33,32 @@ recmac/ Recursive macro evaluation testing
|
|||
openpp/ Testing of open #if*s in pp
|
||||
cpp/ Random preprocessor tests, mostly crap
|
||||
incerr/ 1) .xl/.al should error without -w 2) error should be in
|
||||
the correct file
|
||||
the correct file ('816)
|
||||
binclude/ Binary include code with some weird casing
|
||||
ppstrings/ Don't substitute inside strings (unless -S)
|
||||
neg_offset/ Test negative offsets/values with/without relocation
|
||||
chppch/ Changing preprocessor characters (-p)
|
||||
charset/ Tests of when charsets should be honoured and when not
|
||||
ca65/ Compatibility tests for ca65 compatibility
|
||||
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
|
||||
masmcom/ Another test for -M that generates totally valid code
|
||||
quotch/ Test quoting problematic characters (thanks Simon Rowe)
|
||||
linkr/ Test linking using .dsb and generated code
|
||||
csapiec/ Test on pointer arithmetic in relocating mode
|
||||
math/ Math tests (currently divide by zero, thanks Frederic Cambus)
|
||||
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
|
||||
reset_segment/ Verifies conditions under which a segment is reset
|
||||
expando/ Test of preprocessor expansion (thanks Tom Hargreaves)
|
||||
|
||||
Cameron Kaiser, André Fachat
|
||||
|
||||
|
|
Binary file not shown.
100
xa/tests/align/Makefile
Normal file
100
xa/tests/align/Makefile
Normal 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
10
xa/tests/align/t01.a65
Normal file
|
@ -0,0 +1,10 @@
|
|||
|
||||
.text
|
||||
|
||||
tay
|
||||
|
||||
.align 2
|
||||
|
||||
tay
|
||||
|
||||
|
BIN
xa/tests/align/t01.ok
Normal file
BIN
xa/tests/align/t01.ok
Normal file
Binary file not shown.
10
xa/tests/align/t02.a65
Normal file
10
xa/tests/align/t02.a65
Normal file
|
@ -0,0 +1,10 @@
|
|||
|
||||
.text
|
||||
|
||||
tay
|
||||
|
||||
.align 4
|
||||
|
||||
tay
|
||||
|
||||
|
BIN
xa/tests/align/t02.ok
Normal file
BIN
xa/tests/align/t02.ok
Normal file
Binary file not shown.
10
xa/tests/align/t03.a65
Normal file
10
xa/tests/align/t03.a65
Normal file
|
@ -0,0 +1,10 @@
|
|||
|
||||
.text
|
||||
|
||||
tay
|
||||
|
||||
.align 256
|
||||
|
||||
tay
|
||||
|
||||
|
BIN
xa/tests/align/t03.ok
Normal file
BIN
xa/tests/align/t03.ok
Normal file
Binary file not shown.
10
xa/tests/align/t11.a65
Normal file
10
xa/tests/align/t11.a65
Normal file
|
@ -0,0 +1,10 @@
|
|||
|
||||
.data
|
||||
|
||||
tay
|
||||
|
||||
.align 2
|
||||
|
||||
tay
|
||||
|
||||
|
BIN
xa/tests/align/t11.ok
Normal file
BIN
xa/tests/align/t11.ok
Normal file
Binary file not shown.
10
xa/tests/align/t12.a65
Normal file
10
xa/tests/align/t12.a65
Normal file
|
@ -0,0 +1,10 @@
|
|||
|
||||
.data
|
||||
|
||||
tay
|
||||
|
||||
.align 4
|
||||
|
||||
tay
|
||||
|
||||
|
BIN
xa/tests/align/t12.ok
Normal file
BIN
xa/tests/align/t12.ok
Normal file
Binary file not shown.
10
xa/tests/align/t13.a65
Normal file
10
xa/tests/align/t13.a65
Normal file
|
@ -0,0 +1,10 @@
|
|||
|
||||
.data
|
||||
|
||||
tay
|
||||
|
||||
.align 256
|
||||
|
||||
tay
|
||||
|
||||
|
BIN
xa/tests/align/t13.ok
Normal file
BIN
xa/tests/align/t13.ok
Normal file
Binary file not shown.
1
xa/tests/align/t21.mok
Normal file
1
xa/tests/align/t21.mok
Normal file
|
@ -0,0 +1 @@
|
|||
Warning: text segment ($0401) start address doesn't align to 2!
|
1
xa/tests/align/t21.msg
Normal file
1
xa/tests/align/t21.msg
Normal file
|
@ -0,0 +1 @@
|
|||
Warning: text segment ($0401) start address doesn't align to 2!
|
BIN
xa/tests/align/t21.ok
Normal file
BIN
xa/tests/align/t21.ok
Normal file
Binary file not shown.
1
xa/tests/align/t22.mok
Normal file
1
xa/tests/align/t22.mok
Normal file
|
@ -0,0 +1 @@
|
|||
Warning: text segment ($0401) start address doesn't align to 4!
|
1
xa/tests/align/t22.msg
Normal file
1
xa/tests/align/t22.msg
Normal file
|
@ -0,0 +1 @@
|
|||
Warning: text segment ($0401) start address doesn't align to 4!
|
BIN
xa/tests/align/t22.ok
Normal file
BIN
xa/tests/align/t22.ok
Normal file
Binary file not shown.
1
xa/tests/align/t23.mok
Normal file
1
xa/tests/align/t23.mok
Normal file
|
@ -0,0 +1 @@
|
|||
Warning: text segment ($0401) start address doesn't align to 256!
|
1
xa/tests/align/t23.msg
Normal file
1
xa/tests/align/t23.msg
Normal file
|
@ -0,0 +1 @@
|
|||
Warning: text segment ($0401) start address doesn't align to 256!
|
BIN
xa/tests/align/t23.ok
Normal file
BIN
xa/tests/align/t23.ok
Normal file
Binary file not shown.
1
xa/tests/align/t31.mok
Normal file
1
xa/tests/align/t31.mok
Normal file
|
@ -0,0 +1 @@
|
|||
Warning: data segment ($0401) start address doesn't align to 2!
|
1
xa/tests/align/t31.msg
Normal file
1
xa/tests/align/t31.msg
Normal file
|
@ -0,0 +1 @@
|
|||
Warning: data segment ($0401) start address doesn't align to 2!
|
BIN
xa/tests/align/t31.ok
Normal file
BIN
xa/tests/align/t31.ok
Normal file
Binary file not shown.
1
xa/tests/align/t32.mok
Normal file
1
xa/tests/align/t32.mok
Normal file
|
@ -0,0 +1 @@
|
|||
Warning: data segment ($0401) start address doesn't align to 4!
|
1
xa/tests/align/t32.msg
Normal file
1
xa/tests/align/t32.msg
Normal file
|
@ -0,0 +1 @@
|
|||
Warning: data segment ($0401) start address doesn't align to 4!
|
BIN
xa/tests/align/t32.ok
Normal file
BIN
xa/tests/align/t32.ok
Normal file
Binary file not shown.
1
xa/tests/align/t33.mok
Normal file
1
xa/tests/align/t33.mok
Normal file
|
@ -0,0 +1 @@
|
|||
Warning: data segment ($0401) start address doesn't align to 256!
|
1
xa/tests/align/t33.msg
Normal file
1
xa/tests/align/t33.msg
Normal file
|
@ -0,0 +1 @@
|
|||
Warning: data segment ($0401) start address doesn't align to 256!
|
BIN
xa/tests/align/t33.ok
Normal file
BIN
xa/tests/align/t33.ok
Normal file
Binary file not shown.
1
xa/tests/align/t41.mok
Normal file
1
xa/tests/align/t41.mok
Normal file
|
@ -0,0 +1 @@
|
|||
Warning: data segment ($0401) start address doesn't align to 2!
|
1
xa/tests/align/t41.msg
Normal file
1
xa/tests/align/t41.msg
Normal file
|
@ -0,0 +1 @@
|
|||
Warning: data segment ($0401) start address doesn't align to 2!
|
BIN
xa/tests/align/t41.ok
Normal file
BIN
xa/tests/align/t41.ok
Normal file
Binary file not shown.
1
xa/tests/align/t42.mok
Normal file
1
xa/tests/align/t42.mok
Normal file
|
@ -0,0 +1 @@
|
|||
Warning: data segment ($0401) start address doesn't align to 4!
|
1
xa/tests/align/t42.msg
Normal file
1
xa/tests/align/t42.msg
Normal file
|
@ -0,0 +1 @@
|
|||
Warning: data segment ($0401) start address doesn't align to 4!
|
BIN
xa/tests/align/t42.ok
Normal file
BIN
xa/tests/align/t42.ok
Normal file
Binary file not shown.
1
xa/tests/align/t43.mok
Normal file
1
xa/tests/align/t43.mok
Normal file
|
@ -0,0 +1 @@
|
|||
Warning: data segment ($0401) start address doesn't align to 256!
|
1
xa/tests/align/t43.msg
Normal file
1
xa/tests/align/t43.msg
Normal file
|
@ -0,0 +1 @@
|
|||
Warning: data segment ($0401) start address doesn't align to 256!
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user