added stable version 2.3.5

This commit is contained in:
Andre Fachat 2011-12-16 23:04:51 +01:00
parent 22345e4837
commit ac0f09ba77
128 changed files with 18417 additions and 0 deletions

4
README
View File

@ -8,4 +8,8 @@ xa65 was originally authored by me, André Fachat, but currently and still xa65
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...
These are the directories:
xa - contains the main source. The master branch is the stable version (currently 2.3.5)

340
xa/COPYING Normal file
View File

@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 20yy <name of author>
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 20yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

297
xa/ChangeLog Normal file
View File

@ -0,0 +1,297 @@
xa-2.1.0
* Rewrite of command line option handling to better look like
usual (cc) options.
* Removed ^M from all files.
* Removed all external declarations to header files,
and made all static functions static.
| Now compiles almost without warning with 'gcc -W -Wall'.
-- André Fachat <a.fachat@physik.tu-chemnitz.de> 31 Oct, 1996
xa-2.1.0a
* Introduced concept of code relocation. Now each label being set to
the program counter is a 'pointer', that gets an entry in a
relocation table. Simple arithmetic operations are allowed. The
relocation table is still just printed unsortedly.
-- André Fachat <a.fachat@physik.tu-chemnitz.de> 31 Oct, 1996
xa-2.1.0b
* Produces some preliminary kind of relocatable file, including header
etc. Problems -- relocation table does as if file is assembled for
address 0. Need
a) a better way to set program counter.
b) pseudo opcodes for distinguishing segments.
c) a way to temporarily disable relocation.
d) a way to include extra headers and options into the file.
-- André Fachat <a.fachat@physik.tu-chemnitz.de> 31 Oct, 1996
* Assembler now produces a relocatable file format, as described in
the file ``fileformat.txt''. Temporarily disabling relocation is with
the ``*=value'' directive, while switching back to relocation mode
goes with ``*='' (without value). New pseudo opcodes ``.text'',
``.data'', ``.bss'', ``.zero'' switch between the segments.
-- André Fachat <a.fachat@physik.tu-chemnitz.de> 02 Nov, 1996
xa-2.1.0e
* There was a bug in the arithmetic routine that had set all pointer
to the text segment, if something was added.
* There also was a bug in the loader when actually using options.
* A new pseudo opcode was added -- ``.fopt''.
| Works like ``.byte'', but puts these bytes in a file option.
| The length in the file option is automagically set. ``.fopt''
| may appear anywhere in the file, but it should be at the
| beginning | (might be mandatory in a later version).
-- André Fachat <a.fachat@physik.tu-chemnitz.de> 06 Nov, 1996
xa-2.1.0f
* Added a command line switch ``-M'' to ignore colons in a comment
after a semicolon.
* Without it, a colon separates complete mnemonics, including
the semicolon comment.
| Well, actually this switch is a ``MASM'' compatibility switch, and
will surely be expanded someday, when I get more info on MASM.
* Now ``*'' and ``='' can be separated for the definition
of the program counter and ``.byte'' is also accepted.
This makes it more MASM compatible. ".end" is ignored.
Still missing is ``.include''.
-- André Fachat <a.fachat@physik.tu-chemnitz.de> 11 Nov, 1996
xa-2.1.0g
* Started working on ``official'' o65 fileformat.
If there are no undefined labels, and no relocated code
is embedded in absolute code, the thing should work.
-- André Fachat <a.fachat@physik.tu-chemnitz.de> 21 Dec, 1996
xa-2.1.1
* ``.dsb'' now has an _optional_ parameter ``fillbyte''.
* Undefined references are now put into the relocation table
(i.e. handled correctly) if the ``-c'' option is given.
* The file format conforms to o65 version 1 file format.
* Embedding absolute in relocatable code and vice versa is buggy...
-- André Fachat <a.fachat@physik.tu-chemnitz.de> 21 Dec, 1996
xa-2.1.1a
* Embedding absolute code in relocatable seems to work now.
-- André Fachat <a.fachat@physik.tu-chemnitz.de> 21 Dec, 1996
xa-2.1.1e
* The option to embed relocatable code in absolute code has been
dropped. Therefore the command line options
``-A'' (make it romable), ``-b?'' (set segment start addresses),
and ``-G'' (omit exported globals from file) have been added.
* Internally, the whole thing has been made dynamic; except for the
preprocessor (and the storage between pass1 and pass2), everything
uses dynamically allocated tables. m_alloc, which had been
introduced long time ago because of the buggy malloc
on the Atari ST is gone now!
-- André Fachat <a.fachat@physik.tu-chemnitz.de> 22 Dec, 1996
xa-2.1.1f
* Added the ``-a'' and ``-A'' options to file65, so that it can now
print the start addresses for following files in the ROM when making
romable code.
* Added shell (bash) script ``mkrom.sh'' that assembles a given list
of files and builds a ROMable file. The first two bytes are single
linked list pointers, and then comes the file.
-- André Fachat <a.fachat@physik.tu-chemnitz.de> 02 Jan, 1997
xa-2.1.1g
* Added the file ``reloc65'', to relocate o65 files without
reassembling them.
* Fixed quite some bugs in xa (segment numbering in the globals list
and switched low/high byte relocation entry type in relocation
table. Now conforms to documentation, i.e. fileformat.txt)
-- André Fachat <a.fachat@physik.tu-chemnitz.de> 03 Jan, 1997
xa-2.1.2
* Added ``ld65'', a simple linker for o65 files.
* Another bug in xa fixed now.
-- André Fachat <a.fachat@physik.tu-chemnitz.de> 04 Jan, 1997
xa-2.1.3
* Allows to use ``.data'' etc in absolute mode, too. No relocation
entries are generated then. Segment start can be set with ``-b?''
command line options, though. Also the data segment is discarded
with this method! This allows to use the normal ``.data'' etc
syntax even when assembling a ROM (which is done in absolute mode.)
* Fixed a bug where ``.dsb'' in a data segment didn't fill with the
right value
-- André Fachat <a.fachat@physik.tu-chemnitz.de> 25 Mar, 1997
xa-2.1.3e
* Added preprocessor continuation lines, and .block and .bend
pseudo-opcodes (They map to ``.('' and ``.)'' respectively.)
-- André Fachat <a.fachat@physik.tu-chemnitz.de> 27 Jul, 1997
xa-2.1.4
* Do not leave output file around after an error -- this is
better for ``make''.
* Also it seems to have settled for a while, so I can release
a new version.
-- André Fachat <a.fachat@physik.tu-chemnitz.de> 11 Sep, 1997
xa-2.1.4c
* Fixed a nasty bug that prevented correct relocation table
entries when a ``label2=label1'' contruct was used and
``label2'' was accessed.
* Added ``-I'' option.
-- André Fachat <a.fachat@physik.tu-chemnitz.de> 30 Dec, 1997
xa-2.1.4d
* fixed align code. Now inserts NOP opcodes into text segment, and
sets file mode appropriately.
-- André Fachat <a.fachat@physik.tu-chemnitz.de> 26 Jan, 1998
xa-2.1.4e
* Changed o65 fileformat and adopted it in xa.
-- André Fachat <a.fachat@physik.tu-chemnitz.de> 26 Jan, 1998
xa-2.1.4g
* Fix handling of !zeropageaddress, that was broken (did not result
in absolute address, but gave error message.)
* Add cross reference list to labels if switched on on command line.
* Fix the filename when multiple files are given on the command line
(used to give the first filename for all errors in second pass.)
-- André Fachat <a.fachat@physik.tu-chemnitz.de> 25 Nov, 1998
xa-2.1.4h
* In file65 added support for undefined labels and globals,
also for (some known) file options.
* Fix a preprocessor bug.
-- André Fachat <a.fachat@physik.tu-chemnitz.de> 12 Dec, 1998
xa-2.2.0-p1-1
* Update COPYING to the latest version (Y2K-fixed + new address to GNU)
* Lots of fixes to the Makefiles
* Cleaned up the structure of the TODO file
* Added manual-pages for file65, ld65, printcbm, reloc65, uncpk, and xa
* Commented out LIB-flags -lm, -lcurses and -ltermcap,
since they are all unused
* Added `--help' and `--version' to all binaries
* Removed `-h', `-?' and `-v' options where applicable
* Created a file containing the version-function; version.h
* Moved common macros to a separate file; xad.h
* Restructuring of printcbm to become more readable
* Added ifndef/define/endif traps to all header-files
* Fixed a few typos
* Renamed romadr to romaddr
* Renamed all functions matching *such* to *search*
* Fixed all warnings
* Cleaned up all header-files
* Reformatted xa.log
-- David Weinehall <tao@acc.umu.se> 20 Aug, 2002
xa-2.3.0
* Version number jump for all the unofficial xa's out there
* Fixed addressing bugs for @, ! and completed 65816 merge
Thanks to David for the report
* Moderate legibility overhaul to xat.c (will continue on this)
* More compiler warnings corrected
Thanks to David for the report
* man files completed
* Documentation updated
* Last line bug corrected (where last line not assembled if no newline)
Thanks to silverdr for the report
* ld65 is now ldo65 to avoid conflicts with cc65 package
* Post-defined labels work better, or at least somewhat (no longer attempts
to optimize in pass 2 and generate bad code). Can be forced with `
Thanks to silverdr for the report
* Makefile bugs multiplied
* @ now mostly obligatory for 24-bit addressing
-- Cameron Kaiser <ckaiser@floodgap.com> 2 Apr, 2006
xa-2.3.2
* Introduced switch to convert values in quotes to different character
sets. Currently supported are ASCII (default) and PETSCII
* Fixed some quote bugs
-- André Fachat <afachat@gmx.de> 23 Dec, 2006
Thomas Giesel's reports and suggestions, thank you:
* -M works on colons in comments and nowhere else, as documented
* macro function arguments are properly recursively evaluated
* cpp output now grokked for more complex pre-parsing, rather than
reinvent the wheel
Other things:
* .xl, .xs, .al, .as weren't documented, and now they are (always worked)
for 65816 mode
* ! for forward-defined labels calculated wrong instruction length, fixed
* xap.c cleaned up some, xat.c cleaned up some more
Legibility work is going to be a long-term project.
* -x is now deprecated
* Documentation updated
-- Cameron Kaiser <ckaiser@floodgap.com> 13 Jan, 2007
xa-2.3.3
* Compatibility update for Microsoft Visual Studio and mingw/MSYS (thanks
Fabian Nunez and Mikkel Holm Olsen).
-- Cameron Kaiser <ckaiser@floodgap.com> 15 May, 2007
xa-2.3.4
* -p to define alternate synonym for # for preprocessor to avoid cpp/xa
preprocessor clashes and messes.
* Direct linking into output stream of binary files (.bin).
* Minor overhaul of error system to facilitate future expansion.
* Documentation updated.
-- Cameron Kaiser <ckaiser@floodgap.com> 1 July, 2008
xa-2.3.5
Most of this was suggested by Martin Wendt.
* Fixed bug where .bin was affected by the current character set.
* Added PETSCREEN and HIGH character sets.
* Added .aasc.
* Some more legibility work.
* Documentation updated.
-- Cameron Kaiser <ckaiser@floodgap.com> 7 February, 2009

62
xa/Makefile Normal file
View File

@ -0,0 +1,62 @@
# Unix gcc or DOS go32 cross-compiling gcc
#
CC = gcc
LD = gcc
CFLAGS = -O2 -W -Wall -pedantic -ansi
LDFLAGS = -lc
# for DOS?
# CC = gcc-go32
# LD = gcc-go32
# CFLAGS = -W -Wall -pedantic
# Other cc
#CC = cc
#CFLAGS =
#LD = ld
DESTDIR = /usr/local
BINDIR = $(DESTDIR)/bin
MANDIR = $(DESTDIR)/share/man/man1
DOCDIR = $(DESTDIR)/share/doc
MKDIR = mkdir -p
INSTALL = install
all: xa uncpk
xa:
(cd src && LD=${LD} CC="${CC} ${CFLAGS}" ${MAKE})
load:
(cd loader && CC="${CC} ${CFLAGS}" ${MAKE})
uncpk:
(cd misc && CC="${CC} ${CFLAGS}" ${MAKE})
dos: clean
(cd src && LD=gcc-go32 CC=gcc-go32 CFLAGS="-W -Wall -pedantic" ${MAKE})
(cd misc && CC=gcc-go32 CFLAGS="-W -Wall -pedantic" ${MAKE})
rm -f xa file65 ldo65 uncpk printcbm reloc65 mkrom.sh src/*.o
mingw: clean
(cd src && LD=${LD} CC=${CC} CFLAGS="${CFLAGS}" LDFLAGS="" ${MAKE})
(cd misc && LD=${LD} CC=${CC} CFLAGS="${CFLAGS}" LDFLAGS="" ${MAKE})
clean:
(cd src && ${MAKE} clean)
(cd loader && ${MAKE} clean)
(cd misc && ${MAKE} mrproper)
rm -f xa *.exe *.o65
install: xa uncpk
$(MKDIR) $(BINDIR)
$(MKDIR) $(MANDIR)
$(INSTALL) xa reloc65 ldo65 file65 printcbm uncpk $(BINDIR)
$(INSTALL) man/file65.1 man/ldo65.1 man/printcbm.1 man/reloc65.1 man/uncpk.1 man/xa.1 $(MANDIR)
#$(MKDIR) $(DOCDIR)/xa65
dist: clean
#cd .. ; tar cvf xa-2.3.5A.tar xa-2.3.5 ; gzip xa-2.3.5A.tar
cd .. ; tar cvf xa-2.3.5.tar xa-2.3.5 ; gzip xa-2.3.5.tar

116
xa/README.1st Normal file
View File

@ -0,0 +1,116 @@
This is the readme for xa, a cross-assembler for the 6502 and 65816 CPUs (and
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.
To install on a generic Unixy thing, you should be able to just type
% make # to build the executable, and if it works ...
% 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.
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).
xa is no longer broadly supported outside of Unix due to my inability to test
it, but has nothing that should impair it from compiling elsewhere. To wit,
DOS compilation is still supported with the GO32 package. You should just be
able to type
C:\> make dos
In addition, there are compatibility updates to allow it to compile under
Microsoft Visual Studio and mingw. It should compile under VS2005 as written;
look in the vstudio directory for solution and project files provided by
Fabian Nunez. For mingw, use
make mingw
Similarly, Amiga and Atari ST compilation should still also function with
their particular compatible packages.
xa has a companion disassembler, the dxa package. dxa is not included in the
standard xa distribution, but can be downloaded from the xa home page at
http://www.floodgap.com/retrotech/xa/
Please check by periodically for the latest version of both packages.
xa was originally written and maintained by Andre Fachat. The current version
is maintained by Cameron Kaiser.
Please send me your comments at ckaiser@floodgap.com -- Andre's original
readme follows and applies generally to the present version.
-------------------------------------------------------------------------------
XA is a 6502 cross compiler:
- under GNU public license
- can produce _relocatable_ binaries
- The full fileformat description and 6502 file loader included.
- also included relocation and info utilites, as well as linker
- for any ANSI-C compliant computer (only utilities need 'stat' call
for file size).
- fast by hashtables
- Rockwell CMOS opcodes
- running under DOS and any ANSI C system (Unix, Amiga, Atari ST)
I developed this cross assembler for the 6502 CPU family quite some time
ago on my Atari ST. The assembler has successfully been ported to Amiga
and Unix computer (ported? just compiled... :-)
Lately I came across the problem to need relocatable 6502 binary files, so
I revised the assembler from version 2.0.7 to 2.1.0, adding a (admittedly
proprietary) 6502 relocatable binary format. But there are not many other
formats around and they didn't fit my needs. I have developed this format
myself and it is under the GNU public license.
With version 2.1.1 the 'official' version of the fileformat is supported.
To compile it, just type "make" (if you have the GNU gcc. If not, edit the
Makefile for the compiler options). This produces "xa", the cross assembler;
"uncpk", a small packing utility (where the C64 counterpart is in the
examples subdirectory), "printcbm", that lists C64 BASIC files and
'file65' that prints some information about o65 files. The "loader" in
the loader subdirectory is a basic 6502 implementation of a relocating
binary loader.
"file65" prints file information on 'o65' relocatable files. "reloc65"
can relocate 'o65' files.
If you want to use it under DOS, you have to have the GO32 DOS crosscompiling
tools to compile. Then just type "make dos" and you'll end up with the
appropriate DOS binaries. This has been tested only under i386 Linux, however.
Another archive with the DOS binaries included is provided.
One problem on the Atari was it's broken "malloc". Therefore I used to
alloc everything in one chunk and divide the memory by hand. So everything
was kind of statically allocated. This is almost gone now. Only the
temporary storage between pass1 and pass2 and the preprocessor are still
allocated in one chunk (size definitions in xah.h). The rest is allocated
as needed.
The docs are in the 'doc' subdir. There also is a description of the
6502 relocatable binary format. If you think some things could be
expressed in a better way, feel free and mail me to improve my english ;-)
[ The documentation is now maintained in man(1) format in man/ . -- CK ]
Andre

10
xa/TODO Normal file
View File

@ -0,0 +1,10 @@
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

6
xa/doc/README Normal file
View File

@ -0,0 +1,6 @@
As of 2.3.0, the official documentation will be maintained in the ../man/
directory. However, as the feature set is mostly mature, there is likely to
be little difference. The 2.2.x documents are here for your interest and
historical reference.
Cameron Kaiser

582
xa/doc/fileformat.txt Normal file
View File

@ -0,0 +1,582 @@
6502 binary relocation format
V1.2 as of 26jan1998
(c) André Fachat (a.fachat@physik.tu-chemnitz.de)
_________________________________________________________________
Changes from V1.1
The order for saving the undefined reference and the low byte of a
high byte relocation entry has changed. This makes the OS/A65 lib6502
implementation easier. How many other people use this format
anyway...?
_________________________________________________________________
0) Preface
With some new 6502/C64/C128 operating systems comes the need for a new
binary format. In multitasking operating systems like Lunix, SMOS, or
OS/A65, a binary file cannot be loaded to a fixed location that might
already be used by another program. Therefore it must be possible to
relocate the program to an arbitrary address at least at load time. In
addition to that, more specific information might be stored in a
binary executable file, like interrupt vectors for example.
This text gives a good solution to this problem for the 6502 CPU and
an assembler source format to use this format in a general manner. The
file format can even be used as an object file format, i.e. a format a
linker can use as an input file. It is also usable as a 65816 file
format. Instead of zeropage addressing modes, the 65816 has direct
addressing modes, that add the contents of the direct register to the
zeropage address in the opcode.
1) 6502/65816 specifics
The 6502 has the special feature of a 'zeropage', i.e. a very limited
memory address range used for special addressing modes. So the format
should not only provide a means to relocate absolute addresses but
also zeropage addresses. The 65816 replaces zeropage addressing with
direct addressing modes.
The stack space is also very limited. A binary format has to provide a
measure of how much stack space is needed for the application.
Such limits should be defined as 2 byte values, even if the 6502 only
has a range of 8 address bits for zeropage and stack. But the 65816
behaves differently, it has a 16 bit stack pointer for example. For
further expandability, a 32 bit format should be provided, although
the 16 bit format suffices for the 65816 already.
Another problem is, that an address can be 'split', i.e. you can just
use the high byte or the low byte separately in an opcode. This gives
need to a special relocation table format, that can cope with
half-address references. The 65816 can even have three byte addresses,
i.e. address in a segment and segment number.
2) binary format
2.1) General
The file differs from the known Commodore file formats, in that a lot
more information is stored in the file. First the data is structured
in separate segments to allow different handling of text (program
code), data (like tables) and bss (uninitialized data).
Also tables are included to allow late binding, i.e. linking the file
with other files at load time, and relocation, i.e. executing the file
at different addresses in 6502 address space.
2.2) Segments
As already used in other formats, the assembler uses three different
segment types, i.e. text (the actual program code), data (initialized
variables), and bss (uninitialized variables). To have these different
segments seems to be 'overdesigned', but they actually make memory
handling easier in more complex operating systems on systems with
virtual addresses (OS/A65, for example).
The text segment is defined to be read-only memory. This doesn't allow
self-modifying code in this segment, but allows memory sharing in
virtual memory architectures. The data segment actually is like the
text segment, only it is allocated writable. This segment might not be
shared between different processes. The contents of these two segments
are loaded from the file. The bss segment is uninitialized data, i.e.
upon program start, it is not defined - and not loaded from the file.
This area is read-write and can be used during program execution. It
is also not shared between processes. In addition to these segments,
the 6502 format also includes a zeropage segment type, to allow
zeropage variables to be relocated. This zeropage segment is like a
bss segment, in that only the length, but not the data is saved. For
the 65816 the zeropage segment changes its meaning to a bank zero
segment.
The different segments hold different type of data and can be located
anywhere in memory (except zero segment, which has to be in the
zeropage resp. bank zero). The program must therefore not assume
anything about the relative addresses between different segments.
2.3) Relocation
In general, there are three ways to handle the relocation problem so
far:
- Tables: have a relocation table for a text segment
if the relocation table is put in front of code
you have to save the table in a side-storage
if table is behind, you still cannot relocate 'on the fly'.
- Deassembling: go through the code, deassemble it and change all absolute
addresses. Problem: needs to know or have hints about where some
data is in the code.
- Relocation info in the code: here each address is preceeded with an
'escape' code and is relocated when loading. But this disallows block
oriented transfer from storage media to memory.
This binary format uses the first method, with the table after the
code/data. This way block oriented transfer for the text/data segment
can be used. And while reading the relocation tables bytewise, the
relocation can be done without the need to save the table somewhere.
2.4) External References & Exported Globals
As this file format should not only be used as an executable format,
but also as object file format, it must provide a way to define
references - references exported from this object and labels
referenced in this object. The external references list (also called
'undefined list') lists the addresses where labels not defined in this
object are referenced. The exported globals list lists the addresses
that are available for other objects. The labels are named by
null-terminated ASCII strings.
Even an executable file can have non-empty globals and externals
lists, but only if the operating system allows this. In this case, so
called 'late binding' is used to link the object with some global
libraries at link time.
2.5) File extension
The proposed standard extension for the described format is ".o65"
when used as an object file.
2.6) Format description
The binary format is the following:
(
header
text segment
data segment
external references list
relocation table for text segment
relocation table for data segment
exported globals list
)
The description of the parts follows:
2.6.1) Header
The header contains the minimum needed data in a fixed struct. The
rest of the necessary information is put into the header options.
[Note: .word is a 16 bit value, low byte first, .byt is a simple byte.
.long is a 32 bit value, low byte first. .size is a 16 or 32 bit value
according to .word and .long, depending on the size bit in the mode
field ]
This is the fixed struct:
(
.byt $01,$00 ; non-C64 marker
.asc "o65" ; o65 MAGIC!
.byt 0 ; version
.word mode ; mode word
.size tbase ; address to which text is assembled to
; originally
.size tlen ; length of text segment
.size dbase ; originating address for data segment
.size dlen ; length of data segment
.size bbase ; originating address for bss segment
.size blen ; length of bss segment
.size zbase ; originating address for zero segment
.size zlen ; length of zero segment
.size stack ; minimum needed stack size, 0= not known.
; the OS should add reasonable values for
; interrupt handling before allocating
; stack space
)
The mode word currently has these defined bits:
mode.15 : CPU 0= 6502 1= 65816
mode.14 : reloc 0= bytewise... 1= page(256byte)wise relocation
allowed
mode.13 : size 0= size=16 bit, 1= size=32 bit
mode.12 : obj 0= executable 1= object file
mode.0-1: align 0= byte align,
1= word (i.e. 2 byte) align
2= long (4 byte) align
3= block (256 byte) align
The CPU bit tells the loader for which CPU the file was made. This has
implications on the zero segment, for example. Also a system can check
if the program will run at all (on a 6502 that is). The reloc bit
defines if an object file can be relocated bytewise, or if it must be
page-aligned. A page has 256 bytes. The restriction to pagewise
relocation simplifies the relocation table and also allows simpler
compilers/assemblers. The size bit determines the size of the segment
base address and length entries. Currently the 16 bit size (size bit =
0) works for 6502 and 65816 CPUs.
The obj bit distinguishes between object files and executables. An
object file is used as assembler output that can be linked with other
object files to build an executable or an object library. The two
align bits give the address boundary the segments can be placed. Even
the 6502 needs this, as, for example, "jmp ($xxFF)" is broken. The
align bits are valid for all of the segments. [Note: if reloc=1, then
align should be 3. But if align=3, reloc need not be 1, because reloc
switches to a simpler version of the relocation table. The reloc bit
might be obsoleted in newer versions of this format. Though it should
be set, if necessary.]
All unused bits in the mode field must be zero.
Note that the header size is 26 if the size bit is zero and 44 if the
size bit is one.
The fixed sized struct is immediately followed by a list of header
options. Each header option consists of a single byte total length, a
type byte and some data bytes if needed. A single length byte of $00
ends the header option list.
(
{ ; optional options, more than one allowed
.byt olen ; overall length (including length and type
; byte
.byt otype ; option type
[ .byt option_bytes ]
}
.byt $00 ; end of options marker (i.e. option len=0)
)
The header options currently defined/proposed are:
- Filename:
type=0; len=strlen(filename_in_ascii)+3; content="filename_in_ascii",0
The string contains the name of the object.
- Operating System Header
type=1; len=?
the first data byte is the OS type:
1 OSA/65 header supplement
2 Lunix header supplement
[others to follow?]
the following data contains OS specific information.
A suggested data byte is the OS version as second byte.
- Assemblerprogram:
type=2; len=strlen(ass)+3; content="ass",0
The string contains the name of the assembler resp. linker that produced
this file/object.
For example (syntax see below)
.fopt 2, "xa 2.1.1g",0
becomes
0c 02 78 61 20 32 2e 31 2e 31 67 00
in the file.
- Author:
type=3; len=strlen(author)+3; content="author",0
The string contains the author of the file.
- Creation data:
type=4; len=strlen(date)+3; content="date_string",0
The string contains the creation date in format like:
"Sat Dec 21 14:00:23 MET 1996", where we have the day, Month, date,
time, timezone and year. See output of `date`...
2.6.2) text and data segments
The text and data segments are just the assembled code. The only
difference between text and data segments is the read/write mode of
the two segments. Therefore, to be compliant to this file format,
self-modifying code goes into the data segment.
2.6.3) Undefined references list
The next list is an ASCII list of labels that are referenced in this
file but not defined. The lists is preceeded with the number of
undefined labels (16 or 32 bits, according to the mode.size bit).
undef_list: number_of_undefined_labels.s
"undefined_label1",0
"undefined_label2",0
...
2.6.4) Relocation tables
The relocation tables are the same format for the two segments, text
and data. In general a relocation entry consists of the offset from
the previous relocation address to the next one, the type of the
relocation and additional info. Relocation not only defines the
relocation when moving object code to a different address, but also
filling in the undefined references.
Each table starts at relocation address = segment base address -1.
I.e. if the segment base address is $1000 for example, the first entry
has an offset computed from base address-1 = $0fff. The offset to the
next relocation address is the first byte of each entry. If the offset
is larger than 254 (i.e. 255 or above), than a 255 is set as offset
byte, the offset is decremented by 254 (note the difference) and the
entry is started again.
{ [255,...,255,] offset of next relocation (b), typebyte|segmentID [, low_byte]
}+
where typebyte has the bits 5, 6 and 7 and is one of
WORD $80 2 byte address
HIGH $40 high byte of an address
LOW $20 low byte of an address
SEGADR $c0 3 byte address (65816)
SEG $a0 segment byte of 3 byte address
The segmentID stands for the segment the reference points to:
0 undefined
1 absolute value
2 text segment
3 data segment
4 bss segment
5 zero segment
(Of course the absolute value will never appear in a relocation table,
but this value is necessary for the exported list)
If the type is HIGH, the low byte of the value is stored behind the
relocation table entry, if bytewise relocation is allowed (header mode
field bit 14). If only pagewise relocation is allowed, then only HIGH
relocation entries can occur, and the low byte is implicitely set zero
(i.e. it is _not_ saved in the relocation table).
If the type is SEG, then the two lower bytes of the three byte segment
address are stored behind the entry in the relocation table, lower
byte first.
If the segment is "undefined", the typebyte is immediately followed by
the two (mode size=0) or four (mode size=1) byte value index in the
undefined references list. If it is a high byte relocation, the low
byte is saved behind the index value. The index value determines the
undefined reference, which must be looked up by the loader.
The value taken from the relocation address in the segment, together
with the low byte from the relocation table (if HIGH entry) form the
address used if the segment would be used unrelocated. To relocate the
segment, the difference between the relocated segment base address and
the segment base address from the file is then added to the above
address. The result is again saved in the segment.
A zero offset byte ends the relocation table. The first offset is
computed from the segment base address-1, to avoid a 0 value in the
first entry.
Note that direct addressing modes do not generate entries in the
relocation table. instead it is assumed that the 65816 direct register
holds the correct value (i.e. zero segment base address) when running
this program.
Example:
Segment Base address in file (header.tbase) is $1000. The start
address of the text segment after relocation is real.tbase = $1234.
Now the first (unrelocated) address at which a relocation should take
place is here:
$1222 A9 23 lda #>vector
This generates the offset: $1222-($1000-1) = $223. This is larger than
254 ($fe), so the first byte is 255 ($ff). The offset is decremented
by $fe, and gives $125. This again is larger than $fe, so the next
byte is $ff again. After substracting $fe again, we have $27. But this
is the address of the opcode. To get the address of the address byte,
we have to add 1 to get $28, which becomes the third byte. The next
offset is then computed from $1223, because this is the last
relocation address.
Now we reference the high byte of an address, lets say vector=$23d0
(not relocated), in the text segment. Therefore the relocation type
becomes 'HIGH | text_segmentID = $42', which is the next byte. Because
we are referencing a high byte of an address, the low byte of the
unrelocated address is saved behind the typebyte in the relocation
entry. This byte is missing when referencing a low byte or address.
The relocation table entry is now:
$ff, $ff, $28, $42, $d0.
When actually doing the relocation, the relocation pointer is
initialized to real.tbase-1 = $1233. Then we compute the offset to
$224, which brings us to $1457, where the address byte of the above
opcode is after loading the file to $1234. We now have to compute the
new address, where vector is after relocation. So we take the
unrelocated low byte from the relocation table ($d0) and the high byte
from $1457 ($23).
vector_file = ($23
To this value we add
the difference between the address the program is assembled to and the
real load address:
vector_relocated = vector_file + (real.tbase - header.tbase)
= $23d0 + ($1234 - $1000)
= $23d0 + $234
= $2604
From this value the high byte is then written back to the address $1457.
Had we not saved the low byte in the relocation table, and only added
the high bytes, we would have missed the carry bit that increments
the high byte in this case!
Had "vector" now been an undefined reference, and "vector" would be
the second label in the undefined references list, we would get the
following relocation table entry (assuming mode.size=0):
$ff, $ff, $28, $40, $00, $02, $00
The value computed with the above formula for vector_file is now added
to the address the label "vector" now really has (This must of course
be looked up into an external table or list).
Had the opcode been "LDA #>vector+$567", then the low byte in the relocation
table would be $67, while the high byte in the opcode would be $05.
This value would result in vector_file and the real address of "vector"
would be added before wrting back the high byte to the opcode.
2.6.5) exported globals list
The global list is a list of names, together with the target segment
and the offset in the segment for each name. It is preceeded with the
number of exported labels. This allows the loader to allocate a table
large enough, if needed. The number of labels and the offset value
are 16 bit or 32 bit values according to the size bit in the header mode
field. The segmentID is a byte value and the same as in the relocation
table entry (see section 2.6.3).
number_of_exported_labels.s
"global_label_name_in_asc1",0, segmentID.b, value.s
...
3) assembler source format
The assembler source format is a suggestion only. It will be implemented
in xa65, a cross assembler for 6502 CPUs running on Unix/Atari ST/Amiga
as a reference platform.
The assembler provides a way to embed absolute address code in relocatable
code. This is needed when code should be copied to a specific location
known at assemble time.
There also is a way to make a file 'romable'. You can give the start
address of the _file_ in ROM, and the assembler automatically sets
the text segment start address to where the code will be in the ROM.
Of course, the other segments must be taken care of with -b? command
line parameter, that set the segment start address.
3.1) embed absolute code in relocatable files
When the assembler is started in relocatable mode, everything is put into
a .o65 relocatable file. All address references generate relocation table
entries. If a "*= value" pseudo opcode is encountered,
then the assembler switches to absolute mode. The following opcodes don't
generate relocation table entries. If a "*=" without a value is read,
then the assembler switches back to relocatable mode. The relocation
program counter is increased with the length of the absolute part and
the absolute code is embedded between the relocatable parts.
3.2) embed relocatable code in absolute files
This is dropped - too complicated. Should better be done with some
objdump or linker programs or so.
3.2) Header options
Before any opcode (after starting in relocatable mode, or after a .reloc
opcode), a header option can be set by:
.fopt byte1, byte2, ...
The header option length is automatically set by the assembler.
An example for an file author entry:
.fopt 3, "Andre Fachat",0
The 3 is the type byte for the author header option. The last zero ends
the name. The assembler can be configured to automatically include an
assembler header option into a file header.
3.3) allocation of data segment/zeropage segment address space
The assembler switches between the different segments by the means of
".text", ".data", ".bss" and ".zero" pseudo opcodes. After starting in
relocatable mode, the assembler is in the text segment.
The text segment contains the program code. Data holds the initialized data,
while bss and zero segments contain uninitialized data for normal/zeropage
address space.
Everything that is between one of these segment opcodes and the next segment
opcode gets into the corresponding segment, i.e. labels, assembled code etc.
The text and data segments are saved in the file, while for the bss and
zero segments only the length is saved in the file.
The assembler should issue a warning when a direct addressing mode
is used without a zero segment address and vice versa for 65816 CPUs.
3.4) referencing data/bss/zeropage addresses
One problem with the 6502 is, that it cannot load an address within one
step or assembler opcode. So an address is loaded with standard byte
opcodes, like "lda #
The assembler is now intelligent enough to evaluate such expressions
and check for:
- no address label : ok, absolute
- one address label, only add to label : ok, relocate
- difference between two addresses : If addresses in same segment, compute
diff and set absolute, otherwise bail
- everything else : warning
This way there is no change in syntax. Address labels are distinguished
by using the "label:" syntax, as opposed to "label = value".
Also, if the assembler is capable of doing so, an address label may be
defined by "label opcode", i.e. without a colon.
3.5) aligning code
The 6502 has the problem that some opcodes (e.g. "JMP ($xxFF)" are
broken, if the address given is at some (odd) address. But when loading
a relocatable file, one cannot know if an address will be odd or even.
Therefore there is a new opcode,
.align 2
that aligns the next address at the given address boundary. Valid
values are 2, 4, and 256.
4) Clearance
This file is surely not the optimum and could be improved. Also the
header option "assigned numbers" should be added here.
For this reason the author, André Fachat, will function as a
clearing point, where problems can be discussed and number can be assigned.
Dec. 22, 1996,
André Fachat
(fachat@physik.tu-chemnitz.de)
Appendix
A) File examples
(to be done with reference assembler)

89
xa/doc/xa-de.log Normal file
View File

@ -0,0 +1,89 @@
******** XASS65 1.0 ******** 15.11.89, Andre Fachat
2-Pass-Assembler f<>r 65(C)02. von Rockwell. Der erste Pass berechnet
die Labels, im zweiten Pass wird assembliert. Es wird eine Block-Struktur
unterst<EFBFBD>tzt, d.h. die Pseudo-Opcodes .( und .) verbergen dazwischenliegende
Labels vor Zugriffen aus anderen als dar<61>berliegenden Blocks.
Die Quell-, Object- und Fehlerdateien m<>ssen in der Kommandozeile angegeben
werden.
******** XASS 1.0 ******* 1.4.90, Andre Fachat
Die Object- und Fehlerdateien werden, falls nicht anders angegeben aus
der ersten Quelldatei durch „ndern der Extension ermittelt.
Es gibt jetzt einen C-„hnlichen Preprozessor mit define, ifdef, include etc.
'Funktionen' k”nnen keine definiert werden.
******** XA 2.00 ******** Andre Fachat
Ab jetzt wird das, was im ersten Pass schon zur Ermittelung der Opcode-
L„nge assembliert wurde zwischengespeichert. Das verdoppelt die
Geschwindigkeit ann„hernd. Dabei wird alles, was bekannt ist, vertokend,
um sp„ter nicht wieder soviel suchen zu m<>ssen.
******** XA 2.02 ******** 23.9.90, Andre Fachat
Labels k”nnen mit vorangestelltem '&' eine Blockstufe h”her definiert
werden, mit einem '-' werden sie global definiert (Block=0).
Bei eingeschalteter Option -c werden Fehler bei CMOS-Befehlen erzeugt.
Die Tabellen f<>r die Token-Erkennung sind vereinfacht und damit schneller
gemacht.
******** XA 2.03 ******** 16.6.91, Andre Fachat
Jetzt wird automatisch eine Liste mit Labels erzeugt und in einer .LAB-Datei
gespeichert. Im Preprozessor gibt es jetzt #if.
******** XA 2.04 ******** 14.7.91, Andre Fachat
Die Labeltabelle kann jetzt gr”žer als 32kByte werden. Da ein Eintrag in der
Label-Tabelle ohne den eigentlichen Namen 14 Byte betr„gt, sind jetzt mehr
als 2340 Labels m”glich.
Im Preprozessor sind jetzt auch 'Funktions'definitionen m”glich , also
z.B. #define mult(a,b) ((a)*(b))
******** XA 2.05 ******** 29.7.91, Andre Fachat
F<EFBFBD>r Labels, Defines und die Opcodes wird die Suche nach Hashcode durchgef<65>hrt.
damit werden ca. 350kByte Quelltext f<>r ein 32kByte EPROM nicht mehr in
18 sondern in ca. 3 Minuten assembliert.
******** XA 2.06 ******** 18.9.91,Andre Fachat
Der Preprozessor hat jetzt #ifldef und #iflused, was eigentlich heižt
'if label defined' und 'if label used'. Damit lassen sich Bibliotheks-
„hnliche Dateien aufbauen.
Die Umstellung auf PureC bringt ihn dazu, 350kByte (s.o.) in 2 Minuten zu
assemblieren. Die Vergr”žerung der Datei-Puffer per setvbuf() auf 4kByte
bringt auch noch 7 Sekunden. Aužerdem wird am Ende eine Statistik <20>ber
verbrauchte Resourcen gedruckt.
******** XA 2.07 ******** 30.9.91, Andre Fachat
Jetzt wird Zeit und Datum sowie die verbrauchten Sekunden in der Statistik
gezeigt. Die Environment-Variablen XAINPUT und XAOUTPUT werden unterst<73>tzt.
Falls die Quell- und Include-Dateien nicht gefunden werden, werden die in
XAINPUT aufgef<65>hrten Pfade der Reihe nach durchgetestet. Falls XAOUTPUT
existiert, wird dieser Pfad als Pfad f<>r .ERR, .LAB und .OBJ-Dateien
benutzt. Nach einem Turbo-C Referenzhandbuch sind alle Systemaufrufe
(malloc, fopen etc.) jetzt ANSI-kompatibel. (Der C-Quellcode allerdings
ist die Darstellung von Chaos im besten K&R-Stil...)
******** 16.2.92, Andre Fachat
#print und #printdef werden unterdr<64>ckt, wenn sie in der entsprechenden
#if-Strukur sind (war bisher im Gegensatz zu echo und include nicht so)
******** XA 2.07b ******** 5.1.94, Andre Fachat
Auf englisch uebersetzt, die Abhaengigkeit des Header-files von
stdio.h beseitigt, ebenso die Abhaengigkeit von der integer size.
in xah.h gibt es jetzt einen Define DIRCHAR und DIRCSTRING, die
das Verzeichnistrennzeichen definieren (DIRCHAR als '/' bzw '\\' und
DIRCSTRING als "/" bzw. "\\")
******** XA 2.0.7d ******** 96, Andre Fachat
Mehr auf Englisch übersetzt. #undef kann ein define löschen.

394
xa/doc/xa-de.txt Normal file
View File

@ -0,0 +1,394 @@
----------------------------------------------------------------------------
XA 2.1.0
65(c)02 Cross-Assembler
von Andre Fachat
----------------------------------------------------------------------------
* Block-Struktur (Versteckte Label)
* Sehr schnell durch hashing
* C-ähnlicher Preprozessor
----------------------------------------------------------------------------
1. Was ist das überhaupt und Geschichte
2. Aufruf und Features
3. 6502 Assembler
4. Pseudo-Opcodes, Block-Struktur und Gültigkeitsbereich von Labels
5. Preprozessor
----------------------------------------------------------------------------
1. Was ist das überhaupt und Geschichte
----------------------------------------
Mit dem Cross-Assembler können auf einem Rechner Programme für einen
anderen Rechner(typ) erstellt werden. Die Programmdateien müssen dann
nur noch auf das Zielsystem übertragen werden. In diesem Fall handelt
es sich um einen 6502-Cross-Assembler. Der 6502 ist ein 8-Bit-Prozessor,
der ursprünglich von MOS Technologies entwickelt wurde. Er tut seine
Dienste u.a. im Apple II, Commodore PET, VC20 und C64 (in abgewandelter
Form) und vielen anderen.
Inzwischen gibt es ihn in vielen Varianten mit verschiedenen Zusätzen
und in verschiedenen Gehäusen. Gemeinsam ist allen der Befehlssatz,
der für den Assembler die Grundlage bildet. Die CMOS-Versionen bieten
allerdings Erweiterungen des Befehlssatzes.
Die Idee zu einem Cross-Assembler entstand, als ich mir einen 6502-Computer
selbst baute und der (ebenfalls selbstgeschriebene) Assembler auf dem C64
zu langsam wurde. Nachdem auch noch ein Atari ST bei mir rumstand, war
die Idee schnell in die Tat umgesetzt.
2. Aufruf und Features
-----------------------
Der Assembler besteht nur aus dem Programm "xa".
Der Assembler verarbeitet eine oder mehrere Quelldateien zu einer
Objektdatei, die direkt verwendet werden kann. Das Linken entfällt, da der
Aufwand zu groß und die Geschwindigkeit hoch genug ist, um die
'Libraries' im Quelltext einzubinden. Ca. 350kByte Quelltext werden in
1 Minute und 50 Sekunden zu einer 32kByte Objektdatei für ein EPROM
assembliert (naja, der 8MHz Atari war nicht schnell. Aber dafür ist der
Wert ziemlich gut. Mein 486DX4/100 braucht vielleicht 2 Sekunden)!
Als Ausgabedateien werden eine Objektdatei, eine Fehlerdatei und eine
Labeldatei geschrieben.
Der Aufruf lautet:
XA Quell1 [Quell2 ...] [-oObject] [-eFehler] [-lLabel] [-C] [-v] [-x]
Die Angabe der Objekt-, Fehler- und Labeldatei ist optional, ohne Angabe
wird die Endung der ersten Quelldatei auf 'obj', 'err' und 'lab' verändert,
wenn "-x" angegeben ist. Ansonsten wird "a.o65" als Ausgabedatei verwendet
und keine Fehler- und Labeldatei geschrieben.
Die Option -C erzeugt Fehlermeldungen bei CMOS-Befehlen.
Im Environment werden die Variablen XAOUTPUT und XAINPUT unterstützt.
Falls die Quell- und Include-Dateien nicht gefunden werden, werden die in
XAINPUT aufgeführten Pfade der Reihe nach durchgetestet. Falls XAOUTPUT
existiert, wird dieser Pfad als Pfad für .err, .lab und .obj-Dateien
benutzt. Die Komponenten des Pfades sind mit ',' getrennt.
Die Labeldatei enthält hinterher eine Liste aller Labels mit Block-Nummer
und Wert in dezimal in der Form: 'Label, 1,-1234' in lesbarem ASCII.
Die Fehlerdatei enthält die Version des Assemblers, Datum und Uhrzeit des
Assemblerlaufs, die Liste der Fehler, die Ausdrücke, die mit #echo
und #print im Preprozessor erzeugt werden und eine Statistik über die
benutzten Resourcen (Speicherplatz etc.).
Die Objektdatei wird nur durch die Quelldatei bestimmt, es wird kein Code
vorgesetzt oder angehängt.
Die Quelldatei muß im ASCII-Format vorliegen.
3. 6502 Assembler
------------------
Da dies kein 6502-Assemblerkurs werden soll, nur eine ganz kurze
Beschreibung. Unterstützt wird der Code für alle Standard-6502 sowie
der Code für die Rockwell 65C02-CPU. Der Prozessor hat drei Register,
über die die meisten Operationen laufen. Transferoperationen benötigen
deshalb immer einen Load- und einen Store-Befehl.
Zusätzlich gibt es das Statusregister und den Stackpointer sowie,
natürlich, den Programmzähler. Der Stack liegt immer im Bereich $100 und
$1ff (Hexadezimal mit vorangestelltem '$'), weshalb der Stackpointer ein
8-Bit-Register ist. Eine besondere Behandlung durch kürzere Befehle
erfährt die Zeropage ($0-$ff), bei deren Adresse das Hi-Byte Null ist.
Das Statusregister besitzt folgende Flags:
N = Negativ
O = Overflow
B = Break
D = Dezimal
I = Interrupt
Z = Zeroflag
C = Carry
Befehle:
LDA lade Akkumulator
LDX lade X-Register
LDY lade Y-Register
STA speichere Akkumulator
STX speichere X-Register
STY speichere Y-Register
STZ speichere NULL (*)
TAX Kopiere Akku nach X
TAY Kopiere Akku nach Y
TXA Kopiere X nach Akku
TYA Kopiere Y nach Akku
TSX Kopiere Stackpointer nach X
TXS Kopiere X nach Stackpointer
ADC Addiere zu Akku mit Übertrag (Carry) (D)
SBC Subtrahiere von Akku mit Carry (D)
AND Logisches Und mit Akku
ORA Logisches Oder mit Akku
EOR Exklusiv-Oder mit Akku
BIT Bit-Test: Z=A&M, N=M7, O=M6
ROL Rotiere Links Akku oder Speicher A=A*2+C, C=A7
ROR Rotiere Rechts A=A/2+C*127, C=A0
ASL Arithmetisches Linksschieben A=A*2
LSR Logisches Rechtsschieben A=A/2
INX Erhöhe X-Register um eins
INY Y
INC Erhöhe Akku oder Speicher um eins
DEX Erniedrige X-Register um eins
DEY Y
DEC Erniedrige Akku oder Speicher um eins
CMP Vergleiche mit Akku (Substraktion ohne Akku zu ver„ndern)
CPX Vergleiche mit X-Register
CPY Vergleiche mit Y-Register
BNE Verzweige falls nicht Null
BEQ Null
BMI Negativ
BPL Positiv
BVC Overflow Clear
BVS Overflow Set
BCS Carry Set
BCC Carry Clear
BRA Verzweige immer (*)
JMP Springe an Adresse
JSR Springe in Unterroutine, R<>cksprungadresse auf dem Stack
RTS Return from Subroutine
CLC Carry-Flag löschen
SEC setzen
CLD Dezimal-Flag löschen
SED setzen
CLI Interrupt freigeben
SEI sperren
CLV Overflow-Flag löschen
PHA Akku auf Stack legen
PHX XR (*)
PHY YR (*)
PHP Status
PLA Akku vom Stack holen
PLX XR (*)
PLY YR (*)
PLP Status
BRK Löst Interrupt mit gesetztem Break-Flag aus
RTI Return from Interrupt
NOP No Operation
TRB Test und Reset Speicher mit Akku (*)
BBR Branch on Bit Reset (*)
BBS Branch on Bit Set (*)
RMB Reset Memory Bit (*)
SMB Set Memory Bit (*)
Die mit (*) markierten Befehle sind CMOS-Befehle. Außerdem haben einige
der anderen Befehle zusätzliche Addressierungsarten. Die mit (D) markierten
Befehle arbeiten im Dezimal-Mode (Dezimal-Flag gesetzt) anders, nämlich
im BCD-Mode (eine Ziffer von 0-9 in 4 Bit).
Addressierungsarten:
-Immediate LDA #$12
-Absolute STA $1234
-Zeropage EOR $10
-Bit,ZP,REL BBR #7,$10,label
-Akku ASL
-Implied TAX
-(Indirect,x) LDA ($10,X)
-(Indirect),y STA ($3e),Y
-Zeropage,x CMP $12,X
-Absolut,x LDY $4356,x
-(Absolut,x) jmp (jumptabelle,x)
-Absolut,y ORA $2345,y
-Relative BNE irgendwohin
-(Indirect) jmp (<28>berVektor)
-Zeropage,y ldx $12,y
-Bit,Zeropage RMB #1,zeropage
Bei Adressierungsarten, die in der Zeropage und Absolut existieren, wird,
soweit möglich die Zeropage-Adressierung angewendet. Ein vorangestelltes
'!' erzwingt absolute Adressierung, auch bei einem Wert kleiner 256.
Als Wert oder Adresse können arithmetische Ausdrücke mit Hierarchie und
Klammerung verwendet werden. Der Assembler versteht folgende Operanden:
123 -Dezimal
$234 -Hexadezimal
&123 -Oktal
%010110 -Binär
* -Programmzähler
"A" -ASCII-Code
labelx -Label
-(lab1+1) -Ausdruck
Folgende Operatoren können benutzt werden:
+ -Addition 9
- -Subtraktion 9
* -Multiplikation 10
/ -Integer-Division 10
<< -Shift nach links 8
>> -Shift nach rechts 8
>=,=> -größer oder gleich 7
<=,=< -kleiner oder gleich 7
< -kleiner 7
> -größer 7
= -gleich 6
<>,>< -ungleich 6
&& -Logisches UND 2
|| -Logisches ODER 1
& -Bitweises UND 5
| -Bitweises ODER 3
^ -Bitweises Exklusiv-Oder 4
Die Operatoren mit der höheren Priorität werden zuerst bearbeitet.
Ein gültiger Ausdruck ist dann z.B.
LDA base+number*2,x
Bei Addressierungsarten, die nicht mit einer Klammer beginnen, darf
auch im ersten Ausdruck keine Klammer am Anfang stehen:
LDX (1+2)*2,y ; Falsch !
LDX 2*(1+2),y ; Richtig !
Vor einem Ausdruck kann ein unärer Operator stehen:
< bildet Lo-Byte des Wertes
> bildet Hi-Byte des Wertes
LDA #<adresse
Die Einzelnen Befehle werden durch ':' oder eine neue Zeile getrennt.
Hinter jedem Befehl kann, durch ';' abgetrennt ein Kommentar stehen.
Der Kommentar gilt bis zum nächsten Doppelpunkt oder bis zur nächsten
Zeile.
4. Pseudo-Opcodes, Block-Struktur und Gültigkeitsbereich von Labels
-------------------------------------------------------------------
Folgende Pseudo-Opcodes stehen noch zur Verfügung:
.byt wert1,wert2,wert3, ...
.word wert1,wert2, ...
.asc "text1","text2", ...
.dsb länge [,füllbyte]
*=
.(
.)
Hierbei sind '.byt' und '.asc' identisch und legen Daten Byteweise im
Speicher ab. '.word' legt Daten Wortweise (=2 Byte) im Speicher ab.
'.dsb' füllt einen Speicherbereich der Länge 'länge' mit dem Wert
'füllbyte' ab. Falls füllbyte nicht abgegeben ist, wird mit Null gefüllt.
Die folgenden Opcodes haben keine direkte Einwirkung auf die Objektdatei.
'*=' definiert den Programmzähler.
'.(' eröffnet einen neuen 'Block'. Alle Labels innerhalb eines solchen
Blocks sind lokal. Allerdings darf vorher kein Label gleichen Namens in
einem höheren Block definiert worden sein. '.)' schließt den Block wieder.
Die Maximale Blockschachtelungstiefe beträgt 16 Blocks.
Ein Label wird definiert dadurch, daß es kein Opcode ist:
label1 LDA #0 ; Position(=Programmzähler) des Opcodes
label2 =1234 ; direkte definition
label3 label4 label5 ; implizit Programmzähler, auch mehrere
; Labels werden definiert
label6 label7 = 3 ; label6 wird mit dem Wert des Programm-
; zählers gesetzt, label7 mit 3
label8: sta label2 ; Da Opcodes mit ':' getrennt werden,
; wird auch die übliche Schreibweise mit
; 'label:' erkannt.
Dabei werden Groß- und Kleinbuchstaben unterschieden.
Labels, die mit vorangestelltem '+' definiert werden, sind global (Block=0),
d.h. überall gültig. Mit vorangestellten '&' kann ein Label jeweils eine
Hierarchiestufe höher definiert werden als ohne '&'.
Mit vorangestelltem '-' kann ein Label umdefiniert werden:
-sysmem +=4 ; da gibts ==, +=, -=, *=, /=, &=, |=
-syszp =123
5. Preprozessor
---------------
Der Preprozessor ist stark an den Preprozessor der Sprache C angelehnt.
So sind die für C typischen /* */ -Kommentare möglich.
Ein Preprozessor-Befehl wird mit einem '#' am Beginn der Zeile eingeleitet.
#include "Dateiname" fügt die Datei 'Dateiname' an dieser Stelle in den
Quelltext ein. Beim Laden wird zuerst der Name
direkt gesucht, danach mit den Pfaden aus
XAINPUT.
#echo Kommentar Gibt Kommentar in der Fehlerdatei aus.
#print ausdruck Gibt Ausdruck direkt, nach Preprzessorbehandlung
und nach dem Ausrechnen aus.
#printdef DEFINIERT Gibt die Definition in der Fehlerdatei aus.
#define DEF Text Definiert DEF als Text, deshalb wird hinterher
immer DEF durch Text ersetzt
#ifdef DEF Der Quelltext bis zum folgenden #endif oder #else
wird nur assembliert, falls DEF vorher mit #define
definiert wurde.
#else else halt...
#endif Beendet #if..-Konstrukt. Nach jedem #if.. muž!
ein #endif stehen.
#ifndef DEF .... falls DEF nicht definiert wurde.
#if ausdruck .... falls ausdruck ungleich null ist.
#iflused label .... falls Label schon benutzt wurde.
#ifldef label .... falls Label schon definiert wurde.
Dabei beziehen sich #iflused und #ifldef auf Labels, nicht auf Preprozessor-
Definitionen! Damit l„žt sich z.B. eine Bibliotheksstruktur aufbauen:
#iflused label
#ifldef label
#echo label schon definiert, nicht aus Library
#else
label lda #0
....
#endif
#endif
Die #if-Schachtelungstiefe beträgt 15.
Mit #define können auch wie in C 'Funktionen' mit Parametern definiert
werden.
#define mult(a,b) ((a)*(b))
Literaturangaben
----------------
-"Das Maschinensprachebuch zum Commodore 64"
Lothar Englisch
Data Becker GmbH
-"Controller Products Data Book"
Rockwell International, Semiconductor Products Division
-"Programmieren in C"
Kernighan, Ritchie
Hanser Verlag

362
xa/doc/xa.html Normal file
View File

@ -0,0 +1,362 @@
<html><head><title> xa 2.1.4 6502 Cross Assembler </title></head>
<body bgcolor="#ffffff">
<hr>
<h1 align=center> XA 2.1.4 </h1>
<h2 align=center> 65(c)02 Cross Assembler </h2>
<h2 align=center> (c) Andre Fachat </h2>
<h2 align=center> email: fachat@galileo.rhein-neckar.de </h2>
<hr>
<ol>
<li> what it is
<li> parameters and features
<li> 6502 Assembler
<li> pseudo-opcodes, block structures and where labels are valid
<li> pre-processor
<li> utilities
</ol><ul>
<li> literature
</ul>
<hr>
<h3> What it is </h3>
This Cross-Assembler makes programms for another computer that has a 6502-like
CPU. This CPU has been widely used in the famous Apple II, all the Commodore
8-Bit Computers (PET, VC20 and a derivate in the C64) and many others.
Some are still used in one-chip microcontrollers, e.g. the Rockwell modem
chipset.
All these chip share a common set of standard machine language commands,
some of them (e.g. the CMOS versions) have additional (software) features.
<p>
I had the idea for this assembler when I built my small 6502 System that
had place for 32kByte ROM to take the kernel and lots of other programms.
(After all, it became a multitasking micro-kernel with file-systems for
IBM and Commodore, I can even use the IBM drives as Floppy for my C64 with
this computer as controller. Piping and i/o-redirection included, of course)
Development on my old C64 began to suck with programms growing. So I decided
to do a Cross-Assembler on my new Atari ST.
<p>
First versions were very like the old Assembler on the C64, not really
using the resources (Reading all files two times completely etc).
With files growing the assembler also became more sophisticated.
Now hashcodes are used for mnemonics, preprocessor definition and label
search (Version &gt= 2.0.5). The files are only read once, putting the
preassembled code into memory (Version &gt= 2.0), taking it from there on pass 2.
Now it makes about 350kByte Source Code to about 30kByte ROM code in
less then 2 Minutes on an 8 MHz Atari ST with 2.5 MByte RAM and Harddisk.
(Well, the Atari is not fast. On my 486DX4/100 it takes about 2 seconds...)
But adding the whole relocation stuff slowed it down again.
<p>
<h3> Parameters and features</h3>
The assembler contains only a single programm called "xa" (for Atari: XA.TTP).
It takes one or more Source files into one object file, that can directly
be used.
But the assembler also has a mode to produce relocatable files, conforming
to the 'o65' fileformat (See fileformat.txt).
<p>
Call:
<p><pre>
xa [options] Source1 [Source2 ...]
</pre>
Object: this is the name, the output (object) file gets
Error: Here you will find the Error listing.
Label: this is the label list
<p><pre>
'-C' gives error codes when using CMOS-opcodes. Default is not to
complain.
'-c' do not produce o65 executable, but object files that can
contain undefined references.
'-v' go into verbose mode
'-x' old filename behaviour (overrides -o, -e and -l)
'-R' do not produce absolute code, but do relocation and all that.
'-o filename' set output filename
'-e filename' set errorlog filename
'-l filename' set labellist filename
'-r' add crossreference list to labellist output
(i.e list of filename/line where label is used)
'-M' allow ':' to appear in comments after a semicolon (MASM mode)
'-b? adr' set segment start address for ? = t(ext), d(ata), b(ss) or
z(ero) segment.
'-A adr' If the _file_ starts at adr in a ROM, then the text segment
need not be relocated. That of course only works, if the
data/bss/zero segments are not occupied by other programs too!
'-G' omit writing the exported globals to the file.
'-B' Show lines with '.(' or '.)' pseudo opcodes
'-Llabel' defines 'label' as absolute, undefined reference
'-DDEF=TEXT' define a preprocessor replacement
'-Ipath' additional include path for include files. Is evaluated before
the XAINPUT environment variable. One path per '-I',
multiple '-Ipath' allowed.
</pre>
Omitting the errorfile or labelfile Parameter will cause xa to not
write these files. Using '-x' will cause xa to take the name of the
first source file and change the extension (on an Atari there is only
one, like in DOS) to 'obj', 'err' and 'lab' respectively - if the old
behaviour is selected with the '-x' option or the files are defined with
"-l" and "-e". If no output file is given, "a.o65" is used.
<p>
<h4> Environment variables: </h4>
You can use the variables XAOUTPUT and XAINPUT to adjust the directory
structure. If source or include files are not found, the Path in XAINPUT
is being searched for the files. The different paths are separated by a
comma (','). XAINPUT gives the directory where the *.obj, *.err and
*.lab files are put.
If they are not set, there will be no search, respectively the files
are saved to the current directory.
<p>
The label file is a readable ASCII-file and lists all the labels
together with their block-count (see below) and their address.
The error file lists the version of the assembler, date and time of the
assembler run, all the error messages and the stuff being printed
with #echo and #print and last but not least a statistics of used
resources.
<h3> 6502 Assembler </h3>
xa supports both the standard 6502 opcodes as well as the CMOS versions
(Rockwell 65c02). Not supported are the 6502 undocumented opcodes, they have
to be put in by hand (with ".byte" directives).
<p>
For an introduction to 6502 Assembler please see elsewhere. A (very) short
introduction is given in the german version of this text.
<p>
<h4>Some Assembler specific details:</h4>
When using addressing modes that could be zeropage or absolute, zeropage
will be taken if possible. This can be prevented by prefixing the address
with a '!'. Then absolute addressing is taken, regardless of the address.
<p>
Values or Addresses can be expressed by arithmetik expressions with
hierachy and bracket. The following operands are understood:
<p><pre>
123 -decimal
$234 -hexadecimal
&123 -octal
%010110 -binary
* -program counter
"A" -ASCII-code
labelx -label
-(lab1+1) -expression
</pre>
The following operands can be used (third column is priority):
<p><pre>
+ -addition 9
- -subtraction 9
* -multiplication 10
/ -integer-division 10
&lt;&lt; -shift left 8
&gt;&gt; -shift right 8
&gt;=,=&gt; -more or equal 7
&lt;=,=&lt; -less or equal 7
&lt; -less 7
&gt; -more 7
= -equal 6
&lt;&gt;,&gt;&lt; -not equal 6
&& -logical AND 2
|| -Logical OR 1
& -Bitwise AND 5
| -Bitwise OR 3
^ -Bitwise XOR 4
</pre>
Operators with higher priority are evaluated first.
Brackets can be used as usual.
<p>
Valid expressions are, e.g.:
<p><pre>
LDA base+number*2,x
</pre>
For Addressing modes that do not start with a bracket, you can even use
a bracket at the beginning of an expression. Otherwise try this:
<p><pre>
LDX (1+2)*2,y ; Wrong!
LDX 2*(1+2),y ; Right!
</pre>
Before an expression you can use these unitary operators:
<p><pre>
&lt; Gives the low byte of the expression
&gt; Gives the high byte
LDA #&lt;adresse
</pre>
Single Assembler statements are being separated by a ':' (You remember
the C64 :-) or a newline. Behind Each statement, separated by a ';'
you can write some comments. The next colon or a newline ends the
comment and starts a new statement.
In MASM compatibility mode ('-M' command line option), then a colon
in a comment is ignored, i.e. the comment lasts till the newline.
<p>
<h3> Pseudo opcodes, Block structures and where Labels are valid </h3>
In addition to the 6502 opcodes you have the following Pseudo opcodes:
<p><pre>
.byt value1,value2,value3, ...
.word value1,value2, ...
.asc "text1","text2", ...
.dsb length ,fillbte
.fopt value1, value2, ...
.text
.data
.bss
.zero
.align value
*=
.(
.)
</pre>
'.byt' and '.asc' are identical and save values to the memory (object file)
bytewise. '.word' does the same with words (2 Bytes).
'.dsb' fills a block with a given length with the value of fillbyte.
If fillbyte is not given, zero is taken.
<p>
'*=' changes the programm counter. The programm counter is not saved
to the file as no rewind is being done. Just the internal counter
is reloaded.
If a value is given when the assembler has been started in relocation mode
('-R command line option), the assembler goes into no-relocation mode, i.e
assembles everything without creating relocation table entries.
For '*=' without a value, the assembler switches back to relocation mode.
The absolute code is 'embedded' in the text segment, so the text segment
program counter is increased by the length of the absolute code.
<p>
'.(' opens a new 'block'. All labels in a block are local, i.e.
are only visible from inside the block - including sub-blocks.
An error is returned if a label is defined that is already defined
'above'.
With '.)' the block is closed. You can have a stack of up to 16 blocks
in each other (i.e. 16 times '.(' before the first '.)' will work, 17 not).
<p>
'.text', '.data', '.bss', '.zero' switch between the different segments.
The text segment is where the code goes in. The data segment is where
some initialized data goes in (it's actually like a second text segment).
The data segment might be allocated separated from the text segment.
The contents of the bss and the zero segment are not saved, just the
labels are evaluated. Here goes the uninitialized data stuff.
The zero segment allows allocation of zeropage space, bss is normal address
space.
These opcodes can be used in relative and absolute mode.
<p>
'.align' aligns the current segment to a byte boundary given by the
value. Allowed values are 2, 4, and 256. When using relative mode, the
align value is written to the file header, such that relocation keeps
the alignment.
<p>
'.fopt' works like ".byte", but saves the bytes as a fileoption (see
fileformat.txt). The length is computed automatically, so the first
byte in the ".fopt" list of values should be the type.
For example, the following line sets the filename for the object file.
<p><pre>
.fopt 0, "filename", 0
</pre>
A label is defined by not being an opcode:
<p><pre>
label1 LDA #0 ; assignes the programm counter
label2 =1234 ; explicit definition
label3 label4 label5 ; implicit programm counter
label6 label7 = 3 ; label6 becomes the program counter, while
; label7 is set to 3
label8: sta label2 ; As ':' divides opcodes, this is also
; working
</pre>
You can use more than one label for definition, except for explicit
definition.
Labels are case sensitive.
If a label is proceeded by a '+', this label is defined global.
If a label is proceeded by a '&', this label is defined one level 'up'
in the block hierachy, and you can use more than one '&'.
<p>
Redefinition of a label is possible by proceeding it with a dash '-'.
<p><pre>
-sysmem +=4 ; here you can use ==, +=, -=, *=, /=, &=, |=
-syszp =123
</pre>
<h3> Preprocessor </h3>
The preprocessor is very close to the one of the language C.
So in addition to the ';'-comments you can also use C-like
comments in '/*' and '*/'. Comments can be nested.
<p><pre>
#include "filename" includes a file on exactly this position.
if the file is not found, it is searched using
XAINPUT.
#echo comment gives a comment to the error file.
#print expression prints an expression to the error file (after
preprocessing and calculating)
#printdef DEFINED prints the definition of a preprocessor define to
the error file.
#define DEF text defines 'DEF' by 'text'
#ifdef DEF The source code from here to the following #endif
or #else is only assembled if 'DEF' is defined
with #define.
#else just else... (optionally)
#endif ends an #if-construct. This is a must to end #IF*
#ifndef DEF .... if DEF is not defined
#if expression .... if expression is not zero
#iflused label .... if a label has already been used
#ifldef label .... if a label is already defined
</pre>
#iflused and #ifldef work an labels, not on preprocessor defs! With these
commands a kind of library is easily built:
<p><pre>
#iflused label
#ifldef label
#echo label already defined, not from library
#else
label lda #0
....
#endif
#endif
</pre>
You can have up to 15 #if* on stack before the first #endif
<p>
You can also use #define with functions, like in C.
<p><pre>
#define mult(a,b) ((a)*(b))
</pre>
The preprocessor also allows continuation lines. I.e. lines that end
with a '\' directly before the newline have the following line
concatenated to it.
<p>
<h3> Utilities </h3>
There now are a few utilities that come with the assembler:
<p><pre>
file65 : prints some information about an o65 file. Can compute the
"-A" parameter for xa, to built the following file in a ROM.
reloc65 : relocates o65 files.
mkrom.sh: example shell (bash) script to show how to use the file65 utility
to build a ROM image with several in the ROM runnable programs.
ld65 : a linker for o65 files. The given files are linked together and
one o65 executable file is produced. All header options of all files
are put in the new file. There must not be any undefined reference
left, otherwise the output file is corrupt, because
for now, ld65 cannot produce object files. But you get a warning.
</pre>
<p>
<h3> Literature </h3>
<ul>
<li> "Das Maschinensprachebuch zum Commodore 64" <br>
Lothar Englisch, Data Becker GmbH
<li> "Controller Products Data Book" <br>
Rockwell International, Semiconductor Products Division
<li> "Programmieren in C" <br>
Kernighan, Ritchie, Hanser Verlag
</ul>
</body>
</html>

254
xa/doc/xa.log Normal file
View File

@ -0,0 +1,254 @@
xa-2.1.0
* Rewrite of command line option handling to better look like
usual (cc) options.
* Removed ^M from all files.
* Removed all external declarations to header files,
and made all static functions static.
| Now compiles almost without warning with 'gcc -W -Wall'.
-- André Fachat <a.fachat@physik.tu-chemnitz.de> 31 Oct, 1996
xa-2.1.0a
* Introduced concept of code relocation. Now each label being set to
the program counter is a 'pointer', that gets an entry in a
relocation table. Simple arithmetic operations are allowed. The
relocation table is still just printed unsortedly.
-- André Fachat <a.fachat@physik.tu-chemnitz.de> 31 Oct, 1996
xa-2.1.0b
* Produces some preliminary kind of relocatable file, including header
etc. Problems -- relocation table does as if file is assembled for
address 0. Need
a) a better way to set program counter.
b) pseudo opcodes for distinguishing segments.
c) a way to temporarily disable relocation.
d) a way to include extra headers and options into the file.
-- André Fachat <a.fachat@physik.tu-chemnitz.de> 31 Oct, 1996
* Assembler now produces a relocatable file format, as described in
the file ``fileformat.txt''. Temporarily disabling relocation is with
the ``*=value'' directive, while switching back to relocation mode
goes with ``*='' (without value). New pseudo opcodes ``.text'',
``.data'', ``.bss'', ``.zero'' switch between the segments.
-- André Fachat <a.fachat@physik.tu-chemnitz.de> 02 Nov, 1996
xa-2.1.0e
* There was a bug in the arithmetic routine that had set all pointer
to the text segment, if something was added.
* There also was a bug in the loader when actually using options.
* A new pseudo opcode was added -- ``.fopt''.
| Works like ``.byte'', but puts these bytes in a file option.
| The length in the file option is automagically set. ``.fopt''
| may appear anywhere in the file, but it should be at the
| beginning | (might be mandatory in a later version).
-- André Fachat <a.fachat@physik.tu-chemnitz.de> 06 Nov, 1996
xa-2.1.0f
* Added a command line switch ``-M'' to ignore colons in a comment
after a semicolon.
* Without it, a colon separates complete mnemonics, including
the semicolon comment.
| Well, actually this switch is a ``MASM'' compatibility switch, and
will surely be expanded someday, when I get more info on MASM.
* Now ``*'' and ``='' can be separated for the definition
of the program counter and ``.byte'' is also accepted.
This makes it more MASM compatible. ".end" is ignored.
Still missing is ``.include''.
-- André Fachat <a.fachat@physik.tu-chemnitz.de> 11 Nov, 1996
xa-2.1.0g
* Started working on ``official'' o65 fileformat.
If there are no undefined labels, and no relocated code
is embedded in absolute code, the thing should work.
-- André Fachat <a.fachat@physik.tu-chemnitz.de> 21 Dec, 1996
xa-2.1.1
* ``.dsb'' now has an _optional_ parameter ``fillbyte''.
* Undefined references are now put into the relocation table
(i.e. handled correctly) if the ``-c'' option is given.
* The file format conforms to o65 version 1 file format.
* Embedding absolute in relocatable code and vice versa is buggy...
-- André Fachat <a.fachat@physik.tu-chemnitz.de> 21 Dec, 1996
xa-2.1.1a
* Embedding absolute code in relocatable seems to work now.
-- André Fachat <a.fachat@physik.tu-chemnitz.de> 21 Dec, 1996
xa-2.1.1e
* The option to embed relocatable code in absolute code has been
dropped. Therefore the command line options
``-A'' (make it romable), ``-b?'' (set segment start addresses),
and ``-G'' (omit exported globals from file) have been added.
* Internally, the whole thing has been made dynamic; except for the
preprocessor (and the storage between pass1 and pass2), everything
uses dynamically allocated tables. m_alloc, which had been
introduced long time ago because of the buggy malloc
on the Atari ST is gone now!
-- André Fachat <a.fachat@physik.tu-chemnitz.de> 22 Dec, 1996
xa-2.1.1f
* Added the ``-a'' and ``-A'' options to file65, so that it can now
print the start addresses for following files in the ROM when making
romable code.
* Added shell (bash) script ``mkrom.sh'' that assembles a given list
of files and builds a ROMable file. The first two bytes are single
linked list pointers, and then comes the file.
-- André Fachat <a.fachat@physik.tu-chemnitz.de> 02 Jan, 1997
xa-2.1.1g
* Added the file ``reloc65'', to relocate o65 files without
reassembling them.
* Fixed quite some bugs in xa (segment numbering in the globals list
and switched low/high byte relocation entry type in relocation
table. Now conforms to documentation, i.e. fileformat.txt)
-- André Fachat <a.fachat@physik.tu-chemnitz.de> 03 Jan, 1997
xa-2.1.2
* Added ``ld65'', a simple linker for o65 files.
* Another bug in xa fixed now.
-- André Fachat <a.fachat@physik.tu-chemnitz.de> 04 Jan, 1997
xa-2.1.3
* Allows to use ``.data'' etc in absolute mode, too. No relocation
entries are generated then. Segment start can be set with ``-b?''
command line options, though. Also the data segment is discarded
with this method! This allows to use the normal ``.data'' etc
syntax even when assembling a ROM (which is done in absolute mode.)
* Fixed a bug where ``.dsb'' in a data segment didn't fill with the
right value
-- André Fachat <a.fachat@physik.tu-chemnitz.de> 25 Mar, 1997
xa-2.1.3e
* Added preprocessor continuation lines, and .block and .bend
pseudo-opcodes (They map to ``.('' and ``.)'' respectively.)
-- André Fachat <a.fachat@physik.tu-chemnitz.de> 27 Jul, 1997
xa-2.1.4
* Do not leave output file around after an error -- this is
better for ``make''.
* Also it seems to have settled for a while, so I can release
a new version.
-- André Fachat <a.fachat@physik.tu-chemnitz.de> 11 Sep, 1997
xa-2.1.4c
* Fixed a nasty bug that prevented correct relocation table
entries when a ``label2=label1'' contruct was used and
``label2'' was accessed.
* Added ``-I'' option.
-- André Fachat <a.fachat@physik.tu-chemnitz.de> 30 Dec, 1997
xa-2.1.4d
* fixed align code. Now inserts NOP opcodes into text segment, and
sets file mode appropriately.
-- André Fachat <a.fachat@physik.tu-chemnitz.de> 26 Jan, 1998
xa-2.1.4e
* Changed o65 fileformat and adopted it in xa.
-- André Fachat <a.fachat@physik.tu-chemnitz.de> 26 Jan, 1998
xa-2.1.4g
* Fix handling of !zeropageaddress, that was broken (did not result
in absolute address, but gave error message.)
* Add cross reference list to labels if switched on on command line.
* Fix the filename when multiple files are given on the command line
(used to give the first filename for all errors in second pass.)
-- André Fachat <a.fachat@physik.tu-chemnitz.de> 25 Nov, 1998
xa-2.1.4h
* In file65 added support for undefined labels and globals,
also for (some known) file options.
* Fix a preprocessor bug.
-- André Fachat <a.fachat@physik.tu-chemnitz.de> 12 Dec, 1998
xa-2.2.0-p1-1
* Update COPYING to the latest version (Y2K-fixed + new address to GNU)
* Lots of fixes to the Makefiles
* Cleaned up the structure of the TODO file
* Added manual-pages for file65, ld65, printcbm, reloc65, uncpk, and xa
* Commented out LIB-flags -lm, -lcurses and -ltermcap,
since they are all unused
* Added `--help' and `--version' to all binaries
* Removed `-h', `-?' and `-v' options where applicable
* Created a file containing the version-function; version.h
* Moved common macros to a separate file; xad.h
* Restructuring of printcbm to become more readable
* Added ifndef/define/endif traps to all header-files
* Fixed a few typos
* Renamed romadr to romaddr
* Renamed all functions matching *such* to *search*
* Fixed all warnings
* Cleaned up all header-files
* Reformatted xa.log
-- David Weinehall <tao@acc.umu.se> 20 Aug, 2002
xa-2.3.0
* Version number jump for all the unofficial xa's out there
* Fixed addressing bugs for @, ! and completed 65816 merge
Thanks to David for the report
* Moderate legibility overhaul to xat.c (will continue on this)
* More compiler warnings corrected
Thanks to David for the report
* man files completed
* Documentation updated
* Last line bug corrected (where last line not assembled if no newline)
Thanks to silverdr for the report
* ld65 is now ldo65 to avoid conflicts with cc65 package
* Post-defined labels work better, or at least somewhat (no longer attempts
to optimize in pass 2 and generate bad code). Can be forced with `
Thanks to silverdr for the report
* Makefile bugs multiplied
* @ now mostly obligatory for 24-bit addressing
-- Cameron Kaiser <ckaiser@floodgap.com> 2 Apr, 2006
xa-??
* Introduced switch to convert values in quotes to different character
sets. Currently supported are ASCII (default) and PETSCII
* Fixed some quote bugs
-- André Fachat <afachat@gmx.de> 23 Dec, 2006

358
xa/doc/xa.txt Normal file
View File

@ -0,0 +1,358 @@
_________________________________________________________________
XA 2.1.4
65(c)02 Cross Assembler
(c) Andre Fachat
email: fachat@galileo.rhein-neckar.de
_________________________________________________________________
1. what it is
2. parameters and features
3. 6502 Assembler
4. pseudo-opcodes, block structures and where labels are valid
5. pre-processor
6. utilities
* literature
_________________________________________________________________
What it is
This Cross-Assembler makes programms for another computer that has a
6502-like CPU. This CPU has been widely used in the famous Apple II,
all the Commodore 8-Bit Computers (PET, VC20 and a derivate in the
C64) and many others. Some are still used in one-chip
microcontrollers, e.g. the Rockwell modem chipset. All these chip
share a common set of standard machine language commands, some of them
(e.g. the CMOS versions) have additional (software) features.
I had the idea for this assembler when I built my small 6502 System
that had place for 32kByte ROM to take the kernel and lots of other
programms. (After all, it became a multitasking micro-kernel with
file-systems for IBM and Commodore, I can even use the IBM drives as
Floppy for my C64 with this computer as controller. Piping and
i/o-redirection included, of course) Development on my old C64 began
to suck with programms growing. So I decided to do a Cross-Assembler
on my new Atari ST.
First versions were very like the old Assembler on the C64, not really
using the resources (Reading all files two times completely etc). With
files growing the assembler also became more sophisticated. Now
hashcodes are used for mnemonics, preprocessor definition and label
search (Version >= 2.0.5). The files are only read once, putting the
preassembled code into memory (Version >= 2.0), taking it from there
on pass 2. Now it makes about 350kByte Source Code to about 30kByte
ROM code in less then 2 Minutes on an 8 MHz Atari ST with 2.5 MByte
RAM and Harddisk. (Well, the Atari is not fast. On my 486DX4/100 it
takes about 2 seconds...) But adding the whole relocation stuff slowed
it down again.
Parameters and features
The assembler contains only a single programm called "xa" (for Atari:
XA.TTP). It takes one or more Source files into one object file, that
can directly be used. But the assembler also has a mode to produce
relocatable files, conforming to the 'o65' fileformat (See
fileformat.txt).
Call:
xa [options] Source1 [Source2 ...]
Object: this is the name, the output (object) file gets Error: Here
you will find the Error listing. Label: this is the label list
'-C' gives error codes when using CMOS-opcodes. Default is not to
complain.
'-c' do not produce o65 executable, but object files that can
contain undefined references.
'-v' go into verbose mode
'-x' old filename behaviour (overrides -o, -e and -l)
'-R' do not produce absolute code, but do relocation and all that.
'-o filename' set output filename
'-e filename' set errorlog filename
'-l filename' set labellist filename
'-r' add crossreference list to labellist output
(i.e list of filename/line where label is used)
'-M' allow ':' to appear in comments after a semicolon (MASM mode)
'-b? adr' set segment start address for ? = t(ext), d(ata), b(ss) or
z(ero) segment.
'-A adr' If the _file_ starts at adr in a ROM, then the text segment
need not be relocated. That of course only works, if the
data/bss/zero segments are not occupied by other programs too!
'-G' omit writing the exported globals to the file.
'-B' Show lines with '.(' or '.)' pseudo opcodes
'-Llabel' defines 'label' as absolute, undefined reference
'-DDEF=TEXT' define a preprocessor replacement
'-Ipath' additional include path for include files. Is evaluated before
the XAINPUT environment variable. One path per '-I',
multiple '-Ipath' allowed.
Omitting the errorfile or labelfile Parameter will cause xa to not
write these files. Using '-x' will cause xa to take the name of the
first source file and change the extension (on an Atari there is only
one, like in DOS) to 'obj', 'err' and 'lab' respectively - if the old
behaviour is selected with the '-x' option or the files are defined
with "-l" and "-e". If no output file is given, "a.o65" is used.
Environment variables:
You can use the variables XAOUTPUT and XAINPUT to adjust the directory
structure. If source or include files are not found, the Path in
XAINPUT is being searched for the files. The different paths are
separated by a comma (','). XAINPUT gives the directory where the
*.obj, *.err and *.lab files are put. If they are not set, there will
be no search, respectively the files are saved to the current
directory.
The label file is a readable ASCII-file and lists all the labels
together with their block-count (see below) and their address. The
error file lists the version of the assembler, date and time of the
assembler run, all the error messages and the stuff being printed with
#echo and #print and last but not least a statistics of used
resources.
6502 Assembler
xa supports both the standard 6502 opcodes as well as the CMOS
versions (Rockwell 65c02). Not supported are the 6502 undocumented
opcodes, they have to be put in by hand (with ".byte" directives).
For an introduction to 6502 Assembler please see elsewhere. A (very)
short introduction is given in the german version of this text.
Some Assembler specific details:
When using addressing modes that could be zeropage or absolute,
zeropage will be taken if possible. This can be prevented by prefixing
the address with a '!'. Then absolute addressing is taken, regardless
of the address.
Values or Addresses can be expressed by arithmetik expressions with
hierachy and bracket. The following operands are understood:
123 -decimal
$234 -hexadecimal
&123 -octal
%010110 -binary
* -program counter
"A" -ASCII-code
labelx -label
-(lab1+1) -expression
The following operands can be used (third column is priority):
+ -addition 9
- -subtraction 9
* -multiplication 10
/ -integer-division 10
<< -shift left 8
>> -shift right 8
>=,=> -more or equal 7
<=,=< -less or equal 7
< -less 7
> -more 7
= -equal 6
<>,>< -not equal 6
&& -logical AND 2
|| -Logical OR 1
& -Bitwise AND 5
| -Bitwise OR 3
^ -Bitwise XOR 4
Operators with higher priority are evaluated first. Brackets can be
used as usual.
Valid expressions are, e.g.:
LDA base+number*2,x
For Addressing modes that do not start with a bracket, you can even
use a bracket at the beginning of an expression. Otherwise try this:
LDX (1+2)*2,y ; Wrong!
LDX 2*(1+2),y ; Right!
Before an expression you can use these unitary operators:
< Gives the low byte of the expression
> Gives the high byte
LDA #<adresse
Single Assembler statements are being separated by a ':' (You remember
the C64 :-) or a newline. Behind Each statement, separated by a ';'
you can write some comments. The next colon or a newline ends the
comment and starts a new statement. In MASM compatibility mode ('-M'
command line option), then a colon in a comment is ignored, i.e. the
comment lasts till the newline.
Pseudo opcodes, Block structures and where Labels are valid
In addition to the 6502 opcodes you have the following Pseudo opcodes:
.byt value1,value2,value3, ...
.word value1,value2, ...
.asc "text1","text2", ...
.dsb length ,fillbte
.fopt value1, value2, ...
.text
.data
.bss
.zero
.align value
*=
.(
.)
'.byt' and '.asc' are identical and save values to the memory (object
file) bytewise. '.word' does the same with words (2 Bytes). '.dsb'
fills a block with a given length with the value of fillbyte. If
fillbyte is not given, zero is taken.
'*=' changes the programm counter. The programm counter is not saved
to the file as no rewind is being done. Just the internal counter is
reloaded. If a value is given when the assembler has been started in
relocation mode ('-R command line option), the assembler goes into
no-relocation mode, i.e assembles everything without creating
relocation table entries. For '*=' without a value, the assembler
switches back to relocation mode. The absolute code is 'embedded' in
the text segment, so the text segment program counter is increased by
the length of the absolute code.
'.(' opens a new 'block'. All labels in a block are local, i.e. are
only visible from inside the block - including sub-blocks. An error is
returned if a label is defined that is already defined 'above'. With
'.)' the block is closed. You can have a stack of up to 16 blocks in
each other (i.e. 16 times '.(' before the first '.)' will work, 17
not).
'.text', '.data', '.bss', '.zero' switch between the different
segments. The text segment is where the code goes in. The data segment
is where some initialized data goes in (it's actually like a second
text segment). The data segment might be allocated separated from the
text segment. The contents of the bss and the zero segment are not
saved, just the labels are evaluated. Here goes the uninitialized data
stuff. The zero segment allows allocation of zeropage space, bss is
normal address space. These opcodes can be used in relative and
absolute mode.
'.align' aligns the current segment to a byte boundary given by the
value. Allowed values are 2, 4, and 256. When using relative mode, the
align value is written to the file header, such that relocation keeps
the alignment.
'.fopt' works like ".byte", but saves the bytes as a fileoption (see
fileformat.txt). The length is computed automatically, so the first
byte in the ".fopt" list of values should be the type. For example,
the following line sets the filename for the object file.
.fopt 0, "filename", 0
A label is defined by not being an opcode:
label1 LDA #0 ; assignes the programm counter
label2 =1234 ; explicit definition
label3 label4 label5 ; implicit programm counter
label6 label7 = 3 ; label6 becomes the program counter, while
; label7 is set to 3
label8: sta label2 ; As ':' divides opcodes, this is also
; working
You can use more than one label for definition, except for explicit
definition. Labels are case sensitive. If a label is proceeded by a
'+', this label is defined global. If a label is proceeded by a '&',
this label is defined one level 'up' in the block hierachy, and you
can use more than one '&'.
Redefinition of a label is possible by proceeding it with a dash '-'.
-sysmem +=4 ; here you can use ==, +=, -=, *=, /=, &=, |=
-syszp =123
Preprocessor
The preprocessor is very close to the one of the language C. So in
addition to the ';'-comments you can also use C-like comments in '/*'
and '*/'. Comments can be nested.
#include "filename" includes a file on exactly this position.
if the file is not found, it is searched using
XAINPUT.
#echo comment gives a comment to the error file.
#print expression prints an expression to the error file (after
preprocessing and calculating)
#printdef DEFINED prints the definition of a preprocessor define to
the error file.
#define DEF text defines 'DEF' by 'text'
#ifdef DEF The source code from here to the following #endif
or #else is only assembled if 'DEF' is defined
with #define.
#else just else... (optionally)
#endif ends an #if-construct. This is a must to end #IF*
#ifndef DEF .... if DEF is not defined
#if expression .... if expression is not zero
#iflused label .... if a label has already been used
#ifldef label .... if a label is already defined
#iflused and #ifldef work an labels, not on preprocessor defs! With
these commands a kind of library is easily built:
#iflused label
#ifldef label
#echo label already defined, not from library
#else
label lda #0
....
#endif
#endif
You can have up to 15 #if* on stack before the first #endif
You can also use #define with functions, like in C.
#define mult(a,b) ((a)*(b))
The preprocessor also allows continuation lines. I.e. lines that end
with a '\' directly before the newline have the following line
concatenated to it.
Utilities
There now are a few utilities that come with the assembler:
file65 : prints some information about an o65 file. Can compute the
"-A" parameter for xa, to built the following file in a ROM.
reloc65 : relocates o65 files.
mkrom.sh: example shell (bash) script to show how to use the file65 utility
to build a ROM image with several in the ROM runnable programs.
ld65 : a linker for o65 files. The given files are linked together and
one o65 executable file is produced. All header options of all files
are put in the new file. There must not be any undefined reference
left, otherwise the output file is corrupt, because
for now, ld65 cannot produce object files. But you get a warning.
Literature
* "Das Maschinensprachebuch zum Commodore 64"
Lothar Englisch, Data Becker GmbH
* "Controller Products Data Book"
Rockwell International, Semiconductor Products Division
* "Programmieren in C"
Kernighan, Ritchie, Hanser Verlag

105
xa/doc/xaannounce Normal file
View File

@ -0,0 +1,105 @@
Subject: [ANN] 6502 reloc. binaries & assembler
Newsgroups: comp.sys.cbm,comp.emulators.cbm,comp.sys.atari.8bit,comp.sys.apple2.programmer,comp.arch.embedded
Organization: TU Chemnitz
Summary: Announcement of 6502 relocatable binary format and assembler
Keywords: 6502, 65816, relocation, cross assembler, assembler, file format
relocatable binary file format o65
& 6502 cross assembler xa65
This is the announcement for the 6502 relocatable binary file format 'o65'.
This format allows to
- relocate (i.e. move to a different address) a file when loading it, to
be able to execute at a different address
- produce global label lists, i.e. being able to export labels from one
file to another
- have undefined references, i.e. allow late binding (resolving symbols
at load time)
- code sharing in virtual memory architectures
- do block oriented transfer and have minimum side storage when loading a file
The format works for the 6502 and for the 65816 CPU. It knows object from
executable files and more.
The file format itself is free (I can do the clearance, if you have
suggestions for extensions etc.)
Have a look at: http://www.tu-chemnitz.de/~fachat/c64/xa/fileformat.txt
About another 6502 file format, see note 1).
6502 cross assembler xa65
As reference assembler to produce this kind of code, I have implemented
the file format in my 6502 cross assembler "xa65".
From version 2.1.1 it supports the new file format standard, and from
version 2.1.2a, it comes with the "file65", "reloc65" and
"ld65" utilities to print information about a file, relocate a file
and link several object files together resp.
All the programs are close to production stage (you never know if you
got all bugs...), while the linker is in beta stage. Esp. I want to know
about options you would like to have.
The assembler is under GNU public license and can be found at:
http://www.tu-chemnitz.de/~fachat/c64/xa/index.html
Other changes from earlier versions:
- supports o65 file format, including linker, relocator and file utility.
- much better code quality (only two warnings with
gcc -W -Wall -pedantic -ansi)
- supports more MASM pseudo opcodes (but still not the important ones
that I have my C-like preprocessor for: .if, .macro, .include.
This might change someday...
- DOS support by go32 cross-compiling (only Makefile changes!)
General description:
- C-like Preprocessor to make macros
- label "hiding" on different levels,
i.e. multiple use of the same label possible
- 1.5-pass assembler:
Everything that can be derefenced is being assembled in pass 1 and
saved in memory. The second pass does the rest. This (together
with hashing etc) gives quite a good speed (30kByte binary out of
300kByte source in less than two minutes on an 8MHz Atari ST -
hey, the first versions would have taken half an hour for this
job! - my 486DX4/100 with linux needs around two seconds or so...)
- needs no linker - all stuff is in source code (with this speed,
it's ok)
- (optional) support for relocatable 'o65' file format,
including linker, relocator and file utility. A loader in 6502
assembly code is also included.
- reads DOS and Unix(tm) files (LF or CR+LF)
so long
André Fachat
----
1) There is already another relocatable object file format, called "OMF",
which is mostly used in the Apple community. I didn't take this format
for my projects for several reasons: It has some limits on filename
lengths; the relocation information is encoded between assembler code,
i.e. one cannot easily use block loading; it doesn't provide different
segments (as I can see) that have this meaning.
The OMF file format has never been published on the internet and mostly
commercial companies from the Apple world seem to support it - but then
they even have C compilers for this file format.
--
André Fachat |"I do not feel obliged to believe that the
Institute of physics, | same God who has endowed us with sense,
Technische Universität Chemnitz | reason, and intellect has intended us to
http://www.tu-chemnitz.de/~fachat | forego their use" -- Galileo Galilei

BIN
xa/examples/a.o65 Normal file

Binary file not shown.

309
xa/examples/c64def.def Normal file
View File

@ -0,0 +1,309 @@
/* VIC 6567 */
#define VIC_S0_X 0
#define VIC_S0_Y 1
#define VIC_S1_X 2
#define VIC_S1_Y 3
#define VIC_S2_X 4
#define VIC_S2_Y 5
#define VIC_S3_X 6
#define VIC_S3_Y 7
#define VIC_S4_X 8
#define VIC_S4_Y 9
#define VIC_S5_X 10
#define VIC_S5_Y 11
#define VIC_S6_X 12
#define VIC_S6_Y 13
#define VIC_S7_X 14
#define VIC_S7_Y 15
#define VIC_SP_MSB 16
#define VIC_SR1 17
#define VIC_IRQ_RASTER 18
#define VIC_LP_X 19
#define VIC_LP_Y 20
#define VIC_SP_EN 21
#define VIC_SR2 22
#define VIC_SP_EXPY 23
#define VIC_BASEADR 24
#define VIC_IRR 25
#define VIC_IMR 26
#define VIC_SP_PRIOR 27
#define VIC_SP_MCOLOR 28
#define VIC_SP_EXPX 29
#define VIC_SP_SCOLL 30
#define VIC_SP_BCOLL 31
#define VIC_EXTCOL 32
#define VIC_BCKCOL0 33
#define VIC_BCKCOL1 34
#define VIC_BCKCOL2 35
#define VIC_BCKCOL3 36
#define VIC_SP_MCOL0 37
#define VIC_SP_MCOL1 38
#define VIC_S0_COL 39
#define VIC_S1_COL 40
#define VIC_S2_COL 41
#define VIC_S3_COL 42
#define VIC_S4_COL 43
#define VIC_S5_COL 44
#define VIC_S6_COL 45
#define VIC_S7_COL 46
#define COL_SCHWARZ 0
#define COL_WEISS 1
#define COL_ROT 2
#define COL_TUERKIS 3
#define COL_VIOLETT 4
#define COL_GRUEN 5
#define COL_BLAU 6
#define COL_GELB 7
#define COL_ORANGE 8
#define COL_BRAUN 9
#define COL_HELLROT 10
#define COL_GRAU1 11
#define COL_GRAU2 12
#define COL_HELLGRUEN 13
#define COL_HELLBLAU 14
#define COL_GRAU3 15
#define VIC $d000
/* SID 6581 */
#define SID_0FREQL 0
#define SID_0FREQH 1
#define SID_0PULSL 2
#define SID_0PULSH 3
#define SID_0SR 4
#define SID_0ATTDEC 5
#define SID_0SUSREL 6
#define SID_1FREQL 7
#define SID_1FREQH 8
#define SID_1PULSL 9
#define SID_1PULSH 10
#define SID_1SR 11
#define SID_1ATTDEC 12
#define SID_1SUSREL 13
#define SID_2FREQL 14
#define SID_2FREQH 15
#define SID_2PULSL 16
#define SID_2PULSH 17
#define SID_2SR 18
#define SID_2ATTDEC 19
#define SID_2SUSREL 20
#define SID_FILTL 21
#define SID_FILTH 22
#define SID_SR1 23
#define SID_SR2 24
#define SID $d800
/* CIA 6526 */
#define CIA_DRA 0
#define CIA_DRB 1
#define CIA_DDRA 2
#define CIA_DDRB 3
#define CIA_TAL 4
#define CIA_TAH 5
#define CIA_TBL 6
#define CIA_TBH 7
#define CIA_TOD_THS 8
#define CIA_TOD_SEC 9
#define CIA_TOD_MIN 10
#define CIA_TOD_HR 11
#define CIA_SDR 12
#define CIA_ICR 13
#define CIA_CRA 14
#define CIA_CRB 15
#define CIA1 $dc00
#define CIA2 $dd00
/* ACIA 6551 */
#define ACIA_DR 0
#define ACIA_SR 1
#define ACIA_CMD 2
#define ACIA_CTRL 3
#define ACIA $d600
/* Basic */
#define INT $14
#define PRGANF $2b
#define VARANF $2d
#define ARRANF $2f
#define ARREND $31
#define STRANF $33
#define STRPTR $35
#define RAMEND $37
#define VARNAME $45
#define VARADR $47
#define AKKU3 $57
#define AKKU4 $5c
#define FAC $61
#define ARG $69
#define CHRGET $73
#define CHRGOT $79
#define PRGPTR $7a
#define V_ERR $0300
#define V_WARM $0302
#define V_CONV2CODE $0304
#define V_CONV2ASC $0306
#define V_GETBEFADR $0308
#define V_GETAUSDR $030a
#define SYS_AKKU $030c
#define SYS_XR $030d
#define SYS_YR $030e
#define SYS_SR $030f
#define READY $a474
#define LINEIN $a560
#define INTOUT $bdcd
/* Betriebssystem */
#define STATUS $90
#define FNAMLEN $b7
#define LOGFNR $b8
#define SECADR $b9
#define DEVADR $ba
#define FNAMPTR $bb
#define IOANF $c1
#define IOEND $c3
#define LASTKEY $c5
#define NUMKEY $c6
#define REVFL $c7
#define INLINEEND $c8
#define INZEILE $c9
#define INSPALTE $ca
#define PRESSEDKEY $cb
#define CRSRFLASH $cc
#define CRSRFLASHCNT $cd
#define CHARUNDERCRSR $ce
#define CRSRFLASHFL $cf
#define KEYINPUTFL $d0
#define LINEADR $d1
#define CRSRSPALTE $d3
#define HKFL $d4
#define LENGTHOFLINE $d5
#define CRSRZEILE $d6
#define DIV $d7
#define NUMOFINS $d8
#define RS232INBUFPTR $f7
#define RS232OUTBUFPTR $f9
#define P1 $fb /* freier Pointer */
#define P2 $fd /* freier Pointer */
#define INBUF $200
#define V_USR $0311
#define V_IRQ $0314
#define V_BRK $0316
#define V_NMI $0318
#define V_OPEN $031a
#define V_CLOSE $031c
#define V_CHKIN $031e
#define V_CKOUT $0320
#define V_CLRCH $0322
#define V_INPUT $0324
#define V_OUTPUT $0326
#define V_STOP $0328
#define V_GET $032a
#define V_CLALL $032c
#define V_WARMSTART $032e
#define V_LOAD $0330
#define V_SAVE $0332
#define SENDNAM $f3d5
#define CLSFIL $f642
#define INICIA $ff84
#define INIRAM $ff87
#define INIIO $ff8a
#define INIIOVEC $ff8d
#define SETST $ff90
#define SECLISTEN $ff93
#define SECTALK $ff96
#define RAMEND $ff99
#define RAMSTART $ff9c
#define GETKEY $ff9f
#define IECTIMEOUT $ffa2
#define IECIN $ffa5
#define IECOUT $ffa8
#define UNTALK $ffab
#define UNLISTEN $ffae
#define LISTEN $ffb1
#define TALK $ffb4
#define GETST $ffb7
#define SETFPAR $ffba
#define SETFNPAR $ffbd
#define OPEN $ffc0
#define CLOSE $ffc3
#define CHKIN $ffc6
#define CKOUT $ffc9
#define CLRCH $ffcc
#define BASIN $ffcf
#define BSOUT $ffd2
#define LOAD $ffd5
#define SAVE $ffd8
#define SETTI $ffdb
#define GETTI $ffde
#define GETSTP $ffe1
#define GET $ffe4
#define CLALL $ffe7
#define INCTI $ffea
#define SCREEN $ffed
#define CURSOR $fff0
#define GETIOBASE $fff3
/* Terminal-Commands */
#define TC_SCO 8
#define TC_SCF 9
#define TC_LF 13 /*10*/
#define TC_CR 13
#define TC_LCH $0e
#define TC_REV 18
#define TC_F1 $85
#define TC_F3 $86
#define TC_F5 $87
#define TC_F7 $88
#define TC_F2 $89
#define TC_F4 $8a
#define TC_F6 $8b
#define TC_F8 $8c
#define TC_HCH $8e
#define TC_REO $92
#define TC_FF $93
#define TC_HELLGRUEN $99
#define TC_CRL $9d

12
xa/examples/pack.doc Normal file
View File

@ -0,0 +1,12 @@
******** pack 1.0 ******** 11.10.92, A.Fachat
Dieses Programm f<>r den C64 packt Dateien in eine und kann sie wieder
auspacken. 'packen' ist zuviel, denn es werden nur Folgen gleicher Bytes
mit einer L„nge von mehr als 3 Byte durch die Folge $f7,anz,byte ersetzt.
$f7,0 zeigt das Ende der Datei, $f7 selbst werden durch diese Folge ersetzt,
egal wieviel in Reihe sind.
Das 'Archiv' beginnt mit der Versionsnummer: 1 Byte = 1
Dann folgen die Einzelnen Dateien - der Dateiname in ASCII, mit Nullbyte
abgeschlossen, danach die Datei selbst.

1070
xa/examples/pack_eng.a65 Normal file

File diff suppressed because it is too large Load Diff

1070
xa/examples/pack_ger.a65 Normal file

File diff suppressed because it is too large Load Diff

180
xa/examples/peng.l Normal file
View File

@ -0,0 +1,180 @@
basicend, 0x080b, 1, 0x0000
iniscreen, 0x10c4, 1, 0x0000
inipar, 0x1093, 1, 0x0000
menu1, 0x0819, 2, 0x0000
m1atxt, 0x0897, 2, 0x0000
Txtout, 0x10ae, 1, 0x0000
quellpfad, 0x10d4, 1, 0x0000
m1btxt, 0x08e1, 2, 0x0000
quelldrv, 0x10d2, 1, 0x0000
m1ctxt, 0x08f6, 2, 0x0000
zielpfad, 0x10fc, 1, 0x0000
m1dtxt, 0x090d, 2, 0x0000
zieldrv, 0x10d3, 1, 0x0000
m1etxt, 0x0923, 2, 0x0000
next, 0x085a, 2, 0x0000
l1, 0x0861, 2, 0x0000
befkeys, 0x088f, 2, 0x0000
exe, 0x086d, 2, 0x0000
Anzbefs, 0x0008, 2, 0x0000
exec, 0x0873, 2, 0x0000
madr, 0x087f, 2, 0x0000
pack, 0x0b32, 1, 0x0000
unpack, 0x0970, 1, 0x0000
quelle, 0x0fe5, 1, 0x0000
ziel, 0x102b, 1, 0x0000
switch, 0x1071, 1, 0x0000
dir, 0x0f01, 1, 0x0000
qdrv, 0x0fc5, 1, 0x0000
zdrv, 0x0fd5, 1, 0x0000
openarcrd, 0x0aff, 1, 0x0000
cls, 0x09a1, 12, 0x0000
rcnt, 0x132e, 1, 0x0000
rbyte, 0x0c09, 1, 0x0000
verr, 0x09a7, 12, 0x0000
loop, 0x0984, 12, 0x0000
unpackfile, 0x09dd, 1, 0x0000
t1, 0x09c9, 12, 0x0000
waitkey, 0x0f5f, 1, 0x0000
verrtxt, 0x09b1, 12, 0x0000
wcnt, 0x132c, 1, 0x0000
l1, 0x09ee, 15, 0x0000
endx, 0x0a27, 15, 0x0000
filetab, 0x1332, 1, 0x0000
endnam, 0x0a04, 15, 0x0000
ask, 0x0a8b, 15, 0x0000
nounpack, 0x0a2a, 15, 0x0000
tok, 0x0ec9, 1, 0x0000
fxopen, 0x0ab7, 1, 0x0000
Getzst, 0x0d6a, 1, 0x0000
xa, 0x0a31, 15, 0x0000
lo, 0x0a35, 15, 0x0000
end, 0x0a8a, 15, 0x0000
tno, 0x0ec0, 1, 0x0000
cls, 0x0a6b, 15, 0x0000
xb, 0x0a61, 15, 0x0000
wxanz, 0x1228, 1, 0x0000
wxbyt, 0x1227, 1, 0x0000
ly, 0x0a53, 15, 0x0000
wbyte, 0x0d0f, 1, 0x0000
wbuf, 0x0d25, 1, 0x0000
t1, 0x0aa0, 15, 0x0000
incwcnt, 0x0aae, 1, 0x0000
l1, 0x0ab6, 20, 0x0000
l1, 0x0abb, 21, 0x0000
l2, 0x0ad2, 21, 0x0000
l1a, 0x0acc, 21, 0x0000
l1b, 0x0ace, 21, 0x0000
l3, 0x0ad6, 21, 0x0000
err, 0x0afe, 21, 0x0000
clrwrbuf, 0x0d06, 1, 0x0000
l0, 0x0b01, 22, 0x0000
l1, 0x0b0b, 22, 0x0000
err, 0x0b30, 22, 0x0000
Getqst, 0x0d64, 1, 0x0000
clrrdbuf, 0x0c6a, 1, 0x0000
getlist, 0x0da7, 1, 0x0000
anzfiles, 0x1124, 1, 0x0000
end, 0x0b66, 23, 0x0000
openarcwr, 0x0cd0, 1, 0x0000
cls, 0x0b5e, 23, 0x0000
l1, 0x0b48, 23, 0x0000
setfadr, 0x0ed2, 1, 0x0000
packfile, 0x0b6a, 1, 0x0000
lft, 0x0baf, 24, 0x0000
l1, 0x0b73, 24, 0x0000
fopen, 0x0bb9, 1, 0x0000
le, 0x0b9a, 24, 0x0000
clrwxbyt, 0x0c97, 1, 0x0000
l2, 0x0b8c, 24, 0x0000
l3, 0x0b97, 24, 0x0000
wxbyte, 0x0c76, 1, 0x0000
savwxbyt, 0x0c9d, 1, 0x0000
l1, 0x0bbd, 26, 0x0000
l2, 0x0bd4, 26, 0x0000
l1a, 0x0bce, 26, 0x0000
l1b, 0x0bd0, 26, 0x0000
l3, 0x0bd8, 26, 0x0000
err, 0x0bff, 26, 0x0000
incrcnt, 0x0c00, 1, 0x0000
l1, 0x0c08, 27, 0x0000
ro, 0x122a, 1, 0x0000
ri, 0x1229, 1, 0x0000
leerbuf, 0x0c19, 28, 0x0000
rb, 0x122c, 1, 0x0000
rf, 0x122b, 1, 0x0000
ldbuf, 0x0c20, 28, 0x0000
lok, 0x0c31, 28, 0x0000
l0, 0x0c4a, 28, 0x0000
le, 0x0c5f, 28, 0x0000
add, 0x0c90, 31, 0x0000
ad2, 0x0c86, 31, 0x0000
adx, 0x0c93, 31, 0x0000
nosav, 0x0ccf, 33, 0x0000
savs, 0x0cb9, 33, 0x0000
l1, 0x0cad, 33, 0x0000
l0, 0x0cd2, 34, 0x0000
l1, 0x0cdc, 34, 0x0000
err, 0x0d04, 34, 0x0000
wi, 0x1125, 1, 0x0000
wo, 0x1126, 1, 0x0000
wb, 0x1127, 1, 0x0000
nowr, 0x0d24, 36, 0x0000
l1, 0x0d2d, 37, 0x0000
end, 0x0d58, 37, 0x0000
l0, 0x0d51, 37, 0x0000
Getst, 0x0d6d, 1, 0x0000
l1, 0x0d8a, 38, 0x0000
l2, 0x0d98, 38, 0x0000
err, 0x0da2, 38, 0x0000
l4x, 0x0da4, 39, 0x0000
l4, 0x0e80, 39, 0x0000
setdirnam, 0x0f65, 1, 0x0000
l0, 0x0dc7, 39, 0x0000
l1, 0x0dc9, 39, 0x0000
la, 0x0de3, 39, 0x0000
l3x, 0x0df1, 39, 0x0000
l3, 0x0e5c, 39, 0x0000
lb, 0x0e04, 39, 0x0000
lc, 0x0e19, 39, 0x0000
ld, 0x0e1e, 39, 0x0000
lf, 0x0e35, 39, 0x0000
lg, 0x0e49, 39, 0x0000
testkeys, 0x0e86, 1, 0x0000
lh, 0x0e53, 39, 0x0000
l2, 0x0e6c, 39, 0x0000
l5, 0x0e79, 39, 0x0000
ok, 0x0e8f, 40, 0x0000
t1, 0x0eb0, 40, 0x0000
ja, 0x0ea5, 40, 0x0000
l0, 0x0f1c, 45, 0x0000
l1, 0x0f1e, 45, 0x0000
l4, 0x0f59, 45, 0x0000
l3, 0x0f38, 45, 0x0000
l2, 0x0f48, 45, 0x0000
l5, 0x0f55, 45, 0x0000
p1, 0x0014, 46, 0x0000
l1, 0x0f70, 46, 0x0000
nodp, 0x0f7e, 46, 0x0000
dp, 0x0f84, 46, 0x0000
dp1, 0x0f86, 46, 0x0000
end, 0x0f9e, 46, 0x0000
l2a, 0x0f96, 46, 0x0000
l2, 0x0f98, 46, 0x0000
ok, 0x0fd4, 47, 0x0000
ok, 0x0fe4, 48, 0x0000
quelltxt, 0x1004, 49, 0x0000
q1, 0x0ff1, 49, 0x0000
end, 0x1003, 49, 0x0000
quelltxt, 0x104a, 51, 0x0000
q1, 0x1037, 51, 0x0000
end, 0x1049, 51, 0x0000
l1, 0x107f, 53, 0x0000
noval, 0x10a5, 54, 0x0000
ok, 0x10a7, 54, 0x0000
p, 0x0022, 55, 0x0000
l1, 0x10b2, 55, 0x0000
le, 0x10c3, 55, 0x0000
sysmem, 0x1332, 1, 0x0000
ecnt, 0x1330, 1, 0x0000
ende, 0x10d2, 1, 0x0000

18
xa/loader/Makefile Normal file
View File

@ -0,0 +1,18 @@
all: loader example test2 rom65
loader: loader.a65 file.def
../xa loader.a65 -o loader
clean:
rm -f loader test2 example a.o65 rom65
example: test.a
../xa -R test.a -o example
test2: test2.a
../xa test2.a -o test2
rom65: test.a
../mkrom.sh -O "-G" -S "-bd 1234" -R rom65 test.a test.a

8
xa/loader/README Normal file
View File

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

BIN
xa/loader/ex2 Normal file

Binary file not shown.

BIN
xa/loader/example2 Normal file

Binary file not shown.

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

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

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

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

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

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

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

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

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

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

3
xa/man/README Normal file
View File

@ -0,0 +1,3 @@
Also look at ../doc/ for previous documentation files and the Change log.
Cameron Kaiser

58
xa/man/file65.1 Normal file
View File

@ -0,0 +1,58 @@
.TH FILE65 "1" "11 April 2006"
.SH NAME
file65 \- print information for o65 object files
.SH SYNOPSIS
.B file65
[\fIOPTION\fR]... \fIFILE\fR...
.SH DESCRIPTION
.B file65
prints file information for files in the o65 object format.
.SH OPTIONS
.TP
.B \-V
Print undefined and global labels.
.TP
.B \-P
Print the segment end addresses (suitable for the
.BR xa (1)
command line parameter
.BR \-b ).
.TP
.B \-a offset
Print
.BR xa (1)
"ROMmable" parameter for another file behind this one in
the same ROM, located at the specified offset.
.TP
.B \-A offset
Does the same thing as
.B \-a
but only prints the starting address of the next file in the ROM.
.TP
.B \-\-help
Show summary of options.
.TP
.B \-\-version
Show version of program.
.SH "SEE ALSO"
.BR ldo65 (1),
.BR printcbm (1),
.BR reloc65 (1),
.BR uncpk (1),
.BR xa (1),
.BR dxa (1)
.SH AUTHOR
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
Cameron Kaiser. The current maintainer is Cameron Kaiser.
.SH WEBSITE
http://www.floodgap.com/retrotech/xa/

60
xa/man/ldo65.1 Normal file
View File

@ -0,0 +1,60 @@
.TH LDO65 "1" "11 April 2006"
.SH NAME
ldo65 \- linker for o65 object files
.SH SYNOPSIS
.B ldo65
[\fIOPTION\fR]... \fIFILE\fR...
.SH DESCRIPTION
.B ldo65
is a linker for files in the `o65' object format, formerly
.B ld65
but renamed to avoid conflicts with the
.B cc65
package (a separate product).
.SH OPTIONS
.TP
.B \-b? addr
Relocate segment
.B ?
to
.BR addr \&.
.B ?
must be either t, d, b or z to indicate the text, data, bss or zero
segment respectively. See the
.BR xa (1)
man page for an explanation.
.TP
.B \-o filename
Set output filename. The default is
.BR a.o65 \&.
.TP
.B \-G
Suppress writing of globals.
.TP
.B \-\-help
Show summary of options.
.TP
.B \-\-version
Show version of program.
.SH "SEE ALSO"
.BR file65 (1),
.BR printcbm (1),
.BR reloc65 (1),
.BR uncpk (1),
.BR dxa (1),
.BR xa (1)
.SH AUTHOR
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
Cameron Kaiser. The current maintainer is Cameron Kaiser.
.SH WEBSITE
http://www.floodgap.com/retrotech/xa/

