diff --git a/README b/README index 7c5e089..426f5ca 100644 --- a/README +++ b/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) + diff --git a/xa/COPYING b/xa/COPYING new file mode 100644 index 0000000..2d44dcc --- /dev/null +++ b/xa/COPYING @@ -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. + + + Copyright (C) 20yy + + 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. + + , 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. diff --git a/xa/ChangeLog b/xa/ChangeLog new file mode 100644 index 0000000..a5eb775 --- /dev/null +++ b/xa/ChangeLog @@ -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 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 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 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 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 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 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 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 21 Dec, 1996 + +xa-2.1.1a + + * Embedding absolute code in relocatable seems to work now. + + -- André Fachat 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 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 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 03 Jan, 1997 + +xa-2.1.2 + + * Added ``ld65'', a simple linker for o65 files. + * Another bug in xa fixed now. + + -- André Fachat 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 25 Mar, 1997 + +xa-2.1.3e + + * Added preprocessor continuation lines, and .block and .bend + pseudo-opcodes (They map to ``.('' and ``.)'' respectively.) + + -- André Fachat 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 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 30 Dec, 1997 + +xa-2.1.4d + + * fixed align code. Now inserts NOP opcodes into text segment, and + sets file mode appropriately. + + -- André Fachat 26 Jan, 1998 + +xa-2.1.4e + + * Changed o65 fileformat and adopted it in xa. + + -- André Fachat 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 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 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 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 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 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 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 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 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 7 February, 2009 diff --git a/xa/Makefile b/xa/Makefile new file mode 100644 index 0000000..78ca224 --- /dev/null +++ b/xa/Makefile @@ -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 diff --git a/xa/README.1st b/xa/README.1st new file mode 100644 index 0000000..0c7994a --- /dev/null +++ b/xa/README.1st @@ -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 + diff --git a/xa/TODO b/xa/TODO new file mode 100644 index 0000000..0944889 --- /dev/null +++ b/xa/TODO @@ -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 diff --git a/xa/doc/README b/xa/doc/README new file mode 100644 index 0000000..8f9bf19 --- /dev/null +++ b/xa/doc/README @@ -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 diff --git a/xa/doc/fileformat.txt b/xa/doc/fileformat.txt new file mode 100644 index 0000000..6e5d3ab --- /dev/null +++ b/xa/doc/fileformat.txt @@ -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) diff --git a/xa/doc/xa-de.log b/xa/doc/xa-de.log new file mode 100644 index 0000000..71eee8e --- /dev/null +++ b/xa/doc/xa-de.log @@ -0,0 +1,89 @@ + +******** XASS65 1.0 ******** 15.11.89, Andre Fachat + +2-Pass-Assembler fr 65(C)02. von Rockwell. Der erste Pass berechnet +die Labels, im zweiten Pass wird assembliert. Es wird eine Block-Struktur +untersttzt, d.h. die Pseudo-Opcodes .( und .) verbergen dazwischenliegende +Labels vor Zugriffen aus anderen als darberliegenden Blocks. +Die Quell-, Object- und Fehlerdateien mssen 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 mssen. + +******** 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 fr 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 + +Fr Labels, Defines und die Opcodes wird die Suche nach Hashcode durchgefhrt. +damit werden ca. 350kByte Quelltext fr 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 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 untersttzt. +Falls die Quell- und Include-Dateien nicht gefunden werden, werden die in +XAINPUT aufgefhrten Pfade der Reihe nach durchgetestet. Falls XAOUTPUT +existiert, wird dieser Pfad als Pfad fr .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 unterdrckt, 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. + diff --git a/xa/doc/xa-de.txt b/xa/doc/xa-de.txt new file mode 100644 index 0000000..008846c --- /dev/null +++ b/xa/doc/xa-de.txt @@ -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, Rcksprungadresse 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 (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 # xa 2.1.4 6502 Cross Assembler + +
+

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 +
+ + diff --git a/xa/doc/xa.log b/xa/doc/xa.log new file mode 100644 index 0000000..8685448 --- /dev/null +++ b/xa/doc/xa.log @@ -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 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 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 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 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 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 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 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 21 Dec, 1996 + +xa-2.1.1a + + * Embedding absolute code in relocatable seems to work now. + + -- André Fachat 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 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 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 03 Jan, 1997 + +xa-2.1.2 + + * Added ``ld65'', a simple linker for o65 files. + * Another bug in xa fixed now. + + -- André Fachat 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 25 Mar, 1997 + +xa-2.1.3e + + * Added preprocessor continuation lines, and .block and .bend + pseudo-opcodes (They map to ``.('' and ``.)'' respectively.) + + -- André Fachat 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 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 30 Dec, 1997 + +xa-2.1.4d + + * fixed align code. Now inserts NOP opcodes into text segment, and + sets file mode appropriately. + + -- André Fachat 26 Jan, 1998 + +xa-2.1.4e + + * Changed o65 fileformat and adopted it in xa. + + -- André Fachat 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 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 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 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 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 23 Dec, 2006 + diff --git a/xa/doc/xa.txt b/xa/doc/xa.txt new file mode 100644 index 0000000..39cecaf --- /dev/null +++ b/xa/doc/xa.txt @@ -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 #a:jsr Txtout:.) +#define Aout(a) .(:lda #b:jsr Txtout:jmp c:b .byt a,0:c .) +#define Ibout(a) .(:ldx a:lda #0:jsr INTOUT:.) +#define Iout(a) .(:ldx a:lda a+1:jsr INTOUT:.) + +#define PFADLEN 40 +#define FN_WR 3 +#define FN_RD 4 +#define XCODE $f7 +#define Version 1 + + .( + .word $0801 + *=$0801 + + .word basicend,10 + .byt $9e,"2064",0 ;sys $0810 +basicend .word 0 + .byt 0,0,0 + + .( + jsr CLRCH + jsr iniscreen + jsr inipar +menu1 + Tout(m1atxt) + Tout(quellpfad) + Tout(m1btxt) + Ibout(quelldrv) + Tout(m1ctxt) + Tout(zielpfad) + Tout(m1dtxt) + Ibout(zieldrv) + Tout(m1etxt) + +next jsr GET + beq next + + ldx #0 +l1 cmp befkeys,x + beq exe + inx + cpx #Anzbefs + bcc l1 + bcs next + +exe jsr exec + jmp menu1 + +exec txa + asl + tax + lda madr+1,x + pha + lda madr,x + pha + rts + +madr .word pack-1,unpack-1,quelle-1,ziel-1,switch-1,dir-1,qdrv-1,zdrv-1 +befkeys .asc TC_F1,TC_F2,TC_F3,TC_F5,TC_F8,TC_F7,TC_F4,TC_F6 +Anzbefs =8 + +m1atxt .asc TC_LCH,TC_SCO,TC_FF,TC_LF,TC_LF + .asc "(F1) PACK PROGRAMMS",TC_CR,TC_LF + .asc "(F2) EXTRACT FROM ARCHIVE",TC_CR,TC_LF + .asc "(F3) SOURCEPATH/ARC:",0 +m1btxt .asc TC_CR,TC_LF + .asc "(F4) SOURCEDEVICE:",0 +m1ctxt .asc TC_CR,TC_LF + .asc "(F5) TARGETPATH/ARC:",0 +m1dtxt .asc TC_CR,TC_LF + .asc "(F6) TARGETDEVICE :",0 +m1etxt .asc TC_CR,TC_LF + .asc "(F7) SOURCEDIRECTORY",TC_CR,TC_LF + .asc "(F8) EXCHANGE TARGET AND SOURCE",TC_CR,TC_LF + .asc "YOUR CHOICE PLEASE",TC_CR,0 + .) + +unpack .( + jsr openarcrd + bcs cls + + lda #0 + sta rcnt + sta rcnt+1 + + jsr rbyte + cmp #Version + bne verr + +loop jsr unpackfile + bcc loop + + Tout(t1) + lda rcnt+1 + ldx rcnt + jsr INTOUT + lda #TC_CR + jsr BSOUT + jsr waitkey + +cls lda #FN_RD + jsr CLOSE + rts + +verr Tout(verrtxt) + jmp cls +verrtxt .asc "UNKNOWN ARCHIVE VERSION",0 + +t1 .asc "ARCHIVE HAD BYTES #",0 + .) + +unpackfile + .( + lda #0 + sta wcnt + sta wcnt+1 + lda #TC_CR + jsr BSOUT + ldy #0 + sty P1 +l1 jsr rbyte + bcs endx + ldy P1 + sta filetab,y + inc P1 + cmp #0 + beq endnam + jsr BSOUT + jmp l1 + +endnam Tout(ask) + jsr waitkey + cmp #"J" + bne nounpack + Tout(tok) + lda #<-1 + sta P1+1 + jsr fxopen + jsr Getzst + bcs xa + bcc lo + +endx jmp end +nounpack Tout(tno) +xa lda #0 + sta P1+1 + +lo jsr rbyte + bcs cls + cmp #XCODE + bne xb + jsr rbyte + sta wxanz + cmp #0 + clc + beq cls + jsr rbyte + sta wxbyt + bit P1+1 + bpl lo +ly lda wxbyt + jsr wbyte + dec wxanz + bne ly + jmp lo + +xb bit P1+1 + bpl lo + jsr wbyte + jmp lo + +cls php + jsr wbuf + lda #FN_WR + jsr CLOSE + + Tout(t1) + lda wcnt+1 + ldx wcnt + jsr INTOUT + lda #TC_CR + jsr BSOUT + + plp +end rts + +ask .asc TC_CR,"EXTRACT FILE (Y/N)?",0 + +t1 .asc "GIVES BYTES #",0 + .) + +incwcnt .( + inc wcnt + bne l1 + inc wcnt+1 +l1 rts + .) + +fxopen .( + ldy #0 + sty INT +l1 lda zielpfad,y + sta INBUF,y + beq l2 + iny + cmp #":" + beq l1a + cmp #"/" + bne l1b +l1a sty INT +l1b cpy #PFADLEN + bcc l1 + +l2 ldx INT + ldy #0 +l3 lda filetab,y + sta INBUF,x + inx + iny + cmp #0 + bne l3 + dex + txa + ldx #INBUF + jsr SETFNPAR + lda #FN_WR + ldx zieldrv + ldy #1 + jsr SETFPAR + + jsr OPEN + bcs err + jsr clrwrbuf + clc +err rts + .) + +openarcrd .( + ldy #0 +l0 lda quellpfad,y + beq l1 + iny + cpy #PFADLEN + bcc l0 +l1 cpy #0 + beq err + tya + ldx #quellpfad + jsr SETFNPAR + lda #FN_RD + ldx quelldrv + ldy #0 + jsr SETFPAR + jsr OPEN + bcs err + jsr Getqst + bcs err + jsr clrrdbuf + clc + rts +err sec + rts + .) + +pack .( + jsr getlist + lda anzfiles + beq end + jsr openarcwr + bcs cls + + lda #Version + jsr wbyte + + lda #0 + sta P1 +l1 jsr setfadr + sta P2 + stx P2+1 + jsr packfile + inc P1 + lda P1 + cmp anzfiles + bcc l1 + + jsr wbuf + +cls lda #FN_WR + jsr CLOSE + + jsr Getzst + +end jmp LINEIN:rts + .) + +packfile .( + Tout(lft) + + ldy #0 +l1 sty P1+1 + lda (P2),y + jsr BSOUT + jsr wbyte + ldy P1+1 + iny + cmp #0 + bne l1 + + jsr fopen + bcs le + + jsr clrwxbyt +l2 jsr rbyte + bcs l3 + jsr wxbyte + jmp l2 +l3 jsr savwxbyt + +le lda #FN_RD + jsr CLOSE + + lda #XCODE + jsr wbyte + lda #0 + jsr wbyte + + lda #TC_CR + jsr BSOUT + rts + +lft .asc TC_CR,"cOPYING ",0 + + .) + +fopen .( + ldy #0 + sty INT +l1 lda quellpfad,y + sta INBUF,y + beq l2 + iny + cmp #":" + beq l1a + cmp #"/" + bne l1b +l1a sty INT +l1b cpy #PFADLEN + bcc l1 + +l2 ldx INT + ldy #0 +l3 lda (P2),y + sta INBUF,x + inx + iny + cmp #0 + bne l3 + dex + txa + ldx #INBUF + jsr SETFNPAR + lda #FN_RD + ldx quelldrv + ldy #0 + jsr SETFPAR + + jsr OPEN + bcs err + jsr clrrdbuf + clc +err rts + .) + +incrcnt .( + inc rcnt + bne l1 + inc rcnt+1 +l1 rts + .) + +rbyte .( + ldy ro + cpy ri + beq leerbuf + lda rb,y + inc ro + clc + rts + +leerbuf lda rf + beq ldbuf + sec + rts + +ldbuf lda #0 + sta ri + sta ro + ldx #FN_RD + jsr CHKIN + lda #0 + sta STATUS + +lok jsr BASIN + + pha + lda STATUS + beq l0 + lda #"L" + jsr BSOUT + Ibout($90) + lda #TC_CR + jsr BSOUT +l0 pla + + jsr incrcnt + ldy ri + sta rb,y + iny + sty ri + iny + ;cpy ro + beq le + lda STATUS + beq lok + +le lda STATUS + sta rf + jsr CLRCH + jmp rbyte + .) + +clrrdbuf .( + lda #0 + sta ri + sta ro + sta rf + rts + .) + +wxbyte .( + ldx wxanz + beq add + inx + bne ad2 + pha + jsr savwxbyt + pla + jmp add + +ad2 cmp wxbyt + beq adx + pha + jsr savwxbyt + pla +add sta wxbyt +adx inc wxanz + + rts + .) + +clrwxbyt .( + lda #0 + sta wxanz + rts + .) + +savwxbyt .( + lda wxanz + beq nosav + cmp #4 + bcs savs + lda wxbyt + cmp #XCODE + beq savs + +l1 lda wxbyt + jsr wbyte + dec wxanz + bne l1 + rts + +savs lda #XCODE + jsr wbyte + lda wxanz + jsr wbyte + lda wxbyt + jsr wbyte + lda #0 + sta wxanz +nosav rts + .) + +openarcwr .( + ldy #0 +l0 lda zielpfad,y + beq l1 + iny + cpy #PFADLEN + bcc l0 +l1 cpy #0 + beq err + tya + ldx #zielpfad + jsr SETFNPAR + lda #FN_WR + ldx zieldrv + ldy #1 + jsr SETFPAR + jsr OPEN + bcs err + lda zieldrv + jsr Getzst + bcs err + jsr clrwrbuf + clc + rts +err sec + rts + .) + +clrwrbuf .( + lda #0 + sta wi + sta wo + rts + .) + +wbyte .( + ldy wi + sta wb,y + iny + sty wi + iny + cpy wo + bne nowr + pha + jsr wbuf + pla +nowr rts + .) + +wbuf .( + ldx #FN_WR + jsr CKOUT + ldy wo +l1 cpy wi + beq end + lda wb,y + jsr BSOUT + + lda STATUS + beq l0 + tya + pha + lda #"W" + jsr $e716 + lda $90 + ora #$40 + jsr $e716 + lda #TC_CR + jsr $e716 + pla + tay +l0 + jsr incwcnt + iny + jmp l1 +end lda #0 + sta wi + sta wo + jsr CLRCH + rts + .) + + .( +&Getqst lda quelldrv + jmp Getst +&Getzst lda zieldrv +&Getst + pha + jsr CLRCH + lda #TC_CR + jsr BSOUT + pla + jsr TALK + lda #15+$60 + jsr SECTALK + lda #0 + sta STATUS + jsr IECIN + pha + jsr BSOUT + +l1 jsr IECIN + cmp #0 + beq l2 + jsr BSOUT + lda STATUS + beq l1 +l2 jsr UNTALK + pla + cmp #"0" + bne err + clc + rts +err sec + rts + .) + +/* +showlist .( + lda #0 + sta P1 + +l1 lda P1 + cmp anzfiles + bcs le + + jsr setfadr + lda #TC_CR + jsr BSOUT + lda INT + ldy INT+1 + jsr Txtout + inc P1 + jmp l1 +le rts + .) +*/ + .( +l4x jmp l4 + +&getlist + lda #0 + sta anzfiles + + lda #TC_FF + jsr BSOUT + + jsr setdirnam + jsr SENDNAM + lda DEVADR + jsr TALK + lda SECADR + jsr SECTALK + + lda #0 + sta STATUS + ldy #3 +l0 sty P1 +l1 jsr IECIN + sta P1+1 + ldy STATUS + bne l4x + jsr IECIN + dec P1 + bne l1 + ldx P1+1 + jsr INTOUT + lda #" " + jsr BSOUT + +la jsr IECIN + cmp #0 + beq l4x + cmp #TC_REV + bne l3x + jmp l3 +l3x jsr BSOUT + cmp #34 + bne la + + lda anzfiles + jsr setfadr + sta P2 + stx P2+1 + + ldy #0 +lb sty P1 + jsr IECIN + jsr BSOUT + ldy P1 + cmp #34 + beq lc + sta (P2),y + iny + cpy #17 + bcc lb +lc lda #"," + sta (P2),y + iny + +ld sty P1 + jsr IECIN + jsr BSOUT + ldy P1 + cmp #" " + beq ld + sta P1+1 + sta (P2),y + iny + lda #0 + sta (P2),y +/* + lda #TC_CR + jsr BSOUT + lda P2+1 + ldx P2 + jsr INTOUT + lda #":" + jsr BSOUT + lda P2 + ldy P2+1 + jsr Txtout +*/ +lf tax + jsr IECIN + jsr BSOUT + cmp #" " + bne lf + cpx #"<" + beq lg + lda #" " + jsr BSOUT +lg lda #" " + jsr BSOUT + + lda P1+1 + jsr testkeys + +lh jsr IECIN + cmp #0 + bne lh + beq l2 + +l3 jsr IECIN + ldx STATUS + bne l4 + tax + beq l2 + jsr BSOUT + jmp l3 + +l2 lda #TC_CR + jsr BSOUT + jsr GET + beq l5 + jsr waitkey +l5 ldy #2 + beq l4 + jmp l0 +l4 jsr CLSFIL + jmp waitkey + .) + +testkeys .( + cmp #"P" + beq ok + cmp #"S" + beq ok + rts +ok Tout(t1) + jsr waitkey + cmp #"J" + beq ja + Tout(tno) + rts +ja Tout(tok) + inc anzfiles + rts + +t1 .asc TC_REV,"YES/NO ",TC_CRL,TC_CRL,TC_CRL + .asc TC_CRL,TC_CRL,TC_CRL,TC_CRL,0 +&tno .asc TC_REO,"NO ",0 +&tok .asc TC_REO,"YES ",0 + .) + +setfadr .( + ldx #0 + stx INT+1 + asl + rol INT+1 + asl + rol INT+1 + sta INT + ldx INT+1 + asl + rol INT+1 + asl + rol INT+1 + clc + adc INT + sta INT + txa + adc INT+1 + sta INT+1 + lda #filetab + adc INT+1 + sta INT+1 + tax + pla + rts + .) + +dir .( + lda #TC_FF + jsr BSOUT + + jsr setdirnam + jsr SENDNAM + lda DEVADR + jsr TALK + lda SECADR + jsr SECTALK + + lda #0 + sta STATUS + ldy #3 +l0 sty P1 +l1 jsr IECIN + sta P1+1 + ldy STATUS + bne l4 + jsr IECIN + dec P1 + bne l1 + ldx P1+1 + jsr INTOUT + lda #" " + jsr BSOUT +l3 jsr IECIN + ldx STATUS + bne l4 + tax + beq l2 + jsr BSOUT + jmp l3 +l2 lda #TC_CR + jsr BSOUT + jsr GET + beq l5 + jsr waitkey +l5 ldy #2 + bne l0 +l4 jsr CLSFIL + jmp waitkey + .) + +waitkey jsr GET + beq waitkey + rts + +setdirnam .( +p1 =INT + + lda #"$" + sta INBUF + ldx #1 + stx p1 + + ldy #0 +l1 lda quellpfad,y + beq nodp + cmp #":" + beq dp + iny + cpy #PFADLEN + bcc l1 +nodp lda #":" + sta INBUF,x + inx +dp ldy #0 +dp1 lda quellpfad,y + sta INBUF,x + beq end + cmp #":" + beq l2a + cmp #"/" + bne l2 +l2a stx p1 +l2 inx + iny + cpy #PFADLEN + bcc dp1 +end ldx p1 + inx + lda #"*" + sta INBUF,x + inx + lda #"." + sta INBUF,x + inx + lda #"*" + sta INBUF,x + inx + txa + ldx #INBUF + jsr SETFNPAR + lda #1 + ldx quelldrv + ldy #0 + jmp SETFPAR + .) + +qdrv .( + inc quelldrv + lda quelldrv + cmp #12 + bcc ok + lda #8 + sta quelldrv +ok rts + .) + +zdrv .( + inc zieldrv + lda zieldrv + cmp #12 + bcc ok + lda #8 + sta zieldrv +ok rts + .) + +quelle .( + Tout(quelltxt) + jsr LINEIN + ldy #0 +q1 lda INBUF,y + sta quellpfad,y + beq end + iny + cpy #PFADLEN-1 + bcc q1 + lda #0 + sta quellpfad,y +end rts + +quelltxt .asc TC_CR,"PLEASE INPUT NEW SOURCEPATH/ARCHIVE:",TC_CR,0 + .) + +ziel .( + Tout(quelltxt) + jsr LINEIN + ldy #0 +q1 lda INBUF,y + sta zielpfad,y + beq end + iny + cpy #PFADLEN-1 + bcc q1 + lda #0 + sta zielpfad,y +end rts + +quelltxt .asc TC_CR,"PLEASE INPUT NEW TARGETPATH/ARCHIVE:",TC_CR,0 + .) + +switch .( + lda quelldrv + ldx zieldrv + stx quelldrv + sta zieldrv + ldx #0 +l1 lda quellpfad,x + pha + lda zielpfad,x + sta quellpfad,x + pla + sta zielpfad,x + inx + cpx #PFADLEN + bcc l1 + rts + .) + +inipar .( + lda #0 + sta quellpfad + sta zielpfad + lda DEVADR + cmp #8 + bcc noval + cmp #12 + bcc ok +noval lda #8 +ok sta quelldrv + sta zieldrv + rts + .) + +Txtout .( +p =$22 + + sta p + sty p+1 +l1 ldy #0 + lda (p),y + beq le + jsr BSOUT + inc p + bne l1 + inc p+1 + bne l1 +le rts + .) + +iniscreen .( + lda #COL_SCHWARZ + sta VIC+VIC_EXTCOL + sta VIC+VIC_BCKCOL0 + lda #TC_HELLGRUEN + jsr BSOUT + rts + .) + +sysmem =* + +quelldrv =sysmem +zieldrv =sysmem+1 +-sysmem +=2 + +quellpfad =sysmem +zielpfad =sysmem+PFADLEN +-sysmem +=2*PFADLEN + +anzfiles =sysmem +-sysmem +=1 + +wi =sysmem +wo =sysmem+1 +-sysmem +=2 +wb =sysmem +-sysmem +=256 + +wxbyt =sysmem +wxanz =sysmem+1 +-sysmem +=2 + +ri =sysmem +ro =sysmem+1 +rf =sysmem+2 +-sysmem +=3 +rb =sysmem +-sysmem +=256 + +wcnt =sysmem +-sysmem +=2 +rcnt =sysmem +-sysmem +=2 +ecnt =sysmem +-sysmem +=2 + +filetab =sysmem +ende .) + diff --git a/xa/examples/pack_ger.a65 b/xa/examples/pack_ger.a65 new file mode 100644 index 0000000..c65851d --- /dev/null +++ b/xa/examples/pack_ger.a65 @@ -0,0 +1,1070 @@ + +#include "c64def.def" + +#define Tout(a) .(:lda #a:jsr Txtout:.) +#define Aout(a) .(:lda #b:jsr Txtout:jmp c:b .byt a,0:c .) +#define Ibout(a) .(:ldx a:lda #0:jsr INTOUT:.) +#define Iout(a) .(:ldx a:lda a+1:jsr INTOUT:.) + +#define PFADLEN 40 +#define FN_WR 3 +#define FN_RD 4 +#define XCODE $f7 +#define Version 1 + + .( + .word $0801 + *=$0801 + + .word basicend,10 + .byt $9e,"2064",0 ;sys $0810 +basicend .word 0 + .byt 0,0,0 + + .( + jsr CLRCH + jsr iniscreen + jsr inipar +menu1 + Tout(m1atxt) + Tout(quellpfad) + Tout(m1btxt) + Ibout(quelldrv) + Tout(m1ctxt) + Tout(zielpfad) + Tout(m1dtxt) + Ibout(zieldrv) + Tout(m1etxt) + +next jsr GET + beq next + + ldx #0 +l1 cmp befkeys,x + beq exe + inx + cpx #Anzbefs + bcc l1 + bcs next + +exe jsr exec + jmp menu1 + +exec txa + asl + tax + lda madr+1,x + pha + lda madr,x + pha + rts + +madr .word pack-1,unpack-1,quelle-1,ziel-1,switch-1,dir-1,qdrv-1,zdrv-1 +befkeys .asc TC_F1,TC_F2,TC_F3,TC_F5,TC_F8,TC_F7,TC_F4,TC_F6 +Anzbefs =8 + +m1atxt .asc TC_LCH,TC_SCO,TC_FF,TC_LF,TC_LF + .asc "(F1) PROGRAMME ZUSAMMENPACKEN",TC_CR,TC_LF + .asc "(F2) ARCHIV AUSPACKEN",TC_CR,TC_LF + .asc "(F3) QUELLPFAD:",0 +m1btxt .asc TC_CR,TC_LF + .asc "(F4) QUELLDEVICE:",0 +m1ctxt .asc TC_CR,TC_LF + .asc "(F5) ZIELPFAD :",0 +m1dtxt .asc TC_CR,TC_LF + .asc "(F6) ZIELDEVICE :",0 +m1etxt .asc TC_CR,TC_LF + .asc "(F7) QUELLDIRECTORY",TC_CR,TC_LF + .asc "(F8) QUELLE UND ZIEL TAUSCHEN",TC_CR,TC_LF + .asc "IHRE EINGABE BITTE",TC_CR,0 + .) + +unpack .( + jsr openarcrd + bcs cls + + lda #0 + sta rcnt + sta rcnt+1 + + jsr rbyte + cmp #Version + bne verr + +loop jsr unpackfile + bcc loop + + Tout(t1) + lda rcnt+1 + ldx rcnt + jsr INTOUT + lda #TC_CR + jsr BSOUT + jsr waitkey + +cls lda #FN_RD + jsr CLOSE + rts + +verr Tout(verrtxt) + jmp cls +verrtxt .asc "UNGUELTIGE ARCHIV-VERSION",0 + +t1 .asc "ARCHIV HATTE BYTES #",0 + .) + +unpackfile + .( + lda #0 + sta wcnt + sta wcnt+1 + lda #TC_CR + jsr BSOUT + ldy #0 + sty P1 +l1 jsr rbyte + bcs endx + ldy P1 + sta filetab,y + inc P1 + cmp #0 + beq endnam + jsr BSOUT + jmp l1 + +endnam Tout(ask) + jsr waitkey + cmp #"J" + bne nounpack + Tout(tok) + lda #<-1 + sta P1+1 + jsr fxopen + jsr Getzst + bcs xa + bcc lo + +endx jmp end +nounpack Tout(tno) +xa lda #0 + sta P1+1 + +lo jsr rbyte + bcs cls + cmp #XCODE + bne xb + jsr rbyte + sta wxanz + cmp #0 + clc + beq cls + jsr rbyte + sta wxbyt + bit P1+1 + bpl lo +ly lda wxbyt + jsr wbyte + dec wxanz + bne ly + jmp lo + +xb bit P1+1 + bpl lo + jsr wbyte + jmp lo + +cls php + jsr wbuf + lda #FN_WR + jsr CLOSE + + Tout(t1) + lda wcnt+1 + ldx wcnt + jsr INTOUT + lda #TC_CR + jsr BSOUT + + plp +end rts + +ask .asc TC_CR,"DATEI AUSPACKEN (J/N)?",0 + +t1 .asc "ERGIBT BYTES #",0 + .) + +incwcnt .( + inc wcnt + bne l1 + inc wcnt+1 +l1 rts + .) + +fxopen .( + ldy #0 + sty INT +l1 lda zielpfad,y + sta INBUF,y + beq l2 + iny + cmp #":" + beq l1a + cmp #"/" + bne l1b +l1a sty INT +l1b cpy #PFADLEN + bcc l1 + +l2 ldx INT + ldy #0 +l3 lda filetab,y + sta INBUF,x + inx + iny + cmp #0 + bne l3 + dex + txa + ldx #INBUF + jsr SETFNPAR + lda #FN_WR + ldx zieldrv + ldy #1 + jsr SETFPAR + + jsr OPEN + bcs err + jsr clrwrbuf + clc +err rts + .) + +openarcrd .( + ldy #0 +l0 lda quellpfad,y + beq l1 + iny + cpy #PFADLEN + bcc l0 +l1 cpy #0 + beq err + tya + ldx #quellpfad + jsr SETFNPAR + lda #FN_RD + ldx quelldrv + ldy #0 + jsr SETFPAR + jsr OPEN + bcs err + jsr Getqst + bcs err + jsr clrrdbuf + clc + rts +err sec + rts + .) + +pack .( + jsr getlist + lda anzfiles + beq end + jsr openarcwr + bcs cls + + lda #Version + jsr wbyte + + lda #0 + sta P1 +l1 jsr setfadr + sta P2 + stx P2+1 + jsr packfile + inc P1 + lda P1 + cmp anzfiles + bcc l1 + + jsr wbuf + +cls lda #FN_WR + jsr CLOSE + + jsr Getzst + +end jmp LINEIN:rts + .) + +packfile .( + Tout(lft) + + ldy #0 +l1 sty P1+1 + lda (P2),y + jsr BSOUT + jsr wbyte + ldy P1+1 + iny + cmp #0 + bne l1 + + jsr fopen + bcs le + + jsr clrwxbyt +l2 jsr rbyte + bcs l3 + jsr wxbyte + jmp l2 +l3 jsr savwxbyt + +le lda #FN_RD + jsr CLOSE + + lda #XCODE + jsr wbyte + lda #0 + jsr wbyte + + lda #TC_CR + jsr BSOUT + rts + +lft .asc TC_CR,"cOPYING ",0 + + .) + +fopen .( + ldy #0 + sty INT +l1 lda quellpfad,y + sta INBUF,y + beq l2 + iny + cmp #":" + beq l1a + cmp #"/" + bne l1b +l1a sty INT +l1b cpy #PFADLEN + bcc l1 + +l2 ldx INT + ldy #0 +l3 lda (P2),y + sta INBUF,x + inx + iny + cmp #0 + bne l3 + dex + txa + ldx #INBUF + jsr SETFNPAR + lda #FN_RD + ldx quelldrv + ldy #0 + jsr SETFPAR + + jsr OPEN + bcs err + jsr clrrdbuf + clc +err rts + .) + +incrcnt .( + inc rcnt + bne l1 + inc rcnt+1 +l1 rts + .) + +rbyte .( + ldy ro + cpy ri + beq leerbuf + lda rb,y + inc ro + clc + rts + +leerbuf lda rf + beq ldbuf + sec + rts + +ldbuf lda #0 + sta ri + sta ro + ldx #FN_RD + jsr CHKIN + lda #0 + sta STATUS + +lok jsr BASIN + + pha + lda STATUS + beq l0 + lda #"L" + jsr BSOUT + Ibout($90) + lda #TC_CR + jsr BSOUT +l0 pla + + jsr incrcnt + ldy ri + sta rb,y + iny + sty ri + iny + ;cpy ro + beq le + lda STATUS + beq lok + +le lda STATUS + sta rf + jsr CLRCH + jmp rbyte + .) + +clrrdbuf .( + lda #0 + sta ri + sta ro + sta rf + rts + .) + +wxbyte .( + ldx wxanz + beq add + inx + bne ad2 + pha + jsr savwxbyt + pla + jmp add + +ad2 cmp wxbyt + beq adx + pha + jsr savwxbyt + pla +add sta wxbyt +adx inc wxanz + + rts + .) + +clrwxbyt .( + lda #0 + sta wxanz + rts + .) + +savwxbyt .( + lda wxanz + beq nosav + cmp #4 + bcs savs + lda wxbyt + cmp #XCODE + beq savs + +l1 lda wxbyt + jsr wbyte + dec wxanz + bne l1 + rts + +savs lda #XCODE + jsr wbyte + lda wxanz + jsr wbyte + lda wxbyt + jsr wbyte + lda #0 + sta wxanz +nosav rts + .) + +openarcwr .( + ldy #0 +l0 lda zielpfad,y + beq l1 + iny + cpy #PFADLEN + bcc l0 +l1 cpy #0 + beq err + tya + ldx #zielpfad + jsr SETFNPAR + lda #FN_WR + ldx zieldrv + ldy #1 + jsr SETFPAR + jsr OPEN + bcs err + lda zieldrv + jsr Getzst + bcs err + jsr clrwrbuf + clc + rts +err sec + rts + .) + +clrwrbuf .( + lda #0 + sta wi + sta wo + rts + .) + +wbyte .( + ldy wi + sta wb,y + iny + sty wi + iny + cpy wo + bne nowr + pha + jsr wbuf + pla +nowr rts + .) + +wbuf .( + ldx #FN_WR + jsr CKOUT + ldy wo +l1 cpy wi + beq end + lda wb,y + jsr BSOUT + + lda STATUS + beq l0 + tya + pha + lda #"W" + jsr $e716 + lda $90 + ora #$40 + jsr $e716 + lda #TC_CR + jsr $e716 + pla + tay +l0 + jsr incwcnt + iny + jmp l1 +end lda #0 + sta wi + sta wo + jsr CLRCH + rts + .) + + .( +&Getqst lda quelldrv + jmp Getst +&Getzst lda zieldrv +&Getst + pha + jsr CLRCH + lda #TC_CR + jsr BSOUT + pla + jsr TALK + lda #15+$60 + jsr SECTALK + lda #0 + sta STATUS + jsr IECIN + pha + jsr BSOUT + +l1 jsr IECIN + cmp #0 + beq l2 + jsr BSOUT + lda STATUS + beq l1 +l2 jsr UNTALK + pla + cmp #"0" + bne err + clc + rts +err sec + rts + .) + +/* +showlist .( + lda #0 + sta P1 + +l1 lda P1 + cmp anzfiles + bcs le + + jsr setfadr + lda #TC_CR + jsr BSOUT + lda INT + ldy INT+1 + jsr Txtout + inc P1 + jmp l1 +le rts + .) +*/ + .( +l4x jmp l4 + +&getlist + lda #0 + sta anzfiles + + lda #TC_FF + jsr BSOUT + + jsr setdirnam + jsr SENDNAM + lda DEVADR + jsr TALK + lda SECADR + jsr SECTALK + + lda #0 + sta STATUS + ldy #3 +l0 sty P1 +l1 jsr IECIN + sta P1+1 + ldy STATUS + bne l4x + jsr IECIN + dec P1 + bne l1 + ldx P1+1 + jsr INTOUT + lda #" " + jsr BSOUT + +la jsr IECIN + cmp #0 + beq l4x + cmp #TC_REV + bne l3x + jmp l3 +l3x jsr BSOUT + cmp #34 + bne la + + lda anzfiles + jsr setfadr + sta P2 + stx P2+1 + + ldy #0 +lb sty P1 + jsr IECIN + jsr BSOUT + ldy P1 + cmp #34 + beq lc + sta (P2),y + iny + cpy #17 + bcc lb +lc lda #"," + sta (P2),y + iny + +ld sty P1 + jsr IECIN + jsr BSOUT + ldy P1 + cmp #" " + beq ld + sta P1+1 + sta (P2),y + iny + lda #0 + sta (P2),y +/* + lda #TC_CR + jsr BSOUT + lda P2+1 + ldx P2 + jsr INTOUT + lda #":" + jsr BSOUT + lda P2 + ldy P2+1 + jsr Txtout +*/ +lf tax + jsr IECIN + jsr BSOUT + cmp #" " + bne lf + cpx #"<" + beq lg + lda #" " + jsr BSOUT +lg lda #" " + jsr BSOUT + + lda P1+1 + jsr testkeys + +lh jsr IECIN + cmp #0 + bne lh + beq l2 + +l3 jsr IECIN + ldx STATUS + bne l4 + tax + beq l2 + jsr BSOUT + jmp l3 + +l2 lda #TC_CR + jsr BSOUT + jsr GET + beq l5 + jsr waitkey +l5 ldy #2 + beq l4 + jmp l0 +l4 jsr CLSFIL + jmp waitkey + .) + +testkeys .( + cmp #"P" + beq ok + cmp #"S" + beq ok + rts +ok Tout(t1) + jsr waitkey + cmp #"J" + beq ja + Tout(tno) + rts +ja Tout(tok) + inc anzfiles + rts + +t1 .asc TC_REV,"JA/NEIN",TC_CRL,TC_CRL,TC_CRL + .asc TC_CRL,TC_CRL,TC_CRL,TC_CRL,0 +&tno .asc TC_REO,"NEIN ",0 +&tok .asc TC_REO,"JA ",0 + .) + +setfadr .( + ldx #0 + stx INT+1 + asl + rol INT+1 + asl + rol INT+1 + sta INT + ldx INT+1 + asl + rol INT+1 + asl + rol INT+1 + clc + adc INT + sta INT + txa + adc INT+1 + sta INT+1 + lda #filetab + adc INT+1 + sta INT+1 + tax + pla + rts + .) + +dir .( + lda #TC_FF + jsr BSOUT + + jsr setdirnam + jsr SENDNAM + lda DEVADR + jsr TALK + lda SECADR + jsr SECTALK + + lda #0 + sta STATUS + ldy #3 +l0 sty P1 +l1 jsr IECIN + sta P1+1 + ldy STATUS + bne l4 + jsr IECIN + dec P1 + bne l1 + ldx P1+1 + jsr INTOUT + lda #" " + jsr BSOUT +l3 jsr IECIN + ldx STATUS + bne l4 + tax + beq l2 + jsr BSOUT + jmp l3 +l2 lda #TC_CR + jsr BSOUT + jsr GET + beq l5 + jsr waitkey +l5 ldy #2 + bne l0 +l4 jsr CLSFIL + jmp waitkey + .) + +waitkey jsr GET + beq waitkey + rts + +setdirnam .( +p1 =INT + + lda #"$" + sta INBUF + ldx #1 + stx p1 + + ldy #0 +l1 lda quellpfad,y + beq nodp + cmp #":" + beq dp + iny + cpy #PFADLEN + bcc l1 +nodp lda #":" + sta INBUF,x + inx +dp ldy #0 +dp1 lda quellpfad,y + sta INBUF,x + beq end + cmp #":" + beq l2a + cmp #"/" + bne l2 +l2a stx p1 +l2 inx + iny + cpy #PFADLEN + bcc dp1 +end ldx p1 + inx + lda #"*" + sta INBUF,x + inx + lda #"." + sta INBUF,x + inx + lda #"*" + sta INBUF,x + inx + txa + ldx #INBUF + jsr SETFNPAR + lda #1 + ldx quelldrv + ldy #0 + jmp SETFPAR + .) + +qdrv .( + inc quelldrv + lda quelldrv + cmp #12 + bcc ok + lda #8 + sta quelldrv +ok rts + .) + +zdrv .( + inc zieldrv + lda zieldrv + cmp #12 + bcc ok + lda #8 + sta zieldrv +ok rts + .) + +quelle .( + Tout(quelltxt) + jsr LINEIN + ldy #0 +q1 lda INBUF,y + sta quellpfad,y + beq end + iny + cpy #PFADLEN-1 + bcc q1 + lda #0 + sta quellpfad,y +end rts + +quelltxt .asc TC_CR,"BITTE NEUEN QUELLPFAD EINGEBEN:",TC_CR,0 + .) + +ziel .( + Tout(quelltxt) + jsr LINEIN + ldy #0 +q1 lda INBUF,y + sta zielpfad,y + beq end + iny + cpy #PFADLEN-1 + bcc q1 + lda #0 + sta zielpfad,y +end rts + +quelltxt .asc TC_CR,"BITTE NEUEN ZIELPFAD EINGEBEN:",TC_CR,0 + .) + +switch .( + lda quelldrv + ldx zieldrv + stx quelldrv + sta zieldrv + ldx #0 +l1 lda quellpfad,x + pha + lda zielpfad,x + sta quellpfad,x + pla + sta zielpfad,x + inx + cpx #PFADLEN + bcc l1 + rts + .) + +inipar .( + lda #0 + sta quellpfad + sta zielpfad + lda DEVADR + cmp #8 + bcc noval + cmp #12 + bcc ok +noval lda #8 +ok sta quelldrv + sta zieldrv + rts + .) + +Txtout .( +p =$22 + + sta p + sty p+1 +l1 ldy #0 + lda (p),y + beq le + jsr BSOUT + inc p + bne l1 + inc p+1 + bne l1 +le rts + .) + +iniscreen .( + lda #COL_SCHWARZ + sta VIC+VIC_EXTCOL + sta VIC+VIC_BCKCOL0 + lda #TC_HELLGRUEN + jsr BSOUT + rts + .) + +sysmem =* + +quelldrv =sysmem +zieldrv =sysmem+1 +-sysmem +=2 + +quellpfad =sysmem +zielpfad =sysmem+PFADLEN +-sysmem +=2*PFADLEN + +anzfiles =sysmem +-sysmem +=1 + +wi =sysmem +wo =sysmem+1 +-sysmem +=2 +wb =sysmem +-sysmem +=256 + +wxbyt =sysmem +wxanz =sysmem+1 +-sysmem +=2 + +ri =sysmem +ro =sysmem+1 +rf =sysmem+2 +-sysmem +=3 +rb =sysmem +-sysmem +=256 + +wcnt =sysmem +-sysmem +=2 +rcnt =sysmem +-sysmem +=2 +ecnt =sysmem +-sysmem +=2 + +filetab =sysmem +ende .) + diff --git a/xa/examples/peng.l b/xa/examples/peng.l new file mode 100644 index 0000000..2307df7 --- /dev/null +++ b/xa/examples/peng.l @@ -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 diff --git a/xa/loader/Makefile b/xa/loader/Makefile new file mode 100644 index 0000000..3492c58 --- /dev/null +++ b/xa/loader/Makefile @@ -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 + diff --git a/xa/loader/README b/xa/loader/README new file mode 100644 index 0000000..4087007 --- /dev/null +++ b/xa/loader/README @@ -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. + + + diff --git a/xa/loader/ex2 b/xa/loader/ex2 new file mode 100644 index 0000000..8170f61 Binary files /dev/null and b/xa/loader/ex2 differ diff --git a/xa/loader/example2 b/xa/loader/example2 new file mode 100644 index 0000000..e4bfa99 Binary files /dev/null and b/xa/loader/example2 differ diff --git a/xa/loader/file.def b/xa/loader/file.def new file mode 100644 index 0000000..9e5047e --- /dev/null +++ b/xa/loader/file.def @@ -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 + diff --git a/xa/loader/loader.a65 b/xa/loader/loader.a65 new file mode 100644 index 0000000..ca2f8c3 --- /dev/null +++ b/xa/loader/loader.a65 @@ -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 + 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+1 + lda #HDR_LEN + sta p1+3 + + ldx file + lda #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 + jsr fgetb + bcs no_file + + ldx file + lda #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 + diff --git a/xa/loader/test.a b/xa/loader/test.a new file mode 100644 index 0000000..874a2cd --- /dev/null +++ b/xa/loader/test.a @@ -0,0 +1,36 @@ + + .fopt 1, "filename" + .( + .text +&absv = 4 + lda #>test+4 + bne test +*=$8000 ;* + lda test-8 + .) + .text + nop + +; .fopt 1, "filename" + + lda bsslab + lda zerolab + lda #absv*2 + .bss +bsslab + .dsb 20,1 + .zero +zerolab + .dsb 20 + diff --git a/xa/loader/test2.a b/xa/loader/test2.a new file mode 100644 index 0000000..7921363 --- /dev/null +++ b/xa/loader/test2.a @@ -0,0 +1,28 @@ + + *=$8000 + .( +; .text + lda #>test+4 + bne test +;*=* + lda test-1 + .) +; .text + nop + lda bsslab + lda zerolab +; .bss +bsslab + .dsb 20,1 +; .zero +zerolab + .dsb 20 + diff --git a/xa/loader/test3.a b/xa/loader/test3.a new file mode 100644 index 0000000..d58a411 --- /dev/null +++ b/xa/loader/test3.a @@ -0,0 +1,3 @@ + + lda #label +lab2 diff --git a/xa/man/README b/xa/man/README new file mode 100644 index 0000000..4d54849 --- /dev/null +++ b/xa/man/README @@ -0,0 +1,3 @@ +Also look at ../doc/ for previous documentation files and the Change log. + +Cameron Kaiser diff --git a/xa/man/file65.1 b/xa/man/file65.1 new file mode 100644 index 0000000..7e292a2 --- /dev/null +++ b/xa/man/file65.1 @@ -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 +and Cameron Kaiser . +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/ diff --git a/xa/man/ldo65.1 b/xa/man/ldo65.1 new file mode 100644 index 0000000..87e0b36 --- /dev/null +++ b/xa/man/ldo65.1 @@ -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 +and Cameron Kaiser . +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/ diff --git a/xa/man/printcbm.1 b/xa/man/printcbm.1 new file mode 100644 index 0000000..db252e9 --- /dev/null +++ b/xa/man/printcbm.1 @@ -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 . +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/ diff --git a/xa/man/reloc65.1 b/xa/man/reloc65.1 new file mode 100644 index 0000000..ba891a9 --- /dev/null +++ b/xa/man/reloc65.1 @@ -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 +and Cameron Kaiser . +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/ diff --git a/xa/man/uncpk.1 b/xa/man/uncpk.1 new file mode 100644 index 0000000..20b905e --- /dev/null +++ b/xa/man/uncpk.1 @@ -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 +and Cameron Kaiser . +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/ diff --git a/xa/man/xa.1 b/xa/man/xa.1 new file mode 100644 index 0000000..8dc5e88 --- /dev/null +++ b/xa/man/xa.1 @@ -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 # +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 # 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 , +Andre Fachat +and Cameron Kaiser . +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/ diff --git a/xa/misc/Makefile b/xa/misc/Makefile new file mode 100644 index 0000000..b93b7fd --- /dev/null +++ b/xa/misc/Makefile @@ -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 + diff --git a/xa/misc/file65.c b/xa/misc/file65.c new file mode 100644 index 0000000..e96add1 --- /dev/null +++ b/xa/misc/file65.c @@ -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 +#include +#include +#ifndef _MSC_VER +#include +#endif +#include +#include + +#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=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 +#include +#include +#include +#ifndef _MSC_VER +#include +#endif +#include + +#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=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;itdiff = ((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;ibuf, + 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;ibuf + fp[i]->tpos, 1, fp[i]->tlen, fd); + } + /* write data segment */ + for(i=0;ibuf + 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(iud[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;itbase-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;idbase-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>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;ifname, 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>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; +} diff --git a/xa/misc/mkrom.sh b/xa/misc/mkrom.sh new file mode 100755 index 0000000..3f0297b --- /dev/null +++ b/xa/misc/mkrom.sh @@ -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 \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 + diff --git a/xa/misc/printcbm.c b/xa/misc/printcbm.c new file mode 100644 index 0000000..1ab7c23 --- /dev/null +++ b/xa/misc/printcbm.c @@ -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 +#include +#include + +#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; +} diff --git a/xa/misc/reloc65.c b/xa/misc/reloc65.c new file mode 100644 index 0000000..9b528f7 --- /dev/null +++ b/xa/misc/reloc65.c @@ -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 +#include +#include +#include +#include +#include + +#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 %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; +} + diff --git a/xa/misc/uncpk.c b/xa/misc/uncpk.c new file mode 100644 index 0000000..353d1d4 --- /dev/null +++ b/xa/misc/uncpk.c @@ -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 +#include +#include + +#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=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); +} diff --git a/xa/misc/version.h b/xa/misc/version.h new file mode 100644 index 0000000..cdfbd09 --- /dev/null +++ b/xa/misc/version.h @@ -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__ */ diff --git a/xa/src/Makefile b/xa/src/Makefile new file mode 100644 index 0000000..dc15ea6 --- /dev/null +++ b/xa/src/Makefile @@ -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 + diff --git a/xa/src/version.h b/xa/src/version.h new file mode 100644 index 0000000..cdfbd09 --- /dev/null +++ b/xa/src/version.h @@ -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__ */ diff --git a/xa/src/xa.c b/xa/src/xa.c new file mode 100644 index 0000000..3a54e6c --- /dev/null +++ b/xa/src/xa.c @@ -0,0 +1,1131 @@ +/* xa65 - 65xx/65816 cross-assembler and utility suite + * + * Copyright (C) 1989-1997 André Fachat (a.fachat@physik.tu-chemnitz.de) + * maintained by Cameron Kaiser (ckaiser@floodgap.com) + * + * Main program + * + * 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 +#include +#include +#include +#include +#ifndef _MSC_VER +#include +#endif + +/* macros */ +#include "xad.h" + +/* structs and defs */ +#include "xah.h" +#include "xah2.h" + +/* exported functions are defined here */ +#include "xa.h" +#include "xal.h" +#include "xam.h" +#include "xao.h" +#include "xap.h" +#include "xar.h" +#include "xat.h" +#include "xacharset.h" + +#include "version.h" + +/* ANZERR: total number of errors */ +/* ANZWARN: total number of warnings */ + +#define ANZERR 64 +#define ANZWARN 13 + +#define programname "xa" +#define progversion "v2.3.5" +#define authors "Written by Andre Fachat, Jolse Maginnis, David Weinehall and Cameron Kaiser" +#define copyright "Copyright (C) 1989-2009 Andre Fachat, Jolse Maginnis, David Weinehall\nand Cameron Kaiser." + +/* exported globals */ +int ncmos, cmosfl, w65816, n65816; +int masm = 0; +int nolink = 0; +int romable = 0; +int romaddr = 0; +int noglob = 0; +int showblk = 0; +int crossref = 0; +char altppchar; + +/* local variables */ +static char out[MAXLINE]; +static time_t tim1, tim2; +static FILE *fpout, *fperr, *fplab; +static int ner = 0; + +static int align = 1; + +static void printstat(void); +static void usage(int, FILE *); +static int setfext(char *, char *); +static int x_init(void); +static int pass1(void); +static int pass2(void); +static int puttmp(int); +static int puttmps(signed char *, int); +static void chrput(int); +static int getline(char *); +static void lineout(void); +static long ga_p1(void); +static long gm_p1(void); + +/* text */ +int memode,xmode; +int segment; +int tlen=0, tbase=0x1000; +int dlen=0, dbase=0x0400; +int blen=0, bbase=0x4000; +int zlen=0, zbase=4; +int fmode=0; +int relmode=0; + +int pc[SEG_MAX]; /* segments */ + +int main(int argc,char *argv[]) +{ + int er=1,i; + signed char *s=NULL; + char *tmpp; + + int mifiles = 5; + int nifiles = 0; + int verbose = 0; + int oldfile = 0; + int no_link = 0; + + char **ifiles; + char *ofile; + char *efile; + char *lfile; + char *ifile; + + char old_e[MAXLINE]; + char old_l[MAXLINE]; + char old_o[MAXLINE]; + + tim1=time(NULL); + + ncmos=0; + n65816=0; + cmosfl=1; + w65816=0; /* default: 6502 only */ + + altppchar = '#' ; /* i.e., NO alternate char */ + + if((tmpp = strrchr(argv[0],'/'))) { + tmpp++; + } else { + tmpp = argv[0]; + } + if( (!strcmp(tmpp,"xa65816")) + || (!strcmp(tmpp,"XA65816")) + || (!strcmp(tmpp,"xa816")) + || (!strcmp(tmpp,"XA816")) + ) { + w65816 = 1; /* allow 65816 per default */ + } + + /* default output charset for strings in quotes */ + set_charset("ASCII"); + + ifiles = malloc(mifiles*sizeof(char*)); + + afile = alloc_file(); + + if (argc <= 1) { + usage(w65816, stderr); + exit(1); + } + + if (strstr(argv[1], "--help")) { + usage(w65816, stdout); + exit(0); + } + + if (strstr(argv[1], "--version")) { + version(programname, progversion, authors, copyright); + exit(0); + } + + ofile="a.o65"; + efile=NULL; + lfile=NULL; + + if(pp_init()) { + logout("fatal: pp: no memory!"); + return 1; + } + if(b_init()) { + logout("fatal: b: no memory!"); + return 1; + } + if(l_init()) { + logout("fatal: l: no memory!"); + return 1; + } + + i=1; + while(i filename */ + ifiles[nifiles++] = argv[i]; + if(nifiles>=mifiles) { + mifiles += 5; + ifiles=realloc(ifiles, mifiles*sizeof(char*)); + if(!ifiles) { + fprintf(stderr, "Oops: couldn't alloc enough mem for filelist table..!\n"); + exit(1); + } + } + } + i++; + } + if(!nifiles) { + fprintf(stderr, "No input files given!\n"); + exit(0); + } + + if(oldfile) { + strcpy(old_e, ifiles[0]); + strcpy(old_o, ifiles[0]); + strcpy(old_l, ifiles[0]); + + if(setfext(old_e,".err")==0) efile = old_e; + if(setfext(old_o,".obj")==0) ofile = old_o; + if(setfext(old_l,".lab")==0) lfile = old_l; + } + + fplab= lfile ? xfopen(lfile,"w") : NULL; + fperr= efile ? xfopen(efile,"w") : NULL; + if(!strcmp(ofile,"-")) { + ofile=NULL; + fpout = stdout; + } else { + fpout= xfopen(ofile,"wb"); + } + if(!fpout) { + fprintf(stderr, "Couldn't open output file!\n"); + exit(1); + } + + if(verbose) fprintf(stderr, "%s\n",copyright); + + if(1 /*!m_init()*/) + { + if(1 /*!b_init()*/) + { + if(1 /*!l_init()*/) + { + /*if(!pp_init())*/ + { + if(!x_init()) + { + if(fperr) fprintf(fperr,"%s\n",copyright); + if(verbose) logout(ctime(&tim1)); + + /* Pass 1 */ + + pc[SEG_ABS]= 0; /* abs addressing */ + seg_start(fmode, tbase, dbase, bbase, zbase, 0, relmode); + + if(relmode) { + r_mode(RMODE_RELOC); + segment = SEG_TEXT; + } else { + r_mode(RMODE_ABS); + } + + nolink = no_link; + + for (i=0; ifname)); + + if(!er) { + er=pass1(); + pp_close(); + } else { + sprintf(out, "Couldn't open source file '%s'!\n", ifile); + logout(out); + } + } + + if((er=b_depth())) { + sprintf(out,"Still %d blocks open at end of file!\n",er); + logout(out); + } + + if(tbase & (align-1)) { + sprintf(out,"Warning: text segment ($%04x) start address doesn't align to %d!\n", tbase, align); + logout(out); + } + if(dbase & (align-1)) { + sprintf(out,"Warning: data segment ($%04x) start address doesn't align to %d!\n", dbase, align); + logout(out); + } + if(bbase & (align-1)) { + sprintf(out,"Warning: bss segment ($%04x) start address doesn't align to %d!\n", bbase, align); + logout(out); + } + if(zbase & (align-1)) { + sprintf(out,"Warning: zero segment ($%04x) start address doesn't align to %d!\n", zbase, align); + logout(out); + } + if (n65816>0) + fmode |= 0x8000; + switch(align) { + case 1: break; + case 2: fmode |= 1; break; + case 4: fmode |= 2; break; + case 256: fmode |=3; break; + } + + if((!er) && relmode) + h_write(fpout, fmode, tlen, dlen, blen, zlen, 0); + + + if(!er) + { + if(verbose) logout("xAss65: Pass 2:\n"); + + seg_pass2(); + + if(!relmode) { + r_mode(RMODE_ABS); + } else { + r_mode(RMODE_RELOC); + segment = SEG_TEXT; + } + er=pass2(); + } + + if(fplab) printllist(fplab); + tim2=time(NULL); + if(verbose) printstat(); + + if((!er) && relmode) seg_end(fpout); /* write reloc/label info */ + + if(fperr) fclose(fperr); + if(fplab) fclose(fplab); + if(fpout) fclose(fpout); + + } else { + logout("fatal: x: no memory!\n"); + } + pp_end(); +/* } else { + logout("fatal: pp: no memory!");*/ + } + } else { + logout("fatal: l: no memory!\n"); + } + } else { + logout("fatal: b: no memory!\n"); + } + /*m_exit();*/ + } else { + logout("Not enough memory available!\n"); + } + + if(ner || er) + { + fprintf(stderr, "Break after %d error%c\n",ner,ner?'s':0); + /*unlink();*/ + if(ofile) { + unlink(ofile); + } + } + + free(ifiles); + + return( (er || ner) ? 1 : 0 ); +} + +static void printstat(void) +{ + logout("Statistics:\n"); + sprintf(out," %8d of %8d label used\n",ga_lab(),gm_lab()); logout(out); + sprintf(out," %8ld of %8ld byte label-memory used\n",ga_labm(),gm_labm()); logout(out); + sprintf(out," %8d of %8d PP-defs used\n",ga_pp(),gm_pp()); logout(out); + sprintf(out," %8ld of %8ld byte PP-memory used\n",ga_ppm(),gm_ppm()); logout(out); + sprintf(out," %8ld of %8ld byte buffer memory used\n",ga_p1(),gm_p1()); logout(out); + sprintf(out," %8d blocks used\n",ga_blk()); logout(out); + sprintf(out," %8ld seconds used\n",(long)difftime(tim2,tim1)); logout(out); +} + +int h_length(void) { + return 26+o_length(); +} + +#if 0 +/* write header for relocatable output format */ +int h_write(FILE *fp, int tbase, int tlen, int dbase, int dlen, + int bbase, int blen, int zbase, int zlen) { + + fputc(1, fp); /* version byte */ + fputc(0, fp); /* hi address 0 -> no C64 */ + fputc("o", fp); + fputc("6", fp); + fputc("5", fp); + fputc(0, fp); /* format version */ + fputw(mode, fp); /* file mode */ + fputw(tbase,fp); /* text base */ + fputw(tlen,fp); /* text length */ + fputw(dbase,fp); /* data base */ + fputw(dlen,fp); /* data length */ + fputw(bbase,fp); /* bss base */ + fputw(blen,fp); /* bss length */ + fputw(zbase,fp); /* zerop base */ + fputw(zlen,fp); /* zerop length */ + + o_write(fp); + + return 0; +} +#endif + +static int setfext(char *s, char *ext) +{ + int j,i=(int)strlen(s); + + if(i>MAXLINE-5) + return(-1); + + for(j=i-1;j>=0;j--) + { + if(s[j]==DIRCHAR) + { + strcpy(s+i,ext); + break; + } + if(s[j]=='.') + { + strcpy(s+j,ext); + break; + } + } + if(!j) + strcpy(s+i,ext); + + return(0); +} + +/* +static char *tmp; +static unsigned long tmpz; +static unsigned long tmpe; +*/ + +static long ga_p1(void) +{ + return(afile->mn.tmpz); +} +static long gm_p1(void) +{ + return(TMPMEM); +} + +static int pass2(void) +{ + int c,er,l,ll,i,al; + Datei datei; + signed char *dataseg=NULL; + signed char *datap=NULL; + + memode=0; + xmode=0; + if((dataseg=malloc(dlen))) { + if(!dataseg) { + fprintf(stderr, "Couldn't alloc dataseg memory...\n"); + exit(1); + } + datap=dataseg; + } + filep=&datei; + afile->mn.tmpe=0L; + + while(ner<20 && afile->mn.tmpemn.tmpz) + { + l=afile->mn.tmp[afile->mn.tmpe++]; + ll=l; + + if(!l) + { + if(afile->mn.tmp[afile->mn.tmpe]==T_LINE) + { + datei.fline=(afile->mn.tmp[afile->mn.tmpe+1]&255)+(afile->mn.tmp[afile->mn.tmpe+2]<<8); + afile->mn.tmpe+=3; + } else + if(afile->mn.tmp[afile->mn.tmpe]==T_FILE) + { + datei.fline=(afile->mn.tmp[afile->mn.tmpe+1]&255)+(afile->mn.tmp[afile->mn.tmpe+2]<<8); + + memcpy(&datei.fname, afile->mn.tmp+afile->mn.tmpe+3, sizeof(datei.fname)); + afile->mn.tmpe+=3+sizeof(datei.fname); +/* + datei.fname = malloc(strlen((char*) afile->mn.tmp+afile->mn.tmpe+3)+1); + if(!datei.fname) { + fprintf(stderr,"Oops, no more memory\n"); + exit(1); + } + strcpy(datei.fname,(char*) afile->mn.tmp+afile->mn.tmpe+3); + afile->mn.tmpe+=3+strlen(datei.fname); +*/ + } + } else + { +/* do not attempt address mode optimization on pass 2 */ + er=t_p2(afile->mn.tmp+afile->mn.tmpe,&ll,1,&al); + + if(er==E_NOLINE) + { + } else + if(er==E_OK) + { + if(segmentmn.tmp[afile->mn.tmpe+i]); + } else if (segment==SEG_DATA && datap) { + memcpy(datap,afile->mn.tmp+afile->mn.tmpe,ll); + datap+=ll; + } + } else + if(er==E_DSB) + { + c=afile->mn.tmp[afile->mn.tmpe]; + if(segmentmn.tmp[afile->mn.tmpe]);*/ + for(i=0;imn.tmpe; +/* + fprintf(stderr, "ok, ready to insert\n"); + for (i=0; imn.tmp[afile->mn.tmpe+i]); + } +*/ + + offset = afile->mn.tmp[i] + + (afile->mn.tmp[i+1] << 8) + + (afile->mn.tmp[i+2] << 16); + fstart = afile->mn.tmp[i+3] + 1 + + (afile->mn.tmp[i+4] << 8); + /* usually redundant but here for single-char names + that get interpreted as chars */ + flen = afile->mn.tmp[i+5]; + if (flen > 1) fstart++; + /* now fstart points either to string past quote and + length mark, OR, single char byte */ +/* +fprintf(stderr, "offset = %i length = %i fstart = %i flen = %i charo = %c\n", + offset, ll, fstart, flen, afile->mn.tmp[afile->mn.tmpe+fstart]); +*/ + /* there is a race condition here where altering the + file between validation in t_p2 (xat.c) and + here will cause problems. I'm not going to + worry about this right now. */ + + for(j=0; jmn.tmp[i+fstart+j]; + } + binfnam[flen] = '\0'; +/* + fprintf(stderr, "fnam = %s\n", binfnam); +*/ + /* primitive insurance */ + if (!(foo = fopen(binfnam, "r"))) { + errout(E_FNF); + ner++; + } else { + fseek(foo, offset, SEEK_SET); + for(j=0; jmn.tmpe+=abs(l); + } + if(relmode) { + if((ll=fwrite(dataseg, 1, dlen, fpout))mn.tmpz); +*/ + } + + if(er!=E_EOF) { + fprintf(stderr, "foul through\n"); + errout(er); + } + + + +/* { int i; printf("Pass 1 \n"); + for(i=0;imn.tmpz;i++) + fprintf(stderr, " %02x",255 & afile->mn.tmp[i]); + getchar();} +*/ + return(ner); +} + +static void usage(int default816, FILE *fp) +{ + fprintf(fp, + "Usage: %s [options] file\n" + "Cross-assembler for 65xx/R65C02/65816\n" + "\n", + programname); + fprintf(fp, + " -v verbose output\n" + " -x old filename behaviour (overrides `-o', `-e', `-l')\n" + " This is deprecated and may disappear in future versions!\n" + " -C no CMOS-opcodes\n" + " -W no 65816-opcodes%s\n" + " -w allow 65816-opcodes%s\n", + default816 ? "" : " (default)", + default816 ? " (default)" : ""); + fprintf(fp, + " -B show lines with block open/close\n" + " -c produce `o65' object instead of executable files (i.e. don't link)\n" + " -o filename sets output filename, default is `a.o65'\n" + " A filename of `-' sets stdout as output file\n"); + fprintf(fp, + " -e filename sets errorlog filename, default is none\n" + " -l filename sets labellist filename, default is none\n" + " -r adds crossreference list to labellist (if `-l' given)\n" + " -M allow ``:'' to appear in comments for MASM compatibility\n" + " -R start assembler in relocating mode\n"); + fprintf(fp, + " -Llabel defines `label' as absolute, undefined label even when linking\n" + " -b? addr set segment base address to integer value addr\n" + " `?' stands for t(ext), d(ata), b(ss) and z(ero) segment\n" + " (address can be given more than once, last one is used)\n"); + fprintf(fp, + " -A addr make text segment start at an address that when the _file_\n" + " starts at addr, relocation is not necessary. Overrides -bt\n" + " Other segments must be specified with `-b?'\n" + " -G suppress list of exported globals\n"); + fprintf(fp, + " -DDEF=TEXT defines a preprocessor replacement\n" + " -Ocharset set output charset (PETSCII or ASCII), case-sensitive\n" + " -Idir add directory `dir' to include path (before XAINPUT)\n" + " --version output version information and exit\n" + " --help display this help and exit\n"); +} + +/* +static char *ertxt[] = { "Syntax","Label definiert", + "Label nicht definiert","Labeltabelle voll", + "Label erwartet","Speicher voll","Illegaler Opcode", + "Falsche Adressierungsart","Branch ausserhalb des Bereichs", + "Ueberlauf","Division durch Null","Pseudo-Opcode erwartet", + "Block-Stack-Ueberlauf","Datei nicht gefunden", + "End of File","Block-Struktur nicht abgeschlossen", + "NoBlk","NoKey","NoLine","OKDef","DSB","NewLine", + "NewFile","CMOS-Befehl","pp:Falsche Anzahl Parameter" }; +*/ +static char *ertxt[] = { + "Syntax", + "Label already defined", + "Label not defined", + "Label table full", + "Label expected", + "Out of memory", + "Illegal opcode", + "Wrong addressing mode", + "Branch out of range", + "Overflow", + "Division by zero", + "Pseudo-opcode expected", + "Block stack overflow", + "File not found", + "End of file", + "Unmatched block close", + "NoBlk", + "NoKey", + "NoLine", + "OKDef", + "DSB", + "NewLine", + "NewFile", + "CMOS-Befehl", + "pp:Wrong parameter count", + "Illegal pointer arithmetic", + "Illegal segment", + "File header option too long", + "File option not at file start (when ROM-able)", + "Illegal align value", + "65816 mode used/required", + "Exceeded recursion limit for label evaluation", + "Unresolved preprocessor directive at end of file", + "Data underflow", + "Illegal quantity", + ".bin", +/* placeholders for future fatal errors */ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", +/* warnings */ + "Cutting word relocation in byte value", + "Byte relocation in word value", + "Illegal pointer arithmetic", + "Address access to low or high byte pointer", + "High byte access to low byte pointer", + "Low byte access to high byte pointer", + "Can't optimize forward-defined label; using absolute addressing", + "Open preprocessor directive at end of file (intentional?)", + "Included binary data exceeds 64KB", + "Included binary data exceeds 16MB", +/* more placeholders */ + "", + "", + "", + + }; + +static int gl; +static int gf; + +static int x_init(void) +{ + return 0; +#if 0 + int er=0; + /*er=m_alloc(TMPMEM,&tmp);*/ + afile->mn.tmp=malloc(TMPMEM); + if(!afile->mn.tmp) er=E_NOMEM; + afile->mn.tmpz=0L; + return(er); +#endif +} + +static int puttmp(int c) +{ + int er=E_NOMEM; +/*printf("puttmp: afile=%p, tmp=%p, tmpz=%d\n",afile, afile?afile->mn.tmp:0, afile?afile->mn.tmpz:0);*/ + if(afile->mn.tmpzmn.tmp[afile->mn.tmpz++]=c; + er=E_OK; + } + return(er); +} + +static int puttmps(signed char *s, int l) +{ + int i=0,er=E_NOMEM; + + if(afile->mn.tmpz+lmn.tmp[afile->mn.tmpz++]=s[i++]; + + er=E_OK; + } + return(er); +} + +static char l[MAXLINE]; + +static int getline(char *s) +{ + static int ec; + + static int i,c; + int hkfl,j,comcom; + + j=hkfl=comcom=0; + ec=E_OK; + + if(!gl) + { + do + { + ec=pgetline(l); + i=0; + while(l[i]==' ') + i++; + while(l[i]!='\0' && isdigit(l[i])) + i++; + gf=1; + + if(ec==E_NEWLINE) + { + puttmp(0); + puttmp(T_LINE); + puttmp((filep->fline)&255); + puttmp(((filep->fline)>>8)&255); + ec=E_OK; + + } + else + if(ec==E_NEWFILE) + { + puttmp(0); + puttmp(T_FILE); + puttmp((filep->fline)&255); + puttmp(((filep->fline)>>8)&255); + puttmps((signed char*)&(filep->fname), sizeof(filep->fname)); +/* + puttmps((signed char*)filep->fname, + 1+(int)strlen(filep->fname)); +*/ + ec=E_OK; + } + } while(!ec && l[i]=='\0'); + } + + gl=0; + if(!ec || ec==E_EOF) + { + do { + c=s[j]=l[i++]; + + if (c=='\"') + hkfl^=1; + if (c==';' && !hkfl) + comcom = 1; + if (c=='\0') + break; /* hkfl = comcom = 0 */ + if (c==':' && !hkfl && (!comcom || !masm)) { + gl=1; + break; + } + j++; + } while (c!='\0' && jalign)?a:align; +} + +static void lineout(void) +{ + if(gf) + { + logout(filep->flinep); + logout("\n"); + gf=0; + } +} + +void errout(int er) +{ + if (er<-ANZERR || er>-1) { + if(er>=-(ANZERR+ANZWARN) && er < -ANZERR) { + sprintf(out,"%s:line %d: %04x: Warning - %s\n", + filep->fname, filep->fline, pc[segment], ertxt[(-er)-1]); + } else { + /* sprintf(out,"%s:Zeile %d: %04x:Unbekannter Fehler Nr.: %d\n",*/ + sprintf(out,"%s:line %d: %04x: Unknown error # %d\n", + filep->fname,filep->fline,pc[segment],er); + ner++; + } + } else { + if (er==E_NODEF) + sprintf(out,"%s:line %d: %04x:Label '%s' not defined\n", + filep->fname,filep->fline,pc[segment],lz); + else + sprintf(out,"%s:line %d: %04x:%s error\n", + filep->fname,filep->fline,pc[segment],ertxt[(-er)-1]); + + ner++; + } + logout(out); +} + +static void chrput(int c) +{ + /* printf(" %02x",c&255);*/ + + putc( c&0x00ff,fpout); +} + +void logout(char *s) +{ + fprintf(stderr, "%s",s); + if(fperr) + fprintf(fperr,"%s",s); +} + diff --git a/xa/src/xa.h b/xa/src/xa.h new file mode 100644 index 0000000..67ee3fe --- /dev/null +++ b/xa/src/xa.h @@ -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__ */ diff --git a/xa/src/xaa.c b/xa/src/xaa.c new file mode 100644 index 0000000..73dd861 --- /dev/null +++ b/xa/src/xaa.c @@ -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 + +#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 = *ww2; + 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); +} + diff --git a/xa/src/xaa.h b/xa/src/xaa.h new file mode 100644 index 0000000..bbae273 --- /dev/null +++ b/xa/src/xaa.h @@ -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__ */ diff --git a/xa/src/xacharset.c b/xa/src/xacharset.c new file mode 100644 index 0000000..4f74b48 --- /dev/null +++ b/xa/src/xacharset.c @@ -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 +#include + +#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); +} + + diff --git a/xa/src/xacharset.h b/xa/src/xacharset.h new file mode 100644 index 0000000..f42ae6e --- /dev/null +++ b/xa/src/xacharset.h @@ -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__ */ + diff --git a/xa/src/xad.h b/xa/src/xad.h new file mode 100644 index 0000000..79528fc --- /dev/null +++ b/xa/src/xad.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__ */ diff --git a/xa/src/xah.h b/xa/src/xah.h new file mode 100644 index 0000000..8b98bc8 --- /dev/null +++ b/xa/src/xah.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__ */ diff --git a/xa/src/xah2.h b/xa/src/xah2.h new file mode 100644 index 0000000..2b64cc3 --- /dev/null +++ b/xa/src/xah2.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__ */ diff --git a/xa/src/xal.c b/xa/src/xal.c new file mode 100644 index 0000000..5598c75 --- /dev/null +++ b/xa/src/xal.c @@ -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 +#include +#include +#include + +/* 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;ila.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;ila.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((ltila.lt+afile->la.lti; +/* + s2=ltp->n=ln+lni; + + while((jlen=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;(kn[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;ila.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;ila.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=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); +} + diff --git a/xa/src/xal.h b/xa/src/xal.h new file mode 100644 index 0000000..98a1d75 --- /dev/null +++ b/xa/src/xal.h @@ -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 /* 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__ */ diff --git a/xa/src/xam.c b/xa/src/xam.c new file mode 100644 index 0000000..5e4b8ef --- /dev/null +++ b/xa/src/xam.c @@ -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 +#include +#include + +#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 +#include +#include + +#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;ifo.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;jfo.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;ifo.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; +} + diff --git a/xa/src/xao.h b/xa/src/xao.h new file mode 100644 index 0000000..2f2df40 --- /dev/null +++ b/xa/src/xao.h @@ -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__ */ diff --git a/xa/src/xap.c b/xa/src/xap.c new file mode 100644 index 0000000..da8e3c3 --- /dev/null +++ b/xa/src/xap.c @@ -0,0 +1,1020 @@ +/* xa65 - 65xx/65816 cross-assembler and utility suite + * + * Copyright (C) 1989-1997 André Fachat (a.fachat@physik.tu-chemnitz.de) + * Maintained by Cameron Kaiser + * + * File handling and preprocessor (also see xaa.c) 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 +#include +#include +#include +#ifndef _MSC_VER +#include +#endif + +#include "xad.h" +#include "xah.h" +#include "xah2.h" + +#include "xar.h" +#include "xa.h" +#include "xam.h" +#include "xal.h" +#include "xat.h" +#include "xap.h" + +/* define this for recursive evaluation output */ +/* #define DEBUG_RECMAC */ + +char s[MAXLINE]; +Datei *filep; + +static int tcompare(char*,char**,int); +static int pp_replace(char*,char*,int,int); +static int searchdef(char*); +static int fgetline(char*,int len, int *rlen, FILE*); + +static int icl_open(char*),pp_ifdef(char*),pp_ifndef(char*); +static int pp_else(char*),pp_endif(char*); +static int pp_echo(char*),pp_if(char*),pp_print(char*),pp_prdef(char*); +static int pp_ifldef(char*),pp_iflused(char*); +static int pp_undef(char*); + +#define ANZBEF 13 +#define VALBEF 6 + +static int ungeteof = 0; + +static char *cmd[]={ "echo","include","define","undef","printdef","print", + "ifdef","ifndef","else","endif", + "ifldef","iflused","if" }; + +static int (*func[])(char*) = { pp_echo,icl_open,pp_define,pp_undef, + pp_prdef,pp_print, pp_ifdef,pp_ifndef, + pp_else,pp_endif, + pp_ifldef,pp_iflused,pp_if }; + +static char *mem; +static unsigned long memfre; +static int nlf; +static int nff; +static int hashindex[256]; + +static List *liste; +static unsigned int rlist; +static int fsp; +static int loopfl; +static Datei flist[MAXFILE+1]; +static char in_line[MAXLINE]; + +int pp_comand(char *t) +{ + int i,l,er=1; + + i=tcompare(t,cmd,ANZBEF); + + if(i>=0) + { + if(loopfl && (i>1; + return(0); +} + + +/* stub for handling CPP directives */ +int pp_cpp(char *t) { + + if(sscanf(t, " %d \"%s\"", &filep->fline, filep->fname) == 2) { + /* massage it into our parameters and drop last quote */ + char *u = ""; + + filep->fline--; + if((u = (char *)strrchr(filep->fname, '"'))) + *u = '\0'; + return (0); + } else { + return(E_SYNTAX); + } +} + +/* pp_undef is a great hack to get it working fast... */ +int pp_undef(char *t) { + int i; + if((i=searchdef(t))) { + i+=rlist; + liste[i].s_len=0; + } + return 0; +} + +int pp_prdef(char *t) +{ + char *x; + int i,j; + + if((i=searchdef(t))) + { + i+=rlist; + x=liste[i].search; + sprintf(s,"\n%s",x); + if(liste[i].p_anz) + { + sprintf(s+strlen(s),"("); + for(j=0;j=ANZDEF || memfre=ANZDEF || memfre10) + errout(E_ORECMAC); + } + (void)strcpy(liste[rlist+i].replace, nfto); +#ifdef DEBUG_RECMAC + printf("FINAL: -%s=%s\n",liste[rlist+i].search,liste[rlist+i].replace); +#endif + } + if(!er) + er=pp_replace(fto,fti,rlist,rlist+i); +/* if(flag) printf("sl=%d,",sl);*/ + sl=(int)((long)y+1L-(long)t); +/* if(flag) printf("sl=%d\n",sl);*/ + rs=fto; +/* printf("->%s\n",fto);*/ + } + } + if(er) + return(er); + } + + d=(int)strlen(rs)-sl; + + if(strlen(to)+d>=MAXLINE) + return(E_NOMEM); + +/* + if(d<0) + { + y=t+sl+d; + x=t+sl; + while(*y++=*x++); + } + if(d>0) + { + for(ll=strlen(t);ll>=sl;ll--) + t[ll+d]=t[ll]; + } +*/ + if(d) + (void)strcpy(t+sl+d,ti+sl); + + i=0; + while((c=rs[i])) + t[i++]=c; + l=sl+d;/*=0;*/ + break; + } + } + if(!n) + break; + + n=liste[n].nextindex; + + } while(1); + } else + { + for(n=b-1;n>=a;n--) + { + sl=liste[n].s_len; + + if(sl && (sl==l)) + { + i=0; + x=liste[n].search; + while(t[i]==*x++ && t[i]) + i++; + + if(i==sl) + { + rs=liste[n].replace; + if(liste[n].p_anz) + { + (void)strcpy(fti,liste[n].replace); + if(rlist+liste[n].p_anz>=ANZDEF || memfre=MAXLINE) + return(E_NOMEM); +/* + if(d<0) + { + y=t+sl+d; + x=t+sl; + while(*y++=*x++); + } + if(d>0) + { + for(ll=strlen(t);ll>=sl;ll--) + t[ll+d]=t[ll]; + } +*/ + if(d) + (void)strcpy(t+sl+d,ti+sl); + + i=0; + while((c=rs[i])) + t[i++]=c; + l+=d;/*0;*/ + break; + } + } + } + } + ti+=ld; + t+=l; + } + } + return(E_OK); +} + +int pp_init(void) +{ + int er; + + for(er=0;er<256;er++) + hashindex[er]=0; + + fsp=0; + + er=0; + mem=malloc(MAXPP); + if(!mem) er=E_NOMEM; + + memfre=MAXPP; + rlist=0; + nlf=1; + nff=1; + if(!er) { + liste=malloc((long)ANZDEF*sizeof(List)); + if(!liste) er=E_NOMEM; + } + return(er); +} + +int pp_open(char *name) +{ + FILE *fp; + + fp=xfopen(name,"r"); + + /* we have to alloc it dynamically to make the name survive another + pp_open - it's used in the cross-reference list */ + flist[0].fname = malloc(strlen(name)+1); + if(!flist[0].fname) { + fprintf(stderr,"Oops, no more memory!\n"); + exit(1); + } + (void)strcpy(flist[0].fname,name); + flist[0].fline=0; + flist[0].bdepth=b_depth(); + flist[0].filep=fp; + flist[0].flinep=NULL; + + return(((long)fp)==0l); +} + +void pp_close(void) +{ + if(flist[fsp].bdepth != b_depth()) { + fprintf(stderr, "Blocks not consistent in file %s: start depth=%d, end depth=%d\n", + flist[fsp].fname, flist[fsp].bdepth, b_depth()); + } + fclose(flist[fsp].filep); +} + +void pp_end(void) { } + +Datei *pp_getidat(void) { + return &flist[fsp]; +} + +int icl_close(int *c) +{ + *c='\n'; + if(!fsp) + return(E_EOF); + + if(flist[fsp].bdepth != b_depth()) { + fprintf(stderr, "Blocks not consistent in file %s: start depth=%d, end depth=%d\n", + flist[fsp].fname, flist[fsp].bdepth, b_depth()); + } + + fclose(flist[fsp--].filep); + nff=1; + + return(E_OK); +} + +int icl_open(char *tt) +{ + FILE *fp2; + int j,i=0; + + pp_replace(s,tt,-1,rlist); + + if(fsp>=MAXFILE) + return(-1); + + if(s[i]=='<' || s[i]=='"') + i++; + + for(j=i;s[j];j++) + if(s[j]=='>' || s[j]=='"') + s[j]='\0'; + + fp2=xfopen(s+i,"r"); + + if(!fp2) + return(E_FNF); + + setvbuf(fp2,NULL,_IOFBF,BUFSIZE); + + fsp++; + + /* we have to alloc it dynamically to make the name survive another + pp_open - it's used in the cross-reference list */ + flist[fsp].fname = malloc(strlen(s+i)+1); + if(!flist[fsp].fname) { + fprintf(stderr,"Oops, no more memory!\n"); + exit(1); + } + strcpy(flist[fsp].fname,s+i); + flist[fsp].fline=0; + flist[fsp].bdepth=b_depth(); + flist[fsp].flinep=NULL; + flist[fsp].filep=fp2; + nff=1; + + return(0); +} + +int pgetline(char *t) +{ + int c,er=E_OK; + int rlen, tlen; + char *p = 0; + + loopfl =0; /* set if additional fetch needed */ + + filep =flist+fsp; + + do { + c=fgetline(in_line, MAXLINE, &rlen, flist[fsp].filep); + /* continuation lines */ + tlen = rlen; + while(c=='\n' && tlen && in_line[tlen-1]=='\\') { + c=fgetline(in_line + tlen-1, MAXLINE-tlen, &rlen, flist[fsp].filep); + tlen += rlen-1; + } + if(in_line[0]=='#' || in_line[0] == altppchar) + { + if (in_line[1]==' ') { /* cpp comment -- pp_comand doesn't + handle this right */ + er=pp_cpp(in_line+1); + } else { + if((er=pp_comand(in_line+1))) + { + if(er!=1) + { + logout(in_line); + logout("\n"); + } + } + } + } else + er=1; + + if(c==EOF) { + if (loopfl && fsp) { + char bletch[MAXLINE]; + sprintf(bletch, + "at end of included file %s:\n", flist[fsp].fname); + logout(bletch); + errout(W_OPENPP); + } + er=icl_close(&c); + } + + } while(!er || (loopfl && er!=E_EOF)); + + if (loopfl) { + errout(E_OPENPP); + } + + /* handle the double-slash comment (like in C++) */ + p = strchr(in_line, '/'); + if (p != NULL) { + if (p[1] == '/') { + *p = 0; /* terminate string */ + } + } + + if(!er || loopfl) { + in_line[0]='\0'; + } + + er= (er==1) ? E_OK : er ; + + if(!er) + er=pp_replace(t,in_line,-1,rlist); + + if(!er && nff) + er=E_NEWFILE; + if(!er && nlf) + er=E_NEWLINE; + nlf=nff=0; + + filep=flist+fsp; + filep->flinep=in_line; + + return(er); +} + + +/*************************************************************************/ + +/* this is the most disgusting code I have ever written, but Andre drove me +to it because I can't think of any other F$%Y#*U(%&Y##^#KING way to fix the +last line bug ... a very irritated Cameron */ + +/* however, it also solved the problem of open #ifdefs not bugging out */ + +/* #define DEBUG_EGETC */ +int egetc(FILE *fp) { + int c; + + c = getc(fp); + if (c == EOF) { + if (ungeteof) { +#ifdef DEBUG_EGETC + fprintf(stderr, "eof claimed\n"); +#endif + return c; + } else { +#ifdef DEBUG_EGETC + fprintf(stderr, "got eof!!\n"); +#endif + ungeteof = 1; + return '\n'; + } + } + ungeteof = 0; + return c; +} + +/* smart getc that can skip C comment blocks */ +int rgetc(FILE *fp) +{ + static int c,d,fl; + + fl=0; + + do + { + while((c=egetc(fp))==13); /* remove ^M for unices */ + + if(fl && (c=='*')) + { + if((d=egetc(fp))!='/') + ungetc(d,fp); + else + { + fl--; + while((c=egetc(fp))==13); + } + } + if(c=='\n') + { + flist[fsp].fline++; + nlf=1; + } else + if(c=='/') + { + if((d=egetc(fp))!='*') + ungetc(d,fp); + else + fl++; + } + + } while(fl && (c!=EOF)); + + return(c-'\t'?c:' '); +} + +int fgetline(char *t, int len, int *rlen, FILE *fp) +{ + static int c,i; + + i=0; + + do { + c=rgetc(fp); + + if(c==EOF || c=='\n') + { + t[i]='\0'; + break; + } + t[i]=c; + i= (i +#include + +#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].adrrt.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].adrrt.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; +} + diff --git a/xa/src/xar.h b/xa/src/xar.h new file mode 100644 index 0000000..01aa887 --- /dev/null +++ b/xa/src/xar.h @@ -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__ */ diff --git a/xa/src/xar2.c b/xa/src/xar2.c new file mode 100644 index 0000000..fcf87b1 --- /dev/null +++ b/xa/src/xar2.c @@ -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 +#include + +#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].adrrd.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].adrrd.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; +} + diff --git a/xa/src/xat.c b/xa/src/xat.c new file mode 100644 index 0000000..a08539b --- /dev/null +++ b/xa/src/xat.c @@ -0,0 +1,2097 @@ +/* xa65 - 65xx/65816 cross-assembler and utility suite + * + * Copyright (C) 1989-1997 André Fachat (a.fachat@physik.tu-chemnitz.de) + * maintained by Cameron Kaiser + * + * Core tokenizing module/pass 1 and pass 2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* enable this to turn on (copious) optimization output */ +/* #define DEBUG_AM */ + +#include +#include + +#include "xad.h" +#include "xah.h" +#include "xah2.h" + +#include "xar.h" +#include "xa.h" +#include "xaa.h" +#include "xal.h" +#include "xat.h" +#include "xao.h" +#include "xap.h" +#include "xacharset.h" + +int dsb_len = 0; + +static int t_conv(signed char*,signed char*,int*,int,int*,int*,int*,int,int*); +static int t_keyword(signed char*,int*,int*); +static int tg_asc(signed char*,signed char*,int*,int*,int*,int*,int); +static void tg_dez(signed char*,int*,int*); +static void tg_hex(signed char*,int*,int*); +static void tg_oct(signed char*,int*,int*); +static void tg_bin(signed char*,int*,int*); + +/* assembly mnemonics and pseudo-op tokens */ +/* ina and dea don't work yet */ +static char *kt[] ={ +/* 1 2 3 4 5 6 7 8 9 10 */ + "adc","and","asl","bbr","bbs","bcc","bcs","beq","bit","bmi", + "bne","bpl","bra","brk","bvc","bvs","brl","clc","cld","cli", +/* + "clv","cmp","cpx","cpy","cop","dea","dec","dex","dey","eor", +*/ + "clv","cmp","cpx","cpy","cop",/*"dea",*/"dec","dex","dey","eor", + +/* + "ina","inc","inx","iny","jmp","jsr","lda","ldx","ldy","lsr", +*/ + /*"ina",*/"inc","inx","iny","jmp","jsr","lda","ldx","ldy","lsr", + "mvp","mvn","nop","ora","pha","php","phx","phy","pla","plp", + "plx","ply","phb","phd","phk","plb","pld","pea","pei","per", + + "rmb","rol","ror","rti","rts","rep","rtl","sbc","sec","sed", + "sei","smb","sta","stx","sty","stz","sep","stp","tax","tay", + "trb","tsb","tsx","txa","txs","tya","txy","tyx","tcd","tdc", + + "tcs","tsc","wai","wdb","xba","xce", + + ".byt",".word",".asc",".dsb", ".(", ".)", "*=", ".text",".data",".bss", + ".zero",".fopt", ".byte", ".end", ".list", ".xlist", ".dupb", ".blkb", ".db", ".dw", + ".align",".block", ".bend",".al",".as",".xl",".xs", ".bin", ".aasc" + +}; + +static int lp[]= { 0,1,1,1,1,2,2,1,1,1,2,2,2,1,1,1,2,2 }; + +/* index into token array for pseudo-ops */ +/* last valid mnemonic */ +#define Lastbef 93 +/* last valid token+1 */ +#define Anzkey 123 + +#define Kbyt Lastbef+1 +#define Kword Lastbef+2 +#define Kasc Lastbef+3 +#define Kdsb Lastbef+4 +#define Kopen Lastbef+5 /* .( */ +#define Kclose Lastbef+6 /* .) */ +#define Kpcdef Lastbef+7 /* *=value */ +#define Ktext Lastbef+8 +#define Kdata Lastbef+9 +#define Kbss Lastbef+10 +#define Kzero Lastbef+11 +#define Kfopt Lastbef+12 +#define Kbyte Lastbef+13 /* gets remapped to Kbyt */ +#define Kend Lastbef+14 /* ignored (MASM compat.) */ +#define Klist Lastbef+15 /* ignored (MASM compat.) */ +#define Kxlist Lastbef+16 /* ignored (MASM compat.) */ +#define Kdupb Lastbef+17 /* gets remapped to Kdsb */ +#define Kblkb Lastbef+18 /* gets remapped to Kdsb */ +#define Kdb Lastbef+19 /* gets remapped to Kbyt */ +#define Kdw Lastbef+20 /* gets remapped to Kword */ +#define Kalign Lastbef+21 +#define Kblock Lastbef+22 /* gets remapped to .( */ +#define Kbend Lastbef+23 /* gets remapped to .) */ + +#define Kalong Lastbef+24 +#define Kashort Lastbef+25 +#define Kxlong Lastbef+26 +#define Kxshort Lastbef+27 + +#define Kbin Lastbef+28 +#define Kaasc Lastbef+29 + +#define Kreloc Anzkey /* *= (relocation mode) */ +#define Ksegment Anzkey+1 + +/* array used for hashing tokens (26 entries, a-z) */ + +static int ktp[]={ 0,3,17,25,28,29,29,29,29,32,34,34,38,40,41,42,58, + 58,65,76,90,90,90,92,94,94,94,Anzkey }; + +#define Admodes 24 + +/* + * opcodes for each addressing mode + * high byte: supported architecture (no bits = original NMOS 6502) + * bit 1: R65C02 + * bit 2: 65816 + * bit 3: 65816 and allows 16-bit quantity (immediate only) + * low byte: opcode itself + * + * each opcode is indexed in this order: *=65816, ^=R65C02 + * 00 = implied + * 01 = zero page + * 02 = zero page,x + * 03 = direct page,y* + * 04 = direct page (indirect)* + * 05 = (indirect,x) + * 06 = (indirect),y + * 07 = immediate (8-bit) + * 08 = absolute + * 09 = absolute,x + * 10 = absolute,y + * 11 = relative + * 12 = (indirect-16) i.e., jmp (some_vector) + * 13 = (absolute,x)* + * 14 = zero page+relative test'n'branch ^ + * 15 = zero page clear'n'set'bit ^ + * 16 = relative long* + * 17 = absolute long* + * 18 = absolute long,x* + * 19 = stack relative* + * 20 = stack relative (indirect),y* + * 21 = direct page (indirect long)* + * 22 = direct page (indirect long),y* + * 23 = (indirect long) + */ + +static int ct[Lastbef+1][Admodes] ={ +/* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 imm */ +{ -1, 0x65,0x75,-1,0x172,0x61,0x71,0x469,0x6d,0x7d,0x79,-1, -1, -1, -1, -1, -1,0x26f,0x27f,0x263,0x273,0x267,0x277,-1 }, /*adc*/ +{ -1, 0x25,0x35,-1,0x132,0x21,0x31,0x429,0x2d,0x3d,0x39,-1, -1, -1, -1, -1, -1,0x22f,0x23f,0x223,0x233,0x227,0x237,-1 }, /*and*/ +{ 0x0a,0x06,0x16,-1, -1, -1, -1, -1, 0x0e,0x1e,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*asl*/ +{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0x10f,-1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*bbr*/ +{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0x18f,-1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*bbs*/ +{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0x90,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*bcc*/ +{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0xb0,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*bcs*/ +{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0xf0,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*beq*/ +{ -1, 0x24,0x134,-1, -1, -1, -1, 0x589,0x2c,0x13c,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*bit*/ +{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0x30,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*bmi*/ +{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0xd0,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*bne*/ +{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0x10,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*bpl*/ +{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0x180,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*bra*/ +{ 0x00,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*brk*/ +{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0x50,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*bvc*/ +{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0x70,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*bvs*/ +{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,0x282, -1, -1, -1, -1, -1, -1, -1 }, /*brl*/ +{ 0x18,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*clc*/ +{ 0xd8,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*cld*/ +{ 0x58,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*cli*/ +{ 0xb8,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*clv*/ +{ -1, 0xc5,0xd5,-1, 0x1d2,0xc1,0xd1,0x4c9,0xcd,0xdd,0xd9,-1, -1, -1, -1, -1,-1,0x2cf,0x2df,0x2c3,0x2d3,0x2c7,0x2d7,-1 }, /*cmp*/ +{ -1, 0xe4,-1, -1, -1, -1, -1, 0x8e0,0xec,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*cpx*/ +{ -1, 0xc4,-1, -1, -1, -1, -1, 0x8c0,0xcc,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*cpy*/ +{ -1, -1, -1, -1, -1, -1, -1, 0x202,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*cop*/ +/* +{ 0x13a,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },*/ /*dea*/ +{ 0x13a,0xc6,0xd6,-1, -1, -1, -1, -1, 0xce,0xde,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*dec*/ +{ 0xca,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*dex*/ +{ 0x88,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*dey*/ +{ -1, 0x45,0x55,-1, 0x152,0x41,0x51,0x449,0x4d,0x5d,0x59,-1, -1, -1, -1, -1,-1,0x24f,0x25f,0x243,0x253,0x247,0x257,-1 }, /*eor*/ +/* +{ 0x11a,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },*/ /*ina*/ +{ 0x11a,0xe6,0xf6,-1, -1, -1, -1, -1, 0xee,0xfe,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*inc*/ +{ 0xe8,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*inx*/ +{ 0xc8,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*iny*/ +{ -1, -1, -1, -1, -1, -1, -1, -1, 0x4c,-1, -1, -1, 0x6c,0x17c,-1, -1, -1,0x25c, -1, -1, -1, -1, -1,0x2dc}, /*jmp*/ +{ -1, -1, -1, -1, -1, -1, -1, -1, 0x20,-1, -1, -1, -1, 0x2fc,-1, -1, -1,0x222, -1, -1, -1, -1, -1, -1 }, /*jsr*/ +{ -1, 0xa5,0xb5,-1, 0x1b2,0xa1,0xb1,0x4a9,0xad,0xbd,0xb9,-1, -1, -1, -1, -1,-1,0x2af,0x2bf,0x2a3,0x2b3,0x2a7,0x2b7,-1 }, /*lda*/ +{ -1, 0xa6,-1, 0xb6,-1, -1, -1, 0x8a2,0xae,-1, 0xbe,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*ldx*/ +{ -1, 0xa4,0xb4,-1, -1, -1, -1, 0x8a0,0xac,0xbc,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*ldy*/ +{ 0x4a,0x46,0x56,-1, -1, -1, -1, -1, 0x4e,0x5e,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*lsr*/ +{ -1, -1, -1, -1, -1, -1, -1, -1, 0x244,-1, -1, -1 ,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*mvp*/ +{ -1, -1, -1, -1, -1, -1, -1, -1, 0x254,-1, -1, -1 ,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*mvn*/ +{ 0xea,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*nop*/ +{ -1, 0x05,0x15,-1, 0x112,0x01,0x11,0x409,0x0d,0x1d,0x19,-1, -1, -1, -1, -1,-1,0x20f,0x21f,0x203,0x213,0x207,0x217,-1 }, /*ora*/ +{ 0x48,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*pha*/ +{ 0x08,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*php*/ +{ 0x1da,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*phx*/ +{ 0x15a,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*phy*/ +{ 0x68,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*pla*/ +{ 0x28,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*plp*/ +{ 0x1fa,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*plx*/ +{ 0x17a,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*ply*/ +{ 0x28b,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*phb*/ +{ 0x20b,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*phd*/ +{ 0x24b,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*phk*/ +{ 0x2ab,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*plb*/ +{ 0x22b,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*pld*/ +{ -1, -1, -1, -1, -1, -1, -1, -1, 0x2f4,-1, -1, -1 ,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*pea*/ +{ -1, -1, -1, -1,0x2d4, -1, -1, -1, -1, -1, -1, -1 ,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*pei*/ +{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ,-1, -1, -1, -1, 0x262,-1, -1, -1, -1, -1, -1, -1 }, /*per*/ +{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,0x107, -1, -1, -1, -1, -1, -1, -1, -1 }, /*rmb*/ +{ 0x2a,0x26,0x36,-1, -1, -1, -1, -1, 0x2e,0x3e,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*rol*/ +{ 0x6a,0x66,0x76,-1, -1, -1, -1, -1, 0x6e,0x7e,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*ror*/ +{ 0x40,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*rti*/ +{ 0x60,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*rts*/ +{ -1, -1, -1, -1, -1, -1, -1, 0x2c2,-1, -1, -1, -1 ,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*rep*/ +{ 0x26b,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*rtl*/ +{ -1, 0xe5,0xf5,-1, 0x1f2,0xe1,0xf1,0x4e9,0xed,0xfd,0xf9,-1, -1, -1, -1, -1,-1,0x2ef,0x2ff,0x2e3,0x2f3,0x2e7,0x2f7,-1 }, /*sbc*/ +{ 0x38,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*sec*/ +{ 0xf8,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*sed*/ +{ 0x78,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*sei*/ +{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,0x187, -1, -1, -1, -1, -1, -1, -1, -1 }, /*smb*/ +{ -1, 0x85,0x95,-1, 0x192,0x81,0x91,-1, 0x8d,0x9d,0x99,-1, -1, -1, -1, -1,-1,0x28f,0x29f,0x283,0x293,0x287,0x297,-1 }, /*sta*/ +{ -1, 0x86,-1, 0x96,-1, -1, -1, -1, 0x8e,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*stx*/ +{ -1, 0x84,0x94,-1, -1, -1, -1, -1, 0x8c,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*sty*/ +{ -1, 0x164,0x174,-1, -1, -1, -1, -1, 0x19c,0x19e,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*stz*/ +{ -1, -1, -1, -1, -1, -1, -1, 0x2e2,-1, -1, -1, -1 ,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*sep*/ +{ 0x2db,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*stp*/ +{ 0xaa,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*tax*/ +{ 0xa8,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*tay*/ +{ -1, 0x114,-1, -1, -1, -1, -1, -1, 0x11c,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*trb*/ +{ -1, 0x104,-1, -1, -1, -1, -1, -1, 0x10c,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*tsb*/ +{ 0xba,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*tsx*/ +{ 0x8a,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*txa*/ +{ 0x9a,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*txs*/ +{ 0x98,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*tya*/ +{ 0x29b,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*txy*/ +{ 0x2bb,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*tyx*/ +{ 0x25b,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*tcd*/ +{ 0x27b,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*tdc*/ +{ 0x21b,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*tcs*/ +{ 0x23b,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*tsc*/ +{ 0x2cb,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*wai*/ +{ 0x242,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*wdb*/ +{ 0x2eb,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /*xba*/ +{ 0x2fb,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 ,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } /*xce*/ + + +} ; + +#define Syntax 14 +#define Maxbyt 4 + +/* grouped syntaxes. each row = operand type, column = bytes allowed */ +static int at[Syntax][Maxbyt] ={ +{ 0, -1, -1 ,-1 }, /* implied: no operand */ +{ -1, 7, -1 ,-1 }, /* immediate: single byte operand only */ +{ -1, 15, -1 ,-1 }, /* relative: single byte operand only */ +{ -1, -1, 14 ,-1 }, /* test'n'branch: two bytes only */ +{ -1, 1, 8 ,17 }, /* addressing: 1 byte for zp, + 2 for absolute, + 3 for absolute long */ +{ -1, 2, 9 ,18 }, /* ,x: same */ +{ -1, 3, 10 ,-1 }, /* ,y: 1 byte for dp,y, + 2 for absolute,y */ +{ -1, 4, 12 ,-1 }, /* (indirect): 1 byte for (dp), + 2 for (absolute) */ +{ -1, 5, 13 ,-1 }, /* (i,x): 1 byte for (zp,x), + 2 for (a,x) */ +{ -1, 6, -1 ,-1 }, /* (i),y: 1 byte only */ +{ -1, 21, 23 ,-1 }, /* (indirect long): 1 byte for (dp), + 2 for (a) */ +{ -1, 22, -1 ,-1 }, /* (indirect long),y: 1 byte only */ +{ -1, 19, -1 ,-1 }, /* stack relative: 1 byte only */ +{ -1, 20, -1 ,-1 } /* SR (in),y: 1 byte only */ +}; + +#define AnzAlt 5 + +/* disambiguation table. for example, arbitrary instruction xxx $0000 could + be either interpreted as an absolute operand, or possibly relative. + note: does not look at comma or after, if present. */ +static int xt[AnzAlt][2] ={ /* Alternativ Adr-Modes */ +{ 8, 11 }, /* abs -> rel */ +{ 2, 3 }, /* z,x -> z,y */ +{ 5, 6 }, /* ,x) -> ),y */ +{ 9, 10 }, /* a,x -> a,y */ + +{ 8, 16 } /* abs -> relong */ +}; + +/* cross check: instruction should be this many bytes long in total */ +/* indexed by addressing mode */ +static int le[] ={ 1,2,2,2,2,2,2,2,3,3,3,2,3,3,3,2, + /* new modes */ 3,4,4,2,2,2,2,3 }; + +/* indicates absolute->zp optimizable addressing modes (abs->zp) */ +/* indexed by addressing mode */ +static int opt[] ={ -1,-1,-1,-1,-1,-1,-1,-1,1,2,3,-1,4,5,-1,-1, + /*new*/ -1,8,9,-1,-1,-1,-1,-1 }; /* abs -> zp */ + +/* pass 1 */ +int t_p1(signed char *s, signed char *t, int *ll, int *al) +{ + static int er,l,n,v,nk,na1,na2,bl,am,sy,i,label,byte; /*,j,v2 ;*/ + int afl = 0; + +/* notes and typical conventions ... er = error code + am = addressing mode in use +*/ + + bl=0; + *al = 0; + +/* printf("\n"); */ + + /* convert the next token from string s */ +#ifdef DEBUG_AM +fprintf(stderr, "- p1 %d starting -\n", pc[segment]); +#endif + er=t_conv(s,t,&l,pc[segment],&nk,&na1,&na2,0,&byte); + /* leaving our token sequence in t */ + + *ll=l; +/* + printf("t_conv (er=%d):",er); + for(i=0;i1) && (t[0]base[SEG_TEXT] = pc[SEG_TEXT] = romaddr + h_length(); + romable=1; + } + + if(!er) + { + +/* + * + * pseudo-op dispatch (except .byt, .asc) + * + */ + n=t[0]; + /* TODO: make that a big switch statement... */ + /* maybe later. Cameron */ + + if(n==Kend || n==Klist || n==Kxlist) { + *ll = 0; /* ignore */ + } else + + if(n==Kfopt) { + if(romable==1) er=E_ROMOPT; + t[0] = Kbyt; + set_fopt(l,t,nk+1-na1+na2); + *ll = 0; + } else + if(n==Kpcdef) + { + int tmp; + if(!(er=a_term(t+1,&tmp /*&pc[SEG_ABS]*/,&l,pc[segment],&afl,&label,0))) + { + i=1; + wval(i,tmp /*pc[SEG_ABS]*/); + t[i++]=T_END; + *ll=6; + er=E_OKDEF; +/*printf("set pc=%04x, oldsegment=%d, pc[segm]=%04x, ", + pc[SEG_ABS], segment, pc[segment]); +printf(" wrote %02x %02x %02x %02x %02x %02x\n", + t[0],t[1],t[2],t[3],t[4],t[5]);*/ + if(segment==SEG_TEXT) { + pc[SEG_ABS] = tmp; + r_mode(RMODE_ABS); + } else { + if(!relmode) { + pc[segment] = tmp; + } else { + er = E_ILLSEGMENT; + } + } +/*printf("newsegment=%d, pc[ABS]=%04x\n", segment, pc[SEG_ABS]);*/ + } else { /* TODO: different error code */ + if((segment==SEG_ABS) && (er==E_SYNTAX && l==0)) { +/*printf("reloc: oldseg=%d, pc[oldseg]=%04x, pc[abs]=%04x, pc[text]=%04x\n", + segment, pc[segment], pc[SEG_ABS], pc[SEG_TEXT]);*/ + t[0]=Kreloc; + i=1; + wval(i,pc[SEG_TEXT]); + t[i++]=T_END; + *ll=6; + er=E_OKDEF; + r_mode(RMODE_RELOC); +/*printf(" : newseg=%d, pc[newseg]=%04x, pc[abs]=%04x, pc[text]=%04x\n", + segment, pc[segment], pc[SEG_ABS], pc[SEG_TEXT]);*/ + } + } + } else + if(n==Kopen) + { + if(showblk) fprintf(stderr, "%s line %d: .(\n", pp_getidat()->fname, pp_getidat()->fline); + b_open(); + er=E_NOLINE; + } else + if(n==Kclose) + { + if(showblk) fprintf(stderr, "%s line %d: .)\n", pp_getidat()->fname, pp_getidat()->fline); + er=b_close(); + if(!er) er=E_NOLINE; + } else + if(n==Kalong) + { + if (!w65816) { + er=E_65816; + } else { + memode=1; + t[0]=Kalong; + *ll=1; + er=E_OKDEF; + } + } else + if(n==Kashort) + { + memode=0; + t[0]=Kashort; + *ll=1; + er=E_OKDEF; + } else + if(n==Kxlong) + { + if (!w65816) { + er=E_65816; + } else { + xmode=1; + t[0]=Kxlong; + *ll=1; + er=E_OKDEF; + } + } else + if(n==Kxshort) + { + xmode=0; + t[0]=Kxshort; + *ll=1; + er=E_OKDEF; + } else + if(n==Kdsb) + { + dsb_len = 1; + if(!(er=a_term(t+1,&bl,&l,pc[segment],&afl,&label,0))) { + er=E_OKDEF; + } + dsb_len = 0; + } else + if(n==Ktext) { +/* if(segment!=SEG_ABS) { */ + segment = relmode ? SEG_TEXT : SEG_ABS; + t[0]=Ksegment; + t[1]=segment; + *ll=2; + er=E_OKDEF; +/* } else { + er=E_ILLSEGMENT; + } */ + } else + if(n==Kdata) { +/* if(segment!=SEG_ABS) { */ + segment = SEG_DATA; + t[0]=Ksegment; + t[1]=SEG_DATA; + *ll=2; + er=E_OKDEF; +/* } else { + er=E_ILLSEGMENT; + } */ + } else + if(n==Kbss) { +/* if(segment!=SEG_ABS) { */ + segment = SEG_BSS; + t[0]=Ksegment; + t[1]=SEG_BSS; + *ll=2; + er=E_OKDEF; +/* } else { + er=E_ILLSEGMENT; + } */ + } else + if(n==Kzero) { +/* if(segment!=SEG_ABS) { */ + segment = SEG_ZERO; + t[0]=Ksegment; + t[1]=SEG_ZERO; + *ll=2; + er=E_OKDEF; +/* } else { + er=E_ILLSEGMENT; + } */ + } else + if (n==Kbin) { + int j; + int l; + + /* this first pass just calculates a prospective length + for pass 2. */ + char binfnam[255]; + int offset; + int length; + int fstart; + + i = 1; + j = 0; + + /* get offset */ + if(!(er=a_term(t+i,&offset,&l,pc[segment],&afl,&label,1))) { + i += l; + } + if (offset < 0) + er = E_ILLQUANT; + if(t[i] == ',') { /* skip comma */ + i++; + } else { + er = E_SYNTAX; + } + + /* get length */ + if (!er && + !(er=a_term(t+i,&length,&l,pc[segment],&afl,&label,1))) + { + i += l; + } + if (length < 0) + er = E_ILLQUANT; + if(t[i] == ',') { /* skip comma */ + i++; + } else { + er = E_SYNTAX; + } + + /* get filename. + the tokenizer can either see it as a multichar string ... */ + if (!er) { + int k; + + fstart = i; + if(t[i]=='\"') { + i++; + k=t[i]+i+1; + i++; + while(i 255) + er = E_NOMEM; /* buffer overflow */ + } + binfnam[j] = '\0'; + /* or as a 'char' if it's a single character ("word" would + have been caught by the above) */ + } else + if(!(er=a_term(t+i,&v,&l,pc[segment],&afl,&label,1))) { + binfnam[0] = v; + binfnam[1] = '\0'; + i += l; + } + } + + /* three arguments only please */ + if (!er && t[i] != T_END) { + er = E_SYNTAX; + } + + if (!er) { + FILE *foo; + +#ifdef DEBUG_AM + fprintf(stderr, +"binclude1 offset = %i len = %i filename = %s endchar = %i\n", + offset, length, binfnam, i); +#endif + if (!(foo = fopen(binfnam, "r"))) { + er = E_FNF; + } else { + fseek(foo, 0, SEEK_END); + if ((length+offset) > ftell(foo)) { + er = E_OUTOFDATA; + } else { + length = (length) ? length : + (ftell(foo)-offset); + } + fclose(foo); + } + if (!er) { + if (length > 65535 && !w65816) { + errout(W_OVER64K); + } else if (length > 16777215) { + errout(W_OVER16M); + } + /* pass parameters back to xa.c */ + *ll=i+1; +/* + bl=length+2; +*/ + bl=length; + er = E_OKDEF; /* defer to pass 2 */ + } + } + } else + if(n==Kalign) { + int tmp; + if(segment!=SEG_ABS) { + if(!(er=a_term(t+1,&tmp,&l,pc[segment],&afl,&label,0))) { + if(tmp == 1 || tmp == 2 || tmp == 4 || tmp == 256) { + set_align(tmp); + if(pc[segment] & (tmp-1)) { /* not aligned */ + int tmp2; + t[0]=Kdsb; + i=1; + bl=tmp=(tmp - (pc[segment] & (tmp-1))) & (tmp-1); + wval(i,tmp); + t[i++]=','; + tmp2= 0xea; + wval(i,tmp2); /* nop opcode */ + t[i++]=T_END; + *ll=9; + er=E_OKDEF; + } else { + *ll=0; /* ignore if aligned right */ + } + } else { + er=E_ILLALIGN; + } + } + } else { + er=E_ILLSEGMENT; + } + } else +/* optimization okay on pass 1: use 0 for fl */ + { +#ifdef DEBUG_AM +fprintf(stderr, "E_OK ... t_p2 xat.c\n"); +#endif + er=t_p2(t,ll,(0 | byte), al); + } + + } else + if(er==E_NODEF) + { + +/* + * no label was found from t_conv! + * try to figure out most likely length + * + */ + +#ifdef DEBUG_AM +fprintf(stderr, "E_NODEF pass1 xat.c\n"); +#endif + er = E_OK; /* stuff error */ + n=t[0]; /* look at first token */ + + /* mnemonic dispatch -- abbreviated form in t_p2, but changed here + to not do anything other than 24-bit optimization since we + don't know the value of the label */ + + /* choose addressing mode; add commas found */ + + if(n>=0 && n<=Lastbef) + { + if(t[1]==T_END) + { + sy=0; /* implied */ + } else + if(t[1]=='#') + { + sy=1+nk; /* immediate */ + } else + if(t[1]=='(') + { + sy=7+nk; /* computed */ + } else + sy=4+nk; /* absolute or zero page */ + + /* length counter set to maximum length + 1 */ + bl=Maxbyt+1; + + /* find best fit for length of this operand */ + while(--bl) + { + + /* look at syntax table (at) using syntax (sy) as index. + is there an addressing mode for an operand + of this length? am = addressing mode */ + + if((am=at[sy][bl-1])>=0) + { + if(am>Admodes-1) /* no, it's -1, syntax error */ + { + er=E_SYNTAX; + break; + } + if(ct[n][am]>=0) /* yes, valid token *and* mode, + so we're done */ + break; + + /* no valid mode for this token, see if it's something + ambiguous; if so, try to interpret in that + context. */ + for(v=0;v=0) + break; + if(v=0 && am>16) /* <<< NOTE! */ + if(ct[n][opt[am]]>=0) + am=opt[am]; + } + /* if ` is declared, force further optimization */ + if (t[l-1]=='`') { + if (opt[am]<0 || ct[n][opt[am]]<0) + errout(E_ADRESS); + am=opt[am]; + } + /* if ! is declared, force to 16-bit quantity */ + if (t[l-1]=='!' && am>16 && opt[am]>=0 && bl) { + am=opt[am]; + } + + /* couldn't match anything for this opcode */ + if(!bl) + er=E_SYNTAX; + else { + /* ok, get length of instruction */ + bl=le[am]; + /* and add one for 65816 special instruction modes */ + if( ((ct[n][am]&0x400) && memode) || + ((ct[n][am]&0x800) && xmode)) { + bl++; + } + } + + + if (er == E_NODEF) + er = E_OK; + + /* .byt, .asc, .word, .dsb, .fopt pseudo-op dispatch */ + + } else + if(n==Kbyt || n==Kasc || n==Kaasc) + { +#ifdef DEBUG_AM +fprintf(stderr, "byt pass 1 %i\n", nk+1-na1+na2); +#endif + bl=nk+1-na1+na2; + } else + if(n==Kword) + { + bl=2*nk+2; + } else + if(n==Kdsb) + { + er=a_term(t+1,&bl,&l,pc[segment],&afl,&label,0); + } else + if(n==Kfopt) + { + set_fopt(l-1,t+1, nk+1-na1+na2); + *ll = 0; + } else + if(n==T_OP) + { + er=E_OKDEF; + } else + er=E_NODEF; + + if(!er) + er=E_OKDEF; +#ifdef DEBUG_AM +fprintf(stderr, "guessing instruction length is %d\n", bl); +#endif + } + if(er==E_NOLINE) + { + er=E_OK; + *ll=0; + } + + *al += bl; + pc[segment]+=bl; + if(segment==SEG_TEXT) pc[SEG_ABS]+=bl; + if(segment==SEG_ABS) pc[SEG_TEXT]+=bl; + + return(er); +} + +/*t_pass 2*/ +int t_p2(signed char *t, int *ll, int fl, int *al) +{ + static int afl,nafl, i,j,k,er,v,n,l,bl,sy,am,c,vv[3],v2,label; + static int rlt[3]; /* relocation table */ + static int lab[3]; /* undef. label table */ + +#if(0) + (void)fl; /* quench warning */ +#endif +/* fl was not used in 2.2.0 so I'm overloading it for zp-optimization + control */ + + er=E_OK; + bl=0; + if(*ll<0) /* <0 bei E_OK, >0 bei E_OKDEF */ + { + *ll=-*ll; + bl=*ll; + er=E_OK; + } else + { + n=t[0]; + if(n==T_OP) + { + n=cval(t+1); + er=a_term(t+4,&v,&l,pc[segment],&nafl,&label,0); + + if(!er) + { + if(t[3]=='=') + { + v2=v; + } else { + if( (!(er=l_get(n,&v2, &afl))) + && ((afl & A_FMASK)!=(SEG_UNDEF<<8)) ) + { + if(t[3]=='+') + { + if(afl && nafl) { errout(E_WPOINTER); nafl=0; } + nafl = afl; + v2+=v; + } else + if(t[3]=='-') + { + if( (((nafl & A_FMASK)>>8) != afl) + || ((nafl & A_MASK)==A_HIGH) ) { + errout(E_WPOINTER); + nafl=0; + } else { + nafl = afl; + } + v2-=v; + } else + if(t[3]=='*') + { + if(afl || nafl) { errout(E_WPOINTER); nafl=0; } + v2*=v; + } else + if(t[3]=='/') + { + if(afl || nafl) { errout(E_WPOINTER); nafl=0; } + if(v) + v2/=v; + else + er=E_DIV; + } else + if(t[3]=='|') + { + if(afl || nafl) { errout(E_WPOINTER); nafl=0; } + v2=v|v2; + } else + if(t[3]=='&') + { + if(afl || nafl) { errout(E_WPOINTER); nafl=0; } + v2=v2&v; + } + } + } + l_set(n,v2,nafl>>8); + + *ll=0; + if(!er) + er=E_NOLINE; + } + } else + if(n==Kword) + { + i=1; + j=0; + while(!er && t[i]!=T_END) + { + if(!(er=a_term(t+i,&v,&l,pc[segment],&afl,&label,1))) + { +/*if(afl) printf("relocation 1 %04x at pc=$%04x, value now =$%04x\n", + afl,pc[segment],v); */ + if(afl) u_set(pc[segment]+j, afl, label, 2); + t[j++]=v&255; + t[j++]=(v>>8)&255; + + i+=l; + if(t[i]!=T_END && t[i]!=',') + er=E_SYNTAX; + else + if(t[i]==',') + i++; + + } + } + *ll=j; + bl=j; + } else if (n == Kbin) { + int j; + int l; + + /* figure out our parameters again. repeat most of + the error checking since we might not be over + the total number of bogosities */ + char binfnam[255]; + int offset; + int length; + int fstart; + int flen; + + i = 1; + j = 0; + flen = 0; + + /* get offset */ + if(!(er=a_term(t+i,&offset,&l,pc[segment],&afl,&label,1))) { + i += l; + } + if (offset < 0) + er = E_ILLQUANT; + if(t[i] == ',') { /* skip comma */ + i++; + } else { + er = E_SYNTAX; + } + + /* get length */ + if (!er && + !(er=a_term(t+i,&length,&l,pc[segment],&afl,&label,1))) + { + i += l; + } + if (length < 0) + er = E_ILLQUANT; + if(t[i] == ',') { /* skip comma */ + i++; + } else { + er = E_SYNTAX; + } + + /* get filename. + the tokenizer can either see it as a multichar string ... */ + if (!er) { + int k; + + fstart = i; + if(t[i]=='\"') { + i++; + k=t[i]+i+1; + i++; + while(i 255) + er = E_NOMEM; /* buffer overflow */ + } + binfnam[j] = '\0'; + flen = j; + /* or as a 'char' if it's a single character ("word" would + have been caught by the above) */ + } else + if(!(er=a_term(t+i,&v,&l,pc[segment],&afl,&label,1))) { + binfnam[0] = v; + binfnam[1] = '\0'; + i += l; + flen = 1; + } + } + + /* three arguments only please */ + if (!er && t[i] != T_END) { + er = E_SYNTAX; + } + + if (!er) { + FILE *foo; + +#ifdef DEBUG_AM + fprintf(stderr, +"binclude2 offset = %i len = %i filename = %s endchar = %i\n", + offset, length, binfnam, i); +#endif + if (!(foo = fopen(binfnam, "r"))) { + er = E_FNF; + } else { + fseek(foo, 0, SEEK_END); + if ((length+offset) > ftell(foo)) { + er = E_OUTOFDATA; + } else { + length = (length) ? length : + (ftell(foo)-offset); + } + fclose(foo); + } + if (!er) { + if (length > 65535 && !w65816) { + errout(W_OVER64K); + } else if (length > 16777215) { + errout(W_OVER16M); + } + /* pass parameters back to xa.c */ + *ll=length; +/* + bl=length+2; +*/ + bl=length; + t[0] = offset & 255; + t[1] = (offset >> 8) & 255; + t[2] = (offset >> 16) & 255; + /* God help us if the index is > 65535 */ + t[3] = fstart & 255; + t[4] = (fstart >> 8) & 255; + t[5] = flen; /* to massage 'char' types */ + er = E_BIN; + } + } + } else if(n==Kasc || n==Kbyt || n==Kaasc) { + i=1; + j=0; + while(!er && t[i]!=T_END) + { + if(t[i]=='\"') + { + i++; + k=t[i]+i+1; + i++; + while(i>8) + er=E_OVERFLOW; + t[0]=v&255; + if(!er) + { + *ll=j; + bl=j; +#ifdef DEBUG_AM +fprintf(stderr, "Kdsb E_DSB %i\n", j); +#endif + er=E_DSB; + } + } + if(!er) + bl=j; + } + dsb_len = 0; + } else + if(n<=Lastbef) + { + if((c=t[1])=='#') + { + i=2; + sy=1; + if(!(er=a_term(t+i,vv,&l,pc[segment],&afl,&label,1))) + { +/* if(1) printf("a_term returns afl=%04x\n",afl); */ + + rlt[0] = afl; + lab[0] = label; + i+=l; + if(t[i]!=T_END) + { + if(t[i]!=',') + er=E_SYNTAX; + else + { + i++; + sy++; + if(!(er=a_term(t+i,vv+1,&l,pc[segment],&afl,&label,1))) + { + rlt[1] = afl; + lab[1] = label; + i+=l; + if(t[i]!=T_END) + { + if(t[i]!=',') + er=E_SYNTAX; + else + { + i++; + sy++; + if(!(er=a_term(t+i,vv+2,&l,pc[segment],&afl,&label,1))) + { + rlt[2] = afl; + lab[2] = label; + i+=l; + if(t[i]!=T_END) + er=E_SYNTAX; + } + } + } + } + } + } + } + } else + if(c==T_END) + { + sy=0; + } else + if(c=='(') + { + sy=7; + if(!(er=a_term(t+2,vv,&l,pc[segment],&afl,&label,1))) + { + rlt[0] = afl; + lab[0] = label; + + if(t[2+l]!=T_END) + { + if(t[2+l]==',') + { + if (tolower(t[3+l])=='x') + sy=8; + else + sy=13; + + } else + if(t[2+l]==')') + { + if(t[3+l]==',') + { + if(tolower(t[4+l])=='y') + sy=9; + else + er=E_SYNTAX; + } else + if(t[3+l]!=T_END) + er=E_SYNTAX; + } + } else + er=E_SYNTAX; + } + } else + if(c=='[') + { + sy=10; + if(!(er=a_term(t+2,vv,&l,pc[segment],&afl,&label,1))) + { + rlt[0] = afl; + lab[0] = label; + + if(t[2+l]!=T_END) + { + if(t[2+l]==']') + { + if(t[3+l]==',') + { + if(tolower(t[4+l])=='y') + sy=11; + else + er=E_SYNTAX; + } else + if(t[3+l]!=T_END) + er=E_SYNTAX; + } + } else + er=E_SYNTAX; + } + } else + { + sy=4; + if(!(er=a_term(t+1,vv,&l,pc[segment],&afl,&label,1))) + { + rlt[0] = afl; + lab[0] = label; + if(t[1+l]!=T_END) + { + if(t[1+l]==',') + { + if(tolower(t[2+l])=='y') + sy=6; + else + if(tolower(t[2+l])=='s') + sy=12; + else + sy=5; + } else + er=E_SYNTAX; + } + } + } + + bl=Maxbyt+1; + + while(--bl) + { + if((am=at[sy][bl-1])>=0) + { + if(am>Admodes) + { + er=E_SYNTAX; + break; + } + if(ct[n][am]>=0) + break; + + for(v=0;v=0) + break; + if(v16 && + !er && !(vv[0]&0xff0000) && opt[am]>=0) + if(ct[n][opt[am]]>=0) + am=opt[am]; +#ifdef DEBUG_AM +fprintf(stderr, +"aftaa1: pc= %d, am = %d and vv[0] = %d, optimize = %d, bitmask = %d\n", + pc[segment], am, vv[0], fl, (vv[0]&0xffff00)); +#endif + if(t[*ll-1]!='!') { + if(bl && !er && !(vv[0]&0xffff00) && opt[am]>=0) { + if(ct[n][opt[am]]>=0) { + if (!fl || t[*ll-1]=='`') { + am=opt[am]; + } else { + errout(W_FORLAB); + } + } + } + } +#ifdef DEBUG_AM +fprintf(stderr, +"aftaa2: pc=%d, am=%d and vv[0]=%d, optimize=%d, bitmask=%d, op=%d\n", + pc[segment], am, vv[0], fl, (vv[0]&0xffff00), ct[n][opt[am]]); +#endif + } + + if(!bl) + er=E_SYNTAX; + else + { + bl=le[am]; + if( ((ct[n][am]&0x400) && memode) || ((ct[n][am]&0x800) && xmode)) { + bl++; + } + *ll=bl; + + } + +#ifdef DEBUG_AM +fprintf(stderr, "byte length is now %d\n", bl); +#endif + + if(!er) + { + t[0]=ct[n][am]&0x00ff; + if(ct[n][am]&0x0300) + { + if(ct[n][am]&0x100) { + ncmos++; + if(!cmosfl) + er=E_CMOS; + } else { + n65816++; + if(!w65816) + er=E_65816; + } + } + if(am!=0) + { + if((am<8 && !( ((ct[n][am]&0x400) && memode) || ((ct[n][am]&0x800) && xmode) )) || (am>=19 && am!=23)) + { + if(vv[0]&0xff00) { +#ifdef DEBUG_AM +fprintf(stderr, "address mode: %i address: %i\n", am, vv[0]); +#endif + er=E_OVERFLOW; + } + else + t[1]=vv[0]; +/*if(rlt[0]) printf("relocation 1 byte %04x at pc=$%04x, value now =$%04x\n",rlt[0],pc[segment]+1,*vv); */ + if(rlt[0]) u_set(pc[segment]+1, rlt[0], lab[0], 1); + } else + if(((am<14 || am==23) && am!=11) || am==7) + { + if (vv[0]>0xffff) { +#ifdef DEBUG_AM +fprintf(stderr, "address mode: %i address: %i\n", am, vv[0]); +#endif + er=E_OVERFLOW; + } + else { + t[1]=vv[0]&255; + t[2]=(vv[0]>>8)&255; +/*if(rlt[0]) printf("relocation 2 byte %04x at pc=$%04x, value now =$%04x\n",rlt[0],pc[segment]+1,*vv); */ + if(rlt[0]) u_set(pc[segment]+1, rlt[0], lab[0], 2); + } + } else + if(am==11 || am==16) { + if((segment!=SEG_ABS) && (!rlt[0])) { + er=E_ILLPOINTER; + } else { +/*printf("am=11, pc=%04x, vv[0]=%04x, segment=%d\n",pc[segment],vv[0], segment);*/ + v=vv[0]-pc[segment]-le[am]; + if(((v&0xff80)!=0xff80) && (v&0xff80) && (am==11)) + er=E_RANGE; + else { + t[1]=v&255; + t[2]=(v>>8)&255; + } + } + } else + if(am==14) { + if(vv[0]&0xfff8 || vv[1]&0xff00) + er=E_RANGE; + else + if((segment!=SEG_ABS) && (rlt[0] || !rlt[2])) { + er=E_ILLPOINTER; + } else { +/*if(rlt[1]) printf("relocation 1 byte %04x at pc=$%04x, value now =$%04x\n",rlt[1],pc[segment]+1,*vv); */ + if(rlt[1]) u_set(pc[segment]+1, rlt[1], lab[1], 1); + t[0]=t[0]|(vv[0]<<4); + t[1]=vv[1]; + v=vv[2]-pc[segment]-3; + if((v&0xff80) && ((v&0xff80)!=0xff80)) + er=E_OVERFLOW; + else + t[2]=v; + } + } else + if(am==15) + { +/*if(rlt[1]) printf("relocation 1 byte %04x at pc=$%04x, value now =$%04x\n",rlt[1],pc[segment]+1,*vv); */ + if(rlt[1]) u_set(pc[segment]+1, rlt[1], lab[1], 1); + if(vv[0]&0xfff8 || vv[1]&0xff00) + er=E_OVERFLOW; + else + { + t[0]=t[0]|(vv[0]<<4); + t[1]=vv[1]; + } + } else + if(am==17 || am==18) + { + t[1]=vv[0]&255; + t[2]=(vv[0]>>8)&255; + t[3]=(vv[0]>>16)&255; + if(rlt[0]) { + rlt[0]|=A_LONG; + u_set(pc[segment]+1, rlt[0], lab[0], 3); + } + + } else + er=E_SYNTAX; + } + } + + } else + er=E_SYNTAX; + } +#ifdef DEBUG_AM +fprintf(stderr, "-- endof P2\n"); +#endif + pc[segment]+=bl; + if(segment==SEG_TEXT) pc[SEG_ABS]+=bl; + if(segment==SEG_ABS) pc[SEG_TEXT]+=bl; + *al = bl; + return(er); +} + +int b_term(char *s, int *v, int *l, int pc) +{ + static signed char t[MAXLINE]; + int er,i,afl, label; + + if(!(er=t_conv((signed char*)s,t,l,pc,&i,&i,&i,1,NULL))) + { + er=a_term(t,v,&i,pc,&afl,&label,0); + + } + return(er); +} + +/* translate a string into a first-pass sequence of tokens */ +static int t_conv(signed char *s, signed char *t, int *l, int pc, int *nk, + int *na1, int *na2, int af, int *bytep) /* Pass1 von s nach t */ +/* tr. pass1, from s to t */ +{ + static int v,f; + static int operand,o; + int fl,afl; + int p,q,ud,n,ll,mk,er; + int m, uz, byte; + static unsigned char cast; + +/* ich verstehe deutsch, aber verstehen andere leute nicht; so, werde ich + diese bemerkungen uebersetzen ... cameron */ +/* I understand German, but other folks don't, so I'll translate these + comments ... Cameron */ +/* note that I don't write so good tho' ;) */ + + *nk=0; /* comma count */ + *na1=0; /* asc text count */ + *na2=0; /* total bytecount in asc texts */ + ll=0; + er=E_OK; /* error state */ + p=0; + q=0; + ud = uz = byte =0; + mk=0; /* 0 = add'l commas ok */ + fl=0; /* 1 = pass text thru */ + afl=0; /* pointer flag for label */ + + while(s[p]==' ') p++; + + n=T_END; + cast='\0'; + + if(!af) + { + while(s[p]!='\0' && s[p]!=';') + { + + /* is keyword? */ + if(!(er=t_keyword(s+p,&ll,&n))) + break; + + /* valid syntax, but just not a real token? */ + if(er && er!=E_NOKEY) + break; + + /* if so, try to understand as label */ + if((er=l_def((char*)s+p,&ll,&n,&f))) + break; + + p+=ll; + + while(s[p]==' ') p++; + + if(s[p]=='=') + { + t[q++]=T_OP; + t[q++]=n&255; + t[q++]=(n>>8)&255; + t[q++]='='; + p++; + ll=n=0; + break; + } else + if(f && s[p]!='\0' && s[p+1]=='=') + { + t[q++]=T_OP; + t[q++]=n&255; + t[q++]=(n>>8)&255; + t[q++]=s[p]; + p+=2; + ll=n=0; + break; + } else + if(s[p]==':') /* to support label: ... syntax */ + { + p++; + while(s[p]==' ') p++; + l_set(n,pc,segment); /* set as address value */ + n=0; + } else { /* label ... syntax */ + l_set(n,pc,segment); /* set as address value */ + n=0; + } + + } + + if((n & 0xff) <=Lastbef) + mk=1; /* 1= nur 1 Komma erlaubt *//* = only 1 comma ok */ + } + + if(s[p]=='\0' || s[p]==';') + { + er=E_NOLINE; + ll=0; + } else + if(!er) + { + + p+=ll; + if(ll) { + t[q++]= n & 0xff; +/* + if( (n&0xff) == Kmacro) { + t[q++]= (n >> 8) & 0xff; + } +*/ + } + + operand=1; + + while(s[p]==' ') p++; + + if(s[p]=='#') + { + mk=0; + t[q++]=s[p++]; + while(s[p]==' ') p++; + } + +/* + * + * operand processing + * byte = length of operand in bytes to be assembled + * + * + */ + + /* this addresses forced high/low/two byte addressing, but only + for the first operand. Further processing is done in a_term() + */ + +/* FIXIT2 */ + + while(s[p]!='\0' && s[p]!=';' && !er) + { + if(fl) + { + t[q++]=s[p++]; + } else + { + if(operand) + { + /* are we forcing the operand into a particular + addressing mode? !, @, ` operators */ + if(s[p]=='!' || s[p]=='@' || s[p]=='`') + { + cast=s[p]; + operand= -operand+1; + p++; + } else + if(s[p]=='(' || s[p]=='-' || s[p]=='>' || + s[p]=='<' || s[p]=='[') + { + t[q++]=s[p++]; + operand= -operand+1; /* invert to become reinverted */ + } else + if(s[p]=='*') + { + t[q++]=s[p++]; + } else + /* maybe it's a label */ + if(isalpha(s[p]) || s[p]=='_') + { + m=n; + er=l_search((char*)s+p,&ll,&n,&v,&afl); + +/* + if(m==Kglobl || m==Kextzero) { + if(er==E_NODEF) { + er=E_OK; + } + t[q++]=T_LABEL; + t[q++]=n & 255; + t[q++]=(n>>8) & 255; + } else +*/ + + if(!er) + { + if(afl) { + t[q++]=T_POINTER; + t[q++]=afl & 255; + t[q++]=v & 255; + t[q++]=(v>>8) & 255; + } else { + wval(q,v); + } + } else + if(er==E_NODEF) + { +#ifdef DEBUG_AM +fprintf(stderr, "could not find %s\n", (char *)s+p); +#endif + t[q++]=T_LABEL; + t[q++]=n & 255; + t[q++]=(n>>8) & 255; +/* + if(afl==SEG_ZEROUNDEF) uz++; +*/ + ud++; + er=E_OK; + } + p+=ll; + } + else + if(s[p]<='9' && s[p]>='0') + { + tg_dez(s+p,&ll,&v); + p+=ll; + wval(q,v); + } + else + + /* handle encodings: hex, binary, octal, quoted strings */ + switch(s[p]) { + case '$': + tg_hex(s+p+1,&ll,&v); + p+=1+ll; + wval(q,v); + break; + case '%': + tg_bin(s+p+1,&ll,&v); + p+=1+ll; + wval(q,v); + break; + case '&': + tg_oct(s+p+1,&ll,&v); + p+=1+ll; + wval(q,v); + break; + case '\'': + case '\"': + er=tg_asc(s+p,t+q,&q,&p,na1,na2,n); + break; + case ',': + if(mk) + while(s[p]!='\0' && s[p]!=';') + { + while(s[p]==' ') p++; + *nk+=(s[p]==','); + t[q++]=s[p++]; + } + else + { + *nk+=1; + t[q++]=s[p++]; + } + break; + default : + er=E_SYNTAX; + break; + } + operand= -operand+1; + + } else /* operator */ + { + o=0; + if(s[p]==')' || s[p]==']') + { + t[q++]=s[p++]; + operand =-operand+1; + } else + if(s[p]==',') + { + t[q++]=s[p++]; + if(mk) + fl++; + *nk+=1; + } else + switch(s[p]) { + case '+': + o=1; + break; + case '-': + o=2; + break; + case '*': + o=3; + break; + case '/': + o=4; + break; + case '<': + switch (s[p+1]) { + case '<': + o=6; + break; + case '>': + o=12; + break; + case '=': + o=10; + break; + default : + o=7; + break; + } + break; + case '>': + switch (s[p+1]) { + case '>': + o=5; + break; + case '<': + o=12; + break; + case '=': + o=11; + break; + default: + o=8; + break; + } + break; + case '=': + switch (s[p+1]) { + case '<': + o=10; + break; + case '>': + o=11; + break; + default: + o=9; + break; + } + break; + case '&': + if (s[p+1]=='&') + o=16; + else + o=13; + break; + case '|': + if (s[p+1]=='|') + o=17; + else + o=15; + break; + case '^': + o=14; + break; + default: + er=E_SYNTAX; + break; + } + if(o) + { + t[q++]=o; + p+=lp[o]; +#if(0) + uz++; /* disable 8-bit detection */ +#endif + } + operand= -operand+1; + } + + while(s[p]==' ') p++; + } + } + } + if(!er) + { +/* + if(uz==1 && ud==1 && byte!=2) { + byte=1; + } + if(byte == 1) { + t[q++] = T_FBYTE; + } else if(byte == 2) { + t[q++] = T_FADDR; + } +*/ + byte = 0; + t[q++]=T_END; + if(ud > 0) { + er=E_NODEF; + byte = 1; + } + } + /* FIXME: this is an unholy union of two "!" implementations :-( */ + t[q++]='\0'; + t[q++]=cast; + *l=q; + if(bytep) *bytep=byte; + return(er); +} + +static int t_keyword(signed char *s, int *l, int *n) +{ + int i = 0, j = 0, hash; + + if(!isalpha(s[0]) && s[0]!='.' && s[0]!='*' ) + return(E_NOKEY); + + if(isalpha(s[0])) + hash=tolower(s[0])-'a'; + else + hash=26; + + + if(s[0]=='*') { + j=1; + while(s[j] && isspace(s[j])) j++; + if(s[j]=='=') { + i=Kpcdef; + j++; + } + } + if(!i) { + i=ktp[hash]; + hash=ktp[hash+1]; + while(i='0') + val=val*8+(s[i++]-'0'); + + *l=i; + *v=val; +} + +static void tg_hex(signed char *s, int *l, int *v) +{ + int i=0,val=0; + + while((s[i]>='0' && s[i]<='9') || (tolower(s[i])<='f' && tolower(s[i])>='a')) + { + val=val*16+(s[i]<='9' ? s[i]-'0' : tolower(s[i])-'a'+10); + i++; + } + *l=i; + *v=val; +} + +/* + * tokenize a string - handle two delimiter types, ' and " + */ +static int tg_asc(signed char *s, signed char *t, int *q, int *p, int *na1, int *na2,int n) +{ + + int er=E_OK,i=0,j=0; + + signed char delimiter = s[i++]; + +#ifdef DEBUG_AM +fprintf(stderr, "tg_asc token = %i\n", n); +#endif + + t[j++]='"'; /* pass2 token for string */ + j++; /* skip place for length */ + + while(s[i]!='\0' && s[i]!=delimiter) + { + /* do NOT convert for Kbin or Kaasc, or for initial parse */ + if (!n || n == Kbin || n == Kaasc) { + t[j++]=s[i]; + } else if(s[i]!='^') { /* no escape code "^" */ + t[j++]=convert_char(s[i]); + } else { /* escape code */ + signed char payload = s[i+1]; + switch(payload) { + case '\0': + er=E_SYNTAX; + break; + case '\"': + if (payload == delimiter) { + t[j++]=convert_char(payload); + i++; + } else { + er=E_SYNTAX; + } + break; + case '\'': + if (payload == delimiter) { + t[j++]=convert_char(payload); + i++; + } else { + er=E_SYNTAX; + } + break; + case '^': + t[j++]=convert_char('^'); + i++; + break; + default: + t[j++]=convert_char(payload&0x1f); + i++; + break; + } + } + i++; + } + if(j==3) /* optimize single byte string to value */ + { + t[0]=T_VALUE; + t[1]=t[2]; + t[2]=0; + t[3]=0; + j++; + } else + { /* handle as string */ + t[1]=j-2; + *na1 +=1; + *na2 +=j-2; + } + if(s[i]==delimiter) { /* in case of no error */ + i++; /* skip ending delimiter */ + } + *q +=j; + *p +=i; + return(er); +} + diff --git a/xa/src/xat.h b/xa/src/xat.h new file mode 100644 index 0000000..ad7b82b --- /dev/null +++ b/xa/src/xat.h @@ -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__ */ diff --git a/xa/src/xau.c b/xa/src/xau.c new file mode 100644 index 0000000..c8b7560 --- /dev/null +++ b/xa/src/xau.c @@ -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 +#include + +#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;iud.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;iud.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; +} diff --git a/xa/src/xau.h b/xa/src/xau.h new file mode 100644 index 0000000..aca100a --- /dev/null +++ b/xa/src/xau.h @@ -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); + diff --git a/xa/tests/README b/xa/tests/README new file mode 100644 index 0000000..58442e8 --- /dev/null +++ b/xa/tests/README @@ -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 + diff --git a/xa/tests/adrm/02.asm b/xa/tests/adrm/02.asm new file mode 100644 index 0000000..db2b783 --- /dev/null +++ b/xa/tests/adrm/02.asm @@ -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 + diff --git a/xa/tests/adrm/816.asm b/xa/tests/adrm/816.asm new file mode 100644 index 0000000..7f1b3e0 --- /dev/null +++ b/xa/tests/adrm/816.asm @@ -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 diff --git a/xa/tests/adrm/a.o65 b/xa/tests/adrm/a.o65 new file mode 100644 index 0000000..218516c Binary files /dev/null and b/xa/tests/adrm/a.o65 differ diff --git a/xa/tests/adrm/bip.inc b/xa/tests/adrm/bip.inc new file mode 100644 index 0000000..93bb6cb --- /dev/null +++ b/xa/tests/adrm/bip.inc @@ -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 diff --git a/xa/tests/adrm/c02.asm b/xa/tests/adrm/c02.asm new file mode 100644 index 0000000..a55556a --- /dev/null +++ b/xa/tests/adrm/c02.asm @@ -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 diff --git a/xa/tests/adrm/zab.asm b/xa/tests/adrm/zab.asm new file mode 100644 index 0000000..248f0e2 --- /dev/null +++ b/xa/tests/adrm/zab.asm @@ -0,0 +1,4 @@ + .word $4000 + * = $4000 + +#include "bip.inc" diff --git a/xa/tests/adrm/zpa.asm b/xa/tests/adrm/zpa.asm new file mode 100644 index 0000000..ca9bc5f --- /dev/null +++ b/xa/tests/adrm/zpa.asm @@ -0,0 +1,4 @@ + .word $0000 + * = $0000 + +#include "bip.inc" diff --git a/xa/tests/binclude/README.1st b/xa/tests/binclude/README.1st new file mode 100644 index 0000000..57a3ecf --- /dev/null +++ b/xa/tests/binclude/README.1st @@ -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 + diff --git a/xa/tests/binclude/test.asm b/xa/tests/binclude/test.asm new file mode 100644 index 0000000..850fb15 --- /dev/null +++ b/xa/tests/binclude/test.asm @@ -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 * + diff --git a/xa/tests/binclude/test2.asm b/xa/tests/binclude/test2.asm new file mode 100644 index 0000000..4f88763 --- /dev/null +++ b/xa/tests/binclude/test2.asm @@ -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 * + diff --git a/xa/tests/chardelimiter/a.o65 b/xa/tests/chardelimiter/a.o65 new file mode 100644 index 0000000..a47bbe1 --- /dev/null +++ b/xa/tests/chardelimiter/a.o65 @@ -0,0 +1 @@ +©A©A1234512345"''" \ No newline at end of file diff --git a/xa/tests/chardelimiter/delimtest.a65 b/xa/tests/chardelimiter/delimtest.a65 new file mode 100644 index 0000000..c7b3a84 --- /dev/null +++ b/xa/tests/chardelimiter/delimtest.a65 @@ -0,0 +1,16 @@ + + *=$033c + + lda #"A" + lda #'A' + + .asc "12345" + .asc '12345' + + .asc "^"" ; ^ is escape character + .asc '^'' + .asc "'" + .asc '"' + + .asc "^1" + diff --git a/xa/tests/charset/README.1st b/xa/tests/charset/README.1st new file mode 100644 index 0000000..0c7994a --- /dev/null +++ b/xa/tests/charset/README.1st @@ -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 + diff --git a/xa/tests/charset/a.o65 b/xa/tests/charset/a.o65 new file mode 100644 index 0000000..72ae310 Binary files /dev/null and b/xa/tests/charset/a.o65 differ diff --git a/xa/tests/charset/test.asm b/xa/tests/charset/test.asm new file mode 100644 index 0000000..645b528 --- /dev/null +++ b/xa/tests/charset/test.asm @@ -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" diff --git a/xa/tests/charset/test2.s b/xa/tests/charset/test2.s new file mode 100644 index 0000000..1d6065b --- /dev/null +++ b/xa/tests/charset/test2.s @@ -0,0 +1 @@ +.aasc "test2" diff --git a/xa/tests/chppch/a.o65 b/xa/tests/chppch/a.o65 new file mode 100644 index 0000000..64845fb --- /dev/null +++ b/xa/tests/chppch/a.o65 @@ -0,0 +1 @@ +` \ No newline at end of file diff --git a/xa/tests/chppch/qwerty.h b/xa/tests/chppch/qwerty.h new file mode 100644 index 0000000..28b2b52 --- /dev/null +++ b/xa/tests/chppch/qwerty.h @@ -0,0 +1,4 @@ + rts + +#print 12+12 +~print 10+10 diff --git a/xa/tests/chppch/test.c b/xa/tests/chppch/test.c new file mode 100644 index 0000000..f5b1094 --- /dev/null +++ b/xa/tests/chppch/test.c @@ -0,0 +1,3 @@ +#include "qwerty.h" + +~print 5+5 diff --git a/xa/tests/chppch/test.out b/xa/tests/chppch/test.out new file mode 100644 index 0000000..dd4cdaa --- /dev/null +++ b/xa/tests/chppch/test.out @@ -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 diff --git a/xa/tests/comcom/a.o65 b/xa/tests/comcom/a.o65 new file mode 100644 index 0000000..579a01e Binary files /dev/null and b/xa/tests/comcom/a.o65 differ diff --git a/xa/tests/comcom/comcom.asm b/xa/tests/comcom/comcom.asm new file mode 100644 index 0000000..1281528 --- /dev/null +++ b/xa/tests/comcom/comcom.asm @@ -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 diff --git a/xa/tests/comcom/scomcom.asm b/xa/tests/comcom/scomcom.asm new file mode 100644 index 0000000..388ade4 --- /dev/null +++ b/xa/tests/comcom/scomcom.asm @@ -0,0 +1,5 @@ +; some comment: *2 = 1 + +start + lda #1: sta 2 + diff --git a/xa/tests/cpp/Makefile b/xa/tests/cpp/Makefile new file mode 100644 index 0000000..6cc4878 --- /dev/null +++ b/xa/tests/cpp/Makefile @@ -0,0 +1,3 @@ +default: + cc -E over.c > over.asm + ../../xa over.asm diff --git a/xa/tests/cpp/over.asm b/xa/tests/cpp/over.asm new file mode 100644 index 0000000..c8cc252 --- /dev/null +++ b/xa/tests/cpp/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 + + + diff --git a/xa/tests/cpp/over.c b/xa/tests/cpp/over.c new file mode 100644 index 0000000..5990b0c --- /dev/null +++ b/xa/tests/cpp/over.c @@ -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 */ diff --git a/xa/tests/cpp/over.h b/xa/tests/cpp/over.h new file mode 100644 index 0000000..ab2f3ae --- /dev/null +++ b/xa/tests/cpp/over.h @@ -0,0 +1,10 @@ + +#define X W +#define W 5 + +fuzz lda #W + sta $0400 + bne fuzz + rts + + lda @$c0c0c0 diff --git a/xa/tests/fordef/a.o65 b/xa/tests/fordef/a.o65 new file mode 100644 index 0000000..74a6e57 Binary files /dev/null and b/xa/tests/fordef/a.o65 differ diff --git a/xa/tests/fordef/test.asm b/xa/tests/fordef/test.asm new file mode 100644 index 0000000..3df82bb --- /dev/null +++ b/xa/tests/fordef/test.asm @@ -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" + diff --git a/xa/tests/fordef/test2.asm b/xa/tests/fordef/test2.asm new file mode 100644 index 0000000..9499afb --- /dev/null +++ b/xa/tests/fordef/test2.asm @@ -0,0 +1,5 @@ + +forward1 = $02 +forward2 = $03 + +forward3 rts diff --git a/xa/tests/fordef/test3.asm b/xa/tests/fordef/test3.asm new file mode 100644 index 0000000..0429816 --- /dev/null +++ b/xa/tests/fordef/test3.asm @@ -0,0 +1,21 @@ + .word $0400 + *=$0400 + +/* define this if you want to crash and burn */ + +#ifdef FAIL + jmp `forward3 + bne `forward3 + lda (`forward1),y + lda (`forward3),y +#echo congrats, you have FAILED! +#endif + + sta `forward3 + +/* this looks like it should fail, but won't because there is no ambiguity */ + + lda (forward1),y + jmp forward3 + +#include "test2.asm" diff --git a/xa/tests/incerr/test.6502 b/xa/tests/incerr/test.6502 new file mode 100644 index 0000000..ebec20a --- /dev/null +++ b/xa/tests/incerr/test.6502 @@ -0,0 +1 @@ + .xl diff --git a/xa/tests/incerr/test.s b/xa/tests/incerr/test.s new file mode 100644 index 0000000..6261e7f --- /dev/null +++ b/xa/tests/incerr/test.s @@ -0,0 +1 @@ +#include "test.6502" diff --git a/xa/tests/ldoreloc/1.s b/xa/tests/ldoreloc/1.s new file mode 100644 index 0000000..ce601c7 --- /dev/null +++ b/xa/tests/ldoreloc/1.s @@ -0,0 +1 @@ +jsr bla: loop: jmp loop diff --git a/xa/tests/ldoreloc/2.s b/xa/tests/ldoreloc/2.s new file mode 100644 index 0000000..d350048 --- /dev/null +++ b/xa/tests/ldoreloc/2.s @@ -0,0 +1 @@ +bla: rts diff --git a/xa/tests/ldoreloc/Makefile b/xa/tests/ldoreloc/Makefile new file mode 100644 index 0000000..301ec80 --- /dev/null +++ b/xa/tests/ldoreloc/Makefile @@ -0,0 +1,23 @@ + +all: t + +1.o65: 1.s + xa -R -c -o 1.o65 1.s + hexdump -C 1.o65 > 1.o65.hex + +2.o65: 2.s + xa -R -c -o 2.o65 2.s + hexdump -C 2.o65 > 2.o65.hex + +linked.o65: 1.o65 2.o65 + ldo65 -o linked.o65 1.o65 2.o65 + hexdump -C linked.o65 > linked.o65.hex + +t: linked.o65 + reloc65 -bt 32768 -xt -o t linked.o65 + hexdump -C t > t.hex + diff t t.ok + +clean: + rm -f *.o65 *.hex t + diff --git a/xa/tests/ldoreloc/t.ok b/xa/tests/ldoreloc/t.ok new file mode 100644 index 0000000..683812c --- /dev/null +++ b/xa/tests/ldoreloc/t.ok @@ -0,0 +1 @@ + €L€` \ No newline at end of file diff --git a/xa/tests/ldoreloc/xatestanalysis.txt b/xa/tests/ldoreloc/xatestanalysis.txt new file mode 100644 index 0000000..ba630ba --- /dev/null +++ b/xa/tests/ldoreloc/xatestanalysis.txt @@ -0,0 +1,109 @@ + + +mkdir xatest +cd xatest +echo "jsr bla: loop: jmp loop" > 1.s +echo "bla: rts" > 2.s +xa -R -c -o 1.o65 1.s +xa -R -c -o 2.o65 2.s +ldo65 -o linked.o65 1.o65 2.o65 +reloc65 -bt 32768 -xt -o t linked.o65 +hexdump -C t + +output: + +00000000 20 06 80 4c 03 8c 60 | ..L..`| +00000007 + +The bytes 20 06 80 are correct, it's JSR $8006. But 4c 03 8c means JMP $8c03. What's wrong here? +Do I use it in a wrong way? + +Following procedure leads to the expected code: +echo "jsr bla: loop: jmp loop: bla: rts" > 1.s +xa -R -c -o 1.o65 1.s +ldo65 -o linked.o65 1.o65 +reloc65 -bt 32768 -xt -o t linked.o65 +hexdump -C t + +I use 2.3.0, it comes with Debian Testing. + +============================================================================== +Analysis: + + cat 1.o65.hex +00000000 01 00 6f 36 35 00 00 10 00 10 06 00 00 04 00 00 |..o65...........| +00000010 00 40 00 00 04 00 00 00 00 00 00 20 00 00 4c 03 |.@......... ..L.| +00000020 10 01 00 62 6c 61 00 02 80 00 00 03 82 00 00 01 |...bla..........| +00000030 00 6c 6f 6f 70 00 02 03 10 |.loop....| +00000039 + +file65 -V 1.o65 +1.o65: o65 version 0 object file + mode: 1000 =[object][16bit][byte relocation][CPU 6502][align 1] + text segment @ $1000 - $1006 [$0006 bytes] + data segment @ $0400 - $0400 [$0000 bytes] + bss segment @ $4000 - $4000 [$0000 bytes] + zero segment @ $0004 - $0004 [$0000 bytes] + stack size $0000 bytes (i.e. unknown) +Undefined Labels: 1 +bla +Global Labels: 1 +loop (segID=2 (text), offset=1003) + + +==> text segment start $1000, loop is at $1003 -> ok + undef'd label bla stored as zero (00 00) in opcode -> ok + relocation table entry: $1001, ADR, undef'd, label #0 -> ok + $1004, ADR, text segment -> ok + +--------------------------------------------------- + +cat 2.o65.hex +00000000 01 00 6f 36 35 00 00 10 00 10 01 00 00 04 00 00 |..o65...........| +00000010 00 40 00 00 04 00 00 00 00 00 00 60 00 00 00 00 |.@.........`....| +00000020 01 00 62 6c 61 00 02 00 10 |..bla....| + +file65 -V 2.o65 +2.o65: o65 version 0 object file + mode: 1000 =[object][16bit][byte relocation][CPU 6502][align 1] + text segment @ $1000 - $1001 [$0001 bytes] + data segment @ $0400 - $0400 [$0000 bytes] + bss segment @ $4000 - $4000 [$0000 bytes] + zero segment @ $0004 - $0004 [$0000 bytes] + stack size $0000 bytes (i.e. unknown) +Undefined Labels: 0 +Global Labels: 1 +bla (segID=2 (text), offset=1000) + +=> text segment start $1000 -> ok + no relocation table entries -> ok + global label text segment, at $1000 -> ok + +--------------------------------------------------- + +ldo65 -o linked.o65 1.o65 2.o65 + +linked.o65.hex +00000000 01 00 6f 36 35 00 00 00 00 04 07 00 00 10 00 00 |..o65...........| +00000010 00 40 00 00 02 00 00 00 00 00 00 20 06 04 4c 03 |.@......... ..L.| +00000020 10 60 00 00 02 82 03 82 00 00 02 00 6c 6f 6f 70 |.`..........loop| +00000030 00 02 03 04 62 6c 61 00 02 06 04 |....bla....| + +ile65 -V linked.o65 +linked.o65: o65 version 0 executable file + mode: 0000 =[executable][16bit][byte relocation][CPU 6502][align 1] + text segment @ $0400 - $0407 [$0007 bytes] + data segment @ $1000 - $1000 [$0000 bytes] + bss segment @ $4000 - $4000 [$0000 bytes] + zero segment @ $0002 - $0002 [$0000 bytes] + stack size $0000 bytes (i.e. unknown) +Undefined Labels: 0 +Global Labels: 2 +loop (segID=2 (text), offset=0403) +bla (segID=2 (text), offset=0406) + +=> text segment start $0400 + $0400 jsr $0406 -> RTS -> ok + $0403 jmp $1003 >>>>>>>>>>>>>>>> wrong !!! + should be $0403 + diff --git a/xa/tests/nonl/a.o65 b/xa/tests/nonl/a.o65 new file mode 100644 index 0000000..e69de29 diff --git a/xa/tests/nonl/test.asm b/xa/tests/nonl/test.asm new file mode 100644 index 0000000..0e7fb25 --- /dev/null +++ b/xa/tests/nonl/test.asm @@ -0,0 +1,3 @@ + lda #4 + sta !$0005 + rts \ No newline at end of file diff --git a/xa/tests/nonl/test2.asm b/xa/tests/nonl/test2.asm new file mode 100644 index 0000000..c137904 --- /dev/null +++ b/xa/tests/nonl/test2.asm @@ -0,0 +1 @@ +#include "test.asm" \ No newline at end of file diff --git a/xa/tests/openpp/test.asm b/xa/tests/openpp/test.asm new file mode 100644 index 0000000..8bdb8e9 --- /dev/null +++ b/xa/tests/openpp/test.asm @@ -0,0 +1,27 @@ + .word $c000 + * = $c000 +#if 0 +#error BUGGGGG +#endif + +#if 1 + lda #93 + jsr $ffd2 +#endif + +/* comment this out to stop testing included gaffes */ +#include "test.inc" + +#if 1 +#if 2 + lda #93 + jsr $ffd2 +#endif +#endif + +#ifdef X +/* comment this out for bugs in this file */ +/* +#endif +*/ + diff --git a/xa/tests/openpp/test.inc b/xa/tests/openpp/test.inc new file mode 100644 index 0000000..2669d09 --- /dev/null +++ b/xa/tests/openpp/test.inc @@ -0,0 +1,4 @@ +#ifdef BUGOUTTTTT +/* +#endif +*/ diff --git a/xa/tests/recmac/a.o65 b/xa/tests/recmac/a.o65 new file mode 100644 index 0000000..7cd3c66 --- /dev/null +++ b/xa/tests/recmac/a.o65 @@ -0,0 +1 @@ +© \ No newline at end of file diff --git a/xa/tests/recmac/cpu.inc b/xa/tests/recmac/cpu.inc new file mode 100644 index 0000000..9d5bae2 --- /dev/null +++ b/xa/tests/recmac/cpu.inc @@ -0,0 +1,5 @@ +; +; FILE cpu.inc +; + +#define WDM(v) .byt $42,(v) diff --git a/xa/tests/recmac/test.asm b/xa/tests/recmac/test.asm new file mode 100644 index 0000000..af88314 --- /dev/null +++ b/xa/tests/recmac/test.asm @@ -0,0 +1,31 @@ +#define AA 1 +#define POKE(a,b) lda #b: sta a +#define WW AA + +start + ; next line works + POKE(1, 2) + ; next two lines work + lda #AA + sta 2 + ; next line fails + POKE(AA, 2) + POKE(WW, 2) + lda #WW + sta 2 + +#define WW 94 + POKE(WW, 2) +#define WW 5 +#define AA WW +#define POKE(a,b) lda #a: sta b + POKE(AA, 3) + + bne start + rts + +/* this should bug out */ + +/* + POKE(NOGOOD, 7) +*/ diff --git a/xa/tests/recmac/testi.asm b/xa/tests/recmac/testi.asm new file mode 100644 index 0000000..cd2c5e8 --- /dev/null +++ b/xa/tests/recmac/testi.asm @@ -0,0 +1,13 @@ + +; +; FILE image.a +; + +#include "cpu.inc" + + .text + *=$C000 + +Foo: + WDM(170) + diff --git a/xa/tests/relocundef/Makefile b/xa/tests/relocundef/Makefile new file mode 100644 index 0000000..39eab67 --- /dev/null +++ b/xa/tests/relocundef/Makefile @@ -0,0 +1,25 @@ + +all: a.o65 b.o65 + +a.o65: test1.o65 + echo "********* This should give a warning about an undefined relocation table entry" + reloc65 -X test1.o65 + hexdump -C a.o65 > a.o65.hex + +b.o65: test2.o65 + echo "********* This should NOT give a warning" + reloc65 -X -o b.o65 test2.o65 + hexdump -C b.o65 > b.o65.hex + +test1.o65: test1.a65 + xa -R -Lundefl -Ll2 -o test1.o65 test1.a65 + hexdump -C test1.o65 > test1.o65.hex + +test2.o65: test2.a65 + xa -R -o test2.o65 test2.a65 + hexdump -C test2.o65 > test2.o65.hex + +clean: + rm -f test1.o65 a.o65 test1.o65.hex a.o65.hex + rm -f test2.o65 b.o65 test2.o65.hex b.o65.hex + diff --git a/xa/tests/relocundef/test1.a65 b/xa/tests/relocundef/test1.a65 new file mode 100644 index 0000000..8f6d32b --- /dev/null +++ b/xa/tests/relocundef/test1.a65 @@ -0,0 +1,9 @@ + +// this file defines an undefined label + .text + ldx #1 +l1 lda undefl + dex + bne l1 + rts + diff --git a/xa/tests/relocundef/test2.a65 b/xa/tests/relocundef/test2.a65 new file mode 100644 index 0000000..bd1f74e --- /dev/null +++ b/xa/tests/relocundef/test2.a65 @@ -0,0 +1,11 @@ + +// this file defines an undefined label + .text + ldx #1 +l1 lda undefl + dex + bne l1 + rts + +undefl =1 + diff --git a/xa/vstudio/00readme.txt b/xa/vstudio/00readme.txt new file mode 100644 index 0000000..a075984 --- /dev/null +++ b/xa/vstudio/00readme.txt @@ -0,0 +1,8 @@ +This directory contains a solution and project files that can be used to +build xa and the various tools in the misc directory with the free version +of Microsoft Visual C++ 2005 (AKA Visual Studio 2005 Express). This compiler +and IDE can be dowloaded free from + +http://msdn.microsoft.com/vstudio/express/downloads/default.aspx + +Just run visual studio and load the solution called "vstudio.sln" diff --git a/xa/vstudio/file65.vcproj b/xa/vstudio/file65.vcproj new file mode 100644 index 0000000..83ff040 --- /dev/null +++ b/xa/vstudio/file65.vcproj @@ -0,0 +1,197 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xa/vstudio/ldo65.vcproj b/xa/vstudio/ldo65.vcproj new file mode 100644 index 0000000..a77fc6f --- /dev/null +++ b/xa/vstudio/ldo65.vcproj @@ -0,0 +1,197 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xa/vstudio/printcbm.vcproj b/xa/vstudio/printcbm.vcproj new file mode 100644 index 0000000..514b3b1 --- /dev/null +++ b/xa/vstudio/printcbm.vcproj @@ -0,0 +1,197 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xa/vstudio/uncpk.vcproj b/xa/vstudio/uncpk.vcproj new file mode 100644 index 0000000..a8347d2 --- /dev/null +++ b/xa/vstudio/uncpk.vcproj @@ -0,0 +1,197 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xa/vstudio/vstudio.sln b/xa/vstudio/vstudio.sln new file mode 100644 index 0000000..8edc6a8 --- /dev/null +++ b/xa/vstudio/vstudio.sln @@ -0,0 +1,44 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual C++ Express 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xa", "xa.vcproj", "{55808FFA-DA3B-44AF-AB9E-D937A531F932}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "uncpk", "uncpk.vcproj", "{32CE058C-D818-4756-BAA6-A8AD4378308D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "file65", "file65.vcproj", "{3CB15D2B-3777-4401-BF81-C0BC1B8AE8E6}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ldo65", "ldo65.vcproj", "{EFA4F295-A2CD-4B8A-ABE9-DD9DEB670CA6}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "printcbm", "printcbm.vcproj", "{26727633-7B9B-40CB-A31A-C6C6FEBA00CA}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {55808FFA-DA3B-44AF-AB9E-D937A531F932}.Debug|Win32.ActiveCfg = Debug|Win32 + {55808FFA-DA3B-44AF-AB9E-D937A531F932}.Debug|Win32.Build.0 = Debug|Win32 + {55808FFA-DA3B-44AF-AB9E-D937A531F932}.Release|Win32.ActiveCfg = Release|Win32 + {55808FFA-DA3B-44AF-AB9E-D937A531F932}.Release|Win32.Build.0 = Release|Win32 + {32CE058C-D818-4756-BAA6-A8AD4378308D}.Debug|Win32.ActiveCfg = Debug|Win32 + {32CE058C-D818-4756-BAA6-A8AD4378308D}.Debug|Win32.Build.0 = Debug|Win32 + {32CE058C-D818-4756-BAA6-A8AD4378308D}.Release|Win32.ActiveCfg = Release|Win32 + {32CE058C-D818-4756-BAA6-A8AD4378308D}.Release|Win32.Build.0 = Release|Win32 + {3CB15D2B-3777-4401-BF81-C0BC1B8AE8E6}.Debug|Win32.ActiveCfg = Debug|Win32 + {3CB15D2B-3777-4401-BF81-C0BC1B8AE8E6}.Debug|Win32.Build.0 = Debug|Win32 + {3CB15D2B-3777-4401-BF81-C0BC1B8AE8E6}.Release|Win32.ActiveCfg = Release|Win32 + {3CB15D2B-3777-4401-BF81-C0BC1B8AE8E6}.Release|Win32.Build.0 = Release|Win32 + {EFA4F295-A2CD-4B8A-ABE9-DD9DEB670CA6}.Debug|Win32.ActiveCfg = Debug|Win32 + {EFA4F295-A2CD-4B8A-ABE9-DD9DEB670CA6}.Debug|Win32.Build.0 = Debug|Win32 + {EFA4F295-A2CD-4B8A-ABE9-DD9DEB670CA6}.Release|Win32.ActiveCfg = Release|Win32 + {EFA4F295-A2CD-4B8A-ABE9-DD9DEB670CA6}.Release|Win32.Build.0 = Release|Win32 + {26727633-7B9B-40CB-A31A-C6C6FEBA00CA}.Debug|Win32.ActiveCfg = Debug|Win32 + {26727633-7B9B-40CB-A31A-C6C6FEBA00CA}.Debug|Win32.Build.0 = Debug|Win32 + {26727633-7B9B-40CB-A31A-C6C6FEBA00CA}.Release|Win32.ActiveCfg = Release|Win32 + {26727633-7B9B-40CB-A31A-C6C6FEBA00CA}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/xa/vstudio/xa.vcproj b/xa/vstudio/xa.vcproj new file mode 100644 index 0000000..8c53ed1 --- /dev/null +++ b/xa/vstudio/xa.vcproj @@ -0,0 +1,289 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +