1
0
mirror of https://github.com/fachat/xa65.git synced 2024-06-01 22:41:32 +00:00

Compare commits

...

12 Commits

Author SHA1 Message Date
A. Fachat
3be092964c release 2.4.1 2024-03-12 09:25:18 +01:00
Andre Fachat
e95549dfd1 official xa-2.4.0 2023-11-19 21:24:38 +01:00
Andre Fachat
0cfdf82384 update to official xa-2.3.14 2023-02-11 14:09:07 +01:00
Andre Fachat
b5c1e9b902 update to official xa-2.3.13 2022-03-27 23:01:03 +02:00
Andre Fachat
5d66d3a11a update to official xa-2.3.12 2022-03-27 22:57:02 +02:00
Andre Fachat
eff641bcff update to official xa-2.3.11 2020-05-15 19:20:17 +02:00
Andre Fachat
8becb7ecea update readme 2019-11-10 13:34:39 +01:00
Andre Fachat
4b54dd031e xa-2.3.10 2019-11-10 13:32:56 +01:00
Andre Fachat
a98b3770ee xa-2.3.9 2019-10-28 21:54:15 +01:00
Andre Fachat
c1fb2af9c2 remove version number from readme 2017-10-15 00:53:53 +02:00
Andre Fachat
1006018d26 xa-2.3.8 2017-10-15 00:50:45 +02:00
Andre Fachat
13b4cf53d9 xa-2.3.7 2017-10-15 00:47:56 +02:00
346 changed files with 11228 additions and 1323 deletions

5
README
View File

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

View File

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

View File

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

View File

@ -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
View File

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

View File

@ -0,0 +1,19 @@
all: loader example test2 rom65
clean:
rm -f loader test2 example a.o65 rom65
loader: loader.a65 file.def
../../xa loader.a65 -o loader
example: test.a
../../xa -R test.a -o example
test2: test2.a
../../xa test2.a -o test2
rom65: test.a
# ugly!
# 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

Binary file not shown.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -2,7 +2,7 @@
XCBMLIB = ..
# -Wall -ansi et al. cause compile problems.
CFLAGS = -O2
CFLAGS = -O2 -g
LIBS = #-lncurses -ltermcap -lm

View File

@ -37,6 +37,36 @@
#define author "Written by Andre Fachat"
#define copyright "Copyright (C) 1997-2002 Andre Fachat."
/* o65 file format mode bits */
#define FM_OBJ 0x1000
#define FM_SIZE 0x2000
#define FM_RELOC 0x4000
#define FM_CPU 0x8000
#define FM_CPU2 0x00f0
#define FM_CPU2_6502 0x0000
#define FM_CPU2_65C02 0x0010
#define FM_CPU2_65SC02 0x0020
#define FM_CPU2_65CE02 0x0030
#define FM_CPU2_NMOS 0x0040
#define FM_CPU2_65816E 0x0050
const char *cpunames[16] = {
"6502",
"65C02",
"65SC02",
"65CE02",
"NMOS6502",
"65816",
NULL, NULL,
"6809", NULL, // 1000 -
"Z80", NULL, NULL, // 1010 -
"8086", // 1101 -
"80286", // 1110 -
NULL
};
int read_options(FILE *fp);
int print_labels(FILE *fp, int offset);
@ -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);

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -34,6 +34,21 @@
#define author "Written by Andre Fachat"
#define copyright "Copyright (C) 1997-2002 Andre Fachat."
/* o65 file format mode bits */
#define FM_OBJ 0x1000
#define FM_SIZE 0x2000
#define FM_RELOC 0x4000
#define FM_CPU 0x8000
#define FM_CPU2 0x00f0
#define FM_CPU2_6502 0x0000
#define FM_CPU2_65C02 0x0010
#define FM_CPU2_65SC02 0x0020
#define FM_CPU2_65CE02 0x0030
#define FM_CPU2_NMOS 0x0040
#define FM_CPU2_65816E 0x0050
typedef struct {
char *fname;
size_t fsize;
@ -74,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;

View File

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

View File

@ -1,7 +1,8 @@
OBJ = xa.o xaa.o xal.o xap.o xat.o xar.o xar2.o xao.o xau.o xam.o xacharset.o
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"

View File

@ -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__ */

View File

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

View File

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

View File

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

View File

@ -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__ */

View File

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

View File

@ -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**)&lt)))
er=m_alloc((long)LABMEM,&ln);*/
er=m_alloc((long)(sizeof(Labtab)*ANZLAB),(char**)&lt);
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;
}

View File

@ -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
View 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, "&lt;");
q+=4;
p++;
} else
if (*p == '&') {
strcpy(q, "&amp;");
q+=5;
p++;
} else
if (*p == '>') {
strcpy(q, "&gt;");
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
View 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__ */

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -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__ */

View File

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

View File

@ -25,7 +25,7 @@
extern File *alloc_file(void);
/* jumps to r[td]_set, depending on segment */
int r_set(int pc, int reloc, int len);
/*int r_set(int pc, int reloc, int len);*/
int u_set(int pc, int reloc, int label, int len);
int rt_set(int pc, int reloc, int len, int label);

View File

@ -111,11 +111,17 @@ int rd_write(FILE *fp, int pc) {
}
fputc(pc2-pc, fp);
pc=pc2;
fputc((afl>>8)&255, fp);
if((afile->rd.rlist[p].afl&A_FMASK)==(SEG_UNDEF<<8)) {
if((afile->rd.rlist[p].afl&A_FMASK)==(SEG_UNDEFZP<<8)) {
fputc((((afl & ~A_FMASK)>>8)&255)|SEG_UNDEF, fp);
fputc(afile->rd.rlist[p].lab & 255, fp);
fputc((afile->rd.rlist[p].lab>>8) & 255, fp);
} else {
fputc((afl>>8)&255, fp);
if(((afile->rd.rlist[p].afl&A_FMASK)==(SEG_UNDEF<<8))) {
fputc(afile->rd.rlist[p].lab & 255, fp);
fputc((afile->rd.rlist[p].lab>>8) & 255, fp);
}
}
}
if((afl&A_MASK)==A_HIGH) fputc(afl&255,fp);
}
p=afile->rd.rlist[p].next;

File diff suppressed because it is too large Load Diff

View File

@ -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__ */

View File

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

View File

@ -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
View File

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

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

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

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

Binary file not shown.

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

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

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

Binary file not shown.

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

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

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

Binary file not shown.

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

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

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

Binary file not shown.

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

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

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

Binary file not shown.

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

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

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

Binary file not shown.

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

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

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

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

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

Binary file not shown.

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

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

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

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

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

Binary file not shown.

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

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

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

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

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

Binary file not shown.

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

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

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

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

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

Binary file not shown.

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

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

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

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

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

Binary file not shown.

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

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

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

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

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

Binary file not shown.

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

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

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

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

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

Binary file not shown.

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

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

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

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

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

Binary file not shown.

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

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

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

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

Some files were not shown because too many files have changed in this diff Show More