37
xa/man/printcbm.1 Normal file
View File

@ -0,0 +1,37 @@
.TH PRINTCBM "1" "11 April 2006"
.SH NAME
printcbm \- list a Commodore BASIC file
.SH SYNOPSIS
.B printcbm
\fIFILE\fR
.SH DESCRIPTION
.B printcbm
lists all lines of the specified Commodore BASIC program.
.SH OPTIONS
.TP
.B \-\-help
Show summary of options.
.TP
.B \-\-version
Show version of program.
.SH "SEE ALSO"
.BR file65 (1),
.BR ldo65 (1),
.BR reloc65 (1),
.BR uncpk (1),
.BR dxa (1),
.BR xa (1)
.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
Cameron Kaiser. The current maintainer is Cameron Kaiser.
.SH WEBSITE
http://www.floodgap.com/retrotech/xa/

68
xa/man/reloc65.1 Normal file
View File

@ -0,0 +1,68 @@
.TH RELOC65 "1" "11 April 2006"
.SH NAME
reloc65 \- relocator for o65 object files
.SH SYNOPSIS
.B reloc65
[\fIOPTION\fR]... \fIFILE\fR...
.SH DESCRIPTION
.B reloc65
is a relocator for files in the
.B o65
object format.
.SH OPTIONS
.TP
.B \-o filename
Set output filename. The default is
.BR a.o65 \&.
.TP
.B \-b? addr
Relocate segment
.B ?
to
.BR addr \&.
.B ?
should be t, d, b or z to represent the text, data, bss or zero
segment respectively. See the
.BR xa (1)
man page for an explanation.
.TP
.B \-x?
Extract segment
.B ?
from the file instead of writing back the whole
file. Valid arguments are t and d for the text or data segment
respectively. Not valid for bss or zero.
.TP
.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.
.TP
.B \-\-help
Show summary of options.
.TP
.B \-\-version
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)
.SH AUTHOR
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
Cameron Kaiser. The current maintainer is Cameron Kaiser.
.SH WEBSITE
http://www.floodgap.com/retrotech/xa/

