mirror of https://github.com/fachat/xa65.git
added stable version 2.3.5
This commit is contained in:
parent
22345e4837
commit
ac0f09ba77
4
README
4
README
|
@ -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)
|
||||
|
||||
|
||||
|
|
|
@ -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.
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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)
|
|
@ -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.
|
||||
|
|
@ -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
|
||||
|
|
@ -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 >= 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.
|
||||
<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
|
||||
<< -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
|
||||
</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>
|
||||
< Gives the low byte of the expression
|
||||
> Gives the high byte
|
||||
|
||||
LDA #<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>
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
Binary file not shown.
|
@ -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
|
||||
|
|
@ -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.
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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.
|
||||
|
||||
|
||||
|
Binary file not shown.
Binary file not shown.
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
lda #label
|
||||
lab2
|
|
@ -0,0 +1,3 @@
|
|||
Also look at ../doc/ for previous documentation files and the Change log.
|
||||
|
||||
Cameron Kaiser
|
|
@ -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/
|
|
@ -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/
|
|
@ -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/
|
|
@ -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/
|
|
@ -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/
|
|
@ -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/
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
|
@ -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__ */
|
|
@ -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
|
||||
|
|
@ -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__ */
|
File diff suppressed because it is too large
Load Diff
|
@ -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__ */
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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__ */
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
@ -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__ */
|
||||
|
|
@ -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__ */
|
|
@ -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__ */
|
|
@ -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__ */
|
|
@ -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**)<)))
|
||||
er=m_alloc((long)LABMEM,&ln);*/
|
||||
|
||||
er=m_alloc((long)(sizeof(Labtab)*ANZLAB),(char**)<);
|
||||
|
||||
lti=0;
|
||||
/* lni=0L;*/
|
||||
|
||||
return(er);
|
||||
#endif
|
||||
}
|
||||
|
||||
int ga_lab(void)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
|
@ -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__ */
|
|
@ -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
|
|
@ -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__ */
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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__ */
|
File diff suppressed because it is too large
Load Diff
|
@ -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__ */
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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__ */
|
|
@ -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;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -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__ */
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
Binary file not shown.
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,4 @@
|
|||
.word $4000
|
||||
* = $4000
|
||||
|
||||
#include "bip.inc"
|
|
@ -0,0 +1,4 @@
|
|||
.word $0000
|
||||
* = $0000
|
||||
|
||||
#include "bip.inc"
|
|
@ -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
|
||||
|
|
@ -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 *
|
||||
|
|
@ -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 *
|
||||
|
|
@ -0,0 +1 @@
|
|||
©A©A1234512345"''"
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
*=$033c
|
||||
|
||||
lda #"A"
|
||||
lda #'A'
|
||||
|
||||
.asc "12345"
|
||||
.asc '12345'
|
||||
|
||||
.asc "^"" ; ^ is escape character
|
||||
.asc '^''
|
||||
.asc "'"
|
||||
.asc '"'
|
||||
|
||||
.asc "^1"
|
||||
|
|
@ -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
|
||||
|
Binary file not shown.
|
@ -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"
|
|
@ -0,0 +1 @@
|
|||
.aasc "test2"
|
|
@ -0,0 +1 @@
|
|||
`
|
|
@ -0,0 +1,4 @@
|
|||
rts
|
||||
|
||||
#print 12+12
|
||||
~print 10+10
|
|
@ -0,0 +1,3 @@
|
|||
#include "qwerty.h"
|
||||
|
||||
~print 5+5
|
|
@ -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
|
Binary file not shown.
|
@ -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
|
|
@ -0,0 +1,5 @@
|
|||
; some comment: *2 = 1
|
||||
|
||||
start
|
||||
lda #1: sta 2
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
default:
|
||||
cc -E over.c > over.asm
|
||||
../../xa over.asm
|
|
@ -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
|
||||
|
||||
|
||||
|
|
@ -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 */
|
|
@ -0,0 +1,10 @@
|
|||
|
||||
#define X W
|
||||
#define W 5
|
||||
|
||||
fuzz lda #W
|
||||
sta $0400
|
||||
bne fuzz
|
||||
rts
|
||||
|
||||
lda @$c0c0c0
|
Binary file not shown.
|
@ -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
Loading…
Reference in New Issue