77
xa/man/uncpk.1 Normal file
View File

@ -0,0 +1,77 @@
.TH UNCPK "1" "11 April 2006"
.SH NAME
uncpk \- manage c64 cpk archives
.SH SYNOPSIS
.B uncpk
[\fIOPTION\fR]... \fIFILE\fR...
.SH DESCRIPTION
.B uncpk
is an archive tool for Commodore 64 .cpk-format archives.
.SH OPTIONS
.TP
.B c
Create an archive.
.TP
.B x
Extract from an archive.
.TP
.B l
List contents of archive.
.TP
.B a
Add a file to the archive.
.TP
.B v
Verbose output.
.TP
.B \-\-help
Show summary of options.
.TP
.B \-\-version
Show version of program.
.SH EXAMPLES
.TP
.B uncpk c foo.cpk bar
Create archive
.B foo.cpk
with the single file
.B bar
inside it.
.TP
.B uncpk a foo.cpk bar
Add file
.B bar
to archive
.B foo.cpk
(which must already exist).
.TP
.B uncpk x foo.cpk
Extract all files from archive
.BR foo.cpk \&.
.TP
.B uncpk l foo.cpk
List contents of archive
.BR foo.cpk \&.
.SH "SEE ALSO"
.BR file65 (1),
.BR ldo65 (1),
.BR printcbm (1),
.BR reloc65 (1),
.BR dxa (1),
.BR xa (1)
.SH AUTHOR
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
Cameron Kaiser. The current maintainer is Cameron Kaiser.
.SH WEBSITE
http://www.floodgap.com/retrotech/xa/

837
xa/man/xa.1 Normal file
View File

@ -0,0 +1,837 @@
.TH XA "1" "7 February 2009"
.SH NAME
xa \- 6502/R65C02/65816 cross-assembler
.SH SYNOPSIS
.B xa
[\fIOPTION\fR]... \fIFILE\fR
.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,
6510, 7501, 8500, 8501 and 8502), the Rockwell R65C02, and
the 16-bit 65816 processor. For a description of syntax, see
.B ASSEMBLER SYNTAX
further in this manual page.
.SH OPTIONS
.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)
.TP
.B \-W
No 65816 opcodes (default).
.TP
.B \-w
Allow 65816 opcodes.
.TP
.B \-B
Show lines with block open/close (see
.BR PSEUDO-OPS ).
.TP
.B \-c
Produce o65 object files instead of executable files
(no linking performed); files may contain undefined references.
.TP
.B \-o filename
Set output filename. The default is
.BR a.o65 ;
use the special filename
.BR \-
to output to standard output.
.TP
.B \-e filename
Set errorlog filename, default is none.
.TP
.B \-l filename
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.
.TP
.B \-r
Add cross-reference list to labellist (requires
.BR \-l ).
.TP
.B \-M
Allow colons to appear in comments; for MASM compatibility. This does
not affect colon interpretation elsewhere.
.TP
.B \-R
Start assembler in relocating mode.
.TP
.B \-Llabel
Defines
.B label
as an absolute (but undefined) label even when linking.
.TP
.B \-b? addr
Set segment base for segment
.B ?
to address
.BR addr \&.
.B ?
should be t, d, b or z for text, data, bss or zero segments, respectively.
.TP
.B \-A addr
Make text segment start at an address such that when the file
starts at address
.BR addr ,
relocation is not necessary. Overrides
.BR \-bt ;
other segments still have to be taken care of with
.BR \-b \&.
.TP
.B \-G
Suppress list of exported globals.
.TP
.B \-DDEF=TEXT
Define a preprocessor macro on the command line (see
.BR PREPROCESSOR ).
.TP
.B \-I dir
Add directory
.B dir
to the include path (before
.BR XAINPUT ;
see
.BR ENVIRONMENT ).
.TP
.B \-O charset
Define the output charset for character strings. Currently supported are ASCII
(default), PETSCII (Commodore ASCII),
PETSCREEN (Commodore screen codes) and HIGH (set high bit on all
characters).
.TP
.B \-p?
Set the alternative preprocessor character to
.BR ? .
This is useful when you wish to use
.BR cpp (1)
and the built-in preprocessor at the same time (see
.BR PREPROCESSOR ).
Characters may need to be quoted for your shell (example:
.B \-p'~'
).
.TP
.B \-\-help
Show summary of options.
.TP
.B \-\-version
Show version of program.
.SH ASSEMBLER SYNTAX
An introduction to 6502 assembly language programming and mnemonics is
beyond the scope of this manual page. We invite you to investigate any
number of the excellent books on the subject; one useful title is "Machine
Language For Beginners" by Richard Mansfield (COMPUTE!), covering the Atari,
Commodore and Apple 8-bit systems, and is widely available on the used market.
.LP
.B xa
supports both the standard NMOS 6502 opcodes as well as the Rockwell
CMOS opcodes used in the 65C02 (R65C02). With the
.B \-w
option,
.B xa
will also accept opcodes for the 65816. NMOS 6502
undocumented opcodes are intentionally not supported, and should be entered
manually using the
.B \.byte
pseudo-op (see
.BR PSEUDO-OPS ).
Due to conflicts between the R65C02 and 65816 instruction sets and
undocumented instructions on the NMOS 6502, their use is discouraged.
.LP
In general,
.B xa
accepts the more-or-less standard 6502 assembler format as popularised by
MASM and TurboAssembler. Values and addresses
can be expressed either as literals, or as expressions; to wit,
.TP 10
.B 123
decimal value
.TP
.B $234
hexadecimal value
.TP
.B &123
octal
.TP
.B %010110
binary
.TP
.B *
current value of the program counter
.LP
The ASCII value of any quoted character is
inserted directly into the program text (example:
.B """A"""
inserts the byte "A" into the output stream); see also the
.B PSEUDO-OPS
section. This is affected by the currently selected character set, if any.
.LP
.B Labels
define locations within the program text, just as in other multi-pass
assemblers. A label is defined by anything that is not an opcode; for
example, a line such as
.IP
.B label1 lda #0
.LP
defines
.B label1
to be the current location of the program counter (thus the
address of the
.B LDA
opcode). A label can be explicitly defined by assigning it the value of
an expression, such as
.IP
.B label2 = $d000
.LP
which defines
.B label2
to be the address $d000, namely, the start of the VIC-II register block on
Commodore 64 computers. The program counter
.B *
is considered to be a special kind of label, and can be assigned to with
statements such as
.IP
.B * = $c000
.LP
which sets the program counter to decimal location 49152. 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
.B \-label2 = $d020
.LP
which sets
.B label2
to the Commodore 64 border colour register. The scope of a label is affected
by the block it resides within (see
.B PSEUDO-OPS
for block instructions). A label may also be hard-specified with the
.B \-L
command line option.
.LP
For those instructions where the accumulator is the implied argument (such as
.B asl
and
.BR lsr ;
.B inc
and
.B dec
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
named
.BR a ,
this will actually generate code referencing that label as a memory
location and not the accumulator. Otherwise, the assembler will complain.
.LP
Labels and opcodes may take
.B expressions
as their arguments to allow computed values, and may themselves reference
other labels and/or the program counter. An expression such as
.B lab1+1
(which operates on the current value of label
.B lab1
and increments it by one) may use the following operands, given from highest
to lowest priority:
.TP 8
.B *
multiplication (priority 10)
.TP
.B /
integer division (priority 10)
.TP
.B +
addition (priority 9)
.TP
.B \-
subtraction (9)
.TP
.B <<
shift left (8)
.TP
.B >>
shift right (8)
.TP
.B >= =>
greater than or equal to (7)
.TP
.B <
greater than (7)
.TP
.B <= =<
less than or equal to (7)
.TP
.B <
less than (7)
.TP
.B =
equal to (6)
.TP
.B <> ><
does not equal (6)
.TP
.B &
bitwise AND (5)
.TP
.B ^
bitwise XOR (4)
.TP
.B |
bitwise OR (3)
.TP
.B &&
logical AND (2)
.TP
.B ||
logical OR (1)
.LP
Parentheses are valid. When redefining a label, combining arithmetic or
bitwise operators with the = (equals) operator such as
.B +=
and so on are valid, e.g.,
.IP
.B \-redeflabel += (label12/4)
.LP
Normally,
.B xa
attempts to ascertain the value of the operand and (when referring to
a memory location) use zero page,
16-bit or (for 65816) 24-bit addressing where appropriate and where
supported by the particular opcode. This generates smaller and faster
code, and is almost always preferable.
.LP
Nevertheless, you can use these prefix operators to force a particular
rendering of the operand. Those that generate an eight bit result can also be
used in 8-bit addressing modes, such as immediate and zero page.
.TP
.B <
low byte of expression, e.g.,
.B lda #<vector
.TP
.B >
high byte of expression
.TP
.B !
in situations where the expression could be understood as either an absolute
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
.B \-w
command-line option).
.B This is required to specify any
.B 24-bit quantity!
.TP
.B `
force further optimization, even if the length of the instruction cannot
be reliably determined (see
.BR NOTES'N'BUGS )
.LP
Expressions can occur as arguments to opcodes or within the preprocessor
(see
.B PREPROCESSOR
for syntax). For example,
.IP
.B lda label2+1
.LP
takes the value at
.B label2+1
(using our previous label's value, this would be $d021), and will be assembled
as
.B $ad $21 $d0
to disk. Similarly,
.IP
.B lda #<label2
.LP
will take the lowest 8 bits of
.B label2
(i.e., $20), and assign them to the accumulator (assembling the instruction as
.B $a9 $20
to disk).
.LP
Comments are specified with a semicolon (;), such as
.IP
.B ;this is a comment
.LP
They can also be specified in the C language style, using
.B /* */
and
.B //
which are understood at the
.B PREPROCESSOR
level (q.v.).
.LP
Normally, the colon (:) separates statements, such as
.IP
.B label4 lda #0:sta $d020
.LP
or
.IP
.B label2: lda #2
.LP
(note the use of a colon for specifying a label, similar to some other
assemblers, which
.B xa
also understands with or without the colon). This also applies to semicolon
comments, such that
.IP
.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 /* */
and
.B //
comments, which are dealt with at the preprocessor level (q.v.).
.SH PSEUDO-OPS
.B Pseudo-ops
are false opcodes used by the assembler to denote meta- or inlined commands.
Like most assemblers,
.B xa
has a rich set.
.TP
.B .byt value1,value2,value3,...
Specifies a string of bytes to be directly placed into the assembled object.
The arguments may be expressions. Any number of bytes can be specified.
.TP
.B .asc """text1""","text2",...
Specifies a character string which will be inserted into the assembled
object. Strings are understood according to the currently specified
character set; for example, if ASCII is specified, they will be rendered as
ASCII, and if PETSCII is specified, they will be translated into the equivalent
Commodore ASCII equivalent. Other non-standard ASCIIs such as ATASCII for
Atari computers should use the ASCII equivalent characters; graphic and
control characters should be specified explicitly using
.B .byt
for the precise character you want. Note that
when specifying the argument of an opcode,
.B .asc
is not necessary; the quoted character can simply be inserted (e.g.,
.B lda #"A"
), and is also affected by the current character set.
Any number of character strings can be specified.
.LP
.B .byt
and
.B .asc
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.
.TP
.B .aasc """text1""","text2",...
Specifies a character string that is
.B always
rendered in true ASCII regardless of the current character set. Like
.BR .asc ,
it is synonymous with
.BR .byt .
.TP
.B .word value1,value2,value3...
Specifies a string of 16-bit words to be placed into the assembled object in
6502 little-endian format (that is, low-byte/high-byte). The arguments may
be expressions. Any number of words can be specified.
.TP
.B .dsb length,fillbyte
Specifies a data block; a total of
.B length
repetitions of
.B fillbyte
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.
.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 .
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.
.TP
.B \&.(
Opens a new block for scoping. Within a block, all labels defined are local to
that block and any sub-blocks, and go out of scope as soon as the enclosing
block is closed (i.e., lexically scoped). All labels defined outside of the
block are still visible within it. To explicitly declare a global label within
a block, precede the label with
.B +
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.
.TP
.B \&.)
Closes a block.
.TP
.B \.as \.al \.xs \.xl
Only relevant in 65816 mode (with the
.B \-w
option specified). These pseudo-ops set what size accumulator and X/Y-register
should be used for future instructions;
.B .as
and
.B .xs
set 8-bit operands for the accumulator and index registers, respectively, and
.B .al
and
.B .xl
set 16-bit operands. These pseudo-ops on purpose do not automatically issue
.B sep
and
.B rep
instructions to set the specified width in the CPU;
set the processor bits as you need, or consider constructing
a macro.
.B \.al
and
.B \.xl
generate errors if
.B \-w
is not specified.
.LP
The following pseudo-ops apply primarily to relocatable .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.
.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.
.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
generate an error.
.TP
.B .fopt type,value1,value2,value3,...
Acts like
.B .byt/.asc
except that the values are embedded into the object file as file options.
The argument
.B type
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.
.SH PREPROCESSOR
.B xa
implements a preprocessor very similar to that of the C-language preprocessor
.BR cpp (1)
and many oddiments apply to both. For example, as in C, the use of
.B /* */
for comment delimiters is also supported in
.BR xa ,
and so are comments using the double slash
.BR // .
The preprocessor also supports continuation lines, i.e., lines ending with
a backslash (\\); the following line is then appended to it as if there were
no dividing newline. This too is handled at the preprocessor level.
.LP
For reasons of memory and complexity, the full breadth of the
.BR cpp (1)
syntax is not fully supported. In particular, macro definitions may not
be forward-defined (i.e., a macro definition can only reference a previously
defined macro definition), except for macro functions, where recursive
evaluation is supported; e.g., to
.B #define WW AA
,
.B AA
must have already been defined. Certain other directives are not supported,
nor are most standard pre-defined macros, and there are other
limits on evaluation and line length. Because the maintainers of
.B xa
recognize that some files will require more complicated preparsing than the
built-in preprocessor can supply, the preprocessor will accept
.BR cpp (1)-style
line/filename/flags output. When these lines are seen in the input file,
.B xa
will treat them as
.B cc
would, except that flags are ignored.
.B xa
does not accept files on standard input for parsing reasons, so you should
dump your
.BR cpp (1)
output to an intermediate temporary file, such as
.IP
.B cc -E test.s > test.xa
.br
.B xa test.xa
.LP
No special arguments need to be passed to
.BR xa ;
the presence of
.BR cpp (1)
output is detected automatically.
.LP
Note that passing your file through
.BR cpp (1)
may interfere with
.BR xa 's
own preprocessor directives. In this case, to mask directives from
.BR cpp (1),
use the
.B \-p
option to specify an alternative character instead of
.BR # ,
such as the tilde (e.g.,
.B \-p'~'
). With this option and argument specified, then instead of
.BR #include ,
for example, you can also use
.BR ~include ,
in addition to
.B #include
(which will also still be accepted by the
.B xa
preprocessor, assuming any survive
.BR cpp (1)).
Any character can be used, although frankly pathologic choices may lead
to amusing and frustrating glitches during parsing.
You can also use this option to defer preprocessor directives that
.BR cpp (1)
may interpret too early until the file actually gets to
.B xa
itself for processing.
.LP
The following preprocessor directives are supported.
.TP
.B #include """filename"""
Inserts the contents of file
.B filename
at this position. If the file is not found, it is searched using paths
specified by the
.B \-I
command line option or the environment variable
.B XAINPUT
(q.v.). When inserted, the file will also be parsed for preprocessor
directives.
.TP
.B #echo comment
Inserts comment
.B comment
into the errorlog file, specified with the
.B \-e
command line option.
.TP
.B #print expression
Computes the value of expression
.B expression
and prints it into the errorlog file.
.TP
.B #define DEFINE text
Equates macro
.B DEFINE
with text
.B text
such that wherever
.B DEFINE
appears in the assembly source,
.B text
is substituted in its place (just like
.BR cpp (1)
would do). In addition,
.B #define
can specify macro functions like
.BR cpp (1)
such that a directive like
.B #define mult(a,b) ((a)*(b))
would generate the expected result wherever an expression of the form
.B mult(a,b)
appears in the source. This can also be specified on the command line with
the
.B \-D
option. The arguments of a macro function may be recursively evaluated,
unlike other
.BR #define s;
the preprocessor will attempt to re-evaluate any argument refencing
another preprocessor definition up to ten times before complaining.
.LP
The following directives are conditionals. If the conditional is not
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
is defined.
.TP
.B #ifndef DEFINE
The opposite; true only if macro
.B DEFINE
has not been previously defined.
.TP
.B #if expression
True if expression
.B expression
evaluates to non-zero.
.B expression
may reference other macros.
.TP
.B #iflused label
True if label
.B label
has been used (but not necessarily instantiated with a value).
.I This works on labels, not macros!
.TP
.B #ifldef label
True if label
.B label
is defined
.I and
assigned with a value.
.I This works on labels, not macros!
.LP
Unclosed conditional blocks at the end of included files generate warnings;
unclosed conditional blocks at the end of assembly generate an error.
.LP
.B #iflused
and
.B #ifldef
are useful for building up a library based on labels. For example,
you might use something like this in your library's code:
.IP
.B #iflused label
.br
.B #ifldef label
.br
.B #echo label already defined, library function label cannot be inserted
.br
.B #else
.br
.B label /* your code */
.br
.B #endif
.br
.B #endif
.SH ENVIRONMENT
.B xa
utilises the following environment variables, if they exist:
.TP
.B XAINPUT
Include file path; components should be separated by `,'.
.TP
.B XAOUTPUT
Output file path.
.SH NOTES'N'BUGS
The R65C02 instructions
.B ina
(often rendered
.B inc
.BR a )
and
.B dea
.RB ( dec
.BR a )
must be rendered as bare
.B inc
and
.B dec
instructions respectively.
.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
location, because the assembler does not know the value of the label in
advance during the first pass when the length of an
instruction is computed. On the second pass, a warning will be issued when an
instruction that could have been optimized can't be because of this limitation.
(Obviously, this does not apply to branching or jumping instructions because
they're not optimizable anyhow, and those instructions that can
.I only
take an 8-bit parameter will always be casted to an 8-bit quantity.)
If the label cannot otherwise be defined ahead of the instruction, the backtick
prefix
.B `
may be used to force further optimization no matter where the label is defined
as long as the instruction supports it.
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)
.SH AUTHOR
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,
Cameron Kaiser. The official maintainer is Cameron Kaiser.
.SH WEBSITE
http://www.floodgap.com/retrotech/xa/

44
xa/misc/Makefile Normal file
View File

@ -0,0 +1,44 @@
XCBMLIB = ..
CFLAGS = -Wall -O2 -ansi -W
LIBS = #-lncurses -ltermcap -lm
all: ../mkrom.sh ../uncpk ../printcbm ../file65 ../reloc65 ../ldo65
../uncpk: uncpk.c
${CC} ${CFLAGS} uncpk.c -o $(XCBMLIB)/uncpk
../printcbm: printcbm.c
${CC} ${CFLAGS} printcbm.c -o $(XCBMLIB)/printcbm
../file65: file65.c
${CC} ${CFLAGS} file65.c -o $(XCBMLIB)/file65
../ldo65: ldo65.c
${CC} ${CFLAGS} ldo65.c -o $(XCBMLIB)/ldo65
../reloc65: reloc65.c
${CC} ${CFLAGS} reloc65.c -o $(XCBMLIB)/reloc65
../mkrom.sh: mkrom.sh
cp mkrom.sh ../mkrom.sh
lt1: lt1.a
../xa -R -c -o lt1 lt1.a
lt2: lt2.a
../xa -R -c -o lt2 lt2.a
lt: lt1 lt2
../ldo65 -o lt lt1 lt2
clean:
rm -f *.o
mrproper: clean
rm -f ../uncpk ../printcbm ../file65 ../mkrom.sh ../reloc65 ../ldo65
rm -f lt1 lt2 lt

312
xa/misc/file65.c Normal file
View File

@ -0,0 +1,312 @@
/* file65 -- A part of xa65 - 65xx/65816 cross-assembler and utility suite
* Print information about o65 files
*
* 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.
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#ifndef _MSC_VER
#include <unistd.h>
#endif
#include <errno.h>
#include <string.h>
#include "version.h"
#define BUF (9*4+8)
#define programname "file65"
#define progversion "v0.2.1"
#define author "Written by André Fachat"
#define copyright "Copyright (C) 1997-2002 André Fachat."
int read_options(FILE *fp);
int print_labels(FILE *fp, int offset);
unsigned char hdr[BUF];
unsigned char cmp[] = { 1, 0, 'o', '6', '5' };
int xapar = 0;
int rompar = 0;
int romoff = 0;
int labels = 0;
void usage(FILE *fp)
{
fprintf(fp,
"Usage: %s [options] [file]\n"
"Print file information about o65 files\n"
"\n",
programname);
fprintf(fp,
" -P print the segment end addresses according to `xa' command line\n"
" parameters `-b?'\n"
" -a offset print `xa' ``romable'' parameter for another file behind this one\n"
" 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"
" --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;
FILE *fp;
char *aligntxt[4]= {"[align 1]","[align 2]","[align 4]","[align 256]"};
if(argc<=1) {
usage(stderr);
exit(1);
}
if (strstr(argv[1], "--help")) {
usage(stdout);
exit(0);
}
if (strstr(argv[1], "--version")) {
version(programname, progversion, author, copyright);
exit(0);
}
while(i<argc) {
if(argv[i][0]=='-') {
/* process options */
switch(argv[i][1]) {
case 'V':
labels = 1;
break;
case 'v':
printf("file65: Version 0.2\n");
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]);
break;
case 'P':
xapar = 1;
break;
default:
fprintf(stderr,"file65: %s unknown option\n",argv[i]);
break;
}
} else {
fp = fopen(argv[i],"rb");
if(fp) {
n = fread(hdr, 1, 8, fp);
if((n>=8) && (!memcmp(hdr, cmp, 5))) {
mode=hdr[7]*256+hdr[6];
if(!xapar && !rompar) {
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]",
aligntxt[mode & 3]);
}
if(mode & 0x2000) {
fprintf(stderr,"file65: %s: 32 bit size not supported\n", argv[i]);
} else {
n=fread(hdr+8, 1, 18, fp);
if(n<18) {
fprintf(stderr,"file65: %s: truncated file\n", argv[i]);
} else {
if(!xapar && !rompar) {
printf(" text segment @ $%04x - $%04x [$%04x bytes]\n", hdr[9]*256+hdr[8], hdr[9]*256+hdr[8]+hdr[11]*256+hdr[10], hdr[11]*256+hdr[10]);
printf(" data segment @ $%04x - $%04x [$%04x bytes]\n", hdr[13]*256+hdr[12], hdr[13]*256+hdr[12]+hdr[15]*256+hdr[14], hdr[15]*256+hdr[14]);
printf(" bss segment @ $%04x - $%04x [$%04x bytes]\n", hdr[17]*256+hdr[16], hdr[17]*256+hdr[16]+hdr[19]*256+hdr[18], hdr[19]*256+hdr[18]);
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) {
read_options(fp);
print_labels(fp, hdr[11]*256+hdr[10] + hdr[15]*256+hdr[14]);
}
} else {
struct stat fbuf;
hlen = 8+18+read_options(fp);
stat(argv[i],&fbuf);
if(xapar) {
if(!rompar) printf("-bt %d ",
(hdr[9]*256+hdr[8]) + (hdr[11]*256+hdr[10])
);
printf("-bd %d -bb %d -bz %d ",
(hdr[13]*256+hdr[12]) + (hdr[15]*256+hdr[14]),
(hdr[17]*256+hdr[16]) + (hdr[19]*256+hdr[18]),
(hdr[21]*256+hdr[20]) + (hdr[23]*256+hdr[22])
);
}
if(rompar==1) {
printf("-A %lu ", (unsigned long)((hdr[9]*256+hdr[8])
-hlen +romoff +fbuf.st_size));
} else
if(rompar==2) {
printf("%lu ", (unsigned long)((hdr[9]*256+hdr[8])
-hlen +romoff +fbuf.st_size));
}
printf("\n");
}
}
}
} else {
fprintf(stderr,"file65: %s: not an o65 file!\n", argv[i]);
if(hdr[0]==1 && hdr[1]==8 && hdr[3]==8) {
printf("%s: C64 BASIC executable (start address $0801)?\n", argv[i]);
} else
if(hdr[0]==1 && hdr[1]==4 && hdr[3]==4) {
printf("%s: CBM PET BASIC executable (start address $0401)?\n", argv[i]);
}
}
} else {
fprintf(stderr,"file65: %s: %s\n", argv[i], strerror(errno));
}
}
i++;
}
return 0;
}
static struct { int opt; int strfl; char *string; } otab[] = {
{ 0, 1, "Filename" },
{ 1, 0, "O/S Type" },
{ 2, 1, "Assembler" },
{ 3, 1, "Author" },
{ 4, 1, "Creation Date" },
{ -1, -1, NULL }
};
static char* stab[] = {
"undefined" ,
"absolute" ,
"text" ,
"data" ,
"bss" ,
"zero" ,
"-" ,
"-"
};
void print_option(unsigned char *buf, int len) {
int i, strfl=0;
for(i=0;otab[i].opt>=0; i++) if(*buf==otab[i].opt) break;
if(otab[i].opt>=0) {
printf("fopt: %-17s: ", otab[i].string);
strfl = otab[i].strfl;
} else {
printf("fopt: Unknown Type $%02x : ", (*buf & 0xff));
}
if(strfl) {
buf[len]=0;
printf("%s\n", buf+1);
} else {
for (i=1; i<len-1; i++) {
printf("%02x ", buf[i] & 0xff);
}
printf("\n");
}
}
int read_options(FILE *fp) {
int c, l=0;
unsigned char tb[256];
c=fgetc(fp); l++;
while(c && c!=EOF) {
c&=255;
fread(tb, 1, c-1, fp);
if(labels) print_option(tb, c);
l+=c;
c=fgetc(fp);
}
return l;
}
int print_labels(FILE *fp, int offset) {
int i, nud, c, seg, off;
/*
printf("print_labels:offset=%d\n",offset);
*/
fseek(fp, offset, SEEK_CUR);
nud = (fgetc(fp) & 0xff);
nud += ((fgetc(fp) << 8) & 0xff00);
printf("Undefined Labels: %d\n", nud);
if(nud) {
do {
c=fgetc(fp);
while(c && c!=EOF) {
fputc(c, stdout);
c=fgetc(fp);
}
printf("\t");
} while(--nud);
printf("\n");
}
for(i=0;i<2;i++) {
c=fgetc(fp);
while(c && c!=EOF) {
c&= 0xff;
while(c == 255 && c!= EOF) {
c=fgetc(fp);
if(c==EOF) break;
c&= 0xff;
}
if(c==EOF) break;
c=fgetc(fp);
if( (c & 0xe0) == 0x40 ) fgetc(fp);
if( (c & 0x07) == 0 ) { fgetc(fp); fgetc(fp); }
c=fgetc(fp);
}
}
nud = (fgetc(fp) & 0xff);
nud += ((fgetc(fp) << 8) & 0xff00);
printf("Global Labels: %d\n", nud);
if(nud) {
do {
c=fgetc(fp);
while(c && c!=EOF) {
fputc(c, stdout);
c=fgetc(fp);
}
if(c==EOF) break;
seg = fgetc(fp) & 0xff;
off= (fgetc(fp) & 0xff);
off+= ((fgetc(fp) << 8) & 0xff00);
printf(" (segID=%d (%s), offset=%04x)\n", seg, stab[seg&7], off);
} while(--nud);
}
return 0;
}

698
xa/misc/ldo65.c Normal file
View File

@ -0,0 +1,698 @@
/* ldo65 -- A part of xa65 - 65xx/65816 cross-assembler and utility suite
* o65 relocatable object file linker
*
* A part of the 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.
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef _MSC_VER
#include <unistd.h>
#endif
#include <sys/stat.h>
#include "version.h"
#define BUF (9*2+8) /* 16 bit header */
#define programname "ldo65"
#define progversion "v0.1.1"
#define author "Written by André Fachat"
#define copyright "Copyright (C) 1997-2002 André Fachat. Formerly ld65."
typedef struct {
char *name;
int len;
} undefs;
/* file information */
typedef struct {
char *fname; /* file name */
size_t fsize; /* length of file */
unsigned char *buf; /* file content */
int tbase; /* header: text base */
int tlen; /* text length */
int dbase; /* data base */
int dlen; /* data length */
int bbase; /* bss base */
int blen; /* bss length */
int zbase; /* zero base */
int zlen; /* zero length */
int tdiff; /* text segment relocation diff */
int ddiff; /* data segment relocation diff */
int bdiff; /* bss segment relocation diff */
int zdiff; /* zero segment relocation diff */
int tpos; /* position of text segment in file */
int dpos; /* position of data segment in file */
int upos; /* position of undef'd list in file */
int trpos; /* position of text reloc tab in file */
int drpos; /* position of data reloc tab in file */
int gpos; /* position of globals list in file */
int lasttreloc;
int lastdreloc;
int nundef; /* number of undefined labels */
undefs *ud; /* undefined labels list NULL if none */
} file65;
/* globally defined lables are stored in this struct */
typedef struct {
char *name;
int len; /* length of labelname */
int fl; /* 0=ok, 1=multiply defined */
int val; /* address value */
int seg; /* segment */
file65 *file; /* in which file is it? */
} glob;
file65 *load_file(char *fname);
int read_options(unsigned char *f);
int read_undef(unsigned char *f, file65 *fp);
int len_reloc_seg(unsigned char *buf, int ri);
int reloc_seg(unsigned char *buf, int adr, int ri, int *lreloc, file65 *fp);
unsigned char *reloc_globals(unsigned char *, file65 *fp);
int read_globals(file65 *file);
int write_options(FILE *fp, file65 *file);
int write_reloc(file65 *fp[], int nfp, FILE *f);
int write_globals(FILE *fp);
file65 file;
unsigned char cmp[] = { 1, 0, 'o', '6', '5' };
unsigned char hdr[26] = { 1, 0, 'o', '6', '5', 0 };
void usage(FILE *fp)
{
fprintf(fp,
"Usage: %s [OPTION]... [FILE]...\n"
"Linker for o65 object files\n"
"\n"
" -b? addr relocates segment `?' (i.e. `t' for text segment,\n"
" `d' for data, `b' for bss, and `z' for zeropage) to the new\n"
" address `addr'\n"
" -o file uses `file' as output file. Default is `a.o65'\n"
" -G suppress writing of globals\n"
" --version output version information and exit\n"
" --help display this help and exit\n",
programname);
}
int main(int argc, char *argv[]) {
int noglob=0;
int i = 1;
int tbase = 0x0400, dbase = 0x1000, bbase = 0x4000, zbase = 0x0002;
int ttlen, tdlen, tblen, tzlen;
char *outfile = "a.o65";
int j, jm;
file65 *file, **fp = NULL;
FILE *fd;
if (argc <= 1) {
usage(stderr);
exit(1);
}
if (strstr(argv[1], "--help")) {
usage(stdout);
exit(0);
}
if (strstr(argv[1], "--version")) {
version(programname, progversion, author, copyright);
exit(0);
}
/* read options */
while(i<argc && argv[i][0]=='-') {
/* process options */
switch(argv[i][1]) {
case 'G':
noglob=1;
break;
case 'o':
if(argv[i][2]) outfile=argv[i]+2;
else outfile=argv[++i];
break;
case 'b':
switch(argv[i][2]) {
case 't':
if(argv[i][3]) tbase = atoi(argv[i]+3);
else tbase = atoi(argv[++i]);
break;
case 'd':
if(argv[i][3]) dbase = atoi(argv[i]+3);
else dbase = atoi(argv[++i]);
break;
case 'b':
if(argv[i][3]) bbase = atoi(argv[i]+3);
else bbase = atoi(argv[++i]);
break;
case 'z':
if(argv[i][3]) zbase = atoi(argv[i]+3);
else zbase = atoi(argv[++i]);
break;
default:
printf("Unknown segment type '%c' - ignored!\n", argv[i][2]);
break;
}
break;
default:
fprintf(stderr,"file65: %s unknown option, use '-?' for help\n",argv[i]);
break;
}
i++;
}
/* each file is loaded first */
j=0; jm=0; fp=NULL;
while(i<argc) {
file65 *f;
f = load_file(argv[i]);
if(f) {
if(j>=jm) fp=realloc(fp, (jm=(jm?jm*2:10))*sizeof(file65*));
if(!fp) { fprintf(stderr,"Oops, no more memory\n"); exit(1); }
fp[j++] = f;
}
i++;
}
/* now [tdbz]base holds new segment base address */
/* set total length to zero */
ttlen = tdlen = tblen = tzlen = 0;
/* find new addresses for the files and read globals */
for(i=0;i<j;i++) {
file = fp[i];
/* compute relocation differences */
file->tdiff = ((tbase + ttlen) - file->tbase);
file->ddiff = ((dbase + tdlen) - file->dbase);
file->bdiff = ((bbase + tblen) - file->bbase);
file->zdiff = ((zbase + tzlen) - file->zbase);
/*printf("tbase=%04x, file->tbase=%04x, ttlen=%04x -> tdiff=%04x\n",
tbase, file->tbase, ttlen, file->tdiff);*/
/* update globals (for result file) */
ttlen += file->tlen;
tdlen += file->dlen;
tblen += file->blen;
tzlen += file->zlen;
read_globals(file);
}
for(i=0;i<j;i++) {
file = fp[i];
reloc_seg(file->buf,
file->tpos,
file->trpos,
&(file->lasttreloc),
file);
reloc_seg(file->buf,
file->dpos,
file->drpos,
&(file->lastdreloc),
file);
reloc_globals(file->buf+file->gpos, file);
file->tbase += file->tdiff;
file->dbase += file->ddiff;
file->bbase += file->bdiff;
file->zbase += file->zdiff;
file->lasttreloc += file->tbase - file->tpos;
file->lastdreloc += file->dbase - file->dpos;
}
hdr[ 6] = 0; hdr[ 7] = 0;
hdr[ 8] = tbase & 255; hdr[ 9] = (tbase>>8) & 255;
hdr[10] = ttlen & 255; hdr[11] = (ttlen >>8)& 255;
hdr[12] = dbase & 255; hdr[13] = (dbase>>8) & 255;
hdr[14] = tdlen & 255; hdr[15] = (tdlen >>8)& 255;
hdr[16] = bbase & 255; hdr[17] = (bbase>>8) & 255;
hdr[18] = tblen & 255; hdr[19] = (tblen >>8)& 255;
hdr[20] = zbase & 255; hdr[21] = (zbase>>8) & 255;
hdr[22] = tzlen & 255; hdr[23] = (tzlen >>8)& 255;
hdr[24] = 0; hdr[25] = 0;
fd = fopen(outfile, "wb");
if(!fd) {
fprintf(stderr,"Couldn't open output file %s (%s)\n",
outfile, strerror(errno));
exit(2);
}
fwrite(hdr, 1, 26, fd);
/* this writes _all_ options from _all_files! */
for(i=0;i<j;i++) {
write_options(fd, fp[i]);
}
fputc(0,fd);
/* write text segment */
for(i=0;i<j;i++) {
fwrite(fp[i]->buf + fp[i]->tpos, 1, fp[i]->tlen, fd);
}
/* write data segment */
for(i=0;i<j;i++) {
fwrite(fp[i]->buf + fp[i]->dpos, 1, fp[i]->dlen, fd);
}
write_reloc(fp, j, fd);
if(!noglob) {
write_globals(fd);
} else {
fputc(0,fd);
fputc(0,fd);
}
fclose(fd);
return 0;
}
/***************************************************************************/
int write_options(FILE *fp, file65 *file) {
return fwrite(file->buf+BUF, 1, file->tpos-BUF-1, fp);
}
int read_options(unsigned char *buf) {
int c, l=0;
c=buf[0];
while(c && c!=EOF) {
c&=255;
l+=c;
c=buf[l];
}
return ++l;
}
int read_undef(unsigned char *buf, file65 *file) {
int i, n, l = 2, ll;
n = buf[0] + 256*buf[1];
file->nundef = n;
if (n == 0) {
file->ud = NULL;
} else {
file->ud = malloc(n*sizeof(undefs));
if(!file->ud) {
fprintf(stderr,"Oops, no more memory\n");
exit(1);
}
i=0;
while(i<n){
file->ud[i].name = (char*) buf+l;
ll=l;
while(buf[l++]);
file->ud[i].len = l-ll-1;
/*printf("read undef '%s'(%p), len=%d, ll=%d, l=%d, buf[l]=%d\n",
file->ud[i].name, file->ud[i].name, file->ud[i].len,ll,l,buf[l]);*/
i++;
}
}
return l;
}
/* compute and return the length of the relocation table */
int len_reloc_seg(unsigned char *buf, int ri) {
int type, seg;
while(buf[ri]) {
if((buf[ri] & 255) == 255) {
ri++;
} else {
ri++;
type = buf[ri] & 0xe0;
seg = buf[ri] & 0x07;
/*printf("reloc entry @ rtab=%p (offset=%d), adr=%04x, type=%02x, seg=%d\n",buf+ri-1, *(buf+ri-1), adr, type, seg);*/
ri++;
switch(type) {
case 0x80:
break;
case 0x40:
ri++;
break;
case 0x20:
break;
}
if(seg==0) ri+=2;
}
}
return ++ri;
}
#define reldiff(s) (((s)==2)?fp->tdiff:(((s)==3)?fp->ddiff:(((s)==4)?fp->bdiff:(((s)==5)?fp->zdiff:0))))
unsigned char *reloc_globals(unsigned char *buf, file65 *fp) {
int n, old, new, seg;
n = buf[0] + 256*buf[1];
buf +=2;
while(n) {
/*printf("relocating %s, ", buf);*/
while(*(buf++));
seg = *buf;
old = buf[1] + 256*buf[2];
new = old + reldiff(seg);
/*printf("old=%04x, seg=%d, rel=%04x, new=%04x\n", old, seg, reldiff(seg), new);*/
buf[1] = new & 255;
buf[2] = (new>>8) & 255;
buf +=3;
n--;
}
return buf;
}
/***************************************************************************/
file65 *load_file(char *fname) {
file65 *file;
struct stat fs;
FILE *fp;
int mode, hlen;
size_t n;
file=malloc(sizeof(file65));
if(!file) {
fprintf(stderr,"Oops, not enough memory!\n");
exit(1);
}
/*printf("load_file(%s)\n",fname);*/
file->fname=fname;
stat(fname, &fs);
file->fsize=fs.st_size;
file->buf=malloc(file->fsize);
if(!file->buf) {
fprintf(stderr,"Oops, no more memory!\n");
exit(1);
}
fp = fopen(fname,"rb");
if(fp) {
n = fread(file->buf, 1, file->fsize, fp);
fclose(fp);
if((n>=file->fsize) && (!memcmp(file->buf, cmp, 5))) {
mode=file->buf[7]*256+file->buf[6];
if(mode & 0x2000) {
fprintf(stderr,"file65: %s: 32 bit size not supported\n", fname);
free(file->buf); free(file); file=NULL;
} else
if(mode & 0x4000) {
fprintf(stderr,"file65: %s: pagewise relocation not supported\n",
fname);
free(file->buf); free(file); file=NULL;
} else {
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->dbase = file->buf[13]*256+file->buf[12];
file->dlen = file->buf[15]*256+file->buf[14];
file->bbase = file->buf[17]*256+file->buf[16];
file->blen = file->buf[19]*256+file->buf[18];
file->zbase = file->buf[21]*256+file->buf[20];
file->zlen = file->buf[23]*256+file->buf[21];
file->tpos = hlen;
file->dpos = hlen + file->tlen;
file->upos = file->dpos + file->dlen;
file->trpos= file->upos + read_undef(file->buf+file->upos, file);
file->drpos= len_reloc_seg(file->buf, file->trpos);
file->gpos = len_reloc_seg(file->buf, file->drpos);
}
} else
fprintf(stderr,"file65: %s: %s\n", fname, strerror(errno));
} else
fprintf(stderr,"file65: %s: %s\n", fname, strerror(errno));
return file;
}
/***************************************************************************/
glob *gp = NULL;
int gm=0;
int g=0;
int write_reloc(file65 *fp[], int nfp, FILE *f) {
int tpc, pc, i;
unsigned char *p;
int low = 0, seg, typ, lab;
/* no undefined labels ? TODO */
fputc(0,f);
fputc(0,f);
tpc = fp[0]->tbase-1;
for(i=0;i<nfp;i++) {
pc = fp[i]->tbase-1;
p = fp[i]->buf + fp[i]->trpos;
while(*p) {
while((*p)==255) { pc+=254; p++; }
pc+=*(p++);
seg=(*p)&7;
typ=(*p)&0xe0;
if(typ==0x40) low=*(++p);
p++;
if(seg==0) {
lab=p[0]+256*p[1];
seg=gp[lab].seg;
p+=2;
}
if(seg>1) {
while(pc-tpc>254) {
fputc(255,f);
tpc+=254;
}
fputc(pc-tpc, f);
tpc=pc;
fputc(typ | seg, f);
if(typ==0x40) {
fputc(low,f);
}
}
}
}
fputc(0,f);
tpc = fp[0]->dbase-1;
for(i=0;i<nfp;i++) {
pc = fp[i]->dbase-1;
p = fp[i]->buf + fp[i]->drpos;
while(*p) {
while((*p)==255) { pc+=254; p++; }
pc+=*(p++);
seg=(*p)&7;
typ=(*p)&0xe0;
if(typ==0x40) low=*(++p);
p++;
if(seg==0) {
lab=p[0]+256*p[1];
seg=gp[lab].seg;
p+=2;
}
if(seg>1) {
while(pc-tpc>254) {
fputc(255,f);
tpc+=254;
}
fputc(pc-tpc, f);
tpc=pc;
fputc(typ | seg, f);
if(typ==0x40) {
fputc(low,f);
}
}
}
}
fputc(0,f);
return 0;
}
int write_globals(FILE *fp) {
int i;
fputc(g&255, fp);
fputc((g>>8)&255, fp);
for(i=0;i<g;i++) {
fprintf(fp,"%s%c%c%c%c",gp[i].name,0,gp[i].seg,
gp[i].val & 255, (gp[i].val>>8)&255);
}
return 0;
}
int read_globals(file65 *fp) {
int i, l, n, old, new, seg, ll;
char *name;
unsigned char *buf = fp->buf + fp->gpos;
n = buf[0] + 256*buf[1];
buf +=2;
while(n) {
/*printf("reading %s, ", buf);*/
name = (char*) buf;
l=0;
while(buf[l++]);
buf+=l;
ll=l-1;
seg = *buf;
old = buf[1] + 256*buf[2];
new = old + reldiff(seg);
/*printf("old=%04x, seg=%d, rel=%04x, new=%04x\n", old, seg, reldiff(seg), new);*/
/* multiply defined? */
for(i=0;i<g;i++) {
if(ll==gp[i].len && !strcmp(name, gp[i].name)) {
fprintf(stderr,"Warning: label '%s' multiply defined (%s and %s)\n",
name, fp->fname, gp[i].file->fname);
gp[i].fl = 1;
break;
}
}
/* not already defined */
if(i>=g) {
if(g>=gm) {
gp = realloc(gp, (gm=(gm?2*gm:40))*sizeof(glob));
if(!gp) {
fprintf(stderr,"Oops, no more memory\n");
exit(1);
}
}
if(g>=0x10000) {
fprintf(stderr,"Outch, maximum number of labels (65536) exceeded!\n");
exit(3);
}
gp[g].name = name;
gp[g].len = ll;
gp[g].seg = seg;
gp[g].val = new;
gp[g].fl = 0;
gp[g].file = fp;
/*printf("set label '%s' (l=%d, seg=%d, val=%04x)\n", gp[g].name,
gp[g].len, gp[g].seg, gp[g].val);*/
g++;
}
buf +=3;
n--;
}
return 0;
}
int find_global(unsigned char *bp, file65 *fp, int *seg) {
int i,l;
char *n;
int nl = bp[0]+256*bp[1];
l=fp->ud[nl].len;
n=fp->ud[nl].name;
/*printf("find_global(%s (len=%d))\n",n,l);*/
for(i=0;i<g;i++) {
if(gp[i].len == l && !strcmp(gp[i].name, n)) {
*seg = gp[i].seg;
bp[0] = i & 255; bp[1] = (i>>8) & 255;
/*printf("return gp[%d]=%s (len=%d), val=%04x\n",i,gp[i].name,gp[i].len,gp[i].val);*/
return gp[i].val;
}
}
fprintf(stderr,"Warning: undefined label '%s' in file %s\n",
n, fp->fname);
return 0;
}
int reloc_seg(unsigned char *buf, int pos, int ri, int *lreloc, file65 *fp) {
int type, seg, old, new;
/*
pos = position of segment in *buf
ri = position of relocation table in *buf
*/
pos--;
/*printf("reloc_seg: adr=%04x, tdiff=%04x, ddiff=%04x, bdiff=%04x, zdiff=%04x\n", pos, fp->tdiff, fp->ddiff, fp->bdiff, fp->zdiff); */
while(buf[ri]) {
if((buf[ri] & 255) == 255) {
pos += 254;
ri++;
} else {
pos += buf[ri] & 255;
ri++;
type = buf[ri] & 0xe0;
seg = buf[ri] & 0x07;
/*printf("reloc entry @ ri=%04x, pos=%04x, type=%02x, seg=%d\n",ri, pos, type, seg);*/
ri++;
switch(type) {
case 0x80:
old = buf[pos] + 256*buf[pos+1];
if(seg) {
new = old + reldiff(seg);
} else {
new = old + find_global(buf+ri, fp, &seg);
ri += 2; /* account for label number */
}
/*printf("old=%04x, new=%04x\n",old,new);*/
buf[pos] = new & 255;
buf[pos+1] = (new>>8)&255;
break;
case 0x40:
old = buf[pos]*256 + buf[ri];
if(seg) {
new = old + reldiff(seg);
} else {
new = old + find_global(buf+ri+1, fp, &seg);
ri += 2; /* account for label number */
}
buf[pos] = (new>>8)&255;
buf[ri] = new & 255;
ri++;
break;
case 0x20:
old = buf[pos];
if(seg) {
new = old + reldiff(seg);
} else {
new = old + find_global(buf+ri, fp, &seg);
ri += 2; /* account for label number */
}
buf[pos] = new & 255;
break;
}
}
}
*lreloc = pos;
return ++ri;
}

92
xa/misc/mkrom.sh Executable file
View File

@ -0,0 +1,92 @@
#!/bin/bash
#
# xa65 - 6502 cross assembler and utility suite
# mkrom.sh - assemble several 'romable' files into one binary
# Copyright (C) 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.
#
XA="../xa"
FILE=../file65
start=32768
ende=65536
romfile=rom65
next=$[ start + 2 ];
pars="-A $next"
umask 077
tmp1=/tmp/mkrom65.sh.$$.a
tmp2=/tmp/mkrom65.sh.$$.b
tmp3=/tmp/mkrom65.sh.$$.c
echo -e "#include <stdio.h>\nvoid main(int argc, char *argv[]) { printf(\"%c%c\",atoi(argv[1])&255,(atoi(argv[1])/256)&255);}" \
> $tmp3;
cc $tmp3 -o $tmp2
while [ $# -ne 0 ]; do
case $1 in
-A) # get start address
start=$[ $2 ];
shift
;;
-E) # get end address
ende=$[ $2 ];
shift
;;
-R) # get ROM filename
romfile=$2;
shift
;;
-O) # xa options
XA="$XA $2";
shift
;;
-S) # segment addresses - in xa option format
pars="$pars $2";
shift
;;
*)
break;
;;
esac;
shift
done
#get file list
list="$*"
echo -n > $romfile
for i in $list; do
#echo "next=$next, start=$start, pars=$pars"
#echo "cmd= ${XA} -R $pars -o $tmp1 $i"
$XA -R $pars -o $tmp1 $i
pars=`$FILE -a 2 -P $tmp1`;
next=`$FILE -A 0 $tmp1`;
$tmp2 $next >> $romfile
cat $tmp1 >> $romfile;
done;
$tmp2 65535 >> $romfile
rm -f $tmp1 $tmp2 $tmp3

109
xa/misc/printcbm.c Normal file
View File

@ -0,0 +1,109 @@
/* printcbm -- A part of xa65 - 65xx/65816 cross-assembler and utility suite
* list CBM BASIC programs
*
* 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.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "version.h"
#define programname "printcbm"
#define progversion "v1.0.0"
#define author "Written by André Fachat"
#define copyright "Copyright (C) 1997-2002 André Fachat."
char *cmd[] = {
"end", "for", "next", "data", "input#", "input", "dim", "read",
"let", "goto", "run", "if", "restore", "gosub", "return",
"rem", "stop", "on", "wait", "load", "save", "verify", "def",
"poke", "print#", "print", "cont", "list", "clr", "cmd", "sys",
"open", "close", "get", "new", "tab(", "to", "fn", "spc(",
"then", "not", "step", "+", "-", "*", "/", "^", "and", "or",
">", "=", "<", "sgn", "int", "abs", "usr", "fre", "pos", "sqr",
"rnd", "log", "exp", "cos", "sin", "tan", "atn", "peek", "len",
"str$", "val", "asc", "chr$", "left$", "right$", "mid$", "go"
};
void usage(FILE *fp)
{
fprintf(fp,
"Usage: %s [OPTION]... [FILE]...\n"
"List CBM BASIC programs\n"
"\n"
" --version output version information and exit\n"
" --help display this help and exit\n",
programname);
}
int main(int argc, char *argv[])
{
FILE *fp;
int a, b, c;
if (argc < 2) {
usage(stderr);
exit(1);
}
if (strstr(argv[1], "--help")) {
usage(stdout);
exit(0);
}
if (strstr(argv[1], "--version")) {
version(programname, progversion, author, copyright);
exit(0);
}
fp = fopen(argv[1], "rb");
if (fp) {
b = fgetc(fp);
b = fgetc(fp);
while (b != EOF) {
a = fgetc(fp);
a = a + 256 * fgetc(fp);
if (a) {
a = fgetc(fp);
a = a + 256 * fgetc(fp);
printf("%d ", a);
while ((c = fgetc(fp))) {
if (c == EOF)
break;
if (c >= 0x80 && c < 0xcc)
printf("%s", cmd[c - 0x80]);
else
printf("%c", c);
}
printf("\n");
} else {
break;
}
}
fclose(fp);
} else {
printf("File %s not found!\n", argv[1]);
}
return 0;
}

384
xa/misc/reloc65.c Normal file
View File

@ -0,0 +1,384 @@
/* reloc65 -- A part of xa65 - 65xx/65816 cross-assembler and utility suite
* o65 file relocator
*
* 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.
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include "version.h"
#define BUF (9*2+8) /* 16 bit header */
#define programname "reloc65"
#define progversion "v0.2.1"
#define author "Written by André Fachat"
#define copyright "Copyright (C) 1997-2002 André Fachat."
typedef struct {
char *fname;
size_t fsize;
unsigned char *buf;
int tbase, tlen, dbase, dlen, bbase, blen, zbase, zlen;
int tdiff, ddiff, bdiff, zdiff;
unsigned char *segt;
unsigned char *segd;
unsigned char *utab;
unsigned char *rttab;
unsigned char *rdtab;
unsigned char *extab;
} file65;
int read_options(unsigned char *f);
int read_undef(unsigned char *f);
unsigned char *reloc_seg(unsigned char *f, int len, unsigned char *rtab, file65 *fp, int undefwarn);
unsigned char *reloc_globals(unsigned char *, file65 *fp);
file65 file;
unsigned char cmp[] = { 1, 0, 'o', '6', '5' };
void usage(FILE *fp)
{
fprintf(fp,
"Usage: %s [OPTION]... [FILE]...\n"
"Relocator for o65 object files\n"
"\n"
" -b? addr relocates segment '?' (i.e. 't' for text segment,\n"
" 'd' for data, 'b' for bss and 'z' for zeropage) to the new\n"
" address `addr'\n"
" -o file uses `file' as output file. Default is `a.o65'\n"
" -x? extracts text `?' = `t' or data `?' = `d' segment from file\n",
programname);
fprintf(fp,
" instead of writing back the whole file\n"
" -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"
" --version output version information and exit\n"
" --help display this help and exit\n");
}
int main(int argc, char *argv[]) {
int i = 1, mode, hlen;
size_t n;
FILE *fp;
int tflag = 0, dflag = 0, bflag = 0, zflag = 0;
int tbase = 0, dbase = 0, bbase = 0, zbase = 0;
char *outfile = "a.o65";
int extract = 0;
if (argc <= 1) {
usage(stderr);
exit(1);
}
if (strstr(argv[1], "--help")) {
usage(stdout);
exit(0);
}
if (strstr(argv[1], "--version")) {
version(programname, progversion, author, copyright);
exit(0);
}
while(i<argc) {
if(argv[i][0]=='-') {
/* process options */
switch(argv[i][1]) {
case 'o':
if(argv[i][2]) outfile=argv[i]+2;
else outfile=argv[++i];
break;
case 'X':
extract=3;
break;
case 'b':
switch(argv[i][2]) {
case 't':
tflag= 1;
if(argv[i][3]) tbase = atoi(argv[i]+3);
else tbase = atoi(argv[++i]);
break;
case 'd':
dflag= 1;
if(argv[i][3]) dbase = atoi(argv[i]+3);
else dbase = atoi(argv[++i]);
break;
case 'b':
bflag= 1;
if(argv[i][3]) bbase = atoi(argv[i]+3);
else bbase = atoi(argv[++i]);
break;
case 'z':
zflag= 1;
if(argv[i][3]) zbase = atoi(argv[i]+3);
else zbase = atoi(argv[++i]);
break;
default:
printf("Unknown segment type '%c' - ignored!\n", argv[i][2]);
break;
}
break;
case 'x': /* extract segment */
switch(argv[i][2]) {
case 't':
extract = 1;
break;
case 'd':
extract = 2;
break;
case 'z':
case 'b':
printf("Cannot extract segment type '%c' - ignored!\n", argv[i][2]);
break;
default:
printf("Unknown segment type '%c' - ignored!\n", argv[i][2]);
break;
}
break;
default:
fprintf(stderr,"reloc65: %s unknown option, use '-?' for help\n",argv[i]);
break;
}
} else {
struct stat fs;
file.fname=argv[i];
stat(argv[i], &fs);
file.fsize=fs.st_size;
file.buf=malloc(file.fsize);
if(!file.buf) {
fprintf(stderr,"Oops, no more memory!\n");
exit(1);
}
printf("reloc65: read file %s -> %s\n",argv[i],outfile);
fp = fopen(argv[i],"rb");
if(fp) {
n = fread(file.buf, 1, file.fsize, fp);
fclose(fp);
if((n>=file.fsize) && (!memcmp(file.buf, cmp, 5))) {
mode=file.buf[7]*256+file.buf[6];
if(mode & 0x2000) {
fprintf(stderr,"reloc65: %s: 32 bit size not supported\n", argv[i]);
} else
if(mode & 0x4000) {
fprintf(stderr,"reloc65: %s: pagewise relocation not supported\n", argv[i]);
} else {
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.dbase = file.buf[13]*256+file.buf[12];
file.dlen = file.buf[15]*256+file.buf[14];
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;
}
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.segt = file.buf + hlen;
file.segd = file.segt + file.tlen;
file.utab = file.segd + file.dlen;
file.rttab = file.utab + read_undef(file.utab);
file.rdtab = reloc_seg(file.segt, file.tlen, file.rttab,
&file, extract);
file.extab = reloc_seg(file.segd, file.dlen, file.rdtab,
&file, extract);
reloc_globals(file.extab, &file);
if(tflag) {
file.buf[ 9]= (tbase>>8)&255;
file.buf[ 8]= tbase & 255;
}
if(dflag) {
file.buf[13]= (dbase>>8)&255;
file.buf[12]= dbase & 255;
}
if(bflag) {
file.buf[17]= (bbase>>8)&255;
file.buf[16]= bbase & 255;
}
if(zflag) {
file.buf[21]= (zbase>>8)&255;
file.buf[20]= zbase & 255;
}
fp = fopen(outfile, "wb");
if(fp) {
switch(extract) {
case 0: /* whole file */
fwrite(file.buf, 1, file.fsize, fp);
break;
case 1: /* text segment */
fwrite(file.segt, 1, file.tlen, fp);
break;
case 2: /* data segment */
fwrite(file.segd, 1, file.dlen, fp);
break;
case 3: /* text+data */
fwrite(file.segt, 1, file.tlen, fp);
fwrite(file.segd, 1, file.dlen, fp);
break;
}
fclose(fp);
} else {
fprintf(stderr,"reloc65: write '%s': %s\n",
outfile, strerror(errno));
}
}
} else {
fprintf(stderr,"reloc65: %s: not an o65 file!\n", argv[i]);
if(file.buf[0]==1 && file.buf[1]==8 && file.buf[3]==8) {
printf("%s: C64 BASIC executable (start address $0801)?\n", argv[i]);
} else
if(file.buf[0]==1 && file.buf[1]==4 && file.buf[3]==4) {
printf("%s: CBM PET BASIC executable (start address $0401)?\n", argv[i]);
}
}
} else {
fprintf(stderr,"reloc65: read '%s': %s\n",
argv[i], strerror(errno));
}
}
i++;
}
exit(0);
}
int read_options(unsigned char *buf) {
int c, l=0;
c=buf[0];
while(c && c!=EOF) {
c&=255;
l+=c;
c=buf[l];
}
return ++l;
}
int read_undef(unsigned char *buf) {
int n, l = 2;
n = buf[0] + 256*buf[1];
while(n){
n--;
while(buf[l] != 0) {
l++;
}
l++;
}
return l;
}
#define reldiff(s) (((s)==2)?fp->tdiff:(((s)==3)?fp->ddiff:(((s)==4)?fp->bdiff:(((s)==5)?fp->zdiff:0))))
unsigned char *reloc_seg(unsigned char *buf, int len, unsigned char *rtab,
file65 *fp, int undefwarn) {
int adr = -1;
int type, seg, old, new;
/*printf("tdiff=%04x, ddiff=%04x, bdiff=%04x, zdiff=%04x\n",
fp->tdiff, fp->ddiff, fp->bdiff, fp->zdiff);*/
while(*rtab) {
if((*rtab & 255) == 255) {
adr += 254;
rtab++;
} else {
adr += *rtab & 255;
rtab++;
type = *rtab & 0xe0;
seg = *rtab & 0x07;
/*printf("reloc entry @ rtab=%p (offset=%d), adr=%04x, type=%02x, seg=%d\n",rtab-1, *(rtab-1), adr, type, seg);*/
rtab++;
switch(type) {
case 0x80: /* WORD - two byte address */
old = buf[adr] + 256*buf[adr+1];
new = old + reldiff(seg);
buf[adr] = new & 255;
buf[adr+1] = (new>>8)&255;
break;
case 0x40: /* HIGH - high byte of an address */
old = buf[adr]*256 + *rtab;
new = old + reldiff(seg);
buf[adr] = (new>>8)&255;
*rtab = new & 255;
rtab++;
break;
case 0x20: /* LOW - low byt of an address */
old = buf[adr];
new = old + reldiff(seg);
buf[adr] = new & 255;
break;
}
if(seg==0) {
/* undefined segment entry */
if (undefwarn) {
fprintf(stderr,"reloc65: %s: Warning: undefined relocation table entry not handled!\n", fp->fname);
}
rtab+=2;
}
}
}
if(adr > len) {
fprintf(stderr,"reloc65: %s: Warning: relocation table entries past segment end!\n",
fp->fname);
fprintf(stderr, "reloc65: adr=%x len=%x\n", adr, len);
}
return ++rtab;
}
unsigned char *reloc_globals(unsigned char *buf, file65 *fp) {
int n, old, new, seg;
n = buf[0] + 256*buf[1];
buf +=2;
while(n) {
/*printf("relocating %s, ", buf);*/
while(*(buf++));
seg = *buf;
old = buf[1] + 256*buf[2];
new = old + reldiff(seg);
/*printf("old=%04x, seg=%d, rel=%04x, new=%04x\n", old, seg, reldiff(seg), new);*/
buf[1] = new & 255;
buf[2] = (new>>8) & 255;
buf +=3;
n--;
}
return buf;
}

207
xa/misc/uncpk.c Normal file
View File

@ -0,0 +1,207 @@
/* reloc65 -- A part of xa65 - 65xx/65816 cross-assembler and utility suite
* Pack/Unpack cpk archive files
*
* Copyright (C) 1989-2002 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.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "version.h"
#define max(a, b) (a > b) ? a : b
#define min(a, b) (a < b) ? a : b
#define programname "uncpk"
#define progversion "v0.2.1"
#define author "Written by André Fachat"
#define copyright "Copyright (C) 1997-2002 André Fachat."
FILE *fp;
char name[100];
char *s;
void usage(FILE *fp)
{
fprintf(fp,
"Usage: %s [OPTION]... [FILE]...\n"
"Manage c64 cpk archives\n"
"\n"
" c create an archive\n"
" a add a file to an archive\n"
" x extract archive\n"
" l list contents of archive\n"
" v verbose output\n"
" --version output version information and exit\n"
" --help display this help and exit\n",
programname);
}
int list=0,verbose=0,add=0,create=0;
int main(int argc, char *argv[])
{
int i,c,c2,fileok, nc;
size_t n,n2;
FILE *fp,*fpo=NULL;
if (argc <= 1) {
usage(stderr);
exit(1);
}
if (strstr(argv[1], "--help")) {
usage(stdout);
exit(0);
}
if (strstr(argv[1], "--version")) {
version(programname, progversion, author, copyright);
exit(0);
}
if(strchr(argv[1],(int)'l')) {
list=1;
}
if(strchr(argv[1],(int)'v')) {
verbose=1;
}
if(strchr(argv[1],(int)'a')) {
add=1;
}
if(strchr(argv[1],(int)'c')) {
create=1;
}
if(add||create) {
if (argc <= 3) {
usage(stderr);
exit(1);
}
if(add) {
fpo=fopen(argv[2],"ab");
} else
if(create) {
fpo=fopen(argv[2],"wb");
}
if(fpo) {
if(!add) fputc(1,fpo); /* Version Byte */
for(i=3;i<argc;i++) {
if(verbose) printf("%s\n",argv[i]);
fp=fopen(argv[i],"rb");
if(fp) {
while((s=strchr(argv[i],':'))) *s='/';
fprintf(fpo,"%s",argv[i]);
fputc(0,fpo);
c=fgetc(fp);
while(c!=EOF) {
n=1;
while((c2=fgetc(fp))==c) {
n++;
}
while(n) {
if(n>=4 || c==0xf7) {
n2=min(255,n);
fprintf(fpo,"\xf7%c%c",(char)n2,(char)c);
n-=n2;
} else {
fputc(c,fpo);
n--;
}
}
c=c2;
}
fclose(fp);
fputc(0xf7,fpo); fputc(0,fpo);
} else {
fprintf(stderr,"Couldn't open file '%s' for reading!",argv[i]);
}
}
fclose(fpo);
} else {
fprintf(stderr,"Couldn't open file '%s' for writing!",argv[1]);
}
} else {
if (argc != 3) {
usage(stderr);
exit(1);
}
fp=fopen(argv[2],"rb");
if(fp){
if(fgetc(fp)==1){
do{
/* read name */
i=0;
while((c=fgetc(fp))){
if(c==EOF) break;
name[i++]=c;
}
name[i++]='\0';
if(!c){ /* end of archive ? */
while((s=strchr(name,'/'))) *s=':';
if(verbose+list) printf("%s\n",name);
if(!list) {
fpo=fopen(name,"wb");
if(!fpo) {
fprintf(stderr,"Couldn't open output file %s !\n",name);
}
}
fileok=0;
while((c=fgetc(fp))!=EOF){
/* test if 'compressed' */
if(c==0xf7){
nc=fgetc(fp);
if(!nc) {
fileok=1;
break;
}
c=fgetc(fp);
if(fpo) { /* extract */
if(nc!=EOF && c!=EOF) {
nc &= 255;
while(nc--) {
fputc(c,fpo);
}
}
}
} else {
if(fpo) {
fputc(c,fpo);
}
}
}
if(fpo) {
fclose(fpo);
fpo=NULL;
}
if(!fileok) {
fprintf(stderr,"Unexpected end of file!\n");
}
}
} while(c!=EOF);
} else
fprintf(stderr,"Wrong Version!\n");
fclose(fp);
} else {
fprintf(stderr,"File %s not found!\n",argv[1]);
}
}
return(0);
}

37
xa/misc/version.h Normal file
View File

@ -0,0 +1,37 @@
/* 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_VERSION_H__
#define __XA65_VERSION_H__
void version(const char *programname, const char *progversion,
const char *authors, const char *copyright)
{
fprintf(stdout,
"%s (xa65) %s\n"
"%s\n"
"\n"
"%s\n"
"This is free software; see the source for "
"copying conditions. There is NO\n"
"warranty; not even for MERCHANTABILIY or "
"FITNESS FOR A PARTICULAR PURPOSE.\n",
programname, progversion, authors, copyright);
}
#endif /* __XA65_VERSION_H__ */

18
xa/src/Makefile Normal file
View File

@ -0,0 +1,18 @@
OBJ = xa.o xaa.o xal.o xap.o xat.o xar.o xar2.o xao.o xau.o xam.o xacharset.o
#CFLAGS=-W -Wall -pedantic -ansi #-g
#CFLAGS=-W -Wall -ansi -O2
#LD = ${CC}
#LDFLAGS = "-lc"
all: xa
xa: ${OBJ}
${LD} -o ../xa ${OBJ} ${LDFLAGS}
clean:
rm -f *.o *.o65
mrproper: clean
rm -f ../xa

37
xa/src/version.h Normal file
View File

@ -0,0 +1,37 @@
/* 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_VERSION_H__
#define __XA65_VERSION_H__
void version(const char *programname, const char *progversion,
const char *authors, const char *copyright)
{
fprintf(stdout,
"%s (xa65) %s\n"
"%s\n"
"\n"
"%s\n"
"This is free software; see the source for "
"copying conditions. There is NO\n"
"warranty; not even for MERCHANTABILIY or "
"FITNESS FOR A PARTICULAR PURPOSE.\n",
programname, progversion, authors, copyright);
}
#endif /* __XA65_VERSION_H__ */

1131
xa/src/xa.c Normal file

File diff suppressed because it is too large Load Diff

49
xa/src/xa.h Normal file
View File

@ -0,0 +1,49 @@
/* 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_XA_H__
#define __XA65_XA_H__
#include "xah.h" /* For SEG_MAX */
extern int ncmos, cmosfl, w65816, n65816;
extern int masm, nolink;
extern int noglob;
extern int showblk;
extern int relmode;
extern int crossref;
extern char altppchar;
extern int tlen, tbase;
extern int blen, bbase;
extern int dlen, dbase;
extern int zlen, zbase;
extern int romable, romaddr;
extern int memode,xmode;
extern int segment;
extern int pc[SEG_MAX];
int h_length(void);
void set_align(int align_value);
void errout(int er);
void logout(char *s);
#endif /*__XA65_XA_H__ */

274
xa/src/xaa.c Normal file
View File

@ -0,0 +1,274 @@
/* xa65 - 65xx/65816 cross-assembler and utility suite
*
* Copyright (C) 1989-1997 André Fachat (a.fachat@physik.tu-chemnitz.de)
*
* Preprocessing arithmetic module
*
* 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.
*/
#include <stdio.h>
#include "xah.h"
#include "xad.h"
#include "xar.h"
#include "xa.h"
#include "xal.h"
#include "xaa.h"
#include "xat.h"
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 };
static int pp,pcc;
static int fundef;
static int ag_term(signed char*,int,int*,int*,int*);
static int get_op(signed char*,int*);
static int do_op(int*,int,int);
/* s = string, v = variable */
int a_term(signed char *s, int *v, int *l, int xpc, int *pfl, int *label, int f)
{
int er=E_OK;
int afl = 0, bfl;
*pfl = 0;
fundef = f;
pp=0;
pcc=xpc;
if(s[0]=='<')
{
pp++;
er=ag_term(s,P_START,v,&afl, label);
bfl = afl & (A_MASK>>8);
if( bfl && (bfl != (A_ADR>>8)) && (bfl != (A_LOW>>8)) ) {
/*fprintf(stderr,"low byte relocation for a high byte - won't work!\n");*/
errout(W_LOWACC);
}
if(afl) *pfl=A_LOW | ((afl<<8) & A_FMASK);
*v = *v & 255;
} else
if(s[pp]=='>')
{
pp++;
er=ag_term(s,P_START,v,&afl, label);
bfl = afl & (A_MASK>>8);
if( bfl && (bfl != (A_ADR>>8)) && (bfl != (A_HIGH>>8)) ) {
/*fprintf(stderr,"high byte relocation for a low byte - won't work!\n");*/
errout(W_HIGHACC);
}
if(afl) *pfl=A_HIGH | ((afl<<8) & A_FMASK) | (*v & 255);
*v=(*v>>8)&255;
}
else {
er=ag_term(s,P_START,v,&afl, label);
bfl = afl & (A_MASK>>8);
if(bfl && (bfl != (A_ADR>>8)) ) {
/*fprintf(stderr,"address relocation for a low or high byte - won't work!\n");*/
errout(W_ADDRACC);
}
if(afl) *pfl = A_ADR | ((afl<<8) & A_FMASK);
}
*l=pp;
/* printf("a_term: afl->%04x *pfl=%04x, (pc=%04x)\n",afl,*pfl, xpc); */
return(er);
}
static int ag_term(signed char *s, int p, int *v, int *nafl, int *label)
{
int er=E_OK,o,w,mf=1,afl;
afl = 0;
/*printf("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(s[pp]=='(')
{
pp++;
if(!(er=ag_term(s,P_START,v,&afl,label)))
{
if(s[pp]!=')')
er=E_SYNTAX;
else
pp++;
}
} else
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); */
if(er==E_NODEF && segment != SEG_ABS && fundef ) {
if( nolink || (afl==SEG_UNDEF)) {
er = E_OK;
*v = 0;
afl = SEG_UNDEF;
*label = cval(s+pp+1);
}
}
pp+=3;
}
else
if(s[pp]==T_VALUE)
{
*v=lval(s+pp+1);
pp+=4;
/* 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); */
}
else
if(s[pp]=='*')
{
*v=pcc;
pp++;
afl = segment;
}
else {
er=E_SYNTAX;
}
*v *= mf;
while(!er && s[pp]!=')' && s[pp]!=']' && s[pp]!=',' && s[pp]!=T_END)
{
er=get_op(s,&o);
if(!er && pr[o]>p)
{
pp+=1;
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 */
} 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 */
} else {
if(segment!=SEG_ABS) {
if(!dsb_len) {
er=E_ILLPOINTER;
}
}
afl=0;
}
}
if(!er) er=do_op(v,w,o);
}
} else {
break;
}
}
*nafl = afl;
return(er);
}
static int get_op(signed char *s, int *o)
{
int er;
*o=s[pp];
if(*o<1 || *o>17)
er=E_SYNTAX;
else
er=E_OK;
return(er);
}
static int do_op(int *w,int w2,int o)
{
int er=E_OK;
switch (o) {
case 1:
*w +=w2;
break;
case 2:
*w -=w2;
break;
case 3:
*w *=w2;
break;
case 4:
if (w!=0)
*w /=w2;
else
er =E_DIV;
break;
case 5:
*w >>=w2;
break;
case 6:
*w <<=w2;
break;
case 7:
*w = *w<w2;
break;
case 8:
*w = *w>w2;
break;
case 9:
*w = *w==w2;
break;
case 10:
*w = *w<=w2;
break;
case 11:
*w = *w>=w2;
break;
case 12:
*w = *w!=w2;
break;
case 13:
*w &=w2;
break;
case 14:
*w ^=w2;
break;
case 15:
*w |=w2;
break;
case 16:
*w =*w&&w2;
break;
case 17:
*w =*w||w2;
break;
}
return(er);
}

26
xa/src/xaa.h Normal file
View File

@ -0,0 +1,26 @@
/* 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_XAA_H__
#define __XA65_XAA_H__
/* f = 0 -> label must exist; f = 1 -> SEG_UNDEF entry */
int a_term(signed char *s, int *v, int *l, int xpc, int *afl,
int *label, int f);
#endif /* __XA65_XAA_H__ */

125
xa/src/xacharset.c Normal file
View File

@ -0,0 +1,125 @@
/* xa65 - 65xx/65816 cross-assembler and utility suite
*
* Copyright (C) 1989-1997 Andre Fachat (a.fachat@physik.tu-chemnitz.de)
* Maintained by Cameron Kaiser
*
* Charset conversion module
*
* 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.
*/
#include <stdio.h>
#include <string.h>
#include "xacharset.h"
static signed char (*convert_func)(signed char);
static signed char convert_char_ascii(signed char c) {
return c;
}
/*
* PETSCII conversion roughly follows the PETSCII to UNICODE
* mapping at http://www.df.lth.se/~triad/krad/recode/petscii_c64en_lc.txt
* linked from wikipedia http://en.wikipedia.org/wiki/PETSCII
*/
static signed char convert_char_petscii(signed char c) {
if (c >= 0x41 && c < 0x5b) {
return c + 0x20;
}
if (c >= 0x61 && c < 0x7b) {
return c - 0x20;
}
if (c == 0x7f) {
return 0x14;
}
return c;
}
/*
* Built upon Steve Judd's suggested PETSCII -> screen code algorithm
* This could probably be written a lot better, but it works.
* http://www.floodgap.com/retrobits/ckb/display.cgi?572
*/
static signed char convert_char_petscreen(signed char c) {
int i;
i = (int)convert_char_petscii(c);
#ifdef SIGH
fprintf(stderr, "input: %i output: %i\n", c, i);
#endif
if (i< 0)
i += 0x80;
i ^= 0xe0;
#ifdef SIGH
fprintf(stderr, "(1)input: %i output: %i\n", c, i);
#endif
i += 0x20;
i &= 0xff;
#ifdef SIGH
fprintf(stderr, "(2)input: %i output: %i\n", c, i);
#endif
if (i < 0x80)
return (signed char)i;
i += 0x40;
i &= 0xff;
#ifdef SIGH
fprintf(stderr, "(3)input: %i output: %i\n", c, i);
#endif
if (i < 0x80)
return (signed char)i;
i ^= 0xa0;
#ifdef SIGH
fprintf(stderr, "(4)input: %i output: %i\n", c, i);
#endif
return (signed char)i;
}
static signed char convert_char_high(signed char c) {
return (c | 0x80);
}
typedef struct {
char *name;
signed char (*func)(signed char);
} charset;
static charset charsets[] = {
{ "ASCII", convert_char_ascii },
{ "PETSCII", convert_char_petscii },
{ "PETSCREEN", convert_char_petscreen },
{ "HIGH", convert_char_high },
{ NULL, NULL }
};
int set_charset(char *charset_name) {
int i = 0;
while (charsets[i].name != NULL) {
if (strcmp(charsets[i].name, charset_name) == 0) {
convert_func = charsets[i].func;
return 0;
}
i++;
}
return -1;
}
signed char convert_char(signed char c) {
return convert_func(c);
}

31
xa/src/xacharset.h Normal file
View File

@ -0,0 +1,31 @@
/* xa65 - 65xx/65816 cross-assembler and utility suite
*
* Copyright (C) 1989-2006 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_XA_CHARSET_H__
#define __XA65_XA_CHARSET_H__
/* set the target character set the chars - values in quotes - should
be converted to
returns 0 on success and -1 when the name is not found */
int set_charset(char *charset_name);
/* convert a char */
signed char convert_char(signed char c);
#endif /*__XA65_XA_H__ */

41
xa/src/xad.h Normal file
View File

@ -0,0 +1,41 @@
/* 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_XAD_H__
#define __XA65_XAD_H__
#ifndef abs
#define abs(a) (a >= 0) ? a : -a
#endif
#define hashcode(n, l) (n[0] & 0x0f) | (((l - 1) ? (n[1] & 0x0f) : 0) << 4)
#define fputw(a, fp) do { \
fputc(a & 255, fp); \
fputc((a >> 8) & 255, fp); \
} while (0)
#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 { \
t[i++] = T_VALUE; \
t[i++] = v & 255; \
t[i++] = (v >> 8) & 255; \
t[i++] = (v >> 16) & 255; \
} while (0)
#endif /* __XA65_XAD_H__ */

227
xa/src/xah.h Normal file
View File

@ -0,0 +1,227 @@
/* xa65 - 65xx/65816 cross-assembler and utility suite
*
* Copyright (C) 1989-1997 André Fachat (a.fachat@physik.tu-chemnitz.de)
* Maintained by Cameron Kaiser
*
* 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_XAH_H__
#define __XA65_XAH_H__
#define ANZLAB 5000 /* mal 14 -> 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 */
typedef struct LabOcc {
struct LabOcc *next;
int line;
char *fname;
} LabOcc;
typedef struct {
int blk;
int val;
int len;
int fl; /* 0 = label value not valid/known,
* 1 = label value known
*/
int afl; /* 0 = no address (no relocation), 1 = address label */
int nextindex;
char *n;
struct LabOcc *occlist;
} Labtab;
typedef struct {
char *search;
int s_len;
char *replace;
int p_anz;
int nextindex;
} List;
#define MEMLEN (4 + TMPMEM + MAXPP + LABMEM + \
(long)(sizeof (Labtab) * ANZLAB) + \
(long)(sizeof (List) * ANZDEF))
#define DIRCHAR '/'
#define DIRCSTRING "/"
/* for Atari:
#define DIRCHAR '\\'
#define DIRCSTRING "\\"
*/
#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_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_FNF -14 /* File not found (pp) */
#define E_EOF -15 /* End of File */
#define E_BLOCK -16 /* Block inkonsistent */
#define E_NOBLK -17
#define E_NOKEY -18
#define E_NOLINE -19
#define E_OKDEF -20 /* okdef */
#define E_DSB -21
#define E_NEWLINE -22
#define E_NEWFILE -23
#define E_CMOS -24
#define E_ANZPAR -25
#define E_ILLPOINTER -26 /* illegal pointer arithmetic! */
#define E_ILLSEGMENT -27 /* illegal pointer arithmetic! */
#define E_OPTLEN -28 /* file header option too long */
#define E_ROMOPT -29 /* header option not directly after
* file start in romable mode
*/
#define E_ILLALIGN -30 /* illegal align value */
#define E_65816 -31
#define E_ORECMAC -32 /* exceeded recursion limit for label eval */
#define E_OPENPP -33 /* open preprocessor directive */
#define E_OUTOFDATA -34 /* out of data */
#define E_ILLQUANT -35 /* generic illegal quantity error */
#define E_BIN -36 /* okdef */
/* errors thru 63 are placeholders */
#define W_ADRRELOC -64 /* word relocation in byte value */
#define W_BYTRELOC -65 /* byte relocation in word value */
#define E_WPOINTER -66 /* illegal pointer arithmetic! */
#define W_ADDRACC -67 /* addr access to low or high byte pointer */
#define W_HIGHACC -68 /* high byte access to low byte pointer */
#define W_LOWACC -69 /* low byte access to high byte pointer */
#define W_FORLAB -70 /* no zp-optimization for a forward label */
#define W_OPENPP -71 /* warning about open preprocessor directive */
#define W_OVER64K -72 /* included binary over 64K in 6502 mode */
#define W_OVER16M -73 /* included binary over 16M in 65816 mode */
/* warnings 74-76 are placeholders */
#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
#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_XOR 4
#define P_AND 5
#define P_EQU 6
#define P_CMP 7
#define P_SHIFT 8
#define P_ADD 9
#define P_MULT 10
#define P_INV 11
#define A_ADR 0x8000 /* all are or'd with (afl = segment type)<<8 */
#define A_HIGH 0x4000 /* or'd with the low byte */
#define A_LOW 0x2000
#define A_MASK 0xe000 /* reloc type mask */
#define A_FMASK 0x0f00 /* segment type mask */
#define A_LONG 0xc000
#define FM_OBJ 0x1000
#define FM_SIZE 0x2000
#define FM_RELOC 0x4000
#define FM_CPU 0x8000
#define SEG_ABS 0
#define SEG_UNDEF 1
#define SEG_TEXT 2
#define SEG_DATA 3
#define SEG_BSS 4
#define SEG_ZERO 5
#define SEG_MAX 6
typedef struct Fopt {
signed char *text; /* text after pass1 */
int len;
} Fopt;
typedef struct relocateInfo {
int next;
int adr;
int afl;
int lab;
} relocateInfo;
typedef struct File {
int fmode;
int slen;
int relmode;
int old_abspc;
int base[SEG_MAX];
int len[SEG_MAX];
struct {
signed char *tmp;
unsigned long tmpz;
unsigned long tmpe;
} mn;
struct {
int *ulist;
int un;
int um;
} ud;
struct {
relocateInfo *rlist;
int mlist;
int nlist;
int first;
} rt;
struct {
relocateInfo *rlist;
int mlist;
int nlist;
int first;
} rd;
struct {
Fopt *olist;
int mlist;
int nlist;
} fo;
struct {
int hashindex[256];
Labtab *lt;
int lti;
int ltm;
} la;
} File;
extern File *afile;
#endif /* __XA65_XAH_H__ */

30
xa/src/xah2.h Normal file
View File

@ -0,0 +1,30 @@
/* 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_XAH2_H__
#define __XA65_XAH2_H__
typedef struct {
char *fname; /* fname[MAXLINE]; */
int fline;
int bdepth;
FILE *filep;
char *flinep;
} Datei;
#endif /* __XA65_XAH2_H__ */

595
xa/src/xal.c Normal file
View File

@ -0,0 +1,595 @@
/* xa65 - 65xx/65816 cross-assembler and utility suite
*
* Copyright (C) 1989-1997 André Fachat (a.fachat@physik.tu-chemnitz.de)
*
* Label management module (also see xau.c)
*
* 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.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
/* structs and defs */
#include "xad.h"
#include "xah.h"
#include "xar.h"
#include "xah2.h"
#include "xap.h"
#include "xa.h"
/* externals */
#include "xam.h"
#include "xal.h"
/* exported globals */
char *lz;
/* local prototypes */
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);
/* local variables */
/*
static int hashindex[256];
static Labtab *lt = NULL;
static int lti = 0;
static int ltm = 0;
*/
/*
static char *ln;
static unsigned long lni;
static long sl;
*/
static Labtab *ltp;
int l_init(void)
{
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)
{
return(afile->la.lti);
}
int gm_lab(void)
{
return(ANZLAB);
}
long gm_labm(void)
{
return((long)LABMEM);
}
long ga_labm(void)
{
return(0 /*lni*/);
}
void printllist(fp)
FILE *fp;
{
int i;
LabOcc *p;
char *fname = NULL;
for(i=0;i<afile->la.lti;i++)
{
ltp=afile->la.lt+i;
fprintf(fp,"%s, 0x%04x, %d, 0x%04x\n",ltp->n,ltp->val,ltp->blk,
ltp->afl);
p = ltp->occlist;
if(p) {
while(p) {
if(fname != p->fname) {
if(p!=ltp->occlist) fprintf(fp,"\n");
fprintf(fp," %s",p->fname);
fname=p->fname;
}
fprintf(fp," %d", p->line);
p=p->next;
}
fprintf(fp,"\n");
}
fname=NULL;
}
}
int lg_set(char *s ) {
int n, er;
er = ll_search(s,&n);
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;
}
}
return er;
}
int l_def(char *s, int *l, int *x, int *f)
{
int n,er,b,i=0;
*f=0;
b=0;
n=0;
if(s[0]=='-')
{
*f+=1;
i++;
} else
if(s[0]=='+')
{
i++;
n++;
b=0;
}
while(s[i]=='&')
{
n=0;
i++;
b++;
}
if(!n)
b_fget(&b,b);
if(!isalpha(s[i]) && s[i]!='_')
er=E_SYNTAX;
else
{
er=ll_search(s+i,&n);
if(er==E_OK)
{
ltp=afile->la.lt+n;
if(*f)
{
*l=ltp->len+i;
} else
if(ltp->fl==0)
{
*l=ltp->len+i;
if(b_ltest(ltp->blk,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) */
{
ltp=afile->la.lt+n;
*l=ltp->len+i;
ltp->fl=0;
}
}
*x=n;
}
return(er);
}
int l_search(char *s, int *l, int *x, int *v, int *afl)
{
int n,er,b;
*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);*/
if(er==E_OK)
{
ltp=afile->la.lt+n;
*l=ltp->len;
if(ltp->fl == 1)
{
l_get(n,v,afl);/* *v=lt[n].val;*/
*x=n;
} else
{
er=E_NODEF;
lz=ltp->n;
*x=n;
}
}
else
{
b_get(&b);
er=ll_def(s,x,b); /* ll_def(...,*v); */
ltp=afile->la.lt+(*x);
*l=ltp->len;
if(!er)
{
er=E_NODEF;
lz=ltp->n;
}
}
return(er);
}
int l_vget(int n, int *v, char **s)
{
ltp=afile->la.lt+n;
(*v)=ltp->val;
*s=ltp->n;
return 0;
}
void l_addocc(int n, int *v, int *afl) {
LabOcc *p, *pp;
(void)v; /* quench warning */
(void)afl; /* quench warning */
ltp = afile->la.lt+n;
pp=NULL;
p = ltp->occlist;
while(p) {
if (p->line == filep->fline && p->fname == filep->fname) return;
pp = p;
p = p->next;
}
p = malloc(sizeof(LabOcc));
if(!p) {
fprintf(stderr,"Oops, out of memory!\n");
exit(1);
}
p->next = NULL;
p->line = filep->fline;
p->fname = filep->fname;
if(pp) {
pp->next = p;
} else {
ltp->occlist = p;
}
}
int l_get(int n, int *v, int *afl)
{
if(crossref) l_addocc(n,v,afl);
ltp=afile->la.lt+n;
(*v)=ltp->val;
lz=ltp->n;
*afl = ltp->afl;
/*printf("l_get('%s'(%d), v=$%04x, afl=%d, fl=%d\n",ltp->n, n, *v, *afl, ltp->fl);*/
return( (ltp->fl==1) ? E_OK : E_NODEF);
}
void l_set(int n, int v, int afl)
{
ltp=afile->la.lt+n;
ltp->val = v;
ltp->fl = 1;
ltp->afl = afl;
/*printf("l_set('%s'(%d), v=$%04x, afl=%d\n",ltp->n, n, v, afl);*/
}
static void ll_exblk(int a, int b)
{
int i;
for (i=0;i<afile->la.lti;i++)
{
ltp=afile->la.lt+i;
if((!ltp->fl) && (ltp->blk==a))
ltp->blk=b;
}
}
static int ll_def(char *s, int *n, int b) /* definiert naechstes Label nr->n */
{
int j=0,er=E_NOMEM,hash;
char *s2;
/*printf("ll_def: s=%s\n",s); */
if(!afile->la.lt) {
afile->la.lti = 0;
afile->la.ltm = 1000;
afile->la.lt = malloc(afile->la.ltm * sizeof(Labtab));
}
if(afile->la.lti>=afile->la.ltm) {
afile->la.ltm *= 1.5;
afile->la.lt = realloc(afile->la.lt, afile->la.ltm * sizeof(Labtab));
}
if(!afile->la.lt) {
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) {
fprintf(stderr,"Oops: no memory!\n");
exit(1);
}
strncpy(s2,s,j);
s2[j]=0;
/*
if(j<MAXLAB)
{
*/
er=E_OK;
ltp->len=j;
ltp->n = s2;
ltp->blk=b;
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);*/
return(er);
}
int ll_search(char *s, int *n) /* search Label in Tabelle ,nr->n */
{
int i,j=0,k,er=E_NODEF,hash;
while(s[j] && (isalnum(s[j])||(s[j]=='_'))) j++;
hash=hashcode(s,j);
i=afile->la.hashindex[hash];
/*printf("search?\n");*/
if(i>=afile->la.ltm) return E_NODEF;
do
{
ltp=afile->la.lt+i;
if(j==ltp->len)
{
for (k=0;(k<j)&&(ltp->n[k]==s[k]);k++);
if((j==k)&&(!b_test(ltp->blk)))
{
er=E_OK;
break;
}
}
if(!i)
break;
i=ltp->nextindex;
}while(1);
*n=i;
#if 0
if(er!=E_OK && er!=E_NODEF)
{
fprintf(stderr, "Fehler in ll_search:er=%d\n",er);
getchar();
}
#endif
return(er);
}
int ll_pdef(char *t)
{
int n;
if(ll_search(t,&n)==E_OK)
{
ltp=afile->la.lt+n;
if(ltp->fl)
return(E_OK);
}
return(E_NODEF);
}
int l_write(FILE *fp)
{
int i, afl, n=0;
if(noglob) {
fputc(0, fp);
fputc(0, fp);
return 0;
}
for (i=0;i<afile->la.lti;i++) {
ltp=afile->la.lt+i;
if((!ltp->blk) && (ltp->fl==1)) {
n++;
}
}
fputc(n&255, fp);
fputc((n>>8)&255, fp);
for (i=0;i<afile->la.lti;i++)
{
ltp=afile->la.lt+i;
if((!ltp->blk) && (ltp->fl==1)) {
fprintf(fp, "%s",ltp->n);
fputc(0,fp);
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;
fputc(afl,fp);
fputc(ltp->val&255, fp);
fputc((ltp->val>>8)&255, fp);
}
}
/*fputc(0,fp);*/
return 0;
}
static int bt[MAXBLK];
static int blk;
static int bi;
int b_init(void)
{
blk =0;
bi =0;
bt[bi]=blk;
return(E_OK);
}
int b_depth(void)
{
return bi;
}
int ga_blk(void)
{
return(blk);
}
int b_open(void)
{
int er=E_BLKOVR;
if(bi<MAXBLK-1)
{
bt[++bi]=++blk;
er=E_OK;
}
return(er);
}
int b_close(void)
{
if(bi)
{
ll_exblk(bt[bi],bt[bi-1]);
bi--;
} else {
return E_BLOCK;
}
return(E_OK);
}
static int b_get(int *n)
{
*n=bt[bi];
return(E_OK);
}
static int b_fget(int *n, int i)
{
if((bi-i)>=0)
*n=bt[bi-i];
else
*n=0;
return(E_OK);
}
static int b_test(int n)
{
int i=bi;
while( i>=0 && n!=bt[i] )
i--;
return( i+1 ? E_OK : E_NOBLK );
}
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;
if(a!=b)
{
er=E_OK;
while(i<=bi && b!=bt[i])
{
if(bt[i]==a)
{
er=E_NOBLK;
break;
}
i++;
}
}
return(er);
}

53
xa/src/xal.h Normal file
View File

@ -0,0 +1,53 @@
/* 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_XAL_H__
#define __XA65_XAL_H__
#include <stdio.h> /* for FILE */
extern char *lz;
int l_init(void);
int ga_lab(void);
int gm_lab(void);
long gm_labm(void);
long ga_labm(void);
int lg_set(char *);
int b_init(void);
int b_depth(void);
void printllist(FILE *fp);
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);
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_pdef(char *t);
int b_open(void);
int b_close(void);
int l_write(FILE *fp);
#endif /* __XA65_XAL_H__ */

188
xa/src/xam.c Normal file
View File

@ -0,0 +1,188 @@
/* xa65 - 65xx/65816 cross-assembler and utility suite
*
* Copyright (C) 1989-1997 André Fachat (a.fachat@physik.tu-chemnitz.de)
*
* Memory manager/malloc() stub module
*
* 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.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "xah.h" /* structs */
static int ninc = 0;
static char **nip = NULL;
void reg_include(char *path) {
char **nip2;
if(path && *path) {
nip2 = realloc(nip,sizeof(char*)*(ninc+1));
if(nip2) {
nip = nip2;
nip[ninc++] = path;
} else {
fprintf(stderr,"Warning: couldn' alloc mem (reg_include)\n");
}
}
}
FILE *xfopen(const char *fn,const char *mode)
{
FILE *file;
char c,*cp,n[MAXLINE],path[MAXLINE];
char xname[MAXLINE], n2[MAXLINE];
int i,l=(int)strlen(fn);
if(l>=MAXLINE) {
fprintf(stderr,"filename '%s' too long!\n",fn);
return NULL;
}
for(i=0;i<l+1;i++) {
xname[i]=((fn[i]=='\\')?DIRCHAR:fn[i]);
}
if(mode[0]=='r')
{
if((file=fopen(fn,mode))==NULL
&& (file=fopen(xname, mode))==NULL) {
for(i=0;(!file) && (i<ninc);i++) {
strcpy(n,nip[i]);
c=n[(int)strlen(n)-1];
if(c!=DIRCHAR) strcat(n,DIRCSTRING);
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);
}
if((!file) && (cp=getenv("XAINPUT"))!=NULL)
{
strcpy(path,cp);
cp=strtok(path,",");
while(cp && !file)
{
if(cp[0])
{
strcpy(n,cp);
c=n[(int)strlen(n)-1];
if(c!=DIRCHAR&&c!=':')
strcat(n,DIRCSTRING);
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);
}
cp=strtok(NULL,",");
}
}
}
} else
{
if((cp=getenv("XAOUTPUT"))!=NULL)
{
strcpy(n,cp);
if(n[0])
{
c=n[(int)strlen(n)-1];
if(c!=DIRCHAR&&c!=':')
strcat(n,DIRCSTRING);
}
cp=strrchr(fn,DIRCHAR);
if(!cp)
{
cp=strrchr(fn,':');
if(!cp)
cp=(char*)fn;
else
cp++;
} else
cp++;
strcat(n,cp);
file=fopen(n,mode);
} else
file=fopen(fn,mode);
}
if(file)
setvbuf(file,NULL,_IOFBF,BUFSIZE);
return(file);
}
#if 0
static char *m_base;
static char *m_act;
static char *m_end;
int m_init(void)
{
int er=E_NOMEM;
m_base=m_end=m_act=0L;
/*
fprintf(stderr, "MEMLEN=%ld\n",MEMLEN);
getchar();
*/
/*
if ((m_base=(char*)malloc(MEMLEN))!=NULL)
{
m_end =m_base+MEMLEN;
m_act =(char*)(((long)m_base+3)&0xfffffffcl);
er=E_OK;
}
else m_base=NULL;
*/
er=E_OK;
return(er);
}
void m_exit(void)
{
/*
free(m_base);
*/
}
int m_alloc(long n, char **adr)
{
int er=E_NOMEM;
if((*adr=calloc(n,1))) {
er=E_OK;
}
/*
if(m_act+n<m_end)
{
*adr=m_act;
m_act=m_act+n;
er=E_OK;
}
*/
/*
fprintf(stderr, "m_alloc n=%ld adr=%lx\n",n,*adr);
getchar();
*/
return(er);
}
#endif

25
xa/src/xam.h Normal file
View File

@ -0,0 +1,25 @@
/* 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_XAM_H__
#define __XA65_XAM_H__
FILE *xfopen(const char *fn, const char *mode);
void reg_include(char *);
#endif /* __XA65_XAM_H__ */

102
xa/src/xao.c Normal file
View File

@ -0,0 +1,102 @@
/* xa65 - 65xx/65816 cross-assembler and utility suite
*
* Copyright (C) 1989-1997 André Fachat (a.fachat@physik.tu-chemnitz.de)
*
* Options module (handles pass options and writing them out to disk)
*
* 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.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "xah.h"
#include "xar.h"
#include "xa.h"
#include "xat.h"
#include "xao.h"
/*
static Fopt *olist =NULL;
static int mlist =0;
static int nlist =0;
*/
/* sets file option after pass 1 */
void set_fopt(int l, signed char *buf, int reallen) {
/*printf("set_fopt(%s, l=%d\n",buf,l);*/
while(afile->fo.mlist<=afile->fo.nlist) {
afile->fo.mlist +=5;
afile->fo.olist = realloc(afile->fo.olist, afile->fo.mlist*sizeof(Fopt));
if(!afile->fo.olist) {
fprintf(stderr, "Fatal: Couldn't alloc memory (%lu bytes) for fopt list!\n",
(unsigned long)(
afile->fo.mlist*sizeof(Fopt)));
exit(1);
}
}
afile->fo.olist[afile->fo.nlist].text=malloc(l);
if(!afile->fo.olist[afile->fo.nlist].text) {
fprintf(stderr, "Fatal: Couldn't alloc memory (%d bytes) for fopt!\n",l);
exit(1);
}
memcpy(afile->fo.olist[afile->fo.nlist].text, buf, l);
afile->fo.olist[afile->fo.nlist++].len = reallen;
}
/* writes file options to a file */
void o_write(FILE *fp) {
int i,j,l,afl;
signed char *t;
for(i=0;i<afile->fo.nlist;i++) {
l=afile->fo.olist[i].len;
t=afile->fo.olist[i].text;
/* do not optimize */
t_p2(t, &l, 1, &afl);
if(l>254) {
errout(E_OPTLEN);
} else {
fputc((l+1)&0xff,fp);
}
for(j=0;j<l;j++) {
fputc(t[j],fp);
/*printf("%02x ", t[j]); */
}
/*printf("\n");*/
}
fputc(0,fp); /* end option list */
for(i=0;i<afile->fo.nlist;i++) {
free(afile->fo.olist[i].text);
}
free(afile->fo.olist);
afile->fo.olist = NULL;
afile->fo.nlist = 0;
afile->fo.mlist = 0;
}
size_t o_length(void) {
int i;
size_t n = 0;
for(i=0;i<afile->fo.nlist;i++) {
/*printf("found option: %s, len=%d, n=%d\n", afile->fo.olist[i].text, afile->fo.olist[i].len,n);*/
n += afile->fo.olist[i].len +1;
}
return ++n;
}

31
xa/src/xao.h Normal file
View File

@ -0,0 +1,31 @@
/* 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_XAO_H__
#define __XA65_XAO_H__
/* sets file option after pass 1 */
void set_fopt(int l, signed char *buf, int reallen);
/* writes file options to a file */
void o_write(FILE *fp);
/* return overall length of header options */
size_t o_length(void);
#endif /* __XA65_XAO_H__ */

1020
xa/src/xap.c Normal file

File diff suppressed because it is too large Load Diff

41
xa/src/xap.h Normal file
View File

@ -0,0 +1,41 @@
/* 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_XAP_H__
#define __XA65_XAP_H__
#include "xah2.h" /* for Datei */
int pp_comand(char *t);
int pp_init(void);
int pp_open(char *name);
int pp_define(char *name);
void pp_close(void);
void pp_end(void);
int pgetline(char *t);
Datei *pp_getidat(void);
int ga_pp(void);
int gm_pp(void);
long gm_ppm(void);
long ga_ppm(void);
Datei *filep;
char s[MAXLINE];
#endif /* __XA65_XAP_H__ */

284
xa/src/xar.c Normal file
View File

@ -0,0 +1,284 @@
/* xa65 - 65xx/65816 cross-assembler and utility suite
*
* Copyright (C) 1989-1997 André Fachat (a.fachat@physik.tu-chemnitz.de)
*
* Relocation module (for relocatable objects)
*
* 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.
*/
#include <stdio.h>
#include <stdlib.h>
#include "xad.h"
#include "xah.h"
#include "xar.h"
#include "xa.h"
#include "xal.h"
#include "xao.h"
#include "xau.h"
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))
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;
}
void r_mode(int m) {
static int old_segment = SEG_TEXT;
/*printf("setting mode to %s\n",(m==RMODE_RELOC)?"reloc":"abs");*/
if(rmode!=m) {
if(m==RMODE_RELOC) {
segment = old_segment;
} else { /* absolute mode */
old_segment = segment;
segment = SEG_ABS;
}
}
rmode = m;
}
int rt_set(int pc, int afl, int l, int lab) {
int p,pp;
if(!rmode) return 0;
/*printf("set relocation @$%04x, l=%d, afl=%04x\n",pc, l, afl);*/
if(l==2 && ((afl & A_MASK)!=A_ADR)) {
errout(W_BYTRELOC);
/*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)) {
/*printf("afl=%04x\n",afl);*/
errout(W_ADRRELOC);
}
/*printf("Warning: cutting address relocation in byte value at PC=$%04x!\n",pc);*/
afl = (afl & (~A_MASK)) | A_LOW;
}
if(afile->rt.nlist>=afile->rt.mlist) {
afile->rt.mlist+=500;
afile->rt.rlist=realloc(afile->rt.rlist, afile->rt.mlist*sizeof(relocateInfo));
}
if(!afile->rt.rlist) {
fprintf(stderr, "Oops: no memory for relocation table!\n");
exit(1);
}
afile->rt.rlist[afile->rt.nlist].adr = pc;
afile->rt.rlist[afile->rt.nlist].afl = afl;
afile->rt.rlist[afile->rt.nlist].lab = lab;
afile->rt.rlist[afile->rt.nlist].next= -1;
/* sorting this into the list is not optimized, to be honest... */
if(afile->rt.first<0) {
afile->rt.first = afile->rt.nlist;
} else {
p=afile->rt.first; pp=-1;
while(afile->rt.rlist[p].adr<pc && afile->rt.rlist[p].next>=0) {
pp=p;
p=afile->rt.rlist[p].next;
}
/*
printf("endloop: p=%d(%04x), pp=%d(%04x), nlist=%d(%04x)\n",
p,p<0?0:afile->rt.rlist[p].adr,pp,pp<0?0:afile->rt.rlist[pp].adr,afile->rt.nlist,afile->rt.nlist<0?0:afile->rt.rlist[afile->rt.nlist].adr);
*/
if(afile->rt.rlist[p].next<0 && afile->rt.rlist[p].adr<pc) {
afile->rt.rlist[p].next=afile->rt.nlist;
} else
if(pp==-1) {
afile->rt.rlist[afile->rt.nlist].next = afile->rt.first;
afile->rt.first = afile->rt.nlist;
} else {
afile->rt.rlist[afile->rt.nlist].next = p;
afile->rt.rlist[pp].next = afile->rt.nlist;
}
}
afile->rt.nlist++;
return 0;
}
int rt_write(FILE *fp, int pc) {
int p=afile->rt.first;
int pc2, afl;
while(p>=0) {
pc2=afile->rt.rlist[p].adr;
afl=afile->rt.rlist[p].afl;
/* hack to switch undef and abs flag from internal to file format */
if( ((afl & A_FMASK)>>8) < SEG_TEXT) afl^=0x100;
/*printf("rt_write: pc=%04x, pc2=%04x, afl=%x\n",pc,pc2,afl);*/
if((pc2-pc) < 0) {
fprintf(stderr, "Oops, negative offset!\n");
} else {
while((pc2-pc)>254) {
fputc(255,fp);
pc+=254;
}
fputc(pc2-pc, fp);
pc=pc2;
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);
}
p=afile->rt.rlist[p].next;
}
fputc(0, fp);
free(afile->rt.rlist);
afile->rt.rlist = NULL;
afile->rt.mlist = afile->rt.nlist = 0;
afile->rt.first = -1;
return 0;
}
void seg_start(int fmode, int t_base, int d_base, int b_base, int z_base,
int slen, int relmode) {
afile->fmode = fmode;
afile->slen = slen;
afile->relmode = relmode;
pc[SEG_TEXT] = afile->base[SEG_TEXT] = t_base;
pc[SEG_DATA] = afile->base[SEG_DATA] = d_base;
pc[SEG_BSS] = afile->base[SEG_BSS] = b_base;
pc[SEG_ZERO] = afile->base[SEG_ZERO] = z_base;
afile->old_abspc = pc[SEG_ABS];
pc[SEG_ABS] = pc[SEG_TEXT];
}
File *alloc_file(void) {
File *afile;
int i;
afile = malloc(sizeof(File));
if(!afile) {
fprintf(stderr,"Oops: not enough memory!\n");
exit(1);
}
afile->mn.tmp = malloc(TMPMEM);
if(!afile->mn.tmp) {
fprintf(stderr,"Oops: not enough memory!\n");
exit(1);
}
afile->mn.tmpz = 0;
afile->mn.tmpe = 0;
afile->ud.ulist = NULL; afile->ud.un = afile->ud.um = 0;
afile->rt.rlist = NULL; afile->rt.first = -1;
afile->rt.mlist = afile->rt.nlist = 0;
afile->rd.rlist = NULL; afile->rd.first = -1;
afile->rd.mlist = afile->rd.nlist = 0;
afile->fo.olist = NULL;
afile->fo.mlist = afile->fo.nlist = 0;
for(i=0;i<256;i++) afile->la.hashindex[i]=0;
afile->la.lt = NULL;
afile->la.lti = 0;
afile->la.ltm = 0;
afile->len[SEG_TEXT] = afile->len[SEG_DATA] =
afile->len[SEG_BSS] = afile->len[SEG_ZERO] = 0;
return afile;
}
void seg_pass2(void) {
pc[SEG_TEXT] = afile->base[SEG_TEXT];
pc[SEG_DATA] = afile->base[SEG_DATA];
pc[SEG_BSS] = afile->base[SEG_BSS];
pc[SEG_ZERO] = afile->base[SEG_ZERO];
afile->old_abspc = pc[SEG_ABS];
pc[SEG_ABS] = pc[SEG_TEXT];
}
void seg_end(FILE *fpout) {
#if 0
afile->len[SEG_TEXT] = pc[SEG_TEXT] - afile->base[SEG_TEXT];
afile->len[SEG_DATA] = pc[SEG_DATA] - afile->base[SEG_DATA];
afile->len[SEG_BSS ] = pc[SEG_BSS ] - afile->base[SEG_BSS ];
afile->len[SEG_ZERO] = pc[SEG_ZERO] - afile->base[SEG_ZERO];
#endif
/* TODO: file length to embed */
/* pc[SEG_ABS] = afile->old_abspc + seg_flen();*/
/*printf("seg_end: len[text]=%d, len[data]=%d, len[bss]=%d, len[zero]=%d\n",
afile->len[SEG_TEXT], afile->len[SEG_DATA], afile->len[SEG_BSS], afile->len[SEG_ZERO]);*/
segment = SEG_ABS;
u_write(fpout);
rt_write(fpout, afile->base[SEG_TEXT]-1);
rd_write(fpout, afile->base[SEG_DATA]-1);
l_write(fpout);
}
/* write header for relocatable output format */
int h_write(FILE *fp, int mode, int tlen, int dlen, int blen, int zlen,
int stack) {
afile->len[SEG_TEXT] = tlen;
afile->len[SEG_DATA] = dlen;
afile->len[SEG_BSS ] = blen;
afile->len[SEG_ZERO] = 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(afile->base[SEG_TEXT],fp); /* text base */
fputw(tlen,fp); /* text length */
fputw(afile->base[SEG_DATA],fp); /* data base */
fputw(dlen,fp); /* data length */
fputw(afile->base[SEG_BSS],fp); /* bss base */
fputw(blen,fp); /* bss length */
fputw(afile->base[SEG_ZERO],fp); /* zerop base */
fputw(zlen,fp); /* zerop length */
fputw(stack,fp); /* needed stack size */
o_write(fp);
return 0;
}

48
xa/src/xar.h Normal file
View File

@ -0,0 +1,48 @@
/* 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_XAR_H__
#define __XA65_XAR_H__
#define RMODE_ABS 0
#define RMODE_RELOC 1
extern File *alloc_file(void);
/* jumps to r[td]_set, depending on segment */
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);
int rd_set(int pc, int reloc, int len, int label);
int rt_write(FILE *fp, int pc);
int rd_write(FILE *fp, int pc);
void r_mode(int mode);
/* int rmode; */
int h_write(FILE *fp, int mode, int tlen, int dlen, int blen, int zlen,
int stacklen);
void seg_start(int fmode, int tbase, int dbase, int bbase, int zbase,
int stacklen, int relmode);
void seg_end(FILE *);
void seg_pass2(void);
#endif /* __XA65_XAR_H__ */

132
xa/src/xar2.c Normal file
View File

@ -0,0 +1,132 @@
/* 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.
*/
#include <stdio.h>
#include <stdlib.h>
#include "xah.h"
#include "xa.h"
#include "xar.h"
/*
static relocateInfo *rlist = NULL;
static int mlist = 0, nlist = 0;
static int first = -1;
*/
/* int rmode; */
int rd_set(int pc, int afl, int l, int lab) {
int p,pp;
/* if(!rmode) return 0; */
/*printf("set relocation @$%04x, l=%d, afl=%04x\n",pc, l, afl);*/
if(l==2 && ((afl & A_MASK)!=A_ADR)) {
errout(W_BYTRELOC);
/*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)) errout(W_ADRRELOC);
/*printf("Warning: cutting address relocation in byte value at PC=$%04x!\n",pc);*/
afl = (afl & (~A_MASK)) | A_LOW;
}
if(afile->rd.nlist>=afile->rd.mlist) {
afile->rd.mlist+=500;
afile->rd.rlist=realloc(afile->rd.rlist, afile->rd.mlist*sizeof(relocateInfo));
}
if(!afile->rd.rlist) {
fprintf(stderr, "Oops: no memory for relocation table!\n");
exit(1);
}
afile->rd.rlist[afile->rd.nlist].adr = pc;
afile->rd.rlist[afile->rd.nlist].afl = afl;
afile->rd.rlist[afile->rd.nlist].lab = lab;
afile->rd.rlist[afile->rd.nlist].next= -1;
/* sorting this into the list is not optimized, to be honest... */
if(afile->rd.first<0) {
afile->rd.first = afile->rd.nlist;
} else {
p=afile->rd.first; pp=-1;
while(afile->rd.rlist[p].adr<pc && afile->rd.rlist[p].next>=0) {
pp=p;
p=afile->rd.rlist[p].next;
}
/*
printf("endloop: p=%d(%04x), pp=%d(%04x), nlist=%d(%04x)\n",
p,p<0?0:afile->rd.rlist[p].adr,pp,pp<0?0:afile->rd.rlist[pp].adr,afile->rd.nlist,afile->rd.nlist<0?0:afile->rd.rlist[afile->rd.nlist].adr);
*/
if(afile->rd.rlist[p].next<0 && afile->rd.rlist[p].adr<pc) {
afile->rd.rlist[p].next=afile->rd.nlist;
} else
if(pp==-1) {
afile->rd.rlist[afile->rd.nlist].next = afile->rd.first;
afile->rd.first = afile->rd.nlist;
} else {
afile->rd.rlist[afile->rd.nlist].next = p;
afile->rd.rlist[pp].next = afile->rd.nlist;
}
}
afile->rd.nlist++;
return 0;
}
int rd_write(FILE *fp, int pc) {
int p=afile->rd.first;
int pc2, afl;
while(p>=0) {
pc2=afile->rd.rlist[p].adr;
afl=afile->rd.rlist[p].afl;
/*printf("rd_write: pc=%04x, pc2=%04x, afl=%x\n",pc,pc2,afl);*/
/* hack to switch undef and abs flag from internal to file format */
if( ((afl & A_FMASK)>>8) < SEG_TEXT) afl^=0x100;
if((pc2-pc) < 0) {
fprintf(stderr, "Oops, negative offset!\n");
} else {
while((pc2-pc)>254) {
fputc(255,fp);
pc+=254;
}
fputc(pc2-pc, fp);
pc=pc2;
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;
}
fputc(0, fp);
free(afile->rd.rlist);
afile->rd.rlist = NULL;
afile->rd.mlist = afile->rd.nlist = 0;
afile->rd.first = -1;
return 0;
}

2097
xa/src/xat.c Normal file

File diff suppressed because it is too large Load Diff

28
xa/src/xat.h Normal file
View File

@ -0,0 +1,28 @@
/* 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_XAT_H__
#define __XA65_XAT_H__
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 b_term(char *s, int *v, int *l, int pc);
#endif /* __XA65_XAT_H__ */

73
xa/src/xau.c Normal file
View File

@ -0,0 +1,73 @@
/* xa65 - 65xx/65816 cross-assembler and utility suite
*
* Copyright (C) 1989-1997 André Fachat (a.fachat@physik.tu-chemnitz.de)
*
* Undefined label tracking module (also see xal.c)
*
* 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.
*/
#include <stdio.h>
#include <stdlib.h>
#include "xad.h"
#include "xau.h"
#include "xah.h"
#include "xal.h"
/*
static int *ulist = NULL;
static int un = 0;
static int um = 0;
*/
int u_label(int labnr) {
int i;
/*printf("u_label: %d\n",labnr);*/
if(!afile->ud.ulist) {
afile->ud.ulist = malloc(200*sizeof(int));
if(afile->ud.ulist) afile->ud.um=200;
}
for(i=0;i<afile->ud.un;i++) {
if(afile->ud.ulist[i] == labnr) return i;
}
if(afile->ud.un>=afile->ud.um) {
afile->ud.um *= 1.5;
afile->ud.ulist = realloc(afile->ud.ulist, afile->ud.um * sizeof(int));
if(!afile->ud.ulist) {
fprintf(stderr, "Panic: No memory!\n");
exit(1);
}
}
afile->ud.ulist[afile->ud.un] = labnr;
return afile->ud.un++;
}
void u_write(FILE *fp) {
int i, d;
char *s;
/*printf("u_write: un=%d\n",afile->ud.un);*/
fputw(afile->ud.un, fp);
for(i=0;i<afile->ud.un;i++) {
l_vget(afile->ud.ulist[i], &d, &s);
fprintf(fp,"%s", s);
fputc(0,fp);
}
free(afile->ud.ulist);
afile->ud.ulist=NULL;
afile->ud.um = afile->ud.un = 0;
}

24
xa/src/xau.h Normal file
View File

@ -0,0 +1,24 @@
/*
xa65 - 6502 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.
*/
extern int u_label(int labnr);
extern void u_write(FILE *fp);

24
xa/tests/README Normal file
View File

@ -0,0 +1,24 @@
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.
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
relocundef/ Tests for the detection of undefined references during a
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
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
binclude/ Binary include code with some weird casing
chppch/ Changing preprocessor characters (-p)
charset/ Tests of when charsets should be honoured and when not
Cameron Kaiser, André Fachat

33
xa/tests/adrm/02.asm Normal file
View File

@ -0,0 +1,33 @@
.word $0400
* = $0400
q = $0005
fizz
/* these should be optimized to zero page */
sta $05
sta $0005
sta q
dec q
inc q
lda <$0005
/* these should not */
stx !$0005
sta !q
sta $8765
stx $919c
inc !q
dec $8342
sta $4431
inc $79e0
sty $1b0a
jsr $ffe4
jmp $fce2
jmp breadbox
lsr $2020
bne fizz
rts
breadbox rts
beq fizz
rts

29
xa/tests/adrm/816.asm Normal file
View File

@ -0,0 +1,29 @@
.word $0400
* = $0400
q = $0005
r = $000005
fizz
/* these should be optimized to zero page */
sta $05
sta $0005
sta q
sta r
/* 16-bit */
sta !$0005
sta !q
sta $8765
/* 24-bit */
sta @q
sta @$000005
sta $876543
rts
jmp $fce2
jmp $99fce2
jmp breadbox
jmp @breadbox
breadbox rts
bne fizz
rts

BIN
xa/tests/adrm/a.o65 Normal file

Binary file not shown.

28
xa/tests/adrm/bip.inc Normal file
View File

@ -0,0 +1,28 @@
/*
- tbasic.0.asm: if you make vecwri absolute with !, then the branch gets
generated as if it were NOT absolute. works okay without it (and
gets a warning)
*/
test lda !$0095
bne test
ldx #13
lup0 lda @vecwri,x
sta $2005,x
dex
bne lup0
lda #$00
sta $0020
lda #$02
sta $0021
lda #$ff
sta $0022
lda #$13
sta $0023
jmp $2003
vectors .byt $4c, $5a, $1e, $4c, $a0, $1e, $4c, $00, $01
vecwri = vectors - 1

33
xa/tests/adrm/c02.asm Normal file
View File

@ -0,0 +1,33 @@
.word $0400
* = $0400
q = $0005
fizz
/* these should be optimized to zero page */
sta $05
sta $0005
sta q
dec q
inc q
/* these should not */
stx !$0005
sta !q
sta $8765
stx $919c
inc !q
inc; a
dec $8342
dec; a
sta $4431
inc $79e0
sty $1b0a
jsr $ffe4
jmp $fce2
jmp breadbox
lsr $2020
rts
breadbox rts
bne fizz
rts

4
xa/tests/adrm/zab.asm Normal file
View File

@ -0,0 +1,4 @@
.word $4000
* = $4000
#include "bip.inc"

4
xa/tests/adrm/zpa.asm Normal file
View File

@ -0,0 +1,4 @@
.word $0000
* = $0000
#include "bip.inc"

View File

@ -0,0 +1,117 @@
This is the readme for xa, a cross-assembler for the 6502 and 65816 CPUs (and
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.3, which implements several compatibility
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.
To install on a generic Unixy thing, you should be able to just type
% make # to build the executable, and if it works ...
% 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.
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).
xa is no longer broadly supported outside of Unix due to my inability to test
it, but has nothing that should impair it from compiling elsewhere. To wit,
DOS compilation is still supported with the GO32 package. You should just be
able to type
C:\> make dos
In addition, there are compatibility updates to allow it to compile under
Microsoft Visual Studio and mingw. It should compile under VS2005 as written;
look in the vstudio directory for solution and project files provided by
Fabian Nunez. For mingw, use
make mingw
Similarly, Amiga and Atari ST compilation should still also function with
their particular compatible packages.
xa has a companion disassembler, the dxa package. dxa is not included in the
standard xa distribution, but can be downloaded from the xa home page at
http://www.floodgap.com/retrotech/xa/
Please check by periodically for the latest version of both packages.
xa was originally written and maintained by Andre Fachat. The current version
is maintained by Cameron Kaiser.
Please send me your comments at ckaiser@floodgap.com -- Andre's original
readme follows and applies generally to the present version.
-------------------------------------------------------------------------------
XA is a 6502 cross compiler:
- under GNU public license
- can produce _relocatable_ binaries
- The full fileformat description and 6502 file loader included.
- also included relocation and info utilites, as well as linker
- for any ANSI-C compliant computer (only utilities need 'stat' call
for file size).
- fast by hashtables
- Rockwell CMOS opcodes
- running under DOS and any ANSI C system (Unix, Amiga, Atari ST)
I developed this cross assembler for the 6502 CPU family quite some time
ago on my Atari ST. The assembler has successfully been ported to Amiga
and Unix computer (ported? just compiled... :-)
Lately I came across the problem to need relocatable 6502 binary files, so
I revised the assembler from version 2.0.7 to 2.1.0, adding a (admittedly
proprietary) 6502 relocatable binary format. But there are not many other
formats around and they didn't fit my needs. I have developed this format
myself and it is under the GNU public license.
With version 2.1.1 the 'official' version of the fileformat is supported.
To compile it, just type "make" (if you have the GNU gcc. If not, edit the
Makefile for the compiler options). This produces "xa", the cross assembler;
"uncpk", a small packing utility (where the C64 counterpart is in the
examples subdirectory), "printcbm", that lists C64 BASIC files and
'file65' that prints some information about o65 files. The "loader" in
the loader subdirectory is a basic 6502 implementation of a relocating
binary loader.
"file65" prints file information on 'o65' relocatable files. "reloc65"
can relocate 'o65' files.
If you want to use it under DOS, you have to have the GO32 DOS crosscompiling
tools to compile. Then just type "make dos" and you'll end up with the
appropriate DOS binaries. This has been tested only under i386 Linux, however.
Another archive with the DOS binaries included is provided.
One problem on the Atari was it's broken "malloc". Therefore I used to
alloc everything in one chunk and divide the memory by hand. So everything
was kind of statically allocated. This is almost gone now. Only the
temporary storage between pass1 and pass2 and the preprocessor are still
allocated in one chunk (size definitions in xah.h). The rest is allocated
as needed.
The docs are in the 'doc' subdir. There also is a description of the
6502 relocatable binary format. If you think some things could be
expressed in a better way, feel free and mail me to improve my english ;-)
[ The documentation is now maintained in man(1) format in man/ . -- CK ]
Andre

View File

@ -0,0 +1,19 @@
.word $9000
* = $9000
w = 10
glorb
.dsb 9,10 ; +9
.byt 6, 6, 6, "devil", 'Q' ; +9 => 18
.bin 0,5,'README.1st' ; +5 => 23
.bin w,w+256,'README.1st' ; +266 => 289 ($0121)
gleeb
; $0123
jmp glorb
; should be $9121 (remember the SA)
jmp gleeb
bne *

View File

@ -0,0 +1,18 @@
.word $9000
* = $9000
w = 10
glorb
.dsb 9,10
.byt 6, 6, 6, "devil", 'Q'
.bin 0,109,'README.1st'
.bin w,w+119,'README.1st'
gleeb
jmp glorb
jmp gleeb
bne *

View File

@ -0,0 +1 @@
©A©A1234512345"''"

View File

@ -0,0 +1,16 @@
*=$033c
lda #"A"
lda #'A'
.asc "12345"
.asc '12345'
.asc "^"" ; ^ is escape character
.asc '^''
.asc "'"
.asc '"'
.asc "^1"

116
xa/tests/charset/README.1st Normal file
View File

@ -0,0 +1,116 @@
This is the readme for xa, a cross-assembler for the 6502 and 65816 CPUs (and
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.
To install on a generic Unixy thing, you should be able to just type
% make # to build the executable, and if it works ...
% 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.
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).
xa is no longer broadly supported outside of Unix due to my inability to test
it, but has nothing that should impair it from compiling elsewhere. To wit,
DOS compilation is still supported with the GO32 package. You should just be
able to type
C:\> make dos
In addition, there are compatibility updates to allow it to compile under
Microsoft Visual Studio and mingw. It should compile under VS2005 as written;
look in the vstudio directory for solution and project files provided by
Fabian Nunez. For mingw, use
make mingw
Similarly, Amiga and Atari ST compilation should still also function with
their particular compatible packages.
xa has a companion disassembler, the dxa package. dxa is not included in the
standard xa distribution, but can be downloaded from the xa home page at
http://www.floodgap.com/retrotech/xa/
Please check by periodically for the latest version of both packages.
xa was originally written and maintained by Andre Fachat. The current version
is maintained by Cameron Kaiser.
Please send me your comments at ckaiser@floodgap.com -- Andre's original
readme follows and applies generally to the present version.
-------------------------------------------------------------------------------
XA is a 6502 cross compiler:
- under GNU public license
- can produce _relocatable_ binaries
- The full fileformat description and 6502 file loader included.
- also included relocation and info utilites, as well as linker
- for any ANSI-C compliant computer (only utilities need 'stat' call
for file size).
- fast by hashtables
- Rockwell CMOS opcodes
- running under DOS and any ANSI C system (Unix, Amiga, Atari ST)
I developed this cross assembler for the 6502 CPU family quite some time
ago on my Atari ST. The assembler has successfully been ported to Amiga
and Unix computer (ported? just compiled... :-)
Lately I came across the problem to need relocatable 6502 binary files, so
I revised the assembler from version 2.0.7 to 2.1.0, adding a (admittedly
proprietary) 6502 relocatable binary format. But there are not many other
formats around and they didn't fit my needs. I have developed this format
myself and it is under the GNU public license.
With version 2.1.1 the 'official' version of the fileformat is supported.
To compile it, just type "make" (if you have the GNU gcc. If not, edit the
Makefile for the compiler options). This produces "xa", the cross assembler;
"uncpk", a small packing utility (where the C64 counterpart is in the
examples subdirectory), "printcbm", that lists C64 BASIC files and
'file65' that prints some information about o65 files. The "loader" in
the loader subdirectory is a basic 6502 implementation of a relocating
binary loader.
"file65" prints file information on 'o65' relocatable files. "reloc65"
can relocate 'o65' files.
If you want to use it under DOS, you have to have the GO32 DOS crosscompiling
tools to compile. Then just type "make dos" and you'll end up with the
appropriate DOS binaries. This has been tested only under i386 Linux, however.
Another archive with the DOS binaries included is provided.
One problem on the Atari was it's broken "malloc". Therefore I used to
alloc everything in one chunk and divide the memory by hand. So everything
was kind of statically allocated. This is almost gone now. Only the
temporary storage between pass1 and pass2 and the preprocessor are still
allocated in one chunk (size definitions in xah.h). The rest is allocated
as needed.
The docs are in the 'doc' subdir. There also is a description of the
6502 relocatable binary format. If you think some things could be
expressed in a better way, feel free and mail me to improve my english ;-)
[ The documentation is now maintained in man(1) format in man/ . -- CK ]
Andre

BIN
xa/tests/charset/a.o65 Normal file

Binary file not shown.

16
xa/tests/charset/test.asm Normal file
View File

@ -0,0 +1,16 @@
.word $9000
* = $9000
w = 10
.bin 0,10+w,"README.1st"
.bin 0,10,"README.1st"
#include "test2.s"
.byt "FooBar"
.aasc "FooBar"
.asc "FooBar",65,97,10
.aasc "FooBar"
.bin 0,10,"README.1st"
.aasc "Barfoo",65,97,10
lda #'A'
lda #"A"

1
xa/tests/charset/test2.s Normal file
View File

@ -0,0 +1 @@
.aasc "test2"

1
xa/tests/chppch/a.o65 Normal file
View File

@ -0,0 +1 @@
`

4
xa/tests/chppch/qwerty.h Normal file
View File

@ -0,0 +1,4 @@
rts
#print 12+12
~print 10+10

3
xa/tests/chppch/test.c Normal file
View File

@ -0,0 +1,3 @@
#include "qwerty.h"
~print 5+5

10
xa/tests/chppch/test.out Normal file
View File

@ -0,0 +1,10 @@
# 1 "test.c"
# 1 "qwerty.h" 1
rts
#print 12+12
~print 10+10
# 1 "test.c" 2
~print 5+5

BIN
xa/tests/comcom/a.o65 Normal file

Binary file not shown.

View File

@ -0,0 +1,18 @@
.word $c000
* = $c000
lda #147
; depending on the -M option:lda #65
jsr $ffd2:rts ; maybe some stuff out here:tay
; there will be:cli
; extra code:sei
; or not:rti
; let's ; be ; tricky : ; does it ; work? :nop:nop: ; let's see! ; rts
/* hey,
; what about
now?
: brk */
// do I make you sexy? ; :brk
rti

View File

@ -0,0 +1,5 @@
; some comment: *2 = 1
start
lda #1: sta 2

3
xa/tests/cpp/Makefile Normal file
View File

@ -0,0 +1,3 @@
default:
cc -E over.c > over.asm
../../xa over.asm

32
xa/tests/cpp/over.asm Normal file
View File

@ -0,0 +1,32 @@
# 1 "over.c"
lda #1
jmp buggy
rts
# 1 "over.h" 1
fuzz lda #5
sta $0400
bne fuzz
rts
lda @$c0c0c0
# 17 "over.c" 2

19
xa/tests/cpp/over.c Normal file
View File

@ -0,0 +1,19 @@
/* #define BUG */
#ifdef BUG
#define WW AA
#define AA WW
#else
#define CC 1
#define WW CC
#define AA WW
#endif
/* This has a .c extension for those cc -E's that won't deal with .asm */
lda #AA
jmp buggy
rts
#include "over.h"
/* the buggy will force a line number to be printed */

10
xa/tests/cpp/over.h Normal file
View File

@ -0,0 +1,10 @@
#define X W
#define W 5
fuzz lda #W
sta $0400
bne fuzz
rts
lda @$c0c0c0

BIN
xa/tests/fordef/a.o65 Normal file

Binary file not shown.

20
xa/tests/fordef/test.asm Normal file
View File

@ -0,0 +1,20 @@
.word $0400
* = $0400
/* this should generate optimizer warnings */
lda forward1
sta forward2
/* this shouldn't */
jmp forward3
/* and this won't */
t1 lda `forward1
sta `forward2
rts
#include "test2.asm"

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