# HG changeset patch
# User lost@l-w.ca
# Date 1295501237 25200
# Node ID 2c24602be78fe027ed9861c9d596a3f6f07d50d3
Initial import from lwtools 3.0.1 version, with new hand built build system and file reorganization
diff -r 000000000000 -r 2c24602be78f 00README.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/00README.txt Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,9 @@
+This is LWTOOLS, a cross development system targetting the 6809 CPU.
+
+It consists of an assembler, lwasm, a linker, lwlink, and an archiver,
+lwar which should compile on any reasonably modern POSIX environment.
+
+To see if a quick build will work, just type "make". If it works, you're
+ready to go ahead with "make install". This will install in /usr/local/bin.
+
+See docs/ for additional information.
diff -r 000000000000 -r 2c24602be78f COPYING
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/COPYING Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. 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
+them 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 prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. 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.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey 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;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If 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 convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU 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 that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ 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.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+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.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ 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
+state 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)
+
+ 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 3 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, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ Copyright (C)
+ This program 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, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+ .
+
+ The GNU 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 Lesser General
+Public License instead of this License. But first, please read
+.
diff -r 000000000000 -r 2c24602be78f Makefile
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Makefile Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,70 @@
+CC := gcc
+
+CPPFLAGS += -I lwlib -DPACKAGE_STRING='"lwtools 4.0-pre"' -DPACKAGE_BUGREPORT='"lost@l-w.ca"'
+
+LDFLAGS += -L$(PWD)/lwlib -llw
+
+MAIN_TARGETS := lwasm/lwasm lwlink/lwlink lwar/lwar
+
+.PHONY: all
+all: $(MAIN_TARGETS)
+
+subdirs := lwasm lwlink lwar lwlib
+
+-include $(subdirs:=/rules.make)
+
+lwasm_objs := $(lwasm_srcs:.c=.o)
+lwlink_objs := $(lwlink_srcs:.c=.o)
+lwar_objs := $(lwar_srcs:.c=.o)
+lwlib_objs := $(lwlib_srcs:.c=.o)
+
+lwasm_deps := $(lwasm_srcs:.c=.d)
+lwlink_deps := $(lwlink_srcs:.c=.d)
+lwar_deps := $(lwar_srcs:.c=.d)
+lwlib_deps := $(lwlib_srcs:.c=.d)
+lwobjdump_deps := $(lwobjdump_srcs:.c=.d)
+
+,PHONY: lwlink lwasm lwar
+lwlink: lwlink/lwlink
+lwasm: lwasm/lwasm
+lwar: lwar/lwar
+lwobjdump: lwlink/lwobjdump
+
+lwasm/lwasm: $(lwasm_objs) lwlib
+ $(CC) -o $@ $(lwasm_objs) $(LDFLAGS)
+
+lwlink/lwlink: $(lwlink_objs)
+ $(CC) -o $@ $(lwlink_objs)
+
+lwlink/lwobjdump: $(lwobjdump_objs)
+ $(CC) -o $@ $(lwobjdump_objs)
+
+lwar/lwar: $(lwar_objs)
+ $(CC) -o $@ $(lwar_objs)
+
+
+.phony: lwlib
+lwlib: lwlib/liblw.a
+
+lwlib/liblw.a: $(lwlib_objs)
+ $(AR) rc $@ $^
+
+%.d: %.c
+ @echo "Building dependencies for $@"
+ @$(CC) -MM $(CPPFLAGS) -o $*.d $<
+ @mv -f $*.d $*.d.tmp
+ @sed -e 's|.*:|$*.o $*.d:|' < $*.d.tmp > $*.d
+ @sed -e 's/.*://' -e 's/\\$$//' < $*.d.tmp | fmt -1 | sed -e 's/^ *//' -e 's/$$/:/' >> $*.d
+ @rm -f $*.d.tmp
+
+-include $(lwasm_deps) $(lwlink_deps) $(lwar_deps) $(lwlib_deps) $(lwobjdump_deps)
+
+extra_clean := $(extra_clean) *~ */*~
+
+.PHONY: clean
+clean:
+ rm -f $(lwasm_deps) $(lwlink_deps) $(lwar_deps) $(lwlib_deps) $(lwobjdump_deps)
+ rm -f lwlib/liblw.a lwasm/lwasm lwlink/lwlink lwlink/lwobjdump lwar/lwar
+ rm -f $(lwasm_objs) $(lwlink_objs) $(lwar_objs) $(lwlib_objs) $(lwobjdump_objs)
+ rm -f $(extra_clean)
+
\ No newline at end of file
diff -r 000000000000 -r 2c24602be78f docs/README
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/README Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,16 @@
+If there are no html files in the "manual" directory and there is no
+"manual.html" file, it means that you have either checked out the source
+repository on a non-release branch or the packager messed up.
+
+In either case, if you have "docbook2html" installed, you should be able
+to build the manual with one of the following:
+
+docbook2html -o manual manual.docbook.sgml
+
+or
+
+docbook2html -u manual.docbook.sgml && mv manual.docbook.html manual/manual.html
+
+PDF can be generated by doing:
+
+docbook2pdf -u manual.docbook.sgml && mv manual.docbook.pdf manual/manual.pdf
\ No newline at end of file
diff -r 000000000000 -r 2c24602be78f docs/internals.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/internals.txt Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,57 @@
+LWASM Internals
+===============
+
+LWASM is a table-driven assembler that notionally uses two passes. However,
+it implements its assembly in several passes as follows.
+
+Pass 1
+------
+
+This pass reads the entire source code and parses each line into an internal
+representation. Macros, file inclusions, and conditional assembly
+instructions are resolved at this point as well. Instructions with known
+sizes will have their sizes resolved at this point.
+
+Pass 2
+------
+
+Check all exported symbols for validity and set them as imports if the
+assembler state says so. Also resolve all symbol references in all
+expressions to be direct references either to the symbol table or
+to the import list.
+
+Pass 3
+------
+
+This pass resolves all instruction sizes that can be resolved without
+forcing any instruction sizes. This pass will run repeatedly until no
+no new resolution occurs.
+
+Pass 4
+------
+
+Work through all un-resolved instructions and force sizes. After each size
+is forced, try re-resolving all other instructions. This is done starting
+at the beginning of the source and working forward. If any instruction does
+not resolve when forced, an error will be thrown.
+
+Pass 5
+------
+
+Constantize all line addresses and throw errors if any cannot be. This
+pass will repeat until no further lines addresses are reduced to constants
+at which time all lines will be checked for constant-ness.
+
+Pass 6
+------
+
+Finalize all expressions related to instructions. Carp about any that
+cannot be reduced to a usable form. That means, for the non-object target
+all expressions must resolve to a constant. For the object form, all
+expressions must resolve to symbol references and constants. Those symbol
+references may be internal or external.
+
+Pass 7
+------
+
+Emit object code for each line for later output.
diff -r 000000000000 -r 2c24602be78f docs/lwasm.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/lwasm.txt Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,43 @@
+LWASM 2.0
+=========
+
+LWASM is a cross-assembler for the MC6809 and HD6309 CPUs. It should
+assemble most reasonable EDTASM compatible source code. This document is not
+intended to teach assembly language for these CPUs but rather to document
+the behaviour of LWASM.
+
+
+TARGETS
+-------
+
+LWASM supports several targets for assembly. These are decb, raw, and obj.
+
+The raw target generates a raw binary output. This is useful for building
+ROMs and other items that are not intended to be loaded by any kind of
+loader. In this mode, the ORG directive is merely advisory and does not
+affect the output except for the addresses symbols are defined to have.
+
+The decb target generates output that can be loaded with the CLOADM or LOADM
+commands in Color Basic. There will be approximately one segment in the
+output file for every ORG statement after which any code is emitted. (That
+is, two ORG statements in a row will not generate two output segments.)
+This is approximately equivalent to running A/AO in EDTASM.
+
+The obj target generates output that is intended to be linked later with
+LWLINK. This target disallows the use of ORG for defining anything other
+than constants. In this target, source files consist of a number of sections
+(SECTION/ENDSECTION). Nothing outside of a section is permitted to cause any
+output at all. Use of an ORG statement within a section is an error. This
+target also permits tagging symbols for export (EXPORT) and marking a symbol
+as externally defined (IMPORT/EXTERN). The linker will resolve any external
+references at link time. Additionally, any inter-section references will be
+resolved by the linker. All code in each section is assembled with an
+implicit origin of 0. SETDP has no effect because the assembler has no idea
+what address the linker will assign to the code when it is linked. Any
+direct addressing modes will default to extended to allow for the linker to
+perform relocations. Intersegment references and external references will
+use 16 bit relative addressing but intrasegment internal references may use
+8 bit relative addressing. Forced 8 bit direct modes are probably an error
+but are permitted on the theory that the programmer might know something the
+assembler doesn't.
+
diff -r 000000000000 -r 2c24602be78f docs/manual.docbook.sgml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/manual.docbook.sgml Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,2180 @@
+
+
+
+LW Tool Chain
+William Astle
+2009, 2010 William Astle
+
+
+
+Introduction
+
+
+The LW tool chain provides utilities for building binaries for MC6809 and
+HD6309 CPUs. The tool chain includes a cross-assembler and a cross-linker
+which support several styles of output.
+
+
+
+History
+
+For a long time, I have had an interest in creating an operating system for
+the Coco3. I finally started working on that project around the beginning of
+2006. I had a number of assemblers I could choose from. Eventually, I settled
+on one and started tinkering. After a while, I realized that assembler was not
+going to be sufficient due to lack of macros and issues with forward references.
+Then I tried another which handled forward references correctly but still did
+not support macros. I looked around at other assemblers and they all lacked
+one feature or another that I really wanted for creating my operating system.
+
+
+
+The solution seemed clear at that point. I am a fair programmer so I figured
+I could write an assembler that would do everything I wanted an assembler to
+do. Thus the LWASM probject was born. After more than two years of on and off
+work, version 1.0 of LWASM was released in October of 2008.
+
+
+
+As the aforementioned operating system project progressed further, it became
+clear that while assembling the whole project through a single file was doable,
+it was not practical. When I found myself playing some fancy games with macros
+in a bid to simulate sections, I realized I needed a means of assembling
+source files separately and linking them later. This spawned a major development
+effort to add an object file support to LWASM. It also spawned the LWLINK
+project to provide a means to actually link the files.
+
+
+
+
+
+
+
+Output Formats
+
+
+The LW tool chain supports multiple output formats. Each format has its
+advantages and disadvantages. Each format is described below.
+
+
+
+Raw Binaries
+
+A raw binary is simply a string of bytes. There are no headers or other
+niceties. Both LWLINK and LWASM support generating raw binaries. ORG directives
+in the source code only serve to set the addresses that will be used for
+symbols but otherwise have no direct impact on the resulting binary.
+
+
+
+
+DECB Binaries
+
+A DECB binary is compatible with the LOADM command in Disk Extended
+Color Basic on the CoCo. They are also compatible with CLOADM from Extended
+Color Basic. These binaries include the load address of the binary as well
+as encoding an execution address. These binaries may contain multiple loadable
+sections, each of which has its own load address.
+
+
+Each binary starts with a preamble. Each preamble is five bytes long. The
+first byte is zero. The next two bytes specify the number of bytes to load
+and the last two bytes specify the address to load the bytes at. Then, a
+string of bytes follows. After this string of bytes, there may be another
+preamble or a postamble. A postamble is also five bytes in length. The first
+byte of the postamble is $FF, the next two are zero, and the last two are
+the execution address for the binary.
+
+
+
+Both LWASM and LWLINK can output this format.
+
+
+
+
+OS9 Modules
+
+
+Since version 2.5, LWASM is able to generate OS9 modules. The syntax is
+basically the same as for other assemblers. A module starts with the MOD
+directive and ends with the EMOD directive. The OS9 directive is provided
+as a shortcut for writing system calls.
+
+
+
+
+
+LWASM does NOT provide an OS9Defs file. You must provide your own. Also note
+that the common practice of using "ifp1" around the inclusion of the OS9Defs
+file is discouraged as it is pointless and can lead to unintentional
+problems and phasing errors. Because LWASM reads each file exactly once,
+there is no benefit to restricting the inclusion to the first assembly pass.
+
+
+
+
+
+It is also critical to understand that unlike many OS9 assemblers, LWASM
+does NOT maintain a separate data address counter. Thus, you must define
+all your data offsets and so on outside of the mod/emod segment. It is,
+therefore, likely that source code targeted at other assemblers will require
+edits to build correctly.
+
+
+
+
+
+LWLINK does not, yet, have the ability to create OS9 modules from object
+files.
+
+
+
+
+
+Object Files
+LWASM supports generating a proprietary object file format which is
+described in . LWLINK is then used to link these
+object files into a final binary in any of LWLINK's supported binary
+formats.
+
+Object files also support the concept of sections which are not valid
+for other output types. This allows related code from each object file
+linked to be collapsed together in the final binary.
+
+
+Object files are very flexible in that they allow references that are not
+known at assembly time to be resolved at link time. However, because the
+addresses of such references are not known at assembly time, there is no way
+for the assembler to deduce that an eight bit addressing mode is possible.
+That means the assember will default to using sixteen bit addressing
+whenever an external or cross-section reference is used.
+
+
+
+As of LWASM 2.4, it is possible to force direct page addressing for an
+external reference. Care must be taken to ensure the resulting addresses
+are really in the direct page since the linker does not know what the direct
+page is supposed to be and does not emit errors for byte overflows.
+
+
+
+It is also possible to use external references in an eight bit immediate
+mode instruction. In this case, only the low order eight bits will be used.
+Again, no byte overflows will be flagged.
+
+
+
+
+
+
+
+
+LWASM
+
+The LWTOOLS assembler is called LWASM. This chapter documents the various
+features of the assembler. It is not, however, a tutorial on 6x09 assembly
+language programming.
+
+
+
+Command Line Options
+
+The binary for LWASM is called "lwasm". Note that the binary is in lower
+case. lwasm takes the following command line arguments.
+
+
+
+
+
+--6309
+-3
+
+
+This will cause the assembler to accept the additional instructions available
+on the 6309 processor. This is the default mode; this option is provided for
+completeness and to override preset command arguments.
+
+
+
+
+
+--6809
+-9
+
+
+This will cause the assembler to reject instructions that are only available
+on the 6309 processor.
+
+
+
+
+
+--decb
+-b
+
+
+Select the DECB output format target. Equivalent to --format=decb .
+
+While this is the default output format currently, it is not safe to rely
+on that fact. Future versions may have different defaults. It is also trivial
+to modify the source code to change the default. Thus, it is recommended to specify
+this option if you need DECB output.
+
+
+
+
+--format=type
+-f type
+
+
+Select the output format. Valid values are obj for the
+object file target, decb for the DECB LOADM format,
+os9 for creating OS9 modules, and raw for
+a raw binary.
+
+
+
+
+
+--list[=file]
+-l[file]
+
+
+Cause LWASM to generate a listing. If file is specified,
+the listing will go to that file. Otherwise it will go to the standard output
+stream. By default, no listing is generated. Unless --symbols
+is specified, the list will not include the symbol table.
+
+
+
+
+
+--symbols
+-s
+
+
+Causes LWASM to generate a list of symbols when generating a listing.
+It has no effect unless a listing is being generated.
+
+
+
+
+
+--obj
+
+
+Select the proprietary object file format as the output target.
+
+
+
+
+
+--output=FILE
+-o FILE
+
+
+This option specifies the name of the output file. If not specified, the
+default is a.out .
+
+
+
+
+
+--pragma=pragma
+-p pragma
+
+
+Specify assembler pragmas. Multiple pragmas are separated by commas. The
+pragmas accepted are the same as for the PRAGMA assembler directive described
+below.
+
+
+
+
+
+--raw
+-r
+
+
+Select raw binary as the output target.
+
+
+
+
+
+--includedir=path
+-I path
+
+
+Add path to the end of the include path.
+
+
+
+
+
+--help
+-?
+
+
+Present a help screen describing the command line options.
+
+
+
+
+
+--usage
+
+
+Provide a summary of the command line options.
+
+
+
+
+
+--version
+-V
+
+
+Display the software version.
+
+
+
+
+
+--debug
+-d
+
+
+Increase the debugging level. Only really useful to people hacking on the
+LWASM source code itself.
+
+
+
+
+
+
+
+
+
+Dialects
+
+LWASM supports all documented MC6809 instructions as defined by Motorola.
+It also supports all known HD6309 instructions. While there is general
+agreement on the pneumonics for most of the 6309 instructions, there is some
+variance with the block transfer instructions. TFM for all four variations
+seems to have gained the most traction and, thus, this is the form that is
+recommended for LWASM. However, it also supports COPY, COPY-, IMP, EXP,
+TFRP, TFRM, TFRS, and TFRR. It further adds COPY+ as a synomym for COPY,
+IMPLODE for IMP, and EXPAND for EXP.
+
+
+By default, LWASM accepts 6309 instructions. However, using the
+--6809 parameter, you can cause it to throw errors on
+6309 instructions instead.
+
+
+The standard addressing mode specifiers are supported. These are the
+hash sign ("#") for immediate mode, the less than sign ("<") for forced
+eight bit modes, and the greater than sign (">") for forced sixteen bit modes.
+
+
+
+Additionally, LWASM supports using the asterisk ("*") to indicate
+base page addressing. This should not be used in hand-written source code,
+however, because it is non-standard and may or may not be present in future
+versions of LWASM.
+
+
+
+
+
+Source Format
+
+
+LWASM accepts plain text files in a relatively free form. It can handle
+lines terminated with CR, LF, CRLF, or LFCR which means it should be able
+to assemble files on any platform on which it compiles.
+
+
+Each line may start with a symbol. If a symbol is present, there must not
+be any whitespace preceding it. It is legal for a line to contain nothing
+but a symbol.
+
+The op code is separated from the symbol by whitespace. If there is
+no symbol, there must be at least one white space character preceding it.
+If applicable, the operand follows separated by whitespace. Following the
+opcode and operand is an optional comment.
+
+
+ It is important to note that operands cannot contain any whitespace
+except in the case of delimited strings. This is because the first
+whitespace character will be interpreted as the separator between the
+operand column and the comment. This behaviour is required for approximate
+source compatibility with other 6x09 assemblers.
+
+
+A comment can also be introduced with a * or a ;. The comment character is
+optional for end of statement comments. However, if a symbol is the only
+thing present on the line other than the comment, the comment character is
+mandatory to prevent the assembler from interpreting the comment as an opcode.
+
+
+
+For compatibility with the output generated by some C preprocessors, LWASM
+will also ignore lines that begin with a #. This should not be used as a general
+comment character, however.
+
+
+
+The opcode is not treated case sensitively. Neither are register names in
+the operand fields. Symbols, however, are case sensitive.
+
+
+ As of version 2.6, LWASM supports files with line numbers. If line
+numbers are present, the line must start with a digit. The line number
+itself must consist only of digits. The line number must then be followed
+by either the end of the line or exactly one white space character. After
+that white space character, the lines are interpreted exactly as above.
+
+
+
+
+
+Symbols
+
+
+Symbols have no length restriction. They may contain letters, numbers, dots,
+dollar signs, and underscores. They must start with a letter, dot, or
+underscore.
+
+
+
+LWASM also supports the concept of a local symbol. A local symbol is one
+which contains either a "?" or a "@", which can appear anywhere in the symbol.
+The scope of a local symbol is determined by a number of factors. First,
+each included file gets its own local symbol scope. A blank line will also
+be considered a local scope barrier. Macros each have their own local symbol
+scope as well (which has a side effect that you cannot use a local symbol
+as an argument to a macro). There are other factors as well. In general,
+a local symbol is restricted to the block of code it is defined within.
+
+
+
+By default, unless assembling to the os9 target, a "$" in the symbol will
+also make it local. This can be controlled by the "dollarlocal" and
+"nodollarlocal" pragmas. In the absence of a pragma to the contrary, for
+the os9 target, a "$" in the symbol will not make it considered local while
+for all other targets it will.
+
+
+
+
+
+Numbers and Expressions
+
+
+Numbers can be expressed in binary, octal, decimal, or hexadecimal. Binary
+numbers may be prefixed with a "%" symbol or suffixed with a "b" or "B".
+Octal numbers may be prefixed with "@" or suffixed with "Q", "q", "O", or
+"o". Hexadecimal numbers may be prefixed with "$", "0x" or "0X", or suffixed
+with "H". No prefix or suffix is required for decimal numbers but they can
+be prefixed with "&" if desired. Any constant which begins with a letter
+must be expressed with the correct prefix base identifier or be prefixed
+with a 0. Thus hexadecimal FF would have to be written either 0FFH or $FF.
+Numbers are not case sensitive.
+
+
+
+ A symbol may appear at any point where a number is acceptable. The
+special symbol "*" can be used to represent the starting address of the
+current source line within expressions.
+
+The ASCII value of a character can be included by prefixing it with a
+single quote ('). The ASCII values of two characters can be included by
+prefixing the characters with a quote (").
+
+
+
+LWASM supports the following basic binary operators: +, -, *, /, and %.
+These represent addition, subtraction, multiplication, division, and
+modulus. It also supports unary negation and unary 1's complement (- and ^
+respectively). It is also possible to use ~ for the unary 1's complement
+operator. For completeness, a unary positive (+) is supported though it is
+a no-op. LWASM also supports using |, &, and ^ for bitwise or, bitwise and,
+and bitwise exclusive or respectively.
+
+
+
+
+
+Operator precedence follows the usual rules. Multiplication, division, and
+modulus take precedence over addition and subtraction. Unary operators take
+precedence over binary operators. Bitwise operators are lower precdence
+than addition and subtraction. To force a specific order of evaluation,
+parentheses can be used in the usual manner.
+
+
+
+
+
+As of LWASM 2.5, the operators && and || are recognized for boolean and and
+boolean or respectively. They will return either 0 or 1 (false or true).
+They have the lowest precedence of all the binary operators.
+
+
+
+
+
+
+Assembler Directives
+
+Various directives can be used to control the behaviour of the
+assembler or to include non-code/data in the resulting output. Those directives
+that are not described in detail in other sections of this document are
+described below.
+
+
+
+Data Directives
+
+FCB expr[,...]
+.DB expr[,...]
+.BYTE expr[,...]
+
+Include one or more constant bytes (separated by commas) in the output.
+
+
+
+
+FDB expr[,...]
+.DW expr[,...]
+.WORD expr[,...]
+
+Include one or more words (separated by commas) in the output.
+
+
+
+
+FQB expr[,...]
+.QUAD expr[,...]
+.4BYTE expr[,...]
+
+Include one or more double words (separated by commas) in the output.
+
+
+
+
+FCC string
+.ASCII string
+.STR string
+
+
+Include a string of text in the output. The first character of the operand
+is the delimiter which must appear as the last character and cannot appear
+within the string. The string is included with no modifications>
+
+
+
+
+
+FCN string
+.ASCIZ string
+.STRZ string
+
+
+Include a NUL terminated string of text in the output. The first character of
+the operand is the delimiter which must appear as the last character and
+cannot appear within the string. A NUL byte is automatically appended to
+the string.
+
+
+
+
+
+FCS string
+.ASCIS string
+.STRS string
+
+
+Include a string of text in the output with bit 7 of the final byte set. The
+first character of the operand is the delimiter which must appear as the last
+character and cannot appear within the string.
+
+
+
+
+ZMB expr
+
+
+Include a number of NUL bytes in the output. The number must be fully resolvable
+during pass 1 of assembly so no forward or external references are permitted.
+
+
+
+
+ZMD expr
+
+
+Include a number of zero words in the output. The number must be fully
+resolvable during pass 1 of assembly so no forward or external references are
+permitted.
+
+
+
+
+ZMQ expr
+
+
+Include a number of zero double-words in the output. The number must be fully
+resolvable during pass 1 of assembly so no forward or external references are
+permitted.
+
+
+
+
+
+RMB expr
+.BLKB expr
+.DS expr
+.RS expr
+
+
+Reserve a number of bytes in the output. The number must be fully resolvable
+during pass 1 of assembly so no forward or external references are permitted.
+The value of the bytes is undefined.
+
+
+
+
+RMD expr
+
+
+Reserve a number of words in the output. The number must be fully
+resolvable during pass 1 of assembly so no forward or external references are
+permitted. The value of the words is undefined.
+
+
+
+
+RMQ expr
+
+
+Reserve a number of double-words in the output. The number must be fully
+resolvable during pass 1 of assembly so no forward or external references are
+permitted. The value of the double-words is undefined.
+
+
+
+
+
+INCLUDEBIN filename
+
+
+Treat the contents of filename as a string of bytes to
+be included literally at the current assembly point. This has the same effect
+as converting the file contents to a series of FCB statements and including
+those at the current assembly point.
+
+
+ If filename beings with a /, the file name
+will be taken as absolute. Otherwise, the current directory will be
+searched followed by the search path in the order specified.
+
+ Please note that absolute path detection including drive letters will
+not function correctly on Windows platforms. Non-absolute inclusion will
+work, however.
+
+
+
+
+
+
+
+
+
+Address Definition
+The directives in this section all control the addresses of symbols
+or the assembly process itself.
+
+
+ORG expr
+
+Set the assembly address. The address must be fully resolvable on the
+first pass so no external or forward references are permitted. ORG is not
+permitted within sections when outputting to object files. For the DECB
+target, each ORG directive after which output is generated will cause
+a new preamble to be output. ORG is only used to determine the addresses
+of symbols when the raw target is used.
+
+
+
+
+
+sym EQU expr
+sym = expr
+
+Define the value of sym to be expr .
+
+
+
+
+sym SET expr
+
+Define the value of sym to be expr .
+Unlike EQU, SET permits symbols to be defined multiple times as long as SET
+is used for all instances. Use of the symbol before the first SET statement
+that sets its value is undefined.
+
+
+
+
+SETDP expr
+
+Inform the assembler that it can assume the DP register contains
+expr . This directive is only advice to the assembler
+to determine whether an address is in the direct page and has no effect
+on the contents of the DP register. The value must be fully resolved during
+the first assembly pass because it affects the sizes of subsequent instructions.
+
+This directive has no effect in the object file target.
+
+
+
+
+
+ALIGN expr [,value ]
+
+
+Force the current assembly address to be a multiple of
+expr . If value is not
+specified, a series of NUL bytes is output to force the alignment, if
+required. Otherwise, the low order 8 bits of value
+will be used as the fill. The alignment value must be fully resolved on the
+first pass because it affects the addresses of subsquent instructions.
+However, value may include forward references; as
+long as it resolves to a constant for the second pass, the value will be
+accepted.
+
+Unless value is specified as something like $12,
+this directive is not suitable for inclusion in the middle of actual code.
+The default padding value is $00 which is intended to be used within data
+blocks.
+
+
+
+
+
+
+
+
+
+Conditional Assembly
+
+Portions of the source code can be excluded or included based on conditions
+known at assembly time. Conditionals can be nested arbitrarily deeply. The
+directives associated with conditional assembly are described in this section.
+
+All conditionals must be fully bracketed. That is, every conditional
+statement must eventually be followed by an ENDC at the same level of nesting.
+
+Conditional expressions are only evaluated on the first assembly pass.
+It is not possible to game the assembly process by having a conditional
+change its value between assembly passes. Due to the underlying architecture
+of LWASM, there is no possible utility to IFP1 and IFP2, nor can they, as of LWASM 3.0, actually
+be implemented meaningfully. Thus there is not and never will
+be any equivalent of IFP1 or IFP2 as provided by other assemblers. Use of those opcodes
+will throw a warning and be ignored.
+
+It is important to note that if a conditional does not resolve to a constant
+during the first parsing pass, an error will be thrown. This is unavoidable because the assembler
+must make a decision about which source to include and which source to exclude at this stage.
+Thus, expressions that work normally elsewhere will not work for conditions.
+
+
+
+IFEQ expr
+
+If expr evaluates to zero, the conditional
+will be considered true.
+
+
+
+
+
+IFNE expr
+IF expr
+
+If expr evaluates to a non-zero value, the conditional
+will be considered true.
+
+
+
+
+
+IFGT expr
+
+If expr evaluates to a value greater than zero, the conditional
+will be considered true.
+
+
+
+
+
+IFGE expr
+
+If expr evaluates to a value greater than or equal to zero, the conditional
+will be considered true.
+
+
+
+
+
+IFLT expr
+
+If expr evaluates to a value less than zero, the conditional
+will be considered true.
+
+
+
+
+
+IFLE expr
+
+If expr evaluates to a value less than or equal to zero , the conditional
+will be considered true.
+
+
+
+
+
+IFDEF sym
+
+If sym is defined at this point in the assembly
+process, the conditional
+will be considered true.
+
+
+
+
+
+IFNDEF sym
+
+If sym is not defined at this point in the assembly
+process, the conditional
+will be considered true.
+
+
+
+
+
+ELSE
+
+
+If the preceding conditional at the same level of nesting was false, the
+statements following will be assembled. If the preceding conditional at
+the same level was true, the statements following will not be assembled.
+Note that the preceding conditional might have been another ELSE statement
+although this behaviour is not guaranteed to be supported in future versions
+of LWASM.
+
+
+
+
+ENDC
+
+
+This directive marks the end of a conditional construct. Every conditional
+construct must end with an ENDC directive.
+
+
+
+
+
+
+
+
+OS9 Target Directives
+
+This section includes directives that apply solely to the OS9
+target.
+
+
+
+
+OS9 syscall
+
+
+
+This directive generates a call to the specified system call. syscall may be an arbitrary expression.
+
+
+
+
+
+
+MOD size ,name ,type ,flags ,execoff ,datasize
+
+
+
+This tells LWASM that the beginning of the actual module is here. It will
+generate a module header based on the parameters specified. It will also
+begin calcuating the module CRC.
+
+
+
+
+
+The precise meaning of the various parameters is beyond the scope of this
+document since it is not a tutorial on OS9 module programming.
+
+
+
+
+
+
+
+EMOD
+
+
+
+This marks the end of a module and causes LWASM to emit the calculated CRC
+for the module.
+
+
+
+
+
+
+
+
+Miscelaneous Directives
+
+This section includes directives that do not fit into the other
+categories.
+
+
+
+
+INCLUDE filename
+USE filename
+
+ Include the contents of filename at
+this point in the assembly as though it were a part of the file currently
+being processed. Note that if whitespace appears in the name of the file,
+you must enclose filename in quotes.
+
+
+
+Note that the USE variation is provided only for compatibility with other
+assemblers. It is recommended to use the INCLUDE variation.
+
+If filename begins with a "/", it is
+interpreted as an absolute path. If it does not, the search path will be used
+to find the file. First, the directory containing the file that contains this
+directive. (Includes within an included file are relative to the included file,
+not the file that included it.) If the file is not found there, the include path
+is searched. If it is still not found, an error will be thrown. Note that the
+current directory as understood by your shell or operating system is not searched.
+
+
+
+
+
+
+END [expr]
+
+
+This directive causes the assembler to stop assembling immediately as though
+it ran out of input. For the DECB target only, expr
+can be used to set the execution address of the resulting binary. For all
+other targets, specifying expr will cause an error.
+
+
+
+
+
+ERROR string
+
+
+Causes a custom error message to be printed at this line. This will cause
+assembly to fail. This directive is most useful inside conditional constructs
+to cause assembly to fail if some condition that is known bad happens. Everything
+from the directive to the end of the line is considered the error message.
+
+
+
+
+
+WARNING string
+
+
+Causes a custom warning message to be printed at this line. This will not cause
+assembly to fail. This directive is most useful inside conditional constructs
+or include files to alert the programmer to a deprecated feature being used
+or some other condition that may cause trouble later, but which may, in fact,
+not cause any trouble.
+
+
+
+
+
+.MODULE string
+
+
+This directive is ignored for most output targets. If the output target
+supports encoding a module name into it, string
+will be used as the module name.
+
+
+As of version 3.0, no supported output targets support this directive.
+
+
+
+
+
+
+
+
+
+
+Macros
+
+LWASM is a macro assembler. A macro is simply a name that stands in for a
+series of instructions. Once a macro is defined, it is used like any other
+assembler directive. Defining a macro can be considered equivalent to adding
+additional assembler directives.
+
+Macros may accept parameters. These parameters are referenced within
+a macro by the a backslash ("\") followed by a digit 1 through 9 for the first
+through ninth parameters. They may also be referenced by enclosing the
+decimal parameter number in braces ("{num}"). These parameter references
+are replaced with the verbatim text of the parameter passed to the macro. A
+reference to a non-existent parameter will be replaced by an empty string.
+Macro parameters are expanded everywhere on each source line. That means
+the parameter to a macro could be used as a symbol or it could even appear
+in a comment or could cause an entire source line to be commented out
+when the macro is expanded.
+
+
+Parameters passed to a macro are separated by commas and the parameter list
+is terminated by any whitespace. This means that neither a comma nor whitespace
+may be included in a macro parameter.
+
+
+Macro expansion is done recursively. That is, within a macro, macros are
+expanded. This can lead to infinite loops in macro expansion. If the assembler
+hangs for a long time while assembling a file that uses macros, this may be
+the reason.
+
+Each macro expansion receives its own local symbol context which is not
+inherited by any macros called by it nor is it inherited from the context
+the macro was instantiated in. That means it is possible to use local symbols
+within macros without having them collide with symbols in other macros or
+outside the macro itself. However, this also means that using a local symbol
+as a parameter to a macro, while legal, will not do what it would seem to do
+as it will result in looking up the local symbol in the macro's symbol context
+rather than the enclosing context where it came from, likely yielding either
+an undefined symbol error or bizarre assembly results.
+
+
+Note that there is no way to define a macro as local to a symbol context. All
+macros are part of the global macro namespace. However, macros have a separate
+namespace from symbols so it is possible to have a symbol with the same name
+as a macro.
+
+
+
+Macros are defined only during the first pass. Macro expansion also
+only occurs during the first pass. On the second pass, the macro
+definition is simply ignored. Macros must be defined before they are used.
+
+
+The following directives are used when defining macros.
+
+
+
+macroname MACRO
+
+This directive is used to being the definition of a macro called
+macroname . If macroname already
+exists, it is considered an error. Attempting to define a macro within a
+macro is undefined. It may work and it may not so the behaviour should not
+be relied upon.
+
+
+
+
+
+ENDM
+
+
+This directive indicates the end of the macro currently being defined. It
+causes the assembler to resume interpreting source lines as normal.
+
+
+
+
+
+
+
+Structures
+
+
+Structures are used to group related data in a fixed structure. A structure
+consists a number of fields, defined in sequential order and which take up
+specified size. The assembler does not enforce any means of access within a
+structure; it assumes that whatever you are doing, you intended to do.
+There are two pseudo ops that are used for defining structures.
+
+
+
+
+
+structname STRUCT
+
+
+
+This directive is used to begin the definition of a structure with name
+structname . Subsequent statements all form part of
+the structure definition until the end of the structure is declared.
+
+
+
+
+
+ENDSTRUCT
+ENDS
+
+
+This directive ends the definition of the structure. ENDSTRUCT is the
+preferred form. Prior to version 3.0 of LWASM, ENDS was used to end a
+section instead of a structure.
+
+
+
+
+
+
+
+Within a structure definition, only reservation pseudo ops are permitted.
+Anything else will cause an assembly error.
+
+
+ Once a structure is defined, you can reserve an area of memory in the
+same structure by using the structure name as the opcode. Structures can
+also contain fields that are themselves structures. See the example
+below.
+
+
+tstruct2 STRUCT
+f1 rmb 1
+f2 rmb 1
+ ENDSTRUCT
+
+tstruct STRUCT
+field1 rmb 2
+field2 rmb 3
+field3 tstruct2
+ ENDSTRUCT
+
+ ORG $2000
+var1 tstruct
+var2 tstruct2
+
+
+Fields are referenced using a dot (.) as a separator. To refer to the
+generic offset within a structure, use the structure name to the left of the
+dot. If referring to a field within an actual variable, use the variable's
+symbol name to the left of the dot.
+
+You can also refer to the actual size of a structure (or a variable
+declared as a structure) using the special symbol sizeof{structname} where
+structname will be the name of the structure or the name of the
+variable.
+
+Essentially, structures are a shortcut for defining a vast number of
+symbols. When a structure is defined, the assembler creates symbols for the
+various fields in the form structname.fieldname as well as the appropriate
+sizeof{structname} symbol. When a variable is declared as a structure, the
+assembler does the same thing using the name of the variable. You will see
+these symbols in the symbol table when the assembler is instructed to
+provide a listing. For instance, the above listing will create the
+following symbols (symbol values in parentheses): tstruct2.f1 (0),
+tstruct2.f2 (1), sizeof{tstruct2} (2), tstruct.field1 (0), tstruct.field2
+(2), tstruct.field3 (5), tstruct.field3.f1 (5), tstruct.field3.f2 (6),
+sizeof{tstruct.field3} (2), sizeof{tstruct} (7), var1 {$2000}, var1.field1
+{$2000}, var1.field2 {$2002}, var1.field3 {$2005}, var1.field3.f1 {$2005},
+var1.field3.f2 {$2006}, sizeof(var1.field3} (2), sizeof{var1} (7), var2
+($2007), var2.f1 ($2007), var2.f2 ($2008), sizeof{var2} (2).
+
+
+
+
+Object Files and Sections
+
+The object file target is very useful for large project because it allows
+multiple files to be assembled independently and then linked into the final
+binary at a later time. It allows only the small portion of the project
+that was modified to be re-assembled rather than requiring the entire set
+of source code to be available to the assembler in a single assembly process.
+This can be particularly important if there are a large number of macros,
+symbol definitions, or other metadata that uses resources at assembly time.
+By far the largest benefit, however, is keeping the source files small enough
+for a mere mortal to find things in them.
+
+
+
+With multi-file projects, there needs to be a means of resolving references to
+symbols in other source files. These are known as external references. The
+addresses of these symbols cannot be known until the linker joins all the
+object files into a single binary. This means that the assembler must be
+able to output the object code without knowing the value of the symbol. This
+places some restrictions on the code generated by the assembler. For
+example, the assembler cannot generate direct page addressing for instructions
+that reference external symbols because the address of the symbol may not
+be in the direct page. Similarly, relative branches and PC relative addressing
+cannot be used in their eight bit forms. Everything that must be resolved
+by the linker must be assembled to use the largest address size possible to
+allow the linker to fill in the correct value at link time. Note that the
+same problem applies to absolute address references as well, even those in
+the same source file, because the address is not known until link time.
+
+
+
+It is often desired in multi-file projects to have code of various types grouped
+together in the final binary generated by the linker as well. The same applies
+to data. In order for the linker to do that, the bits that are to be grouped
+must be tagged in some manner. This is where the concept of sections comes in.
+Each chunk of code or data is part of a section in the object file. Then,
+when the linker reads all the object files, it coalesces all sections of the
+same name into a single section and then considers it as a unit.
+
+
+
+The existence of sections, however, raises a problem for symbols even
+within the same source file. Thus, the assembler must treat symbols from
+different sections within the same source file in the same manner as external
+symbols. That is, it must leave them for the linker to resolve at link time,
+with all the limitations that entails.
+
+
+
+In the object file target mode, LWASM requires all source lines that
+cause bytes to be output to be inside a section. Any directives that do
+not cause any bytes to be output can appear outside of a section. This includes
+such things as EQU or RMB. Even ORG can appear outside a section. ORG, however,
+makes no sense within a section because it is the linker that determines
+the starting address of the section's code, not the assembler.
+
+
+
+All symbols defined globally in the assembly process are local to the
+source file and cannot be exported. All symbols defined within a section are
+considered local to the source file unless otherwise explicitly exported.
+Symbols referenced from external source files must be declared external,
+either explicitly or by asking the assembler to assume that all undefined
+symbols are external.
+
+
+
+It is often handy to define a number of memory addresses that will be
+used for data at run-time but which need not be included in the binary file.
+These memory addresses are not initialized until run-time, either by the
+program itself or by the program loader, depending on the operating environment.
+Such sections are often known as BSS sections. LWASM supports generating
+sections with a BSS attribute set which causes the section definition including
+symbols exported from that section and those symbols required to resolve
+references from the local file, but with no actual code in the object file.
+It is illegal for any source lines within a BSS flagged section to cause any
+bytes to be output.
+
+
+The following directives apply to section handling.
+
+
+
+SECTION name[,flags]
+SECT name[,flags]
+.AREA name[,flags]
+
+
+Instructs the assembler that the code following this directive is to be
+considered part of the section name . A section name
+may appear multiple times in which case it is as though all the code from
+all the instances of that section appeared adjacent within the source file.
+However, flags may only be specified on the first
+instance of the section.
+
+There is a single flag supported in flags . The
+flag bss will cause the section to be treated as a BSS
+section and, thus, no code will be included in the object file nor will any
+bytes be permitted to be output.
+
+If the section name is "bss" or ".bss" in any combination of upper and
+lower case, the section is assumed to be a BSS section. In that case,
+the flag !bss can be used to override this assumption.
+
+
+If assembly is already happening within a section, the section is implicitly
+ended and the new section started. This is not considered an error although
+it is recommended that all sections be explicitly closed.
+
+
+
+
+
+ENDSECTION
+ENDSECT
+
+
+This directive ends the current section. This puts assembly outside of any
+sections until the next SECTION directive. ENDSECTION is the preferred form.
+Prior to version 3.0 of LWASM, ENDS could also be used to end a section but
+as of version 3.0, it is now an alias for ENDSTRUCT instead.
+
+
+
+
+sym EXTERN
+sym EXTERNAL
+sym IMPORT
+
+
+This directive defines sym as an external symbol.
+This directive may occur at any point in the source code. EXTERN definitions
+are resolved on the first pass so an EXTERN definition anywhere in the
+source file is valid for the entire file. The use of this directive is
+optional when the assembler is instructed to assume that all undefined
+symbols are external. In fact, in that mode, if the symbol is referenced
+before the EXTERN directive, an error will occur.
+
+
+
+
+
+sym EXPORT
+sym .GLOBL
+
+EXPORT sym
+.GLOBL sym
+
+
+
+This directive defines sym as an exported symbol.
+This directive may occur at any point in the source code, even before the
+definition of the exported symbol.
+
+
+Note that sym may appear as the operand or as the
+statement's symbol. If there is a symbol on the statement, that will
+take precedence over any operand that is present.
+
+
+
+
+
+
+sym EXTDEP
+
+
+This directive forces an external dependency on
+sym , even if it is never referenced anywhere else in
+this file.
+
+
+
+
+
+
+
+
+Assembler Modes and Pragmas
+
+There are a number of options that affect the way assembly is performed.
+Some of these options can only be specified on the command line because
+they determine something absolute about the assembly process. These include
+such things as the output target. Other things may be switchable during
+the assembly process. These are known as pragmas and are, by definition,
+not portable between assemblers.
+
+
+LWASM supports a number of pragmas that affect code generation or
+otherwise affect the behaviour of the assembler. These may be specified by
+way of a command line option or by assembler directives. The directives
+are as follows.
+
+
+
+
+PRAGMA pragma[,...]
+
+
+Specifies that the assembler should bring into force all pragma s
+specified. Any unrecognized pragma will cause an assembly error. The new
+pragmas will take effect immediately. This directive should be used when
+the program will assemble incorrectly if the pragma is ignored or not supported.
+
+
+
+
+
+*PRAGMA pragma[,...]
+
+
+This is identical to the PRAGMA directive except no error will occur with
+unrecognized or unsupported pragmas. This directive, by virtue of starting
+with a comment character, will also be ignored by assemblers that do not
+support this directive. Use this variation if the pragma is not required
+for correct functioning of the code.
+
+
+
+
+
+Each pragma supported has a positive version and a negative version.
+The positive version enables the pragma while the negative version disables
+it. The negatitve version is simply the positive version with "no" prefixed
+to it. For instance, "pragma" vs. "nopragma". Only the positive version is
+listed below.
+
+Pragmas are not case sensitive.
+
+
+
+index0tonone
+
+
+When in force, this pragma enables an optimization affecting indexed addressing
+modes. When the offset expression in an indexed mode evaluates to zero but is
+not explicity written as 0, this will replace the operand with the equivalent
+no offset mode, thus creating slightly faster code. Because of the advantages
+of this optimization, it is enabled by default.
+
+
+
+
+
+cescapes
+
+
+This pragma will cause strings in the FCC, FCS, and FCN pseudo operations to
+have C-style escape sequences interpreted. The one departure from the official
+spec is that unrecognized escape sequences will return either the character
+immediately following the backslash or some undefined value. Do not rely
+on the behaviour of undefined escape sequences.
+
+
+
+
+
+importundefexport
+
+
+This pragma is only valid for targets that support external references. When
+in force, it will cause the EXPORT directive to act as IMPORT if the symbol
+to be exported is not defined. This is provided for compatibility with the
+output of gcc6809 and should not be used in hand written code. Because of
+the confusion this pragma can cause, it is disabled by default.
+
+
+
+
+
+undefextern
+
+
+This pragma is only valid for targets that support external references. When in
+force, if the assembler sees an undefined symbol on the second pass, it will
+automatically define it as an external symbol. This automatic definition will
+apply for the remainder of the assembly process, even if the pragma is
+subsequently turned off. Because this behaviour would be potentially surprising,
+this pragma defaults to off.
+
+
+The primary use for this pragma is for projects that share a large number of
+symbols between source files. In such cases, it is impractical to enumerate
+all the external references in every source file. This allows the assembler
+and linker to do the heavy lifting while not preventing a particular source
+module from defining a local symbol of the same name as an external symbol
+if it does not need the external symbol. (This pragma will not cause an
+automatic external definition if there is already a locally defined symbol.)
+
+
+This pragma will often be specified on the command line for large projects.
+However, depending on the specific dynamics of the project, it may be sufficient
+for one or two files to use this pragma internally.
+
+
+
+
+
+dollarlocal
+
+
+When set, a "$" in a symbol makes it local. When not set, "$" does not
+cause a symbol to be local. It is set by default except when using the OS9
+target.
+
+
+
+
+
+dollarnotlocal
+
+
+ This is the same as the "dollarlocal" pragma except its sense is
+reversed. That is, "dollarlocal" and "nodollarnotlocal" are equivalent and
+"nodollarlocal" and "dollarnotlocal" are equivalent.
+
+
+
+
+
+pcaspcr
+
+
+ Normally, LWASM makes a distinction between PC and PCR in program
+counter relative addressing. In particular, the use of PC means an absolute
+offset from PC while PCR causes the assembler to calculate the offset to the
+specified operand and use that as the offset from PC. By setting this
+pragma, you can have PC treated the same as PCR.
+
+
+
+
+
+
+
+
+
+
+
+
+LWLINK
+
+The LWTOOLS linker is called LWLINK. This chapter documents the various features
+of the linker.
+
+
+
+Command Line Options
+
+The binary for LWLINK is called "lwlink". Note that the binary is in lower
+case. lwlink takes the following command line arguments.
+
+
+
+--decb
+-b
+
+
+Selects the DECB output format target. This is equivalent to --format=decb
+
+
+
+
+
+--output=FILE
+-o FILE
+
+
+This option specifies the name of the output file. If not specified, the
+default is a.out .
+
+
+
+
+
+--format=TYPE
+-f TYPE
+
+
+This option specifies the output format. Valid values are decb
+and raw
+
+
+
+
+
+--raw
+-r
+
+
+This option specifies the raw output format.
+It is equivalent to --format=raw
+and -f raw
+
+
+
+
+
+--script=FILE
+-s
+
+
+This option allows specifying a linking script to override the linker's
+built in defaults.
+
+
+
+
+
+--section-base=SECT=BASE
+
+
+Cause section SECT to load at base address BASE. This will be prepended
+to the built-in link script. It is ignored if a link script is provided.
+
+
+
+
+
+--map=FILE
+-m FILE
+
+
+This will output a description of the link result to FILE.
+
+
+
+
+
+--library=LIBSPEC
+-l LIBSPEC
+
+
+Load a library using the library search path. LIBSPEC will have "lib" prepended
+and ".a" appended.
+
+
+
+
+
+--library-path=DIR
+-L DIR
+
+
+Add DIR to the library search path.
+
+
+
+
+
+--debug
+-d
+
+
+This option increases the debugging level. It is only useful for LWTOOLS
+developers.
+
+
+
+
+
+--help
+-?
+
+
+This provides a listing of command line options and a brief description
+of each.
+
+
+
+
+
+--usage
+
+
+This will display a usage summary
+of each command line option.
+
+
+
+
+
+
+--version
+-V
+
+
+This will display the version of LWLINK.
+
+
+
+
+
+
+
+Linker Operation
+
+
+
+LWLINK takes one or more files in supported input formats and links them
+into a single binary. Currently supported formats are the LWTOOLS object
+file format and the archive format used by LWAR. While the precise method is
+slightly different, linking can be conceptualized as the following steps.
+
+
+
+
+
+
+First, the linker loads a linking script. If no script is specified, it
+loads a built-in default script based on the output format selected. This
+script tells the linker how to lay out the various sections in the final
+binary.
+
+
+
+
+
+Next, the linker reads all the input files into memory. At this time, it
+flags any format errors in those files. It constructs a table of symbols
+for each object at this time.
+
+
+
+
+
+The linker then proceeds with organizing the sections loaded from each file
+according to the linking script. As it does so, it is able to assign addresses
+to each symbol defined in each object file. At this time, the linker may
+also collapse different instances of the same section name into a single
+section by appending the data from each subsequent instance of the section
+to the first instance of the section.
+
+
+
+
+
+Next, the linker looks through every object file for every incomplete reference.
+It then attempts to fully resolve that reference. If it cannot do so, it
+throws an error. Once a reference is resolved, the value is placed into
+the binary code at the specified section. It should be noted that an
+incomplete reference can reference either a symbol internal to the object
+file or an external symbol which is in the export list of another object
+file.
+
+
+
+
+
+If all of the above steps are successful, the linker opens the output file
+and actually constructs the binary.
+
+
+
+
+
+
+Linking Scripts
+
+A linker script is used to instruct the linker about how to assemble the
+various sections into a completed binary. It consists of a series of
+directives which are considered in the order they are encountered.
+
+
+The sections will appear in the resulting binary in the order they are
+specified in the script file. If a referenced section is not found, the linker will behave as though the
+section did exist but had a zero size, no relocations, and no exports.
+A section should only be referenced once. Any subsequent references will have
+an undefined effect.
+
+
+
+All numbers are in linking scripts are specified in hexadecimal. All directives
+are case sensitive although the hexadecimal numbers are not.
+
+
+A section name can be specified as a "*", then any section not
+already matched by the script will be matched. The "*" can be followed
+by a comma and a flag to narrow the section down slightly, also.
+If the flag is "!bss", then any section that is not flagged as a bss section
+will be matched. If the flag is "bss", then any section that is flagged as
+bss will be matched.
+
+
+The following directives are understood in a linker script.
+
+
+section name load addr
+
+
+This causes the section name to load at
+addr . For the raw target, only one "load at" entry is
+allowed for non-bss sections and it must be the first one. For raw targets,
+it affects the addresses the linker assigns to symbols but has no other
+affect on the output. bss sections may all have separate load addresses but
+since they will not appear in the binary anyway, this is okay.
+
+For the decb target, each "load" entry will cause a new "block" to be
+output to the binary which will contain the load address. It is legal for
+sections to overlap in this manner - the linker assumes the loader will sort
+everything out.
+
+
+
+
+section name
+
+
+This will cause the section name to load after the previously listed
+section.
+
+
+exec addr or sym
+
+
+This will cause the execution address (entry point) to be the address
+specified (in hex) or the specified symbol name. The symbol name must
+match a symbol that is exported by one of the object files being linked.
+This has no effect for targets that do not encode the entry point into the
+resulting file. If not specified, the entry point is assumed to be address 0
+which is probably not what you want. The default link scripts for targets
+that support this directive automatically starts at the beginning of the
+first section (usually "init" or "code") that is emitted in the binary.
+
+
+
+
+
+pad size
+
+This will cause the output file to be padded with NUL bytes to be exactly
+size bytes in length. This only makes sense for a raw target.
+
+
+
+
+
+
+
+
+
+
+
+
+Libraries and LWAR
+
+
+LWTOOLS also includes a tool for managing libraries. These are analogous to
+the static libraries created with the "ar" tool on POSIX systems. Each library
+file contains one or more object files. The linker will treat the object
+files within a library as though they had been specified individually on
+the command line except when resolving external references. External references
+are looked up first within the object files within the library and then, if
+not found, the usual lookup based on the order the files are specified on
+the command line occurs.
+
+
+
+The tool for creating these libary files is called LWAR.
+
+
+
+Command Line Options
+
+The binary for LWAR is called "lwar". Note that the binary is in lower
+case. The options lwar understands are listed below. For archive manipulation
+options, the first non-option argument is the name of the archive. All other
+non-option arguments are the names of files to operate on.
+
+
+
+
+--add
+-a
+
+
+This option specifies that an archive is going to have files added to it.
+If the archive does not already exist, it is created. New files are added
+to the end of the archive.
+
+
+
+
+
+--create
+-c
+
+
+This option specifies that an archive is going to be created and have files
+added to it. If the archive already exists, it is truncated.
+
+
+
+
+
+--merge
+-m
+
+
+If specified, any files specified to be added to an archive will be checked
+to see if they are archives themselves. If so, their constituent members are
+added to the archive. This is useful for avoiding archives containing archives.
+
+
+
+
+
+--list
+-l
+
+
+This will display a list of the files contained in the archive.
+
+
+
+
+
+--debug
+-d
+
+
+This option increases the debugging level. It is only useful for LWTOOLS
+developers.
+
+
+
+
+
+--help
+-?
+
+
+This provides a listing of command line options and a brief description
+of each.
+
+
+
+
+
+--usage
+
+
+This will display a usage summary
+of each command line option.
+
+
+
+
+
+
+--version
+-V
+
+
+This will display the version of LWLINK.
+of each.
+
+
+
+
+
+
+
+
+
+Object Files
+
+LWTOOLS uses a proprietary object file format. It is proprietary in the sense
+that it is specific to LWTOOLS, not that it is a hidden format. It would be
+hard to keep it hidden in an open source tool chain anyway. This chapter
+documents the object file format.
+
+
+
+An object file consists of a series of sections each of which contains a
+list of exported symbols, a list of incomplete references, and a list of
+"local" symbols which may be used in calculating incomplete references. Each
+section will obviously also contain the object code.
+
+
+
+Exported symbols must be completely resolved to an address within the
+section it is exported from. That is, an exported symbol must be a constant
+rather than defined in terms of other symbols.
+
+
+Each object file starts with a magic number and version number. The magic
+number is the string "LWOBJ16" for this 16 bit object file format. The only
+defined version number is currently 0. Thus, the first 8 bytes of the object
+file are 4C574F424A313600
+
+
+
+Each section has the following items in order:
+
+
+
+section name
+flags
+list of local symbols (and addresses within the section)
+list of exported symbols (and addresses within the section)
+list of incomplete references along with the expressions to calculate them
+the actual object code (for non-BSS sections)
+
+
+
+The section starts with the name of the section with a NUL termination
+followed by a series of flag bytes terminated by NUL. There are only two
+flag bytes defined. A NUL (0) indicates no more flags and a value of 1
+indicates the section is a BSS section. For a BSS section, no actual
+code is included in the object file.
+
+
+
+Either a NULL section name or end of file indicate the presence of no more
+sections.
+
+
+
+Each entry in the exported and local symbols table consists of the symbol
+(NUL terminated) followed by two bytes which contain the value in big endian
+order. The end of a symbol table is indicated by a NULL symbol name.
+
+
+
+Each entry in the incomplete references table consists of an expression
+followed by a 16 bit offset where the reference goes. Expressions are
+defined as a series of terms up to an "end of expression" term. Each term
+consists of a single byte which identifies the type of term (see below)
+followed by any data required by the term. Then end of the list is flagged
+by a NULL expression (only an end of expression term).
+
+
+Object File Term Types
+
+
+
+TERMTYPE
+Meaning
+
+
+
+
+00
+end of expression
+
+
+
+01
+integer (16 bit in big endian order follows)
+
+
+02
+ external symbol reference (NUL terminated symbol name follows)
+
+
+
+03
+local symbol reference (NUL terminated symbol name follows)
+
+
+
+04
+operator (1 byte operator number)
+
+
+05
+section base address reference
+
+
+
+FF
+This term will set flags for the expression. Each one of these terms will set a single flag. All of them should be specified first in an expression. If they are not, the behaviour is undefined. The byte following is the flag. Flag 01 indicates an 8 bit relocation. Flag 02 indicates a zero-width relocation (see the EXTDEP pseudo op in LWASM).
+
+
+
+
+
+
+
+External references are resolved using other object files while local
+references are resolved using the local symbol table(s) from this file. This
+allows local symbols that are not exported to have the same names as
+exported symbols or external references.
+
+
+Object File Operator Numbers
+
+
+
+Number
+Operator
+
+
+
+
+01
+addition (+)
+
+
+02
+subtraction (-)
+
+
+03
+multiplication (*)
+
+
+04
+division (/)
+
+
+05
+modulus (%)
+
+
+06
+integer division (\) (same as division)
+
+
+
+07
+bitwise and
+
+
+
+08
+bitwise or
+
+
+
+09
+bitwise xor
+
+
+
+0A
+boolean and
+
+
+
+0B
+boolean or
+
+
+
+0C
+unary negation, 2's complement (-)
+
+
+
+0D
+unary 1's complement (^)
+
+
+
+
+
+
+An expression is represented in a postfix manner with both operands for
+binary operators preceding the operator and the single operand for unary
+operators preceding the operator.
+
+
+
+
+
diff -r 000000000000 -r 2c24602be78f docs/manual/README
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/manual/README Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,3 @@
+This folder contains the manual in various forms which may or may
+not be present unless this is an actual release. Even then, they may
+or may not be present.
diff -r 000000000000 -r 2c24602be78f docs/readme-4.0.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/readme-4.0.txt Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,17 @@
+With LWTOOLS 4.0, a substantial reorganization of the project has occurred.
+This document serves to explain the reasoning behind the various changes.
+
+The most obvious change is that the gnu auto tools have been eliminated.
+While they proved useful for initial distribution of the software,
+particularly for construction of the win32 binaries, they have since proved
+to add an unacceptable level of complexity to every aspect of development
+from merely tinkering with source files to doing complete releases. Thus,
+the auto tools have been ditched in favour of specific hand tuned help where
+required.
+
+The other substantial change is that the source code repository has been
+recreated from scratch. The old repository was full of cruft from various
+revision control systems that were used over the years (CVS, Subversion, and
+Mercurial). It was felt that starting a new Mercurial repository with a
+completely clean slate would simplify matters substantially. Thus, the old
+repository now serves as an archive.
diff -r 000000000000 -r 2c24602be78f lwar/add.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwar/add.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,193 @@
+/*
+add.c
+Copyright © 2009 William Astle
+
+This file is part of LWAR.
+
+LWAR 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 3 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, see .
+
+
+Implements the program startup code
+
+*/
+
+#include
+#include
+#include
+
+#include "lwar.h"
+
+void do_add(void)
+{
+ FILE *f;
+ unsigned char buf[8];
+ long l;
+ int c;
+ FILE *f2;
+ int i;
+
+ f = fopen(archive_file, "r+");
+ if (!f)
+ {
+ if (errno == ENOENT)
+ {
+ f = fopen(archive_file, "w");
+ if (f)
+ {
+ fputs("LWAR1V", f);
+ goto doadd;
+ }
+ }
+ perror("Cannot open archive file");
+ }
+
+ fread(buf, 1, 6, f);
+ if (memcmp("LWAR1V", buf, 6))
+ {
+ fprintf(stderr, "%s is not a valid archive file.\n", archive_file);
+ exit(1);
+ }
+
+ for (;;)
+ {
+ c = fgetc(f);
+ if (c == EOF && ferror(f))
+ {
+ perror("Reading archive file");
+ exit(1);
+ }
+ if (c == EOF)
+ goto doadd;
+
+ if (!c)
+ {
+ fseek(f, -1, SEEK_CUR);
+ goto doadd;
+ }
+
+ // find the end of the file name
+ while (c)
+ {
+ c = fgetc(f);
+ if (c == EOF || ferror(f))
+ {
+ fprintf(stderr, "Bad archive file\n");
+ exit(1);
+ }
+ }
+
+ // get length of archive member
+ l = 0;
+ c = fgetc(f);
+ l = c << 24;
+ c = fgetc(f);
+ l |= c << 16;
+ c = fgetc(f);
+ l |= c << 8;
+ c = fgetc(f);
+ l |= c;
+
+ fseek(f, l, SEEK_CUR);
+ }
+ // back up to the NUL byte at the end of the file
+ fseek(f, -1, SEEK_CUR);
+doadd:
+ for (i = 0; i < nfiles; i++)
+ {
+ f2 = fopen(files[i], "r");
+ if (!f2)
+ {
+ fprintf(stderr, "Cannot open file %s:", files[i]);
+ perror("");
+ exit(1);
+ }
+ fread(buf, 1, 6, f2);
+ if (mergeflag && !memcmp("LWAR1V", buf, 6))
+ {
+ // add archive contents...
+ for (;;)
+ {
+ c = fgetc(f2);
+ if (c == EOF || ferror(f2))
+ {
+ perror("Reading input archive file");
+ exit(1);
+ }
+ if (c == EOF)
+ break;
+
+ if (!c)
+ {
+ break;
+ }
+
+ // find the end of the file name
+ while (c)
+ {
+ fputc(c, f);
+ c = fgetc(f2);
+ if (c == EOF || ferror(f))
+ {
+ fprintf(stderr, "Bad input archive file\n");
+ exit(1);
+ }
+ }
+ fputc(0, f);
+
+ // get length of archive member
+ l = 0;
+ c = fgetc(f2);
+ fputc(c, f);
+ l = c << 24;
+ c = fgetc(f2);
+ fputc(c, f);
+ l |= c << 16;
+ c = fgetc(f2);
+ fputc(c, f);
+ l |= c << 8;
+ c = fgetc(f2);
+ fputc(c, f);
+ l |= c;
+
+ while (l)
+ {
+ c = fgetc(f2);
+ fputc(c, f);
+ l--;
+ }
+ }
+
+ fclose(f2);
+ continue;
+ }
+ fseek(f2, 0, SEEK_END);
+ l = ftell(f2);
+ fseek(f2, 0, SEEK_SET);
+ fputs(files[i], f);
+ fputc(0, f);
+ fputc(l >> 24, f);
+ fputc((l >> 16) & 0xff, f);
+ fputc((l >> 8) & 0xff, f);
+ fputc(l & 0xff, f);
+ while (l)
+ {
+ c = fgetc(f2);
+ fputc(c, f);
+ l--;
+ }
+ }
+
+ // flag end of file
+ fputc(0, f);
+}
diff -r 000000000000 -r 2c24602be78f lwar/extract.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwar/extract.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,121 @@
+/*
+extract.c
+Copyright © 2009 William Astle
+
+This file is part of LWAR.
+
+LWAR 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 3 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, see .
+
+*/
+
+#include
+#include
+#include
+#include
+
+#include "lwar.h"
+
+void do_extract(void)
+{
+ FILE *f;
+ char buf[8];
+ long l;
+ int c;
+ char fnbuf[1024];
+ int i;
+ FILE *nf;
+
+ f = fopen(archive_file, "r");
+ if (!f)
+ {
+ perror("Opening archive file");
+ exit(1);
+ }
+
+ fread(buf, 1, 6, f);
+ if (memcmp("LWAR1V", buf, 6))
+ {
+ fprintf(stderr, "%s is not a valid archive file.\n", archive_file);
+ exit(1);
+ }
+
+ for (;;)
+ {
+ c = fgetc(f);
+ if (ferror(f))
+ {
+ perror("Reading archive file");
+ exit(1);
+ }
+ if (c == EOF)
+ return;
+
+
+ // find the end of the file name
+ if (!c)
+ return;
+
+ i = 0;
+ while (c)
+ {
+ fnbuf[i++] = c;
+ c = fgetc(f);
+ if (c == EOF || ferror(f))
+ {
+ fprintf(stderr, "Bad archive file\n");
+ exit(1);
+ }
+ }
+ fnbuf[i] = 0;
+
+ // get length of archive member
+ l = 0;
+ c = fgetc(f);
+ l = c << 24;
+ c = fgetc(f);
+ l |= c << 16;
+ c = fgetc(f);
+ l |= c << 8;
+ c = fgetc(f);
+ l |= c;
+
+ for (i = 0; i < nfiles; i++)
+ {
+ if (!strcmp(files[i], fnbuf))
+ break;
+ }
+ if (i < nfiles || nfiles == 0)
+ {
+ // extract the file
+ nf = fopen(fnbuf, "w");
+ if (!nf)
+ {
+ fprintf(stderr, "Cannot extract '%s': %s\n", fnbuf, strerror(errno));
+ exit(1);
+ }
+ while (l)
+ {
+ c = fgetc(f);
+ fputc(c, nf);
+ l--;
+ }
+ fclose(nf);
+ }
+ else
+ {
+ // skip the file
+ fseek(f, l, SEEK_CUR);
+ }
+ }
+}
diff -r 000000000000 -r 2c24602be78f lwar/list.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwar/list.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,93 @@
+/*
+list.c
+Copyright © 2009 William Astle
+
+This file is part of LWAR.
+
+LWAR 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 3 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, see .
+
+
+Implements the program startup code
+
+*/
+
+#include
+#include
+#include
+#include
+
+#include "lwar.h"
+
+void do_list(void)
+{
+ FILE *f;
+ char buf[8];
+ long l;
+ int c;
+
+ f = fopen(archive_file, "r");
+ if (!f)
+ {
+ perror("Opening archive file");
+ exit(1);
+ }
+
+ fread(buf, 1, 6, f);
+ if (memcmp("LWAR1V", buf, 6))
+ {
+ fprintf(stderr, "%s is not a valid archive file.\n", archive_file);
+ exit(1);
+ }
+
+ for (;;)
+ {
+ c = fgetc(f);
+ if (ferror(f))
+ {
+ perror("Reading archive file");
+ exit(1);
+ }
+ if (c == EOF)
+ return;
+
+
+ // find the end of the file name
+ if (!c)
+ return;
+
+ while (c)
+ {
+ putchar(c);
+ c = fgetc(f);
+ if (c == EOF || ferror(f))
+ {
+ fprintf(stderr, "Bad archive file\n");
+ exit(1);
+ }
+ }
+
+ // get length of archive member
+ l = 0;
+ c = fgetc(f);
+ l = c << 24;
+ c = fgetc(f);
+ l |= c << 16;
+ c = fgetc(f);
+ l |= c << 8;
+ c = fgetc(f);
+ l |= c;
+ printf(": %04lx bytes\n", l);
+ fseek(f, l, SEEK_CUR);
+ }
+}
diff -r 000000000000 -r 2c24602be78f lwar/lwar.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwar/lwar.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,53 @@
+/*
+lwar.c
+Copyright © 2009 William Astle
+
+This file is part of LWAR.
+
+LWAR 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 3 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, see .
+
+
+Implements the program startup code
+
+*/
+
+#include
+#include
+#include
+#include
+#include
+
+#define __lwar_c_seen__
+#include "lwar.h"
+#include "util.h"
+
+typedef struct
+{
+ FILE *f;
+} arhandle_real;
+
+int debug_level = 0;
+int operation = 0;
+int nfiles = 0;
+char *archive_file = NULL;
+int mergeflag = 0;
+
+char **files = NULL;
+
+void add_file_name(char *fn)
+{
+ files = lw_realloc(files, sizeof(char *) * (nfiles + 1));
+ files[nfiles] = fn;
+ nfiles++;
+}
diff -r 000000000000 -r 2c24602be78f lwar/lwar.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwar/lwar.h Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,62 @@
+/*
+lwar.h
+Copyright © 2009 William Astle
+
+This file is part of LWAR.
+
+LWAR 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 3 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, see .
+
+Contains the main defs used by the linker
+*/
+
+
+#define LWAR_OP_LIST 1
+#define LWAR_OP_ADD 2
+#define LWAR_OP_REMOVE 3
+#define LWAR_OP_CREATE 4
+#define LWAR_OP_EXTRACT 5
+#define LWAR_OP_REPLACE 6
+
+#ifndef __lwar_h_seen__
+#define __lwar_h_seen__
+
+#ifndef __lwar_c_seen__
+
+extern char *archive_file;
+extern int debug_level;
+extern int operation;
+extern int nfiles;
+extern char **files;
+extern int mergeflag;
+
+//typedef void * ARHANDLE;
+
+#define AR_MODE_RD 1
+#define AR_MODE_WR 2
+#define AR_MODE_RW 3
+#define AR_MODE_CREATE 4
+
+
+#define __lwar_E__ extern
+#else
+#define __lwar_E__
+#endif // __lwar_c_seen__
+
+__lwar_E__ void add_file_name(char *fn);
+
+//__lwar_E__ ARHANDLE open_archive(char *fn, int mode);
+
+#undef __lwar_E__
+
+#endif //__lwar_h_seen__
diff -r 000000000000 -r 2c24602be78f lwar/main.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwar/main.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,206 @@
+/*
+main.c
+Copyright © 2009 William Astle
+
+This file is part of LWAR.
+
+LWAR 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 3 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, see .
+
+
+Implements the program startup code
+
+*/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "lwar.h"
+
+// command line option handling
+const char *argp_program_version = "LWAR from " PACKAGE_STRING;
+const char *argp_program_bug_address = PACKAGE_BUGREPORT;
+char *program_name;
+
+static error_t parse_opts(int key, char *arg, struct argp_state *state)
+{
+ switch (key)
+ {
+ case 'd':
+ // debug
+ debug_level++;
+ break;
+
+ case 'a':
+ // add members
+ operation = LWAR_OP_ADD;
+ break;
+
+ case 'c':
+ // create archive
+ operation = LWAR_OP_CREATE;
+ break;
+
+ case 'm':
+ mergeflag = 1;
+ break;
+
+ case 'r':
+ // replace members
+ operation = LWAR_OP_REPLACE;
+ break;
+
+ case 'l':
+ // list members
+ operation = LWAR_OP_LIST;
+ break;
+
+ case 'x':
+ // extract members
+ operation = LWAR_OP_EXTRACT;
+ break;
+
+ case ARGP_KEY_ARG:
+ if (archive_file)
+ {
+ // add archive member to list
+ add_file_name(arg);
+ }
+ else
+ archive_file = arg;
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+static struct argp_option options[] =
+{
+ { "replace", 'r', 0, 0,
+ "Add or replace archive members" },
+ { "extract", 'x', 0, 0,
+ "Extract members from the archive" },
+ { "add", 'a', 0, 0,
+ "Add members to the archive" },
+ { "list", 'l', 0, 0,
+ "List the contents of the archive" },
+ { "create", 'c', 0, 0,
+ "Create new archive (or truncate existing one)" },
+ { "merge", 'm', 0, 0,
+ "Add the contents of archive arguments instead of the archives themselves" },
+ { "debug", 'd', 0, 0,
+ "Set debug mode"},
+ { 0 }
+};
+
+static struct argp argp =
+{
+ options,
+ parse_opts,
+ " [ ...]",
+ "LWAR, a library file manager for LWLINK"
+};
+
+extern void do_list(void);
+extern void do_add(void);
+extern void do_remove(void);
+extern void do_replace(void);
+extern void do_extract(void);
+
+// main function; parse command line, set up assembler state, and run the
+// assembler on the first file
+int main(int argc, char **argv)
+{
+ program_name = argv[0];
+ argp_parse(&argp, argc, argv, 0, 0, NULL);
+ if (archive_file == NULL)
+ {
+ fprintf(stderr, "You must specify an archive file.\n");
+ exit(1);
+ }
+
+ if (operation == 0)
+ {
+ fprintf(stderr, "You must specify an operation.\n");
+ exit(1);
+ }
+
+ if (operation == LWAR_OP_LIST || operation == LWAR_OP_REMOVE || operation == LWAR_OP_EXTRACT)
+ {
+ struct stat stbuf;
+ // make sure the archive exists
+ if (stat(archive_file, &stbuf) < 0)
+ {
+ fprintf(stderr, "Cannot open archive file %s:\n", archive_file);
+ perror("");
+ exit(2);
+ }
+ }
+ if (operation == LWAR_OP_CREATE)
+ {
+ struct stat stbuf;
+ // check if the archive exists
+ if (stat(archive_file, &stbuf) < 0)
+ {
+ if (errno != ENOENT)
+ {
+ fprintf(stderr, "Cannot create archive file %s:\n", archive_file);
+ perror("");
+ exit(2);
+ }
+ }
+ else
+ {
+ if (unlink(archive_file) < 0)
+ {
+ fprintf(stderr, "Cannot create archive file %s:\n", archive_file);
+ perror("");
+ exit(2);
+ }
+
+ }
+ }
+
+ switch (operation)
+ {
+ case LWAR_OP_LIST:
+ do_list();
+ break;
+
+ case LWAR_OP_ADD:
+ case LWAR_OP_CREATE:
+ do_add();
+ break;
+
+ case LWAR_OP_REMOVE:
+ do_remove();
+ break;
+
+ case LWAR_OP_REPLACE:
+ do_replace();
+ break;
+
+ case LWAR_OP_EXTRACT:
+ do_extract();
+ break;
+ }
+
+ exit(0);
+}
diff -r 000000000000 -r 2c24602be78f lwar/remove.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwar/remove.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,29 @@
+/*
+remove.c
+Copyright © 2009 William Astle
+
+This file is part of LWAR.
+
+LWAR 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 3 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, see .
+
+
+Implements the program startup code
+
+*/
+
+#include "lwar.h"
+
+void do_remove(void)
+{
+}
diff -r 000000000000 -r 2c24602be78f lwar/replace.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwar/replace.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,241 @@
+/*
+replace.c
+Copyright © 2009 William Astle
+
+This file is part of LWAR.
+
+LWAR 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 3 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, see .
+
+*/
+
+#include
+#include
+#include
+#include
+
+#include "lwar.h"
+
+void do_replace(void)
+{
+ FILE *f;
+ FILE *nf;
+ unsigned char buf[8];
+ long l;
+ int c;
+ FILE *f2;
+ int i;
+ char fnbuf[1024];
+ char fnbuf2[1024];
+
+ sprintf(fnbuf, "%s.tmp", archive_file);
+
+ f = fopen(archive_file, "r+");
+ if (!f)
+ {
+ if (errno == ENOENT)
+ {
+ nf = fopen(fnbuf, "w");
+ if (nf)
+ {
+ fputs("LWAR1V", nf);
+ goto doadd;
+ }
+ }
+ perror("Cannot open archive file");
+ }
+
+ fread(buf, 1, 6, f);
+ if (memcmp("LWAR1V", buf, 6))
+ {
+ fprintf(stderr, "%s is not a valid archive file.\n", archive_file);
+ exit(1);
+ }
+
+ nf = fopen(fnbuf, "w");
+ if (!nf)
+ {
+ perror("Cannot create temp archive file");
+ exit(1);
+ }
+
+ fputs("LWAR1V", nf);
+
+ for (;;)
+ {
+ c = fgetc(f);
+ if (c == EOF && ferror(f))
+ {
+ perror("Reading archive file");
+ exit(1);
+ }
+ if (c == EOF)
+ goto doadd;
+
+ if (!c)
+ {
+ goto doadd;
+ }
+
+ // find the end of the file name
+ i = 0;
+ while (c)
+ {
+ fnbuf2[i++] = c;
+ c = fgetc(f);
+ if (c == EOF || ferror(f))
+ {
+ fprintf(stderr, "Bad archive file\n");
+ exit(1);
+ }
+ }
+ fnbuf2[i] = 0;
+
+ // get length of archive member
+ l = 0;
+ c = fgetc(f);
+ l = c << 24;
+ c = fgetc(f);
+ l |= c << 16;
+ c = fgetc(f);
+ l |= c << 8;
+ c = fgetc(f);
+ l |= c;
+
+ // is it a file we are replacing? if so, do not copy it
+ for (i = 0; i < nfiles; i++)
+ {
+ if (!strcmp(files[i], fnbuf2))
+ break;
+ }
+ if (i < nfiles)
+ {
+ fseek(f, l, SEEK_CUR);
+ }
+ else
+ {
+ // otherwise, copy it
+ fprintf(nf, "%s", fnbuf2);
+ fputc(0, nf);
+ fputc(l >> 24, nf);
+ fputc((l >> 16) & 0xff, nf);
+ fputc((l >> 8) & 0xff, nf);
+ fputc(l & 0xff, nf);
+ while (l)
+ {
+ c = fgetc(f);
+ fputc(c, nf);
+ l--;
+ }
+ }
+ }
+
+ // done with the original file
+ fclose(f);
+doadd:
+ for (i = 0; i < nfiles; i++)
+ {
+ f2 = fopen(files[i], "r");
+ if (!f2)
+ {
+ fprintf(stderr, "Cannot open file %s:", files[i]);
+ perror("");
+ exit(1);
+ }
+ fread(buf, 1, 6, f2);
+ if (mergeflag && !memcmp("LWAR1V", buf, 6))
+ {
+ // add archive contents...
+ for (;;)
+ {
+ c = fgetc(f2);
+ if (c == EOF || ferror(f2))
+ {
+ perror("Reading input archive file");
+ exit(1);
+ }
+ if (c == EOF)
+ break;
+
+ if (!c)
+ {
+ break;
+ }
+
+ // find the end of the file name
+ while (c)
+ {
+ fputc(c, nf);
+ c = fgetc(f2);
+ if (c == EOF || ferror(f))
+ {
+ fprintf(stderr, "Bad input archive file\n");
+ exit(1);
+ }
+ }
+ fputc(0, nf);
+
+ // get length of archive member
+ l = 0;
+ c = fgetc(f2);
+ fputc(c, nf);
+ l = c << 24;
+ c = fgetc(f2);
+ fputc(c, nf);
+ l |= c << 16;
+ c = fgetc(f2);
+ fputc(c, nf);
+ l |= c << 8;
+ c = fgetc(f2);
+ fputc(c, nf);
+ l |= c;
+
+ while (l)
+ {
+ c = fgetc(f2);
+ fputc(c, nf);
+ l--;
+ }
+ }
+
+ fclose(f2);
+ continue;
+ }
+ fseek(f2, 0, SEEK_END);
+ l = ftell(f2);
+ fseek(f2, 0, SEEK_SET);
+ fputs(files[i], nf);
+ fputc(0, nf);
+ fputc(l >> 24, nf);
+ fputc((l >> 16) & 0xff, nf);
+ fputc((l >> 8) & 0xff, nf);
+ fputc(l & 0xff, nf);
+ while (l)
+ {
+ c = fgetc(f2);
+ fputc(c, nf);
+ l--;
+ }
+ }
+
+ // flag end of file
+ fputc(0, nf);
+
+ fclose(nf);
+
+ if (rename(fnbuf, archive_file) < 0)
+ {
+ perror("Cannot replace old archive file");
+ unlink(fnbuf);
+ }
+}
diff -r 000000000000 -r 2c24602be78f lwar/rules.make
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwar/rules.make Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,5 @@
+dirname := $(dir $(lastword $(MAKEFILE_LIST)))
+
+lwar_srcs_local := add.c extract.c list.c lwar.c main.c remove.c replace.c util.c
+
+lwar_srcs := $(lwar_srcs) $(addprefix $(dirname),$(lwar_srcs_local))
diff -r 000000000000 -r 2c24602be78f lwar/util.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwar/util.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,87 @@
+/*
+util.c
+Copyright © 2009 William Astle
+
+This file is part of LWAR.
+
+LWAR 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 3 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, see .
+*/
+
+/*
+Utility functions
+*/
+
+#define __util_c_seen__
+
+#include
+#include
+#include
+#include
+
+#include "util.h"
+
+void *lw_malloc(int size)
+{
+ void *ptr;
+
+ ptr = malloc(size);
+ if (!ptr)
+ {
+ // bail out; memory allocation error
+ fprintf(stderr, "lw_malloc(): Memory allocation error\n");
+ exit(1);
+ }
+ return ptr;
+}
+
+void *lw_realloc(void *optr, int size)
+{
+ void *ptr;
+
+ if (size == 0)
+ {
+ lw_free(optr);
+ return;
+ }
+
+ ptr = realloc(optr, size);
+ if (!ptr)
+ {
+ fprintf(stderr, "lw_realloc(): memory allocation error\n");
+ exit(1);
+ }
+}
+
+void lw_free(void *ptr)
+{
+ if (ptr)
+ free(ptr);
+}
+
+char *lw_strdup(const char *s)
+{
+ char *d;
+
+ if (!s)
+ return NULL;
+
+ d = strdup(s);
+ if (!d)
+ {
+ fprintf(stderr, "lw_strdup(): memory allocation error\n");
+ exit(1);
+ }
+
+ return d;
+}
diff -r 000000000000 -r 2c24602be78f lwar/util.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwar/util.h Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,44 @@
+/*
+util.h
+Copyright © 2009 William Astle
+
+This file is part of LWAR.
+
+LWAR 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 3 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, see .
+*/
+
+/*
+Utility functions
+*/
+
+#ifndef __util_h_seen__
+#define __util_h_seen__
+
+#ifndef __util_c_seen__
+#define __util_E__ extern
+#else
+#define __util_E__
+#endif
+
+// allocate memory
+__util_E__ void *lw_malloc(int size);
+__util_E__ void lw_free(void *ptr);
+__util_E__ void *lw_realloc(void *optr, int size);
+
+// string stuff
+__util_E__ char *lw_strdup(const char *s);
+
+#undef __util_E__
+
+#endif // __util_h_seen__
diff -r 000000000000 -r 2c24602be78f lwasm/debug.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwasm/debug.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,90 @@
+/*
+debug.c
+
+Copyright © 2010 William Astle
+
+This file is part of LWTOOLS.
+
+LWTOOLS 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 3 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, see .
+*/
+
+#include
+#include
+#include
+
+#include "lwasm.h"
+#include "instab.h"
+
+/*
+
+Various debug utilities
+
+*/
+void dump_state(asmstate_t *as)
+{
+ line_t *cl;
+ exportlist_t *ex;
+ struct symtabe *s;
+ importlist_t *im;
+ struct line_expr_s *le;
+ lwasm_error_t *e;
+
+ debug_message(as, 100, "Lines:");
+
+ for (cl = as -> line_head; cl; cl = cl -> next)
+ {
+ debug_message(as, 100, "%p INSN %d (%s) LEN %d", cl, cl -> insn, (cl -> insn >= 0) ? instab[cl -> insn].opcode : "", cl -> len);
+ debug_message(as, 100, " ADDR: %s", lw_expr_print(cl -> addr));
+ debug_message(as, 100, " PB: %02X; LINT: %X; LINT2: %X", cl -> pb, cl -> lint, cl -> lint2);
+ for (le = cl -> exprs; le; le = le -> next)
+ {
+ debug_message(as, 100, " EXPR %d: %s", le -> id, lw_expr_print(le -> expr));
+ }
+ if (cl -> outputl > 0)
+ {
+ int i;
+ for (i = 0; i < cl -> outputl; i++)
+ {
+ debug_message(as, 100, " OBYTE %02X: %02X", i, cl -> output[i]);
+ }
+ }
+ for (e = cl -> err; e; e = e -> next)
+ {
+ debug_message(as, 100, " ERR: %s", e -> mess);
+ }
+ for (e = cl -> warn; e; e = e -> next)
+ {
+ debug_message(as, 100, " WARN: %s", e -> mess);
+ }
+ }
+}
+
+void debug_message(asmstate_t *as, int level, const char *fmt, ...)
+{
+ va_list args;
+
+ if (as -> debug_level < level)
+ return;
+
+ if (as -> debug_file == NULL)
+ as -> debug_file = stderr;
+
+ va_start(args, fmt);
+
+ fprintf(as -> debug_file, "DEBUG %03d: ", level);
+ vfprintf(as -> debug_file, fmt, args);
+ fputc('\n', as -> debug_file);
+
+ va_end(args);
+}
diff -r 000000000000 -r 2c24602be78f lwasm/input.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwasm/input.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,413 @@
+/*
+input.c
+
+Copyright © 2010 William Astle
+
+This file is part of LWTOOLS.
+
+LWTOOLS 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 3 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, see .
+*/
+
+/*
+This file is used to handle reading input files. It serves to encapsulate
+the entire input system to make porting to different media and systems
+less difficult.
+*/
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include "lwasm.h"
+
+/*
+Data type for storing input buffers
+*/
+
+enum input_types_e
+{
+ input_type_file, // regular file, no search path
+ input_type_include, // include path, start from "local"
+ input_type_string, // input from a string
+
+ input_type_error // invalid input type
+};
+
+struct input_stack
+{
+ struct input_stack *next;
+ int type;
+ void *data;
+ int data2;
+ char *filespec;
+};
+
+#define IS ((struct input_stack *)(as -> input_data))
+
+void input_init(asmstate_t *as)
+{
+ struct input_stack *t;
+
+ if (as -> file_dir)
+ lw_stack_destroy(as -> file_dir);
+ as -> file_dir = lw_stack_create(lw_free);
+ as -> includelist = lw_stack_create(lw_free);
+ lw_stringlist_reset(as -> input_files);
+ while (IS)
+ {
+ t = IS;
+ as -> input_data = IS -> next;
+ lw_free(t);
+ }
+}
+
+void input_pushpath(asmstate_t *as, char *fn)
+{
+ /* take apart fn into path and filename then push the path */
+ /* onto the current file path stack */
+
+ /* also add it to the list of files included */
+ char *dn, *dp;
+ int o;
+
+ dn = lw_strdup(fn);
+ lw_stack_push(as -> includelist, dn);
+
+ dn = lw_strdup(fn);
+ dp = dn + strlen(dn);
+
+ while (--dp != dn)
+ {
+ if (*dp == '/')
+ break;
+ }
+ if (*dp == '/')
+ *dp = '\0';
+
+ if (dp == dn)
+ {
+ lw_free(dn);
+ dn = lw_strdup(".");
+ lw_stack_push(as -> file_dir, dn);
+ return;
+ }
+ dp = lw_strdup(dn);
+ lw_free(dn);
+ lw_stack_push(as -> file_dir, dp);
+}
+
+void input_openstring(asmstate_t *as, char *s, char *str)
+{
+ struct input_stack *t;
+
+ t = lw_alloc(sizeof(struct input_stack));
+ t -> filespec = lw_strdup(s);
+
+ t -> type = input_type_string;
+ t -> data = lw_strdup(str);
+ t -> data2 = 0;
+ t -> next = IS;
+ as -> input_data = t;
+ t -> filespec = lw_strdup(s);
+}
+
+void input_open(asmstate_t *as, char *s)
+{
+ struct input_stack *t;
+ char *s2;
+ char *p, *p2;
+
+ t = lw_alloc(sizeof(struct input_stack));
+ t -> filespec = lw_strdup(s);
+
+ for (s2 = s; *s2 && (*s2 != ':'); s2++)
+ /* do nothing */ ;
+ if (!*s2)
+ {
+ t -> type = input_type_file;
+ }
+ else
+ {
+ char *ts;
+
+ ts = lw_strndup(s, s2 - s);
+ s = s2 + 1;
+ if (!strcmp(ts, "include"))
+ t -> type = input_type_include;
+ else if (!strcmp(ts, "file"))
+ t -> type = input_type_file;
+ else
+ t -> type = input_type_error;
+
+ lw_free(ts);
+ }
+ t -> next = as -> input_data;
+ as -> input_data = t;
+
+ switch (IS -> type)
+ {
+ case input_type_include:
+ /* first check for absolute path and if so, skip path */
+ if (*s == '/')
+ {
+ /* absolute path */
+ IS -> data = fopen(s, "rb");
+ debug_message(as, 1, "Opening (abs) %s", s);
+ if (!IS -> data)
+ {
+ lw_error("Cannot open file '%s': %s", s, strerror(errno));
+ }
+ input_pushpath(as, s);
+ return;
+ }
+
+ /* relative path, check relative to "current file" directory */
+ p = lw_stack_top(as -> file_dir);
+ 0 == asprintf(&p2, "%s/%s", p, s);
+ debug_message(as, 1, "Open: (cd) %s\n", p2);
+ IS -> data = fopen(p2, "rb");
+ if (IS -> data)
+ {
+ input_pushpath(as, p2);
+ lw_free(p2);
+ return;
+ }
+ debug_message(as, 2, "Failed to open: (cd) %s (%s)\n", p2, strerror(errno));
+ lw_free(p2);
+
+ /* now check relative to entries in the search path */
+ lw_stringlist_reset(as -> include_list);
+ while (p = lw_stringlist_current(as -> include_list))
+ {
+ 0 == asprintf(&p2, "%s/%s", p, s);
+ debug_message(as, 1, "Open (sp): %s\n", p2);
+ IS -> data = fopen(p2, "rb");
+ if (IS -> data)
+ {
+ input_pushpath(as, p2);
+ lw_free(p2);
+ return;
+ }
+ debug_message(as, 2, "Failed to open: (sp) %s (%s)\n", p2, strerror(errno));
+ lw_free(p2);
+ lw_stringlist_next(as -> include_list);
+ }
+ lw_error("Cannot open include file '%s': %s", s, strerror(errno));
+ break;
+
+ case input_type_file:
+ debug_message(as, 1, "Opening (reg): %s\n", s);
+ IS -> data = fopen(s, "rb");
+
+ if (!IS -> data)
+ {
+ lw_error("Cannot open file '%s': %s", s, strerror(errno));
+ }
+ input_pushpath(as, s);
+ return;
+ }
+
+ lw_error("Cannot figure out how to open '%s'.", t -> filespec);
+}
+
+FILE *input_open_standalone(asmstate_t *as, char *s)
+{
+ char *s2;
+ FILE *fp;
+ char *p, *p2;
+
+ /* first check for absolute path and if so, skip path */
+ if (*s == '/')
+ {
+ /* absolute path */
+ debug_message(as, 2, "Open file (st abs) %s", s);
+ fp = fopen(s, "rb");
+ if (!fp)
+ {
+ return NULL;
+ }
+ return fp;
+ }
+
+ /* relative path, check relative to "current file" directory */
+ p = lw_stack_top(as -> file_dir);
+ 0 == asprintf(&p2, "%s/%s", p, s);
+ debug_message(as, 2, "Open file (st cd) %s", p2);
+ fp = fopen(p2, "rb");
+ if (fp)
+ {
+ lw_free(p2);
+ return fp;
+ }
+ lw_free(p2);
+
+ /* now check relative to entries in the search path */
+ lw_stringlist_reset(as -> include_list);
+ while (p = lw_stringlist_current(as -> include_list))
+ {
+ 0 == asprintf(&p2, "%s/%s", p, s);
+ debug_message(as, 2, "Open file (st ip) %s", p2);
+ fp = fopen(p2, "rb");
+ if (fp)
+ {
+ lw_free(p2);
+ return fp;
+ }
+ lw_free(p2);
+ lw_stringlist_next(as -> include_list);
+ }
+
+ return NULL;
+}
+
+char *input_readline(asmstate_t *as)
+{
+ char *s;
+ char linebuff[2049];
+ int lbloc;
+ int eol = 0;
+
+ /* if no file is open, open one */
+nextfile:
+ if (!IS) {
+ s = lw_stringlist_current(as -> input_files);
+ if (!s)
+ return NULL;
+ lw_stringlist_next(as -> input_files);
+ input_open(as, s);
+ }
+
+ switch (IS -> type)
+ {
+ case input_type_file:
+ case input_type_include:
+ /* read from a file */
+ lbloc = 0;
+ for (;;)
+ {
+ int c, c2;
+ c = fgetc(IS -> data);
+ if (c == EOF)
+ {
+ if (lbloc == 0)
+ {
+ struct input_stack *t;
+ fclose(IS -> data);
+ lw_free(lw_stack_pop(as -> file_dir));
+ lw_free(IS -> filespec);
+ t = IS -> next;
+ lw_free(IS);
+ as -> input_data = t;
+ goto nextfile;
+ }
+ linebuff[lbloc] = '\0';
+ eol = 1;
+ }
+ else if (c == '\r')
+ {
+ linebuff[lbloc] = '\0';
+ eol = 1;
+ c2 = fgetc(IS -> data);
+ if (c2 == EOF)
+ c = EOF;
+ else if (c2 != '\n')
+ ungetc(c2, IS -> data);
+ }
+ else if (c == '\n')
+ {
+ linebuff[lbloc] = '\0';
+ eol = 1;
+ c2 = fgetc(IS -> data);
+ if (c2 == EOF)
+ c = EOF;
+ else if (c2 != '\r')
+ ungetc(c2, IS -> data);
+ }
+ else
+ {
+ if (lbloc < 2048)
+ linebuff[lbloc++] = c;
+ }
+ if (eol)
+ {
+ s = lw_strdup(linebuff);
+ return s;
+ }
+ }
+
+ case input_type_string:
+ /* read from a string */
+ if (((char *)(IS -> data))[IS -> data2] == '\0')
+ {
+ struct input_stack *t;
+ lw_free(IS -> data);
+ lw_free(IS -> filespec);
+ t = IS -> next;
+ lw_free(IS);
+ as -> input_data = t;
+ goto nextfile;
+ }
+ s = (char *)(IS -> data);
+ lbloc = 0;
+ for (;;)
+ {
+ int c;
+ c = s[IS -> data2];
+ if (c)
+ IS -> data2++;
+ if (c == '\0')
+ {
+ linebuff[lbloc] = '\0';
+ eol = 1;
+ }
+ else if (c == '\r')
+ {
+ linebuff[lbloc] = '\0';
+ eol = 1;
+ if (s[IS -> data2] == '\n')
+ IS -> data2++;
+ }
+ else if (c == '\n')
+ {
+ linebuff[lbloc] = '\0';
+ eol = 1;
+ if (s[IS -> data2] == '\r')
+ IS -> data2++;
+ }
+ else
+ {
+ if (lbloc < 2048)
+ linebuff[lbloc++] = c;
+ }
+ if (eol)
+ {
+ s = lw_strdup(linebuff);
+ return s;
+ }
+ }
+
+ default:
+ lw_error("Problem reading from unknown input type");
+ }
+}
+
+char *input_curspec(asmstate_t *as)
+{
+ if (IS)
+ return IS -> filespec;
+ return NULL;
+}
diff -r 000000000000 -r 2c24602be78f lwasm/input.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwasm/input.h Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,34 @@
+/*
+input.h
+
+Copyright © 2010 William Astle
+
+This file is part of LWTOOLS.
+
+LWTOOLS 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 3 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, see .
+*/
+
+#ifndef ___input_h_seen___
+#define ___input_h_seen___
+
+#include "lwasm.h"
+
+extern void input_init(asmstate_t *as);
+extern void input_openstring(asmstate_t *as, char *s, char *str);
+extern void input_open(asmstate_t *as, char *s);
+extern char *input_readline(asmstate_t *as);
+extern char *input_curspec(asmstate_t *as);
+extern FILE *input_open_standalone(asmstate_t *as, char *s);
+
+#endif
diff -r 000000000000 -r 2c24602be78f lwasm/insn_bitbit.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwasm/insn_bitbit.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,146 @@
+/*
+insn_bitbit.c
+Copyright © 2009 William Astle
+
+This file is part of LWASM.
+
+LWASM 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 3 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, see .
+*/
+
+#include
+
+#include
+
+#include "lwasm.h"
+#include "instab.h"
+
+// these instructions cannot tolerate external references
+PARSEFUNC(insn_parse_bitbit)
+{
+ int r;
+ lw_expr_t e;
+ int v1;
+ int tv;
+
+ r = toupper(*(*p)++);
+ if (r == 'A')
+ r = 1;
+ else if (r == 'B')
+ r = 2;
+ else if (r == 'C' && toupper(**p) == 'C')
+ {
+ r = 0;
+ (*p)++;
+ }
+ else
+ {
+ lwasm_register_error(as, l, "Bad register");
+ return;
+ }
+
+ if (*(*p)++ != ',')
+ {
+ lwasm_register_error(as, l, "Bad operand");
+ return;
+ }
+ e = lwasm_parse_expr(as, p);
+ if (!e)
+ {
+ lwasm_register_error(as, l, "Bad operand");
+ return;
+ }
+ lwasm_save_expr(l, 0, e);
+ if (*(*p)++ != ',')
+ {
+ lwasm_register_error(as, l, "Bad operand");
+ return;
+ }
+
+ e = lwasm_parse_expr(as, p);
+ if (!e)
+ {
+ lwasm_register_error(as, l, "Bad operand");
+ return;
+ }
+ lwasm_save_expr(l, 1, e);
+
+ if (*(*p)++ != ',')
+ {
+ lwasm_register_error(as, l, "Bad operand");
+ return;
+ }
+
+ // ignore base page address modifier
+ if (**p == '<')
+ (*p)++;
+
+ e = lwasm_parse_expr(as, p);
+ if (!e)
+ {
+ lwasm_register_error(as, l, "Bad operand");
+ return;
+ }
+ lwasm_save_expr(l, 2, e);
+
+ l -> lint = r;
+ l -> len = OPLEN(instab[l -> insn].ops[0]) + 2;
+}
+
+EMITFUNC(insn_emit_bitbit)
+{
+ int v1, v2;
+ lw_expr_t e;
+
+ e = lwasm_fetch_expr(l, 0);
+ if (!lw_expr_istype(e, lw_expr_type_int))
+ {
+ lwasm_register_error(as, l, "Bit number must be fully resolved");
+ return;
+ }
+ v1 = lw_expr_intval(e);
+ if (v1 < 0 || v1 > 7)
+ {
+ lwasm_register_error(as, l, "Invalid bit number");
+ v1 = 0;
+ }
+
+ e = lwasm_fetch_expr(l, 1);
+ if (!lw_expr_istype(e, lw_expr_type_int))
+ {
+ lwasm_register_error(as, l, "Bit number must be fully resolved");
+ return;
+ }
+ v2 = lw_expr_intval(e);
+ if (v2 < 0 || v2 > 7)
+ {
+ lwasm_register_error(as, l, "Invalid bit number");
+ v2 = 0;
+ }
+ l -> pb = (l -> lint << 6) | (v1 << 3) | v2;
+
+ e = lwasm_fetch_expr(l, 2);
+ if (lw_expr_istype(e, lw_expr_type_int))
+ {
+ v1 = lw_expr_intval(e) & 0xFFFF;
+ v2 = v1 - ((l -> dpval) << 8);
+ if (v2 > 0xFF || v2 < 0)
+ {
+ lwasm_register_error(as, l, "Byte overflow");
+ return;
+ }
+ }
+ lwasm_emitop(l, instab[l -> insn].ops[0]);
+ lwasm_emit(l, l -> pb);
+ lwasm_emitexpr(l, e, 1);
+}
diff -r 000000000000 -r 2c24602be78f lwasm/insn_gen.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwasm/insn_gen.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,441 @@
+/*
+insn_gen.c, Copyright © 2009 William Astle
+
+This file is part of LWASM.
+
+LWASM 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 3 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, see .
+
+Contains code for parsing general addressing modes (IMM+DIR+EXT+IND)
+*/
+
+#include
+#include
+
+#include
+
+#include "lwasm.h"
+#include "instab.h"
+
+extern void insn_indexed_parse_aux(asmstate_t *as, line_t *l, char **p);
+extern void insn_indexed_resolve_aux(asmstate_t *as, line_t *l, int force, int elen);
+extern void insn_indexed_emit_aux(asmstate_t *as, line_t *l);
+
+// "extra" is required due to the way OIM, EIM, TIM, and AIM work
+void insn_parse_gen_aux(asmstate_t *as, line_t *l, char **p)
+{
+ const char *optr2;
+ int v1, tv, rval;
+ lw_expr_t s;
+
+ optr2 = *p;
+ while (*optr2 && !isspace(*optr2) && *optr2 != ',') optr2++
+ /* do nothing */ ;
+
+ if (*optr2 == ',' || **p == '[')
+ {
+ l -> lint = -1;
+ l -> lint2 = 1;
+ insn_parse_indexed_aux(as, l, p);
+ goto out;
+ }
+
+ if (**p == '<')
+ {
+ (*p)++;
+ l -> lint2 = 0;
+ }
+
+ // for compatibility with asxxxx
+ // * followed by a digit, alpha, or _, or ., or ?, or another * is "f8"
+ else if (**p == '*')
+ {
+ tv = *(*p + 1);
+ if (isdigit(tv) || isalpha(tv) || tv == '_' || tv == '.' || tv == '?' || tv == '@' || tv == '*' || tv == '+' || tv == '-')
+ {
+ l -> lint2 = 0;
+ (*p)++;
+ }
+ }
+ else if (**p == '>')
+ {
+ (*p)++;
+ l -> lint2 = 2;
+ }
+ else
+ {
+ l -> lint2 = -1;
+ }
+
+ s = lwasm_parse_expr(as, p);
+ if (!s)
+ {
+ lwasm_register_error(as, l, "Bad operand");
+ return;
+ }
+
+ lwasm_save_expr(l, 0, s);
+
+ if (as -> output_format == OUTPUT_OBJ && l -> lint2 == -1)
+ {
+ l -> lint2 = 2;
+ goto out;
+ }
+
+ if (l -> lint2 != -1)
+ goto out;
+
+ // if we have a constant now, figure out dp vs nondp
+ if (lw_expr_istype(s, lw_expr_type_int))
+ {
+ v1 = lw_expr_intval(s);
+ if (((v1 >> 8) & 0xff) == (l -> dpval & 0xff))
+ {
+ l -> lint2 = 0;
+ goto out;
+ }
+ l -> lint2 = 2;
+ }
+
+out:
+ if (l -> lint2 != -1)
+ {
+ if (l -> lint2 == 0)
+ {
+ l -> len = OPLEN(instab[l -> insn].ops[0]) + 1;
+ }
+ else if (l -> lint2 == 2)
+ {
+ l -> len = OPLEN(instab[l -> insn].ops[2]) + 2;
+ }
+ else if (l -> lint2 == 1 && l -> lint != -1)
+ {
+ l -> len = OPLEN(instab[l -> insn].ops[1]) + l -> lint + 1;
+ }
+ }
+}
+
+void insn_resolve_gen_aux(asmstate_t *as, line_t *l, int force, int elen)
+{
+ lw_expr_t e;
+
+ if (l -> lint2 == 1)
+ {
+ // indexed
+ insn_resolve_indexed_aux(as, l, force, elen);
+ goto out;
+ }
+
+ if (l -> lint2 != -1)
+ return;
+
+ e = lwasm_fetch_expr(l, 0);
+ if (lw_expr_istype(e, lw_expr_type_int))
+ {
+ int v;
+
+ v = lw_expr_intval(e);
+
+ if (((v >> 8) & 0xff) == (l -> dpval & 0xff))
+ {
+ l -> lint2 = 0;
+ goto out;
+ }
+ l -> lint2 = 2;
+ goto out;
+ }
+
+ if (force)
+ {
+ l -> lint2 = 2;
+ }
+
+out:
+ if (l -> lint2 != -1)
+ {
+ if (l -> lint2 == 0)
+ {
+ l -> len = OPLEN(instab[l -> insn].ops[0]) + 1;
+ }
+ else if (l -> lint2 == 2)
+ {
+ l -> len = OPLEN(instab[l -> insn].ops[2]) + 2;
+ }
+ else if (l -> lint2 == 1 && l -> lint != -1)
+ {
+ l -> len = OPLEN(instab[l -> insn].ops[1]) + l -> lint + 1;
+ }
+ }
+}
+
+void insn_emit_gen_aux(asmstate_t *as, line_t *l, int extra)
+{
+ lw_expr_t e;
+
+ e = lwasm_fetch_expr(l, 0);
+ lwasm_emitop(l, instab[l -> insn].ops[l -> lint2]);
+
+ if (extra != -1)
+ lwasm_emit(l, extra);
+
+ if (l -> lint2 == 1)
+ {
+ lwasm_emit(l, l -> pb);
+ if (l -> lint > 0)
+ lwasm_emitexpr(l, e, l -> lint);
+ return;
+ }
+
+ if (l -> lint2 == 2)
+ lwasm_emitexpr(l, e, 2);
+ else
+ lwasm_emitexpr(l, e, 1);
+}
+
+// the various insn_gen? functions have an immediate mode of ? bits
+PARSEFUNC(insn_parse_gen0)
+{
+ if (**p == '#')
+ {
+ lwasm_register_error(as, l, "Immediate mode not allowed");
+ return;
+ }
+
+ // handle non-immediate
+ insn_parse_gen_aux(as, l, p);
+}
+
+RESOLVEFUNC(insn_resolve_gen0)
+{
+ if (l -> len != -1)
+ return;
+
+ // handle non-immediate
+ insn_resolve_gen_aux(as, l, force, 0);
+}
+
+EMITFUNC(insn_emit_gen0)
+{
+ insn_emit_gen_aux(as, l, -1);
+}
+
+PARSEFUNC(insn_parse_gen8)
+{
+ if (**p == '#')
+ {
+ lw_expr_t e;
+
+ (*p)++;
+ e = lwasm_parse_expr(as, p);
+ if (!e)
+ {
+ lwasm_register_error(as, l, "Bad operand");
+ return;
+ }
+ l -> len = OPLEN(instab[l -> insn].ops[3]) + 1;
+ l -> lint2 = 3;
+ lwasm_save_expr(l, 0, e);
+ return;
+ }
+
+ // handle non-immediate
+ insn_parse_gen_aux(as, l, p);
+ if (l -> lint2 != -1)
+ {
+ if (l -> lint2 == 0)
+ {
+ l -> len = OPLEN(instab[l -> insn].ops[0]) + 1;
+ }
+ else if (l -> lint2 == 2)
+ {
+ l -> len = OPLEN(instab[l -> insn].ops[2]) + 2;
+ }
+ else if (l -> lint2 == 1 && l -> lint != -1)
+ {
+ l -> len = OPLEN(instab[l -> insn].ops[1]) + l -> lint + 1;
+ }
+ }
+}
+
+RESOLVEFUNC(insn_resolve_gen8)
+{
+ if (l -> len != -1)
+ return;
+
+ // handle non-immediate
+ insn_resolve_gen_aux(as, l, force, 0);
+}
+
+EMITFUNC(insn_emit_gen8)
+{
+ if (l -> lint2 == 3)
+ {
+ lw_expr_t e;
+ e = lwasm_fetch_expr(l, 0);
+ lwasm_emitop(l, instab[l -> insn].ops[3]);
+ lwasm_emitexpr(l, e, 1);
+ return;
+ }
+
+ insn_emit_gen_aux(as, l, -1);
+}
+
+PARSEFUNC(insn_parse_gen16)
+{
+ if (**p == '#')
+ {
+ lw_expr_t e;
+
+ (*p)++;
+ e = lwasm_parse_expr(as, p);
+ if (!e)
+ {
+ lwasm_register_error(as, l, "Bad operand");
+ return;
+ }
+ l -> len = OPLEN(instab[l -> insn].ops[3]) + 2;
+ l -> lint2 = 3;
+ lwasm_save_expr(l, 0, e);
+ return;
+ }
+
+ // handle non-immediate
+ insn_parse_gen_aux(as, l, p);
+ if (l -> lint2 != -1)
+ {
+ if (l -> lint2 == 0)
+ {
+ l -> len = OPLEN(instab[l -> insn].ops[0]) + 1;
+ }
+ else if (l -> lint2 == 2)
+ {
+ l -> len = OPLEN(instab[l -> insn].ops[2]) + 2;
+ }
+ else if (l -> lint2 == 1 && l -> lint != -1)
+ {
+ l -> len = OPLEN(instab[l -> insn].ops[1]) + l -> lint + 1;
+ }
+ }
+}
+
+RESOLVEFUNC(insn_resolve_gen16)
+{
+ if (l -> len != -1)
+ return;
+
+ // handle non-immediate
+ insn_resolve_gen_aux(as, l, force, 0);
+}
+
+EMITFUNC(insn_emit_gen16)
+{
+ if (l -> lint2 == 3)
+ {
+ lw_expr_t e;
+ e = lwasm_fetch_expr(l, 0);
+ lwasm_emitop(l, instab[l -> insn].ops[3]);
+ lwasm_emitexpr(l, e, 2);
+ return;
+ }
+
+ insn_emit_gen_aux(as, l, -1);
+}
+
+PARSEFUNC(insn_parse_gen32)
+{
+ if (**p == '#')
+ {
+ lw_expr_t e;
+
+ (*p)++;
+ e = lwasm_parse_expr(as, p);
+ if (!e)
+ {
+ lwasm_register_error(as, l, "Bad operand");
+ return;
+ }
+ l -> len = OPLEN(instab[l -> insn].ops[3]) + 4;
+ l -> lint2 = 3;
+ lwasm_save_expr(l, 0, e);
+ return;
+ }
+
+ // handle non-immediate
+ insn_parse_gen_aux(as, l, p);
+ if (l -> lint2 != -1)
+ {
+ if (l -> lint2 == 0)
+ {
+ l -> len = OPLEN(instab[l -> insn].ops[0]) + 1;
+ }
+ else if (l -> lint2 == 2)
+ {
+ l -> len = OPLEN(instab[l -> insn].ops[2]) + 2;
+ }
+ else if (l -> lint2 == 1 && l -> lint != -1)
+ {
+ l -> len = OPLEN(instab[l -> insn].ops[1]) + l -> lint + 1;
+ }
+ }
+}
+
+RESOLVEFUNC(insn_resolve_gen32)
+{
+ if (l -> len != -1)
+ return;
+
+ // handle non-immediate
+ insn_resolve_gen_aux(as, l, force, 0);
+}
+
+EMITFUNC(insn_emit_gen32)
+{
+ if (l -> lint2 == 3)
+ {
+ lw_expr_t e;
+ e = lwasm_fetch_expr(l, 0);
+ lwasm_emitop(l, instab[l -> insn].ops[3]);
+ lwasm_emitexpr(l, e, 4);
+ return;
+ }
+
+ insn_emit_gen_aux(as, l, -1);
+}
+
+PARSEFUNC(insn_parse_imm8)
+{
+ lw_expr_t e;
+
+ if (**p == '#')
+ {
+ (*p)++;
+
+ e = lwasm_parse_expr(as, p);
+ if (!e)
+ {
+ lwasm_register_error(as, l, "Bad operand");
+ return;
+ }
+ l -> len = OPLEN(instab[l -> insn].ops[0]) + 1;
+ lwasm_save_expr(l, 0, e);
+ }
+}
+
+EMITFUNC(insn_emit_imm8)
+{
+ lw_expr_t e;
+
+ lwasm_emitop(l, instab[l -> insn].ops[0]);
+ e = lwasm_fetch_expr(l, 0);
+ lwasm_emitexpr(l, e, 1);
+}
diff -r 000000000000 -r 2c24602be78f lwasm/insn_indexed.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwasm/insn_indexed.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,546 @@
+/*
+insn_indexed.c
+Copyright © 2009 William Astle
+
+This file is part of LWASM.
+
+LWASM 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 3 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, see .
+*/
+
+/*
+for handling indexed mode instructions
+*/
+
+#include
+#include
+
+#include
+
+#include "lwasm.h"
+#include "instab.h"
+
+/*
+l -> lint: size of operand (0, 1, 2, -1 if not determined)
+l -> pb: actual post byte (from "resolve" stage) or info passed
+ forward to the resolve stage (if l -> line is -1); 0x80 is indir
+ bits 0-2 are register number
+*/
+void insn_parse_indexed_aux(asmstate_t *as, line_t *l, char **p)
+{
+ struct opvals { char *opstr; int pb; };
+
+ static const char *regs = "X Y U S W PCRPC ";
+ static const struct opvals simpleindex[] =
+ {
+ {",x", 0x84}, {",y", 0xa4}, {",u", 0xc4}, {",s", 0xe4},
+ {",x+", 0x80}, {",y+", 0xa0}, {",u+", 0xc0}, {",s+", 0xe0},
+ {",x++", 0x81}, {",y++", 0xa1}, {",u++", 0xc1}, {",s++", 0xe1},
+ {",-x", 0x82}, {",-y", 0xa2}, {",-u", 0xc2}, {",-s", 0xe2},
+ {",--x", 0x83}, {",--y", 0xa3}, {",--u", 0xc3}, {",--s", 0xe3},
+ {"a,x", 0x86}, {"a,y", 0xa6}, {"a,u", 0xc6}, {"a,s", 0xe6},
+ {"b,x", 0x85}, {"b,y", 0xa5}, {"b,u", 0xc5}, {"b,s", 0xe5},
+ {"e,x", 0x87}, {"e,y", 0xa7}, {"e,u", 0xc7}, {"e,s", 0xe7},
+ {"f,x", 0x8a}, {"f,y", 0xaa}, {"f,u", 0xca}, {"f,s", 0xea},
+ {"d,x", 0x8b}, {"d,y", 0xab}, {"d,u", 0xcb}, {"d,s", 0xed},
+ {"w,x", 0x8e}, {"w,y", 0xae}, {"w,u", 0xce}, {"w,s", 0xee},
+ {",w", 0x8f}, {",w++", 0xcf}, {",--w", 0xef},
+
+ {"[,x]", 0x94}, {"[,y]", 0xb4}, {"[,u", 0xd4}, {"[,s]", 0xf4},
+ {"[,x++]", 0x91}, {"[,y++]", 0xb1}, {"[,u++]", 0xd1}, {"[,s++]", 0xf1},
+ {"[,--x]", 0x93}, {"[,--y]", 0xb3}, {"[,--u]", 0xd3}, {"[,--s]", 0xf3},
+ {"[a,x]", 0x96}, {"[a,y]", 0xb6}, {"[a,u]", 0xd6}, {"[a,s]", 0xf6},
+ {"[b,x]", 0x95}, {"[b,y]", 0xb5}, {"[b,u]", 0xd5}, {"[b,s]", 0xf5},
+ {"[e,x]", 0x97}, {"[e,y]", 0xb7}, {"[e,u]", 0xd7}, {"[e,s]", 0xf7},
+ {"[f,x]", 0x9a}, {"[f,y]", 0xba}, {"[f,u]", 0xda}, {"[f,s]", 0xfa},
+ {"[d,x]", 0x9b}, {"[d,y]", 0xbb}, {"[d,u]", 0xdb}, {"[d,s]", 0xfd},
+ {"[w,x]", 0x9e}, {"[w,y]", 0xbe}, {"[w,u]", 0xde}, {"[w,s]", 0xfe},
+ {"[,w]", 0x90}, {"[,w++]", 0xd0}, {"[,--w]", 0xf0},
+
+ { "", -1 }
+ };
+
+ static const char *regs9 = "X Y U S PCRPC ";
+ static const struct opvals simpleindex9[] =
+ {
+ {",x", 0x84}, {",y", 0xa4}, {",u", 0xc4}, {",s", 0xe4},
+ {",x+", 0x80}, {",y+", 0xa0}, {",u+", 0xc0}, {",s+", 0xe0},
+ {",x++", 0x81}, {",y++", 0xa1}, {",u++", 0xc1}, {",s++", 0xe1},
+ {",-x", 0x82}, {",-y", 0xa2}, {",-u", 0xc2}, {",-s", 0xe2},
+ {",--x", 0x83}, {",--y", 0xa3}, {",--u", 0xc3}, {",--s", 0xe3},
+ {"a,x", 0x86}, {"a,y", 0xa6}, {"a,u", 0xc6}, {"a,s", 0xe6},
+ {"b,x", 0x85}, {"b,y", 0xa5}, {"b,u", 0xc5}, {"b,s", 0xe5},
+ {"d,x", 0x8b}, {"d,y", 0xab}, {"d,u", 0xcb}, {"d,s", 0xed},
+
+ {"[,x]", 0x94}, {"[,y]", 0xb4}, {"[,u", 0xd4}, {"[,s]", 0xf4},
+ {"[,x++]", 0x91}, {"[,y++]", 0xb1}, {"[,u++]", 0xd1}, {"[,s++]", 0xf1},
+ {"[,--x]", 0x93}, {"[,--y]", 0xb3}, {"[,--u]", 0xd3}, {"[,--s]", 0xf3},
+ {"[a,x]", 0x96}, {"[a,y]", 0xb6}, {"[a,u]", 0xd6}, {"[a,s]", 0xf6},
+ {"[b,x]", 0x95}, {"[b,y]", 0xb5}, {"[b,u]", 0xd5}, {"[b,s]", 0xf5},
+ {"[d,x]", 0x9b}, {"[d,y]", 0xbb}, {"[d,u]", 0xdb}, {"[d,s]", 0xfd},
+
+ { "", -1 }
+ };
+ char stbuf[25];
+ int i, j, rn;
+ int indir = 0;
+ int f0 = 1;
+ const struct opvals *simples;
+ const char *reglist;
+ lw_expr_t e;
+
+ if (as -> target == TARGET_6809)
+ {
+ simples = simpleindex9;
+ reglist = regs9;
+ }
+ else
+ {
+ simples = simpleindex;
+ reglist = regs;
+ }
+
+ // fetch out operand for lookup
+ for (i = 0; i < 24; i++)
+ {
+ if (*((*p) + i) && !isspace(*((*p) + i)))
+ stbuf[i] = *((*p) + i);
+ else
+ break;
+ }
+ stbuf[i] = '\0';
+
+ // now look up operand in "simple" table
+ if (!*((*p) + i) || isspace(*((*p) + i)))
+ {
+ // do simple lookup
+ for (j = 0; simples[j].opstr[0]; j++)
+ {
+ if (!strcasecmp(stbuf, simples[j].opstr))
+ break;
+ }
+ if (simples[j].opstr[0])
+ {
+ l -> pb = simples[j].pb;
+ l -> lint = 0;
+ (*p) += i;
+ return;
+ }
+ }
+
+ // now do the "hard" ones
+
+ // is it indirect?
+ if (**p == '[')
+ {
+ indir = 1;
+ (*p)++;
+ }
+
+ // look for a "," - all indexed modes have a "," except extended indir
+ rn = 0;
+ for (i = 0; (*p)[i] && !isspace((*p)[i]); i++)
+ {
+ if ((*p)[i] == ',')
+ {
+ rn = 1;
+ break;
+ }
+ }
+
+ // if no "," and indirect, do extended indir
+ if (!rn && indir)
+ {
+ // extended indir
+ l -> pb = 0x9f;
+ e = lwasm_parse_expr(as, p);
+ if (!e || **p != ']')
+ {
+ lwasm_register_error(as, l, "Bad operand");
+ return;
+ }
+ lwasm_save_expr(l, 0, e);
+
+ (*p)++;
+ l -> lint = 2;
+ return;
+ }
+
+ if (**p == '<')
+ {
+ l -> lint = 1;
+ (*p)++;
+ }
+ else if (**p == '>')
+ {
+ l -> lint = 2;
+ (*p)++;
+ }
+
+ if (**p == '0' && *(*p+1) == ',')
+ {
+ f0 = 1;
+ }
+
+ // now we have to evaluate the expression
+ e = lwasm_parse_expr(as, p);
+ if (!e)
+ {
+ lwasm_register_error(as, l, "Bad operand");
+ return;
+ }
+ lwasm_save_expr(l, 0, e);
+
+ // now look for a comma; if not present, explode
+ if (*(*p)++ != ',')
+ {
+ lwasm_register_error(as, l, "Bad operand");
+ return;
+ }
+
+ // now get the register
+ rn = lwasm_lookupreg3(reglist, p);
+ if (rn < 0)
+ {
+ lwasm_register_error(as, l, "Bad register");
+ return;
+ }
+
+ if (indir)
+ {
+ if (**p != ']')
+ {
+ lwasm_register_error(as, l, "Bad operand");
+ return;
+ }
+ else
+ (*p)++;
+ }
+
+ // nnnn,W is only 16 bit (or 0 bit)
+ if (rn == 4)
+ {
+ if (l -> lint == 1)
+ {
+ lwasm_register_error(as, l, "n,W cannot be 8 bit");
+ return;
+ }
+
+ if (l -> lint == 2)
+ {
+ l -> pb = indir ? 0xb0 : 0xcf;
+ l -> lint = 2;
+ return;
+ }
+
+ l -> pb = (0x80 * indir) | rn;
+
+/* [,w] and ,w
+ if (indir)
+ *b1 = 0x90;
+ else
+ *b1 = 0x8f;
+*/
+ return;
+ }
+
+ // PCR? then we have PC relative addressing (like B??, LB??)
+ if (rn == 5 || (rn == 6 && CURPRAGMA(l, PRAGMA_PCASPCR)))
+ {
+ lw_expr_t e1, e2;
+ // external references are handled exactly the same as for
+ // relative addressing modes
+ // on pass 1, adjust the expression for a subtraction of the
+ // current address
+ // e - (addr + linelen) => e - addr - linelen
+
+ e2 = lw_expr_build(lw_expr_type_special, lwasm_expr_linelen, l);
+ e1 = lw_expr_build(lw_expr_type_oper, lw_expr_oper_minus, e, e2);
+ lw_expr_destroy(e2);
+ e2 = lw_expr_build(lw_expr_type_oper, lw_expr_oper_minus, e1, l -> addr);
+ lw_expr_destroy(e1);
+ lwasm_save_expr(l, 0, e2);
+ if (l -> lint == 1)
+ {
+ l -> pb = indir ? 0x9C : 0x8C;
+ return;
+ }
+ if (l -> lint == 2)
+ {
+ l -> pb = indir ? 0x9D : 0x8D;
+ return;
+ }
+ }
+
+ if (rn == 6)
+ {
+ if (l -> lint == 1)
+ {
+ l -> pb = indir ? 0x9C : 0x8C;
+ return;
+ }
+ if (l -> lint == 2)
+ {
+ l -> pb = indir ? 0x9D : 0x8D;
+ return;
+ }
+ }
+
+ l -> pb = (indir * 0x80) | rn | (f0 * 0x40);
+}
+
+PARSEFUNC(insn_parse_indexed)
+{
+ l -> lint = -1;
+ insn_parse_indexed_aux(as, l, p);
+
+ if (l -> lint != -1)
+ {
+ l -> len = OPLEN(instab[l -> insn].ops[0]) + l -> lint + 1;
+ }
+}
+
+void insn_resolve_indexed_aux(asmstate_t *as, line_t *l, int force, int elen)
+{
+ // here, we have an expression which needs to be
+ // resolved; the post byte is determined here as well
+ lw_expr_t e, e2, e3;
+ int pb = -1;
+ int v;
+
+ if (l -> len != -1)
+ return;
+
+ e = lwasm_fetch_expr(l, 0);
+ if (!lw_expr_istype(e, lw_expr_type_int))
+ {
+ // temporarily set the instruction length to see if we get a
+ // constant for our expression; if so, we can select an instruction
+ // size
+ e2 = lw_expr_copy(e);
+ // magic 2 for 8 bit (post byte + offset)
+ l -> len = OPLEN(instab[l -> insn].ops[0]) + elen + 2;
+ lwasm_reduce_expr(as, e2);
+// l -> len += 1;
+// e3 = lw_expr_copy(e);
+// lwasm_reduce_expr(as, e3);
+ l -> len = -1;
+ if (lw_expr_istype(e2, lw_expr_type_int))
+ {
+ v = lw_expr_intval(e2);
+ // we have a reducible expression here which depends on
+ // the size of this instruction
+ if (v < -128 || v > 127)
+ {
+ l -> lint = 2;
+ switch (l -> pb & 0x07)
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ pb = 0x89 | ((l -> pb & 0x03) << 5) | (0x10 * (l -> pb & 0x80));
+ break;
+
+ case 4: // W
+ pb = (l -> pb & 0x80) ? 0xD0 : 0xCF;
+ break;
+
+ case 5: // PCR
+ case 6: // PC
+ pb = (l -> pb & 0x80) ? 0x9D : 0x8D;
+ break;
+ }
+
+ l -> pb = pb;
+ lw_expr_destroy(e2);
+// lw_expr_destroy(e3);
+ return;
+ }
+ else if ((l -> pb & 0x80) || ((l -> pb & 0x07) > 3) || v < -16 || v > 15)
+ {
+ // if not a 5 bit value, is indirect, or is not X,Y,U,S
+ l -> lint = 1;
+ switch (l -> pb & 0x07)
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ pb = 0x88 | ((l -> pb & 0x03) << 5) | (0x10 * (l -> pb & 0x80));
+ break;
+
+ case 4: // W
+ // use 16 bit because W doesn't have 8 bit, unless 0
+ if (v == 0 && !(CURPRAGMA(l, PRAGMA_NOINDEX0TONONE) || l -> pb & 0x40))
+ {
+ pb = (l -> pb & 0x80) ? 0x90 : 0x8F;
+ l -> lint = 0;
+ }
+ else
+ {
+ pb = (l -> pb & 0x80) ? 0xD0 : 0xCF;
+ l -> lint = 2;
+ }
+ break;
+
+ case 5: // PCR
+ case 6: // PC
+ pb = (l -> pb & 0x80) ? 0x9C : 0x8C;
+ break;
+ }
+
+ l -> pb = pb;
+ return;
+ }
+ else
+ {
+ // we have X,Y,U,S and a possible 16 bit here
+ l -> lint = 0;
+
+ if (v == 0 && !(CURPRAGMA(l, PRAGMA_NOINDEX0TONONE) || l -> pb & 0x40))
+ {
+ pb = (l -> pb & 0x03) << 5 | 0x84;
+ }
+ else
+ {
+ pb = (l -> pb & 0x03) << 5 | v & 0x1F;
+ }
+ l -> pb = pb;
+ return;
+ }
+ }
+ }
+
+ if (lw_expr_istype(e, lw_expr_type_int))
+ {
+ // we know how big it is
+ v = lw_expr_intval(e);
+ if (v < -128 || v > 127)
+ {
+ do16bit:
+ l -> lint = 2;
+ switch (l -> pb & 0x07)
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ pb = 0x89 | (l -> pb & 0x03) << 5 | (0x10 * (l -> pb & 0x80));
+ break;
+
+ case 4: // W
+ pb = (l -> pb & 0x80) ? 0xD0 : 0xCF;
+ break;
+
+ case 5: // PCR
+ case 6: // PC
+ pb = (l -> pb & 0x80) ? 0x9D : 0x8D;
+ break;
+ }
+
+ l -> pb = pb;
+ return;
+ }
+ else if ((l -> pb & 0x80) || ((l -> pb & 0x07) > 3) || v < -16 || v > 15)
+ {
+ // if not a 5 bit value, is indirect, or is not X,Y,U,S
+ l -> lint = 1;
+ switch (l -> pb & 0x07)
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ pb = 0x88 | (l -> pb & 0x03) << 5 | (0x10 * (l -> pb & 0x80));
+ break;
+
+ case 4: // W
+ // use 16 bit because W doesn't have 8 bit, unless 0
+ if (v == 0 && !(CURPRAGMA(l, PRAGMA_NOINDEX0TONONE) || l -> pb & 0x40))
+ {
+ pb = (l -> pb & 0x80) ? 0x90 : 0x8F;
+ l -> lint = 0;
+ }
+ else
+ {
+ pb = (l -> pb & 0x80) ? 0xD0 : 0xCF;
+ l -> lint = 2;
+ }
+ break;
+
+ case 5: // PCR
+ case 6: // PC
+ pb = (l -> pb & 0x80) ? 0x9C : 0x8C;
+ break;
+ }
+
+ l -> pb = pb;
+ return;
+ }
+ else
+ {
+ // we have X,Y,U,S and a possible 16 bit here
+ l -> lint = 0;
+
+ if (v == 0 && !(CURPRAGMA(l, PRAGMA_NOINDEX0TONONE) || l -> pb & 0x40))
+ {
+ pb = (l -> pb & 0x03) << 5 | 0x84;
+ }
+ else
+ {
+ pb = (l -> pb & 0x03) << 5 | v & 0x1F;
+ }
+ l -> pb = pb;
+ return;
+ }
+ }
+ else
+ {
+ // we don't know how big it is
+ if (!force)
+ return;
+ // force 16 bit if we don't know
+ l -> lint = 2;
+ goto do16bit;
+ }
+}
+
+RESOLVEFUNC(insn_resolve_indexed)
+{
+ if (l -> lint == -1)
+ insn_resolve_indexed_aux(as, l, force, 0);
+
+ if (l -> lint != -1 && l -> pb != -1)
+ {
+ l -> len = OPLEN(instab[l -> insn].ops[0]) + l -> lint + 1;
+ }
+}
+
+void insn_emit_indexed_aux(asmstate_t *as, line_t *l)
+{
+ lw_expr_t e;
+
+ lwasm_emitop(l, instab[l -> insn].ops[0]);
+ lwasm_emitop(l, l -> pb);
+ if (l -> lint > 0)
+ {
+ e = lwasm_fetch_expr(l, 0);
+ lwasm_emitexpr(l, e, l -> lint);
+ }
+}
+
+EMITFUNC(insn_emit_indexed)
+{
+ insn_emit_indexed_aux(as, l);
+}
diff -r 000000000000 -r 2c24602be78f lwasm/insn_inh.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwasm/insn_inh.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,34 @@
+/*
+insn_inh.c
+Copyright © 2010 William Astle
+
+This file is part of LWASM.
+
+LWASM 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 3 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, see .
+
+*/
+
+#include "lwasm.h"
+#include "instab.h"
+
+PARSEFUNC(insn_parse_inh)
+{
+ l -> len = OPLEN(instab[l -> insn].ops[0]);
+ skip_operand(p);
+}
+
+EMITFUNC(insn_emit_inh)
+{
+ lwasm_emitop(l, instab[l -> insn].ops[0]);
+}
diff -r 000000000000 -r 2c24602be78f lwasm/insn_logicmem.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwasm/insn_logicmem.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,93 @@
+/*
+insn_logicmem.c
+Copyright © 2009 William Astle
+
+This file is part of LWASM.
+
+LWASM 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 3 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, see .
+
+Contains code for handling logic/mem instructions
+*/
+
+#include
+#include
+#include
+
+#include
+
+#include "lwasm.h"
+#include "instab.h"
+
+extern void insn_parse_gen_aux(asmstate_t *as, line_t *l, char **optr);
+extern void insn_resolve_gen_aux(asmstate_t *as, line_t *l, int force, int elen);
+extern void insn_emit_gen_aux(asmstate_t *as, line_t *l, int extra);
+
+// for aim, oim, eim, tim
+PARSEFUNC(insn_parse_logicmem)
+{
+ const char *p2;
+ lw_expr_t s;
+
+ if (**p == '#')
+ (*p)++;
+
+ s = lwasm_parse_expr(as, p);
+ if (!s)
+ {
+ lwasm_register_error(as, l, "Bad operand");
+ return;
+ }
+
+ lwasm_save_expr(l, 100, s);
+ if (**p != ',' && **p != ';')
+ {
+ lwasm_register_error(as, l, "Bad operand");
+ return;
+ }
+
+ (*p)++;
+
+ // now we have a general addressing mode - call for it
+ insn_parse_gen_aux(as, l, p);
+}
+
+RESOLVEFUNC(insn_resolve_logicmem)
+{
+ if (l -> len != -1)
+ return;
+
+ insn_resolve_gen_aux(as, l, force, 1);
+}
+
+EMITFUNC(insn_emit_logicmem)
+{
+ lw_expr_t e;
+ int v;
+
+ e = lwasm_fetch_expr(l, 100);
+ if (!lw_expr_istype(e, lw_expr_type_int))
+ {
+ lwasm_register_error(as, l, "Immediate byte must be fully resolved");
+ return;
+ }
+
+ v = lw_expr_intval(e);
+ if (v < -128 || v > 255)
+ {
+ lwasm_register_error(as, l, "Byte overflow");
+ return;
+ }
+
+ insn_emit_gen_aux(as, l, v);
+}
diff -r 000000000000 -r 2c24602be78f lwasm/insn_rel.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwasm/insn_rel.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,116 @@
+/*
+insn_rel.c
+Copyright © 2009 William Astle
+
+This file is part of LWASM.
+
+LWASM 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 3 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, see .
+*/
+
+/*
+for handling relative mode instructions
+*/
+
+#include
+
+#include
+
+#include "lwasm.h"
+#include "instab.h"
+
+PARSEFUNC(insn_parse_rel8)
+{
+ int v;
+ lw_expr_t t, e1, e2;
+ int r;
+
+ // sometimes there is a "#", ignore if there
+ if (**p == '#')
+ (*p)++;
+
+ t = lwasm_parse_expr(as, p);
+ if (!t)
+ {
+ lwasm_register_error(as, l, "Bad operand");
+ return;
+ }
+ l -> len = OPLEN(instab[l -> insn].ops[0]) + 1;
+
+ e1 = lw_expr_build(lw_expr_type_special, lwasm_expr_linelen, l);
+ e2 = lw_expr_build(lw_expr_type_oper, lw_expr_oper_plus, e1, l -> addr);
+ lw_expr_destroy(e1);
+ e1 = lw_expr_build(lw_expr_type_oper, lw_expr_oper_minus, t, e2);
+ lw_expr_destroy(e2);
+ lwasm_save_expr(l, 0, e1);
+}
+
+EMITFUNC(insn_emit_rel8)
+{
+ lw_expr_t e;
+ int offs;
+
+ e = lwasm_fetch_expr(l, 0);
+ if (!lw_expr_istype(e, lw_expr_type_int))
+ {
+ lwasm_register_error(as, l, "Illegal non-constant expression");
+ return;
+ }
+
+ offs = lw_expr_intval(e);
+ if (offs < -128 || offs > 127)
+ {
+ lwasm_register_error(as, l, "Byte overflow");
+ return;
+ }
+
+ lwasm_emitop(l, instab[l -> insn].ops[0]);
+ lwasm_emit(l, offs);
+}
+
+PARSEFUNC(insn_parse_rel16)
+{
+ int v;
+ lw_expr_t t, e1, e2;
+ int r;
+
+ // sometimes there is a "#", ignore if there
+ if (**p == '#')
+ (*p)++;
+
+ t = lwasm_parse_expr(as, p);
+ if (!t)
+ {
+ lwasm_register_error(as, l, "Bad operand");
+ return;
+ }
+ l -> len = OPLEN(instab[l -> insn].ops[0]) + 2;
+
+ e1 = lw_expr_build(lw_expr_type_special, lwasm_expr_linelen, l);
+ e2 = lw_expr_build(lw_expr_type_oper, lw_expr_oper_plus, e1, l -> addr);
+ lw_expr_destroy(e1);
+ e1 = lw_expr_build(lw_expr_type_oper, lw_expr_oper_minus, t, e2);
+ lw_expr_destroy(e2);
+ lwasm_save_expr(l, 0, e1);
+}
+
+EMITFUNC(insn_emit_rel16)
+{
+ lw_expr_t e;
+ int offs;
+
+ e = lwasm_fetch_expr(l, 0);
+
+ lwasm_emitop(l, instab[l -> insn].ops[0]);
+ lwasm_emitexpr(l, e, 2);
+}
diff -r 000000000000 -r 2c24602be78f lwasm/insn_rlist.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwasm/insn_rlist.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,64 @@
+/*
+insn_rlist.c
+Copyright © 2009 William Astle
+
+This file is part of LWASM.
+
+LWASM 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 3 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, see .
+*/
+
+/*
+for handling inherent mode instructions
+*/
+
+#include "lwasm.h"
+#include "instab.h"
+
+PARSEFUNC(insn_parse_rlist)
+{
+ int rb = 0;
+ int rn;
+ static const char *regs = "CCA B DPX Y U PCD S ";
+
+ while (**p && !isspace(**p))
+ {
+ rn = lwasm_lookupreg2(regs, p);
+ if (rn < 0)
+ {
+ lwasm_register_error(as, l, "Bad register '%s'", *p);
+ return;
+ }
+ if (**p && **p != ',' && !isspace(**p))
+ {
+ lwasm_register_error(as, l, "Bad operand");
+ }
+ if (**p == ',')
+ (*p)++;
+ if (rn == 8)
+ rn = 6;
+ else if (rn == 9)
+ rn = 0x40;
+ else
+ rn = 1 << rn;
+ rb |= rn;
+ }
+ l -> len = OPLEN(instab[l -> insn].ops[0]) + 1;
+ l -> pb = rb;
+}
+
+EMITFUNC(insn_emit_rlist)
+{
+ lwasm_emitop(l, instab[l -> insn].ops[0]);
+ lwasm_emit(l, l -> pb);
+}
diff -r 000000000000 -r 2c24602be78f lwasm/insn_rtor.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwasm/insn_rtor.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,60 @@
+/*
+insn_rtor.c
+Copyright © 2010 William Astle
+
+This file is part of LWASM.
+
+LWASM 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 3 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, see .
+
+*/
+
+#include "lwasm.h"
+#include "instab.h"
+
+PARSEFUNC(insn_parse_rtor)
+{
+ int r0, r1;
+
+ static const char *regs = "D X Y U S PCW V A B CCDP0 0 E F ";
+ static const char *regs9 = "D X Y U S PC A B CCDP ";
+
+ // register to register (r0,r1)
+ // registers are in order:
+ // D,X,Y,U,S,PC,W,V
+ // A,B,CC,DP,0,0,E,F
+
+ r0 = lwasm_lookupreg2((as -> target == TARGET_6309) ? regs9 : regs, p);
+ if (r0 < 0 || *(*p)++ != ',')
+ {
+ lwasm_register_error(as, l, "Bad operand");
+ r0 = r1 = 0;
+ }
+ else
+ {
+ r1 = lwasm_lookupreg2((as -> target = TARGET_6309) ? regs9 : regs, p);
+ if (r1 < 0)
+ {
+ lwasm_register_error(as, l, "Bad operand");
+ r0 = r1 = 0;
+ }
+ }
+ l -> pb = (r0 << 4) | r1;
+ l -> len = OPLEN(instab[l -> insn].ops[0]) + 1;
+}
+
+EMITFUNC(insn_emit_rtor)
+{
+ lwasm_emitop(l, instab[l -> insn].ops[0]);
+ lwasm_emit(l, l -> pb);
+}
diff -r 000000000000 -r 2c24602be78f lwasm/insn_tfm.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwasm/insn_tfm.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,150 @@
+/*
+insn_tfm.c
+Copyright © 2009 William Astle
+
+This file is part of LWASM.
+
+LWASM 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 3 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, see .
+*/
+
+#include
+#include
+
+#include "lwasm.h"
+#include "instab.h"
+
+PARSEFUNC(insn_parse_tfm)
+{
+ static const char *reglist = "DXYUS AB 00EF";
+ int r0, r1;
+ char *c;
+ int tfm = 0;
+
+ c = strchr(reglist, toupper(*(*p)++));
+ if (!c)
+ {
+ lwasm_register_error(as, l, "Unknown operation");
+ return;
+ }
+ r0 = c - reglist;
+ if (**p == '+')
+ {
+ (*p)++;
+ tfm = 1;
+ }
+ else if (**p == '-')
+ {
+ (*p)++;
+ tfm = 2;
+ }
+ if (*(*p)++ != ',')
+ {
+ lwasm_register_error(as, l, "Unknown operation");
+ return;
+ }
+ c = strchr(reglist, toupper(*(*p)++));
+ if (!c)
+ {
+ lwasm_register_error(as, l, "Unknown operation");
+ return;
+ }
+ r1 = c - reglist;
+
+ if (**p == '+')
+ {
+ (*p)++;
+ tfm |= 4;
+ }
+ else if (**p == '-')
+ {
+ (*p)++;
+ tfm |= 8;
+ }
+
+ if (**p && !isspace(**p))
+ {
+ lwasm_register_error(as, l, "Bad operand");
+ return;
+ }
+
+ // valid values of tfm here are:
+ // 1: r0+,r1 (2)
+ // 4: r0,r1+ (3)
+ // 5: r0+,r1+ (0)
+ // 10: r0-,r1- (1)
+ switch (tfm)
+ {
+ case 5: //r0+,r1+
+ l -> lint = instab[l -> insn].ops[0];
+ break;
+
+ case 10: //r0-,r1-
+ l -> lint = instab[l -> insn].ops[1];
+ break;
+
+ case 1: // r0+,r1
+ l -> lint = instab[l -> insn].ops[2];
+ break;
+
+ case 4: // r0,r1+
+ l -> lint = instab[l -> insn].ops[3];
+ break;
+
+ default:
+ lwasm_register_error(as, l, "Unknown operation");
+ return;
+ }
+ l -> pb = (r0 << 4) | r1;
+ l -> len = OPLEN(l -> lint);
+}
+
+EMITFUNC(insn_emit_tfm)
+{
+ lwasm_emitop(l, l -> lint);
+ lwasm_emit(l, l -> pb);
+}
+
+PARSEFUNC(insn_parse_tfmrtor)
+{
+ int r0, r1;
+ static const char *regs = "D X Y U S A B 0 0 E F ";
+
+ // register to register (r0,r1)
+ // registers are in order:
+ // D,X,Y,U,S,PC,W,V
+ // A,B,CC,DP,0,0,E,F
+ r0 = lwasm_lookupreg2(regs, p);
+ if (r0 < 0 || *(*p)++ != ',')
+ {
+ lwasm_register_error(as, l, "Bad operand");
+ r0 = r1 = 0;
+ }
+ else
+ {
+ r1 = lwasm_lookupreg2(regs, p);
+ if (r1 < 0)
+ {
+ lwasm_register_error(as, l, "Bad operand");
+ r0 = r1 = 0;
+ }
+ }
+ l -> len = instab[l -> insn].ops[0] + 1;
+ l -> pb = (r0 << 4) | r1;
+}
+
+EMITFUNC(insn_emit_tfmrtor)
+{
+ lwasm_emitop(l, instab[l -> insn].ops[0]);
+ lwasm_emit(l, l -> pb);
+}
diff -r 000000000000 -r 2c24602be78f lwasm/instab.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwasm/instab.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,677 @@
+/*
+instab.c
+Copyright © 2008 William Astle
+
+This file is part of LWASM.
+
+LWASM 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 3 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, see .
+
+
+Contains the instruction table for assembling code
+*/
+#include
+#define __instab_c_seen__
+#include "instab.h"
+
+// inherent
+extern PARSEFUNC(insn_parse_inh);
+#define insn_resolve_inh NULL
+extern EMITFUNC(insn_emit_inh);
+
+// register to register
+extern PARSEFUNC(insn_parse_rtor);
+#define insn_resolve_rtor NULL
+extern EMITFUNC(insn_emit_rtor);
+
+// TFM and variants
+extern PARSEFUNC(insn_parse_tfmrtor);
+#define insn_resolve_tfmrtor NULL
+extern EMITFUNC(insn_emit_tfmrtor);
+extern PARSEFUNC(insn_parse_tfm);
+#define insn_resolve_tfm NULL
+extern EMITFUNC(insn_emit_tfm);
+
+// register list
+extern PARSEFUNC(insn_parse_rlist);
+#define insn_resolve_rlist NULL
+extern EMITFUNC(insn_emit_rlist);
+
+// indexed
+extern PARSEFUNC(insn_parse_indexed);
+extern RESOLVEFUNC(insn_resolve_indexed);
+extern EMITFUNC(insn_emit_indexed);
+
+// generic 32 bit immediate
+extern PARSEFUNC(insn_parse_gen32);
+extern RESOLVEFUNC(insn_resolve_gen32);
+extern EMITFUNC(insn_emit_gen32);
+
+// generic 16 bit immediate
+extern PARSEFUNC(insn_parse_gen16);
+extern RESOLVEFUNC(insn_resolve_gen16);
+extern EMITFUNC(insn_emit_gen16);
+
+// generic 8 bit immediate
+extern PARSEFUNC(insn_parse_gen8);
+extern RESOLVEFUNC(insn_resolve_gen8);
+extern EMITFUNC(insn_emit_gen8);
+
+// generic no immediate
+extern PARSEFUNC(insn_parse_gen0);
+extern RESOLVEFUNC(insn_resolve_gen0);
+extern EMITFUNC(insn_emit_gen0);
+
+// logic memory
+extern PARSEFUNC(insn_parse_logicmem);
+extern RESOLVEFUNC(insn_resolve_logicmem);
+extern EMITFUNC(insn_emit_logicmem);
+
+// 8 bit immediate only
+extern PARSEFUNC(insn_parse_imm8);
+#define insn_resolve_imm8 NULL
+extern EMITFUNC(insn_emit_imm8);
+
+// bit to bit ops
+extern PARSEFUNC(insn_parse_bitbit);
+#define insn_resolve_bitbit NULL
+extern EMITFUNC(insn_emit_bitbit);
+
+// 8 bit relative
+extern PARSEFUNC(insn_parse_rel8);
+#define insn_resolve_rel8 NULL
+extern EMITFUNC(insn_emit_rel8);
+
+// 16 bit relative
+extern PARSEFUNC(insn_parse_rel16);
+#define insn_resolve_rel16 NULL
+extern EMITFUNC(insn_emit_rel16);
+
+// MACRO pseudo op
+extern PARSEFUNC(pseudo_parse_macro);
+#define pseudo_resolve_macro NULL
+#define pseudo_emit_macro NULL
+
+// ENDM pseudo op
+extern PARSEFUNC(pseudo_parse_endm);
+#define pseudo_resolve_endm NULL
+#define pseudo_emit_endm NULL
+
+#define pseudo_parse_noop NULL
+#define pseudo_resolve_noop NULL
+#define pseudo_emit_noop NULL
+
+extern PARSEFUNC(pseudo_parse_end);
+#define pseudo_resolve_end NULL
+extern EMITFUNC(pseudo_emit_end);
+
+extern PARSEFUNC(pseudo_parse_fcb);
+#define pseudo_resolve_fcb NULL
+extern EMITFUNC(pseudo_emit_fcb);
+
+extern PARSEFUNC(pseudo_parse_fdb);
+#define pseudo_resolve_fdb NULL
+extern EMITFUNC(pseudo_emit_fdb);
+
+extern PARSEFUNC(pseudo_parse_fqb);
+#define pseudo_resolve_fqb NULL
+extern EMITFUNC(pseudo_emit_fqb);
+
+extern PARSEFUNC(pseudo_parse_fcc);
+#define pseudo_resolve_fcc NULL
+extern EMITFUNC(pseudo_emit_fcc);
+
+extern PARSEFUNC(pseudo_parse_fcs);
+#define pseudo_resolve_fcs NULL
+extern EMITFUNC(pseudo_emit_fcs);
+
+extern PARSEFUNC(pseudo_parse_fcn);
+#define pseudo_resolve_fcn NULL
+extern EMITFUNC(pseudo_emit_fcn);
+
+extern PARSEFUNC(pseudo_parse_rmb);
+extern RESOLVEFUNC(pseudo_resolve_rmb);
+extern EMITFUNC(pseudo_emit_rmb);
+
+extern PARSEFUNC(pseudo_parse_rmd);
+extern RESOLVEFUNC(pseudo_resolve_rmd);
+extern EMITFUNC(pseudo_emit_rmd);
+
+extern PARSEFUNC(pseudo_parse_rmq);
+extern RESOLVEFUNC(pseudo_resolve_rmq);
+extern EMITFUNC(pseudo_emit_rmq);
+
+extern PARSEFUNC(pseudo_parse_zmb);
+extern RESOLVEFUNC(pseudo_resolve_zmb);
+extern EMITFUNC(pseudo_emit_zmb);
+
+extern PARSEFUNC(pseudo_parse_zmd);
+extern RESOLVEFUNC(pseudo_resolve_zmd);
+extern EMITFUNC(pseudo_emit_zmd);
+
+extern PARSEFUNC(pseudo_parse_zmq);
+extern RESOLVEFUNC(pseudo_resolve_zmq);
+extern EMITFUNC(pseudo_emit_zmq);
+
+extern PARSEFUNC(pseudo_parse_org);
+#define pseudo_resolve_org NULL
+#define pseudo_emit_org NULL
+
+extern PARSEFUNC(pseudo_parse_equ);
+#define pseudo_resolve_equ NULL
+#define pseudo_emit_equ NULL
+
+extern PARSEFUNC(pseudo_parse_set);
+#define pseudo_resolve_set NULL
+#define pseudo_emit_set NULL
+
+extern PARSEFUNC(pseudo_parse_setdp);
+#define pseudo_resolve_setdp NULL
+#define pseudo_emit_setdp NULL
+
+extern PARSEFUNC(pseudo_parse_ifp1);
+#define pseudo_resolve_ifp1 NULL
+#define pseudo_emit_ifp1 NULL
+
+extern PARSEFUNC(pseudo_parse_ifp2);
+#define pseudo_resolve_ifp2 NULL
+#define pseudo_emit_ifp2 NULL
+
+extern PARSEFUNC(pseudo_parse_ifne);
+#define pseudo_resolve_ifne NULL
+#define pseudo_emit_ifne NULL
+
+extern PARSEFUNC(pseudo_parse_ifeq);
+#define pseudo_resolve_ifeq NULL
+#define pseudo_emit_ifeq NULL
+
+extern PARSEFUNC(pseudo_parse_iflt);
+#define pseudo_resolve_iflt NULL
+#define pseudo_emit_iflt NULL
+
+extern PARSEFUNC(pseudo_parse_ifle);
+#define pseudo_resolve_ifle NULL
+#define pseudo_emit_ifle NULL
+
+extern PARSEFUNC(pseudo_parse_ifgt);
+#define pseudo_resolve_ifgt NULL
+#define pseudo_emit_ifgt NULL
+
+extern PARSEFUNC(pseudo_parse_ifge);
+#define pseudo_resolve_ifge NULL
+#define pseudo_emit_ifge NULL
+
+extern PARSEFUNC(pseudo_parse_ifdef);
+#define pseudo_resolve_ifdef NULL
+#define pseudo_emit_ifdef NULL
+
+extern PARSEFUNC(pseudo_parse_ifndef);
+#define pseudo_resolve_ifndef NULL
+#define pseudo_emit_ifndef NULL
+
+extern PARSEFUNC(pseudo_parse_endc);
+#define pseudo_resolve_endc NULL
+#define pseudo_emit_endc NULL
+
+extern PARSEFUNC(pseudo_parse_else);
+#define pseudo_resolve_else NULL
+#define pseudo_emit_else NULL
+
+extern PARSEFUNC(pseudo_parse_pragma);
+#define pseudo_resolve_pragma NULL
+#define pseudo_emit_pragma NULL
+
+extern PARSEFUNC(pseudo_parse_starpragma);
+#define pseudo_resolve_starpragma NULL
+#define pseudo_emit_starpragma NULL
+
+extern PARSEFUNC(pseudo_parse_section);
+#define pseudo_resolve_section NULL
+#define pseudo_emit_section NULL
+
+extern PARSEFUNC(pseudo_parse_endsection);
+#define pseudo_resolve_endsection NULL
+#define pseudo_emit_endsection NULL
+
+extern PARSEFUNC(pseudo_parse_error);
+#define pseudo_resolve_error NULL
+#define pseudo_emit_error NULL
+
+extern PARSEFUNC(pseudo_parse_warning);
+#define pseudo_resolve_warning NULL
+#define pseudo_emit_warning NULL
+
+extern PARSEFUNC(pseudo_parse_os9);
+#define pseudo_resolve_os9 NULL
+extern EMITFUNC(pseudo_emit_os9);
+
+extern PARSEFUNC(pseudo_parse_mod);
+#define pseudo_resolve_mod NULL
+extern EMITFUNC(pseudo_emit_mod);
+
+extern PARSEFUNC(pseudo_parse_emod);
+#define pseudo_resolve_emod NULL
+extern EMITFUNC(pseudo_emit_emod);
+
+extern PARSEFUNC(pseudo_parse_extdep);
+#define pseudo_resolve_extdep NULL
+#define pseudo_emit_extdep NULL
+
+extern PARSEFUNC(pseudo_parse_extern);
+#define pseudo_resolve_extern NULL
+#define pseudo_emit_extern NULL
+
+extern PARSEFUNC(pseudo_parse_export);
+#define pseudo_resolve_export NULL
+#define pseudo_emit_export NULL
+
+extern PARSEFUNC(pseudo_parse_includebin);
+#define pseudo_resolve_includebin NULL
+extern EMITFUNC(pseudo_emit_includebin);
+
+extern PARSEFUNC(pseudo_parse_include);
+#define pseudo_resolve_include NULL
+#define pseudo_emit_include NULL
+
+extern PARSEFUNC(pseudo_parse_align);
+extern RESOLVEFUNC(pseudo_resolve_align);
+extern EMITFUNC(pseudo_emit_align);
+
+extern PARSEFUNC(pseudo_parse_struct);
+#define pseudo_resolve_struct NULL
+#define pseudo_emit_struct NULL
+
+extern PARSEFUNC(pseudo_parse_endstruct);
+#define pseudo_resolve_endstruct NULL
+#define pseudo_emit_endstruct NULL
+
+instab_t instab[] =
+{
+
+ { "abx", { 0x3a, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_normal},
+ { "adca", { 0x99, 0xa9, 0xb9, 0x89}, insn_parse_gen8, insn_resolve_gen8, insn_emit_gen8, lwasm_insn_normal},
+ { "adcb", { 0xd9, 0xe9, 0xf9, 0xc9}, insn_parse_gen8, insn_resolve_gen8, insn_emit_gen8, lwasm_insn_normal},
+ { "adcd", { 0x1099, 0x10a9, 0x10b9, 0x1089},insn_parse_gen16, insn_resolve_gen16, insn_emit_gen16, lwasm_insn_is6309},
+ { "adcr", { 0x1031, -1, -1, -1 }, insn_parse_rtor, insn_resolve_rtor, insn_emit_rtor, lwasm_insn_is6309},
+ { "adda", { 0x9b, 0xab, 0xbb, 0x8b}, insn_parse_gen8, insn_resolve_gen8, insn_emit_gen8, lwasm_insn_normal},
+ { "addb", { 0xdb, 0xeb, 0xfb, 0xcb}, insn_parse_gen8, insn_resolve_gen8, insn_emit_gen8, lwasm_insn_normal},
+ { "addd", { 0xd3, 0xe3, 0xf3, 0xc3}, insn_parse_gen16, insn_resolve_gen16, insn_emit_gen16, lwasm_insn_normal},
+ { "adde", { 0x119b, 0x11ab, 0x11bb, 0x118b},insn_parse_gen8, insn_resolve_gen8, insn_emit_gen8, lwasm_insn_is6309},
+ { "addf", { 0x11db, 0x11eb, 0x11fb, 0x11cb},insn_parse_gen8, insn_resolve_gen8, insn_emit_gen8, lwasm_insn_is6309},
+ { "addr", { 0x1030, -1, -1, -1 }, insn_parse_rtor, insn_resolve_rtor, insn_emit_rtor, lwasm_insn_is6309},
+ { "addw", { 0x109b, 0x10ab, 0x10bb, 0x108b},insn_parse_gen16, insn_resolve_gen16, insn_emit_gen16, lwasm_insn_is6309},
+ { "aim", { 0x02, 0x62, 0x72, -1 }, insn_parse_logicmem, insn_resolve_logicmem, insn_emit_logicmem, lwasm_insn_is6309},
+ { "anda", { 0x94, 0xa4, 0xb4, 0x84}, insn_parse_gen8, insn_resolve_gen8, insn_emit_gen8, lwasm_insn_normal},
+ { "andb", { 0xd4, 0xe4, 0xf4, 0xc4}, insn_parse_gen8, insn_resolve_gen8, insn_emit_gen8, lwasm_insn_normal},
+ { "andcc", { 0x1c, -1, -1, 0x1c}, insn_parse_imm8, insn_resolve_imm8, insn_emit_imm8, lwasm_insn_normal},
+ { "andd", { 0x1094, 0x10a4, 0x10b4, 0x1084},insn_parse_gen16, insn_resolve_gen16, insn_emit_gen16, lwasm_insn_is6309},
+ { "andr", { 0x1034, -1, -1, -1 }, insn_parse_rtor, insn_resolve_rtor, insn_emit_rtor, lwasm_insn_is6309},
+ { "asl", { 0x08, 0x68, 0x78, -1 }, insn_parse_gen0, insn_resolve_gen0, insn_emit_gen0, lwasm_insn_normal},
+ { "asla", { 0x48, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_normal},
+ { "aslb", { 0x58, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_normal},
+ { "asld", { 0x1048, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_is6309},
+ { "asr", { 0x07, 0x67, 0x77, -1 }, insn_parse_gen0, insn_resolve_gen0, insn_emit_gen0, lwasm_insn_normal},
+ { "asra", { 0x47, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_normal},
+ { "asrb", { 0x57, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_normal},
+ { "asrd", { 0x1047, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_is6309},
+
+ { "band", { 0x1130, -1, -1, -1 }, insn_parse_bitbit, insn_resolve_bitbit, insn_emit_bitbit, lwasm_insn_is6309},
+ { "bcc", { 0x24, -1, -1, -1 }, insn_parse_rel8, insn_resolve_rel8, insn_emit_rel8, lwasm_insn_normal},
+ { "bcs", { 0x25, -1, -1, -1 }, insn_parse_rel8, insn_resolve_rel8, insn_emit_rel8, lwasm_insn_normal},
+ { "beor", { 0x1134, -1, -1, -1 }, insn_parse_bitbit, insn_resolve_bitbit, insn_emit_bitbit, lwasm_insn_is6309},
+ { "beq", { 0x27, -1, -1, -1 }, insn_parse_rel8, insn_resolve_rel8, insn_emit_rel8, lwasm_insn_normal},
+ { "bge", { 0x2c, -1, -1, -1 }, insn_parse_rel8, insn_resolve_rel8, insn_emit_rel8, lwasm_insn_normal},
+ { "bgt", { 0x2e, -1, -1, -1 }, insn_parse_rel8, insn_resolve_rel8, insn_emit_rel8, lwasm_insn_normal},
+ { "bhi", { 0x22, -1, -1, -1 }, insn_parse_rel8, insn_resolve_rel8, insn_emit_rel8, lwasm_insn_normal},
+ { "bhs", { 0x24, -1, -1, -1 }, insn_parse_rel8, insn_resolve_rel8, insn_emit_rel8, lwasm_insn_normal},
+ { "biand", { 0x1131, -1, -1, -1 }, insn_parse_bitbit, insn_resolve_bitbit, insn_emit_bitbit, lwasm_insn_is6309},
+ { "bieor", { 0x1135, -1, -1, -1 }, insn_parse_bitbit, insn_resolve_bitbit, insn_emit_bitbit, lwasm_insn_is6309},
+ { "bior", { 0x1133, -1, -1, -1 }, insn_parse_bitbit, insn_resolve_bitbit, insn_emit_bitbit, lwasm_insn_is6309},
+ { "bita", { 0x95, 0xa5, 0xb5, 0x85}, insn_parse_gen8, insn_resolve_gen8, insn_emit_gen8, lwasm_insn_normal},
+ { "bitb", { 0xd5, 0xe5, 0xf5, 0xc5}, insn_parse_gen8, insn_resolve_gen8, insn_emit_gen8, lwasm_insn_normal},
+ { "bitd", { 0x1095, 0x10a5, 0x10b5, 0x1085},insn_parse_gen16, insn_resolve_gen16, insn_emit_gen16, lwasm_insn_is6309},
+ { "bitmd", { 0x113c, -1, -1, 0x113c},insn_parse_imm8, insn_resolve_imm8, insn_emit_imm8, lwasm_insn_is6309},
+ { "ble", { 0x2f, -1, -1, -1 }, insn_parse_rel8, insn_resolve_rel8, insn_emit_rel8, lwasm_insn_normal},
+ { "blo", { 0x25, -1, -1, -1 }, insn_parse_rel8, insn_resolve_rel8, insn_emit_rel8, lwasm_insn_normal},
+ { "bls", { 0x23, -1, -1, -1 }, insn_parse_rel8, insn_resolve_rel8, insn_emit_rel8, lwasm_insn_normal},
+ { "blt", { 0x2d, -1, -1, -1 }, insn_parse_rel8, insn_resolve_rel8, insn_emit_rel8, lwasm_insn_normal},
+ { "bmi", { 0x2b, -1, -1, -1 }, insn_parse_rel8, insn_resolve_rel8, insn_emit_rel8, lwasm_insn_normal},
+ { "bne", { 0x26, -1, -1, -1 }, insn_parse_rel8, insn_resolve_rel8, insn_emit_rel8, lwasm_insn_normal},
+ { "bor", { 0x1132, -1, -1, -1 }, insn_parse_bitbit, insn_resolve_bitbit, insn_emit_bitbit, lwasm_insn_is6309},
+ { "bpl", { 0x2a, -1, -1, -1 }, insn_parse_rel8, insn_resolve_rel8, insn_emit_rel8, lwasm_insn_normal},
+ { "bra", { 0x20, -1, -1, -1 }, insn_parse_rel8, insn_resolve_rel8, insn_emit_rel8, lwasm_insn_normal},
+ { "brn", { 0x21, -1, -1, -1 }, insn_parse_rel8, insn_resolve_rel8, insn_emit_rel8, lwasm_insn_normal},
+ { "bsr", { 0x8d, -1, -1, -1 }, insn_parse_rel8, insn_resolve_rel8, insn_emit_rel8, lwasm_insn_normal},
+ { "bvc", { 0x28, -1, -1, -1 }, insn_parse_rel8, insn_resolve_rel8, insn_emit_rel8, lwasm_insn_normal},
+ { "bvs", { 0x29, -1, -1, -1 }, insn_parse_rel8, insn_resolve_rel8, insn_emit_rel8, lwasm_insn_normal},
+
+ { "clr", { 0x0f, 0x6f, 0x7f, -1 }, insn_parse_gen0, insn_resolve_gen0, insn_emit_gen0, lwasm_insn_normal},
+ { "clra", { 0x4f, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_normal},
+ { "clrb", { 0x5f, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_normal},
+ { "clrd", { 0x104f, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_is6309},
+ { "clre", { 0x114f, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_is6309},
+ { "clrf", { 0x115f, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_is6309},
+ { "clrw", { 0x105f, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_is6309},
+ { "cmpa", { 0x91, 0xa1, 0xb1, 0x81}, insn_parse_gen8, insn_resolve_gen8, insn_emit_gen8, lwasm_insn_normal},
+ { "cmpb", { 0xd1, 0xe1, 0xf1, 0xc1}, insn_parse_gen8, insn_resolve_gen8, insn_emit_gen8, lwasm_insn_normal},
+ { "cmpd", { 0x1093, 0x10a3, 0x10b3, 0x1083},insn_parse_gen16, insn_resolve_gen16, insn_emit_gen16, lwasm_insn_normal},
+ { "cmpe", { 0x1191, 0x11a1, 0x11b1, 0x1181},insn_parse_gen8, insn_resolve_gen8, insn_emit_gen8, lwasm_insn_is6309},
+ { "cmpf", { 0x11d1, 0x11e1, 0x11f1, 0x11c1},insn_parse_gen8, insn_resolve_gen8, insn_emit_gen8, lwasm_insn_is6309},
+ { "cmpr", { 0x1037, -1, -1, -1 }, insn_parse_rtor, insn_resolve_rtor, insn_emit_rtor, lwasm_insn_is6309},
+ { "cmps", { 0x119c, 0x11ac, 0x11bc, 0x118c},insn_parse_gen16, insn_resolve_gen16, insn_emit_gen16, lwasm_insn_normal},
+ { "cmpu", { 0x1193, 0x11a3, 0x11b3, 0x1183},insn_parse_gen16, insn_resolve_gen16, insn_emit_gen16, lwasm_insn_normal},
+ { "cmpw", { 0x1091, 0x10a1, 0x10b1, 0x1081},insn_parse_gen16, insn_resolve_gen16, insn_emit_gen16, lwasm_insn_is6309},
+ { "cmpx", { 0x9c, 0xac, 0xbc, 0x8c}, insn_parse_gen16, insn_resolve_gen16, insn_emit_gen16, lwasm_insn_normal},
+ { "cmpy", { 0x109c, 0x10ac, 0x10bc, 0x108c},insn_parse_gen16, insn_resolve_gen16, insn_emit_gen16, lwasm_insn_normal},
+ { "com", { 0x03, 0x63, 0x73, -1 }, insn_parse_gen0, insn_resolve_gen0, insn_emit_gen0, lwasm_insn_normal},
+ { "coma", { 0x43, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_normal},
+ { "comb", { 0x53, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_normal},
+ { "comd", { 0x1043, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_is6309},
+ { "come", { 0x1143, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_is6309},
+ { "comf", { 0x1153, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_is6309},
+ { "comw", { 0x1053, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_is6309},
+ { "cwai", { 0x3c, -1, -1, -1 }, insn_parse_imm8, insn_resolve_imm8, insn_emit_imm8, lwasm_insn_normal},
+
+ { "daa", { 0x19, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_normal},
+ { "dec", { 0x0a, 0x6a, 0x7a, -1 }, insn_parse_gen0, insn_resolve_gen0, insn_emit_gen0, lwasm_insn_normal},
+ { "deca", { 0x4a, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_normal},
+ { "decb", { 0x5a, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_normal},
+ { "decd", { 0x104a, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_is6309},
+ { "dece", { 0x114a, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_is6309},
+ { "decf", { 0x115a, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_is6309},
+ { "decw", { 0x105a, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_is6309},
+ { "divd", { 0x118d, 0x119d, 0x11ad, 0x11bd},insn_parse_gen8, insn_resolve_gen8, insn_emit_gen8, lwasm_insn_is6309},
+ { "divq", { 0x118e, 0x119e, 0x11ae, 0x11be},insn_parse_gen16, insn_resolve_gen16, insn_emit_gen16, lwasm_insn_is6309},
+
+ { "eim", { 0x05, 0x65, 0x75, -1 }, insn_parse_logicmem, insn_resolve_logicmem, insn_emit_logicmem, lwasm_insn_is6309},
+ { "eora", { 0x98, 0xa8, 0xb8, 0x88}, insn_parse_gen8, insn_resolve_gen8, insn_emit_gen8, lwasm_insn_normal},
+ { "eorb", { 0xd8, 0xe8, 0xf8, 0xc8}, insn_parse_gen8, insn_resolve_gen8, insn_emit_gen8, lwasm_insn_normal},
+ { "eord", { 0x1098, 0x10a8, 0x10b8, 0x1088},insn_parse_gen16, insn_resolve_gen16, insn_emit_gen16, lwasm_insn_is6309},
+ { "eorr", { 0x1036, -1, -1, -1 }, insn_parse_rtor, insn_resolve_rtor, insn_emit_rtor, lwasm_insn_is6309},
+ { "exg", { 0x1e, -1, -1, -1 }, insn_parse_rtor, insn_resolve_rtor, insn_emit_rtor, lwasm_insn_normal},
+
+ { "inc", { 0x0c, 0x6c, 0x7c, -1 }, insn_parse_gen0, insn_resolve_gen0, insn_emit_gen0, lwasm_insn_normal},
+ { "inca", { 0x4c, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_normal},
+ { "incb", { 0x5c, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_normal},
+ { "incd", { 0x104c, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_is6309},
+ { "ince", { 0x114c, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_is6309},
+ { "incf", { 0x115c, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_is6309},
+ { "incw", { 0x105c, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_is6309},
+
+ { "jmp", { 0x0e, 0x6e, 0x7e, -1 }, insn_parse_gen0, insn_resolve_gen0, insn_emit_gen0, lwasm_insn_normal},
+ { "jsr", { 0x9d, 0xad, 0xbd, -1 }, insn_parse_gen0, insn_resolve_gen0, insn_emit_gen0, lwasm_insn_normal},
+
+ { "lbcc", { 0x1024, -1, -1, -1 }, insn_parse_rel16, insn_resolve_rel16, insn_emit_rel16, lwasm_insn_normal},
+ { "lbcs", { 0x1025, -1, -1, -1 }, insn_parse_rel16, insn_resolve_rel16, insn_emit_rel16, lwasm_insn_normal},
+ { "lbeq", { 0x1027, -1, -1, -1 }, insn_parse_rel16, insn_resolve_rel16, insn_emit_rel16, lwasm_insn_normal},
+ { "lbge", { 0x102c, -1, -1, -1 }, insn_parse_rel16, insn_resolve_rel16, insn_emit_rel16, lwasm_insn_normal},
+ { "lbgt", { 0x102e, -1, -1, -1 }, insn_parse_rel16, insn_resolve_rel16, insn_emit_rel16, lwasm_insn_normal},
+ { "lbhi", { 0x1022, -1, -1, -1 }, insn_parse_rel16, insn_resolve_rel16, insn_emit_rel16, lwasm_insn_normal},
+ { "lbhs", { 0x1024, -1, -1, -1 }, insn_parse_rel16, insn_resolve_rel16, insn_emit_rel16, lwasm_insn_normal},
+ { "lble", { 0x102f, -1, -1, -1 }, insn_parse_rel16, insn_resolve_rel16, insn_emit_rel16, lwasm_insn_normal},
+ { "lblo", { 0x1025, -1, -1, -1 }, insn_parse_rel16, insn_resolve_rel16, insn_emit_rel16, lwasm_insn_normal},
+ { "lbls", { 0x1023, -1, -1, -1 }, insn_parse_rel16, insn_resolve_rel16, insn_emit_rel16, lwasm_insn_normal},
+ { "lblt", { 0x102d, -1, -1, -1 }, insn_parse_rel16, insn_resolve_rel16, insn_emit_rel16, lwasm_insn_normal},
+ { "lbmi", { 0x102b, -1, -1, -1 }, insn_parse_rel16, insn_resolve_rel16, insn_emit_rel16, lwasm_insn_normal},
+ { "lbne", { 0x1026, -1, -1, -1 }, insn_parse_rel16, insn_resolve_rel16, insn_emit_rel16, lwasm_insn_normal},
+ { "lbpl", { 0x102a, -1, -1, -1 }, insn_parse_rel16, insn_resolve_rel16, insn_emit_rel16, lwasm_insn_normal},
+ { "lbra", { 0x16, -1, -1, -1 }, insn_parse_rel16, insn_resolve_rel16, insn_emit_rel16, lwasm_insn_normal},
+ { "lbrn", { 0x1021, -1, -1, -1 }, insn_parse_rel16, insn_resolve_rel16, insn_emit_rel16, lwasm_insn_normal},
+ { "lbsr", { 0x17, -1, -1, -1 }, insn_parse_rel16, insn_resolve_rel16, insn_emit_rel16, lwasm_insn_normal},
+ { "lbvc", { 0x1028, -1, -1, -1 }, insn_parse_rel16, insn_resolve_rel16, insn_emit_rel16, lwasm_insn_normal},
+ { "lbvs", { 0x1029, -1, -1, -1 }, insn_parse_rel16, insn_resolve_rel16, insn_emit_rel16, lwasm_insn_normal},
+ { "lda", { 0x96, 0xa6, 0xb6, 0x86}, insn_parse_gen8, insn_resolve_gen8, insn_emit_gen8, lwasm_insn_normal},
+ { "ldb", { 0xd6, 0xe6, 0xf6, 0xc6}, insn_parse_gen8, insn_resolve_gen8, insn_emit_gen8, lwasm_insn_normal},
+ { "ldbt", { 0x1136, -1, -1, -1 }, insn_parse_bitbit, insn_resolve_bitbit, insn_emit_bitbit, lwasm_insn_is6309},
+ { "ldd", { 0xdc, 0xec, 0xfc, 0xcc}, insn_parse_gen16, insn_resolve_gen16, insn_emit_gen16, lwasm_insn_normal},
+ { "lde", { 0x1196, 0x11a6, 0x11b6, 0x1186},insn_parse_gen8, insn_resolve_gen8, insn_emit_gen8, lwasm_insn_is6309},
+ { "ldf", { 0x11d6, 0x11e6, 0x11f6, 0x11c6},insn_parse_gen8, insn_resolve_gen8, insn_emit_gen8, lwasm_insn_is6309},
+ { "ldq", { 0x10dc, 0x10ec, 0x10fc, 0xcd}, insn_parse_gen32, insn_resolve_gen32, insn_emit_gen32, lwasm_insn_is6309},
+ { "lds", { 0x10de, 0x10ee, 0x10fe, 0x10ce},insn_parse_gen16, insn_resolve_gen16, insn_emit_gen16, lwasm_insn_normal},
+ { "ldu", { 0xde, 0xee, 0xfe, 0xce}, insn_parse_gen16, insn_resolve_gen16, insn_emit_gen16, lwasm_insn_normal},
+ { "ldw", { 0x1096, 0x10a6, 0x10b6, 0x1086},insn_parse_gen16, insn_resolve_gen16, insn_emit_gen16, lwasm_insn_is6309},
+ { "ldx", { 0x9e, 0xae, 0xbe, 0x8e}, insn_parse_gen16, insn_resolve_gen16, insn_emit_gen16, lwasm_insn_normal},
+ { "ldy", { 0x109e, 0x10ae, 0x10be, 0x108e},insn_parse_gen16, insn_resolve_gen16, insn_emit_gen16, lwasm_insn_normal},
+ { "ldmd", { 0x113d, -1, -1, 0x113d},insn_parse_imm8, insn_resolve_imm8, insn_emit_imm8, lwasm_insn_is6309},
+ { "leas", { 0x32, -1, -1, -1 }, insn_parse_indexed, insn_resolve_indexed, insn_emit_indexed, lwasm_insn_normal},
+ { "leau", { 0x33, -1, -1, -1 }, insn_parse_indexed, insn_resolve_indexed, insn_emit_indexed, lwasm_insn_normal},
+ { "leax", { 0x30, -1, -1, -1 }, insn_parse_indexed, insn_resolve_indexed, insn_emit_indexed, lwasm_insn_normal},
+ { "leay", { 0x31, -1, -1, -1 }, insn_parse_indexed, insn_resolve_indexed, insn_emit_indexed, lwasm_insn_normal},
+ { "lsl", { 0x08, 0x68, 0x78, -1 }, insn_parse_gen0, insn_resolve_gen0, insn_emit_gen0, lwasm_insn_normal},
+ { "lsla", { 0x48, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_normal},
+ { "lslb", { 0x58, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_normal},
+ { "lsld", { 0x1048, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_is6309},
+ { "lsr", { 0x04, 0x64, 0x74, -1 }, insn_parse_gen0, insn_resolve_gen0, insn_emit_gen0, lwasm_insn_normal},
+ { "lsra", { 0x44, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_normal},
+ { "lsrb", { 0x54, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_normal},
+ { "lsrd", { 0x1044, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_is6309},
+ { "lsrw", { 0x1054, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_is6309},
+
+ { "mul", { 0x3d, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_normal},
+ { "muld", { 0x118f, 0x119f, 0x11af, 0x11bf},insn_parse_gen16, insn_resolve_gen16, insn_emit_gen16, lwasm_insn_is6309},
+
+ { "neg", { 0x00, 0x60, 0x70, -1 }, insn_parse_gen0, insn_resolve_gen0, insn_emit_gen0, lwasm_insn_normal},
+ { "nega", { 0x40, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_normal},
+ { "negb", { 0x50, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_normal},
+ { "negd", { 0x1040, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_is6309},
+
+ { "nop", { 0x12, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_normal},
+
+ { "oim", { 0x01, 0x61, 0x71, -1 }, insn_parse_logicmem, insn_resolve_logicmem, insn_emit_logicmem, lwasm_insn_is6309},
+ { "ora", { 0x9a, 0xaa, 0xba, 0x8a}, insn_parse_gen8, insn_resolve_gen8, insn_emit_gen8, lwasm_insn_normal},
+ { "orb", { 0xda, 0xea, 0xfa, 0xca}, insn_parse_gen8, insn_resolve_gen8, insn_emit_gen8, lwasm_insn_normal},
+ { "orcc", { 0x1a, -1, -1, 0x1a }, insn_parse_imm8, insn_resolve_imm8, insn_emit_imm8, lwasm_insn_normal},
+ { "ord", { 0x109a, 0x10aa, 0x10ba, 0x108a},insn_parse_gen16, insn_resolve_gen16, insn_emit_gen16, lwasm_insn_is6309},
+ { "orr", { 0x1035, -1, -1, -1 }, insn_parse_rtor, insn_resolve_rtor, insn_emit_rtor, lwasm_insn_is6309},
+
+ { "pshs", { 0x34, -1, -1, -1 }, insn_parse_rlist, insn_resolve_rlist, insn_emit_rlist, lwasm_insn_normal},
+ { "pshsw", { 0x1038, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_is6309},
+ { "pshu", { 0x36, -1, -1, -1 }, insn_parse_rlist, insn_resolve_rlist, insn_emit_rlist, lwasm_insn_normal},
+ { "pshuw", { 0x103a, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_is6309},
+ { "puls", { 0x35, -1, -1, -1 }, insn_parse_rlist, insn_resolve_rlist, insn_emit_rlist, lwasm_insn_normal},
+ { "pulsw", { 0x1039, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_is6309},
+ { "pulu", { 0x37, -1, -1, -1 }, insn_parse_rlist, insn_resolve_rlist, insn_emit_rlist, lwasm_insn_normal},
+ { "puluw", { 0x103b, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_is6309},
+
+ { "rol", { 0x09, 0x69, 0x79, -1 }, insn_parse_gen0, insn_resolve_gen0, insn_emit_gen0, lwasm_insn_normal},
+ { "rola", { 0x49, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_normal},
+ { "rolb", { 0x59, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_normal},
+ { "rold", { 0x1049, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_is6309},
+ { "rolw", { 0x1059, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_is6309},
+ { "ror", { 0x06, 0x66, 0x76, -1 }, insn_parse_gen0, insn_resolve_gen0, insn_emit_gen0, lwasm_insn_normal},
+ { "rora", { 0x46, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_normal},
+ { "rorb", { 0x56, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_normal},
+ { "rord", { 0x1046, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_is6309},
+ { "rorw", { 0x1056, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_is6309},
+ { "rti", { 0x3b, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_normal},
+ { "rts", { 0x39, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_normal},
+
+ { "sbca", { 0x92, 0xa2, 0xb2, 0x82}, insn_parse_gen8, insn_resolve_gen8, insn_emit_gen8, lwasm_insn_normal},
+ { "sbcb", { 0xd2, 0xe2, 0xf2, 0xc2}, insn_parse_gen8, insn_resolve_gen8, insn_emit_gen8, lwasm_insn_normal},
+ { "sbcd", { 0x1092, 0x10a2, 0x10b2, 0x1082},insn_parse_gen16, insn_resolve_gen16, insn_emit_gen16, lwasm_insn_is6309},
+ { "sbcr", { 0x1033, -1, -1, -1 }, insn_parse_rtor, insn_resolve_rtor, insn_emit_rtor, lwasm_insn_is6309},
+ { "sex", { 0x1d, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_normal},
+ { "sexw", { 0x14, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_is6309},
+ { "sta", { 0x97, 0xa7, 0xb7, -1 }, insn_parse_gen0, insn_resolve_gen0, insn_emit_gen0, lwasm_insn_normal},
+ { "stb", { 0xd7, 0xe7, 0xf7, -1 }, insn_parse_gen0, insn_resolve_gen0, insn_emit_gen0, lwasm_insn_normal},
+ { "stbt", { 0x1137, -1, -1, -1 }, insn_parse_bitbit, insn_resolve_bitbit, insn_emit_bitbit, lwasm_insn_is6309},
+ { "std", { 0xdd, 0xed, 0xfd, -1 }, insn_parse_gen0, insn_resolve_gen0, insn_emit_gen0, lwasm_insn_normal},
+ { "ste", { 0x1197, 0x11a7, 0x11b7, -1 }, insn_parse_gen0, insn_resolve_gen0, insn_emit_gen0, lwasm_insn_is6309},
+ { "stf", { 0x11d7, 0x11e7, 0x11f7, -1 }, insn_parse_gen0, insn_resolve_gen0, insn_emit_gen0, lwasm_insn_is6309},
+ { "stq", { 0x10dd, 0x10ed, 0x10fd, -1 }, insn_parse_gen0, insn_resolve_gen0, insn_emit_gen0, lwasm_insn_is6309},
+ { "sts", { 0x10df, 0x10ef, 0x10ff, -1 }, insn_parse_gen0, insn_resolve_gen0, insn_emit_gen0, lwasm_insn_normal},
+ { "stu", { 0xdf, 0xef, 0xff, -1 }, insn_parse_gen0, insn_resolve_gen0, insn_emit_gen0, lwasm_insn_normal},
+ { "stw", { 0x1097, 0x10a7, 0x10b7, -1 }, insn_parse_gen0, insn_resolve_gen0, insn_emit_gen0, lwasm_insn_is6309},
+ { "stx", { 0x9f, 0xaf, 0xbf, -1 }, insn_parse_gen0, insn_resolve_gen0, insn_emit_gen0, lwasm_insn_normal},
+ { "sty", { 0x109f, 0x10af, 0x10bf, -1 }, insn_parse_gen0, insn_resolve_gen0, insn_emit_gen0, lwasm_insn_normal},
+ { "suba", { 0x90, 0xa0, 0xb0, 0x80}, insn_parse_gen8, insn_resolve_gen8, insn_emit_gen8, lwasm_insn_normal},
+ { "subb", { 0xd0, 0xe0, 0xf0, 0xc0}, insn_parse_gen8, insn_resolve_gen8, insn_emit_gen8, lwasm_insn_normal},
+ { "subd", { 0x93, 0xa3, 0xb3, 0x83}, insn_parse_gen16, insn_resolve_gen16, insn_emit_gen16, lwasm_insn_normal},
+ { "sube", { 0x1190, 0x11a0, 0x11b0, 0x1180},insn_parse_gen8, insn_resolve_gen8, insn_emit_gen8, lwasm_insn_is6309},
+ { "subf", { 0x11d0, 0x11e0, 0x11f0, 0x11c0},insn_parse_gen8, insn_resolve_gen8, insn_emit_gen8, lwasm_insn_is6309},
+ { "subr", { 0x1032, -1, -1, -1 }, insn_parse_rtor, insn_resolve_rtor, insn_emit_rtor, lwasm_insn_is6309},
+ { "subw", { 0x1090, 0x10a0, 0x1090, 0x1080},insn_parse_gen8, insn_resolve_gen8, insn_emit_gen8, lwasm_insn_is6309},
+ { "swi", { 0x3f, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_normal},
+ { "swi2", { 0x103f, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_normal},
+ { "swi3", { 0x113f, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_normal},
+ { "sync", { 0x13, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_normal},
+
+ // note: r+,r+ r-,r- r+,r r,r+
+ { "tfm", { 0x1138, 0x1139, 0x113a, 0x113b },insn_parse_tfm, insn_resolve_tfm, insn_emit_tfm, lwasm_insn_is6309},
+
+ // compatibility opcodes for tfm in other assemblers
+ { "copy", { 0x1138, -1, -1, -1}, insn_parse_tfmrtor, insn_resolve_tfmrtor, insn_emit_tfmrtor, lwasm_insn_is6309},
+ { "copy+", { 0x1138, -1, -1, -1}, insn_parse_tfmrtor, insn_resolve_tfmrtor, insn_emit_tfmrtor, lwasm_insn_is6309},
+ { "tfrp", { 0x1138, -1, -1, -1}, insn_parse_tfmrtor, insn_resolve_tfmrtor, insn_emit_tfmrtor, lwasm_insn_is6309},
+
+ { "copy-", { 0x1139, -1, -1, -1}, insn_parse_tfmrtor, insn_resolve_tfmrtor, insn_emit_tfmrtor, lwasm_insn_is6309},
+ { "tfrm", { 0x1139, -1, -1, -1}, insn_parse_tfmrtor, insn_resolve_tfmrtor, insn_emit_tfmrtor, lwasm_insn_is6309},
+
+ { "imp", { 0x113a, -1, -1, -1}, insn_parse_tfmrtor, insn_resolve_tfmrtor, insn_emit_tfmrtor, lwasm_insn_is6309},
+ { "implode", { 0x113a, -1, -1, -1}, insn_parse_tfmrtor, insn_resolve_tfmrtor, insn_emit_tfmrtor, lwasm_insn_is6309},
+ { "tfrs", { 0x113a, -1, -1, -1}, insn_parse_tfmrtor, insn_resolve_tfmrtor, insn_emit_tfmrtor, lwasm_insn_is6309},
+
+ { "exp", { 0x113b, -1, -1, -1}, insn_parse_tfmrtor, insn_resolve_tfmrtor, insn_emit_tfmrtor, lwasm_insn_is6309},
+ { "expand", { 0x113b, -1, -1, -1}, insn_parse_tfmrtor, insn_resolve_tfmrtor, insn_emit_tfmrtor, lwasm_insn_is6309},
+ { "tfrr", { 0x113b, -1, -1, -1}, insn_parse_tfmrtor, insn_resolve_tfmrtor, insn_emit_tfmrtor, lwasm_insn_is6309},
+
+ { "tfr", { 0x1f, -1, -1, -1 }, insn_parse_rtor, insn_resolve_rtor, insn_emit_rtor, lwasm_insn_normal},
+ { "tim", { 0x0b, 0x6b, 0x7b, -1 }, insn_parse_logicmem, insn_resolve_logicmem, insn_emit_logicmem, lwasm_insn_is6309},
+ { "tst", { 0x0d, 0x6d, 0x7d, -1 }, insn_parse_gen0, insn_resolve_gen0, insn_emit_gen0, lwasm_insn_normal},
+ { "tsta", { 0x4d, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_normal},
+ { "tstb", { 0x5d, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_normal},
+ { "tstd", { 0x104d, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_is6309},
+ { "tste", { 0x114d, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_is6309},
+ { "tstf", { 0x115d, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_is6309},
+ { "tstw", { 0x105d, -1, -1, -1 }, insn_parse_inh, insn_resolve_inh, insn_emit_inh, lwasm_insn_is6309},
+
+ { "org", { -1, -1, -1, -1 }, pseudo_parse_org, pseudo_resolve_org, pseudo_emit_org, lwasm_insn_normal},
+ { "equ", { -1, -1, -1, -1 }, pseudo_parse_equ, pseudo_resolve_equ, pseudo_emit_equ, lwasm_insn_setsym},
+ { "=", { -1, -1, -1, -1 }, pseudo_parse_equ, pseudo_resolve_equ, pseudo_emit_equ, lwasm_insn_setsym},
+
+ { "extern", { -1, -1, -1, -1 }, pseudo_parse_extern, pseudo_resolve_extern, pseudo_emit_extern, lwasm_insn_setsym},
+ { "external", { -1, -1, -1, -1 }, pseudo_parse_extern, pseudo_resolve_extern, pseudo_emit_extern, lwasm_insn_setsym},
+ { "import", { -1, -1, -1, -1 }, pseudo_parse_extern, pseudo_resolve_extern, pseudo_emit_extern, lwasm_insn_setsym},
+ { "export", { -1, -1, -1, -1 }, pseudo_parse_export, pseudo_resolve_export, pseudo_emit_export, lwasm_insn_setsym},
+ { "extdep", { -1, -1, -1, -1 }, pseudo_parse_extdep, pseudo_resolve_extdep, pseudo_emit_extdep, lwasm_insn_setsym},
+
+ { "rmb", { -1, -1, -1, -1 }, pseudo_parse_rmb, pseudo_resolve_rmb, pseudo_emit_rmb, lwasm_insn_struct},
+ { "rmd", { -1, -1, -1, -1 }, pseudo_parse_rmd, pseudo_resolve_rmd, pseudo_emit_rmd, lwasm_insn_struct},
+ { "rmw", { -1, -1, -1, -1 }, pseudo_parse_rmd, pseudo_resolve_rmd, pseudo_emit_rmd, lwasm_insn_struct},
+ { "rmq", { -1, -1, -1, -1 }, pseudo_parse_rmq, pseudo_resolve_rmq, pseudo_emit_rmq, lwasm_insn_struct},
+
+ { "zmb", { -1, -1, -1, -1 }, pseudo_parse_zmb, pseudo_resolve_zmb, pseudo_emit_zmb, lwasm_insn_normal},
+ { "zmd", { -1, -1, -1, -1 }, pseudo_parse_zmd, pseudo_resolve_zmd, pseudo_emit_zmd, lwasm_insn_normal},
+ { "zmq", { -1, -1, -1, -1 }, pseudo_parse_zmq, pseudo_resolve_zmq, pseudo_emit_zmq, lwasm_insn_normal},
+
+ { "fcc", { -1, -1, -1, -1 }, pseudo_parse_fcc, pseudo_resolve_fcc, pseudo_emit_fcc, lwasm_insn_normal},
+ { "fcn", { -1, -1, -1, -1 }, pseudo_parse_fcn, pseudo_resolve_fcn, pseudo_emit_fcn, lwasm_insn_normal},
+ { "fcs", { -1, -1, -1, -1 }, pseudo_parse_fcs, pseudo_resolve_fcs, pseudo_emit_fcs, lwasm_insn_normal},
+
+ { "fcb", { -1, -1, -1, -1 }, pseudo_parse_fcb, pseudo_resolve_fcb, pseudo_emit_fcb, lwasm_insn_normal},
+ { "fdb", { -1, -1, -1, -1 }, pseudo_parse_fdb, pseudo_resolve_fdb, pseudo_emit_fdb, lwasm_insn_normal},
+ { "fqb", { -1, -1, -1, -1 }, pseudo_parse_fqb, pseudo_resolve_fqb, pseudo_emit_fqb, lwasm_insn_normal},
+ { "end", { -1, -1, -1, -1 }, pseudo_parse_end, pseudo_resolve_end, pseudo_emit_end, lwasm_insn_normal},
+
+ { "includebin", { -1, -1, -1, -1}, pseudo_parse_includebin,pseudo_resolve_includebin, pseudo_emit_includebin, lwasm_insn_normal},
+ { "include", { -1, -1, -1, -1 }, pseudo_parse_include, pseudo_resolve_include, pseudo_emit_include, lwasm_insn_normal},
+ { "use", { -1, -1, -1, -1 }, pseudo_parse_include, pseudo_resolve_include, pseudo_emit_include, lwasm_insn_normal},
+
+ { "align", { -1, -1, -1, -1 }, pseudo_parse_align, pseudo_resolve_align, pseudo_emit_align, lwasm_insn_normal},
+
+ { "error", { -1, -1, -1, -1}, pseudo_parse_error, pseudo_resolve_error, pseudo_emit_error, lwasm_insn_normal},
+ { "warning", { -1, -1, -1, -1}, pseudo_parse_warning, pseudo_resolve_warning, pseudo_emit_warning, lwasm_insn_normal},
+
+ // these are *dangerous*
+ { "ifp1", { -1, -1, -1, -1}, pseudo_parse_ifp1, pseudo_resolve_ifp1, pseudo_emit_ifp1, lwasm_insn_cond},
+ { "ifp2", { -1, -1, -1, -1}, pseudo_parse_ifp2, pseudo_resolve_ifp2, pseudo_emit_ifp2, lwasm_insn_cond},
+
+ { "ifeq", { -1, -1, -1, -1}, pseudo_parse_ifeq, pseudo_resolve_ifeq, pseudo_emit_ifeq, lwasm_insn_cond},
+ { "ifne", { -1, -1, -1, -1}, pseudo_parse_ifne, pseudo_resolve_ifne, pseudo_emit_ifne, lwasm_insn_cond},
+ { "if", { -1, -1, -1, -1}, pseudo_parse_ifne, pseudo_resolve_ifne, pseudo_emit_ifne, lwasm_insn_cond},
+ { "ifgt", { -1, -1, -1, -1}, pseudo_parse_ifgt, pseudo_resolve_ifgt, pseudo_emit_ifgt, lwasm_insn_cond},
+ { "ifge", { -1, -1, -1, -1}, pseudo_parse_ifge, pseudo_resolve_ifge, pseudo_emit_ifge, lwasm_insn_cond},
+ { "iflt", { -1, -1, -1, -1}, pseudo_parse_iflt, pseudo_resolve_iflt, pseudo_emit_iflt, lwasm_insn_cond},
+ { "ifle", { -1, -1, -1, -1}, pseudo_parse_ifle, pseudo_resolve_ifle, pseudo_emit_ifle, lwasm_insn_cond},
+ { "endc", { -1, -1, -1, -1}, pseudo_parse_endc, pseudo_resolve_endc, pseudo_emit_endc, lwasm_insn_cond},
+ { "else", { -1, -1, -1, -1}, pseudo_parse_else, pseudo_resolve_else, pseudo_emit_else, lwasm_insn_cond},
+ { "ifdef", { -1, -1, -1, -1}, pseudo_parse_ifdef, pseudo_resolve_ifdef, pseudo_emit_ifdef, lwasm_insn_cond},
+ { "ifndef", { -1, -1, -1, -1}, pseudo_parse_ifndef, pseudo_resolve_ifndef, pseudo_emit_ifndef, lwasm_insn_cond},
+
+ { "macro", { -1, -1, -1, -1}, pseudo_parse_macro, pseudo_resolve_macro, pseudo_emit_macro, lwasm_insn_cond | lwasm_insn_setsym},
+ { "endm", { -1, -1, -1, -1}, pseudo_parse_endm, pseudo_resolve_endm, pseudo_emit_endm, lwasm_insn_cond | lwasm_insn_setsym | lwasm_insn_endm},
+
+ { "setdp", { -1, -1, -1, -1}, pseudo_parse_setdp, pseudo_resolve_setdp, pseudo_emit_setdp, lwasm_insn_normal},
+ { "set", { -1, -1, -1, -1}, pseudo_parse_set, pseudo_resolve_set, pseudo_emit_set, lwasm_insn_setsym},
+
+
+ { "section", { -1, -1, -1, -1}, pseudo_parse_section, pseudo_resolve_section, pseudo_emit_section, lwasm_insn_normal},
+ { "sect", { -1, -1, -1, -1}, pseudo_parse_section, pseudo_resolve_section, pseudo_emit_section, lwasm_insn_normal},
+ { "endsect", { -1, -1, -1, -1}, pseudo_parse_endsection,pseudo_resolve_endsection, pseudo_emit_endsection, lwasm_insn_normal},
+ { "endsection", { -1, -1, -1, -1}, pseudo_parse_endsection,pseudo_resolve_endsection, pseudo_emit_endsection, lwasm_insn_normal},
+
+ { "struct", { -1, -1, -1, -1}, pseudo_parse_struct, pseudo_resolve_struct, pseudo_emit_struct, lwasm_insn_normal},
+ { "ends", { -1, -1, -1, -1}, pseudo_parse_endstruct, pseudo_resolve_endstruct, pseudo_emit_endstruct, lwasm_insn_struct},
+ { "endstruct", { -1, -1, -1, -1}, pseudo_parse_endstruct, pseudo_resolve_endstruct, pseudo_emit_endstruct, lwasm_insn_struct},
+
+
+ { "pragma", { -1, -1, -1, -1}, pseudo_parse_pragma, pseudo_resolve_pragma, pseudo_emit_pragma, lwasm_insn_normal},
+ { "*pragma", { -1, -1, -1, -1}, pseudo_parse_starpragma,pseudo_resolve_starpragma, pseudo_emit_starpragma, lwasm_insn_normal},
+
+ // for os9 target
+ { "os9", { -1, -1, -1, -1 }, pseudo_parse_os9, pseudo_resolve_os9, pseudo_emit_os9, lwasm_insn_normal},
+ { "mod", { -1, -1, -1, -1 }, pseudo_parse_mod, pseudo_resolve_mod, pseudo_emit_mod, lwasm_insn_normal},
+ { "emod", { -1, -1, -1, -1 }, pseudo_parse_emod, pseudo_resolve_emod, pseudo_emit_emod, lwasm_insn_normal},
+
+ // for compatibility with gcc6809 output...
+
+ { ".area", { -1, -1, -1, -1}, pseudo_parse_section, pseudo_resolve_section, pseudo_emit_section, lwasm_insn_normal},
+ { ".globl", { -1, -1, -1, -1}, pseudo_parse_export, pseudo_resolve_export, pseudo_emit_export, lwasm_insn_normal},
+
+ { ".module", { -1, -1, -1, -1}, pseudo_parse_noop, pseudo_resolve_noop, pseudo_emit_noop, lwasm_insn_normal},
+
+ { ".4byte", { -1, -1, -1, -1}, pseudo_parse_fqb, pseudo_resolve_fqb, pseudo_emit_fqb, lwasm_insn_normal},
+ { ".quad", { -1, -1, -1, -1}, pseudo_parse_fqb, pseudo_resolve_fqb, pseudo_emit_fqb, lwasm_insn_normal},
+
+ { ".word", { -1, -1, -1, -1}, pseudo_parse_fdb, pseudo_resolve_fdb, pseudo_emit_fdb, lwasm_insn_normal},
+ { ".dw", { -1, -1, -1, -1}, pseudo_parse_fdb, pseudo_resolve_fdb, pseudo_emit_fdb, lwasm_insn_normal},
+
+ { ".byte", { -1, -1, -1, -1}, pseudo_parse_fcb, pseudo_resolve_fcb, pseudo_emit_fcb, lwasm_insn_normal},
+ { ".db", { -1, -1, -1, -1}, pseudo_parse_fcb, pseudo_resolve_fcb, pseudo_emit_fcb, lwasm_insn_normal},
+
+ { ".ascii", { -1, -1, -1, -1}, pseudo_parse_fcc, pseudo_resolve_fcc, pseudo_emit_fcc, lwasm_insn_normal},
+ { ".str", { -1, -1, -1, -1}, pseudo_parse_fcc, pseudo_resolve_fcc, pseudo_emit_fcc, lwasm_insn_normal},
+
+ { ".ascis", { -1, -1, -1, -1}, pseudo_parse_fcs, pseudo_resolve_fcs, pseudo_emit_fcs, lwasm_insn_normal},
+ { ".strs", { -1, -1, -1, -1}, pseudo_parse_fcs, pseudo_resolve_fcs, pseudo_emit_fcs, lwasm_insn_normal},
+
+ { ".asciz", { -1, -1, -1, -1}, pseudo_parse_fcn, pseudo_resolve_fcn, pseudo_emit_fcn, lwasm_insn_normal},
+ { ".strz", { -1, -1, -1, -1}, pseudo_parse_fcn, pseudo_resolve_fcn, pseudo_emit_fcn, lwasm_insn_normal},
+
+ { ".blkb", { -1, -1, -1, -1}, pseudo_parse_rmb, pseudo_resolve_rmb, pseudo_emit_rmb, lwasm_insn_struct},
+ { ".ds", { -1, -1, -1, -1}, pseudo_parse_rmb, pseudo_resolve_rmb, pseudo_emit_rmb, lwasm_insn_struct},
+ { ".rs", { -1, -1, -1, -1}, pseudo_parse_rmb, pseudo_resolve_rmb, pseudo_emit_rmb, lwasm_insn_struct},
+
+ // for compatibility
+ { ".end", { -1, -1, -1, -1 }, pseudo_parse_end, pseudo_resolve_end, pseudo_emit_end, lwasm_insn_normal},
+
+ // extra ops that are ignored because they are generally only for
+ // pretty printing the listing
+ { "nam", { -1, -1, -1, -1 }, pseudo_parse_noop, pseudo_resolve_noop, pseudo_emit_noop, lwasm_insn_normal},
+ { "pag", { -1, -1, -1, -1 }, pseudo_parse_noop, pseudo_resolve_noop, pseudo_emit_noop, lwasm_insn_normal},
+ { "ttl", { -1, -1, -1, -1 }, pseudo_parse_noop, pseudo_resolve_noop, pseudo_emit_noop, lwasm_insn_normal},
+ { ".bank", { -1, -1, -1, -1 }, pseudo_parse_noop, pseudo_resolve_noop, pseudo_emit_noop, lwasm_insn_normal},
+
+ // flag end of table
+ { NULL, { -1, -1, -1, -1 }, NULL, NULL, lwasm_insn_normal}
+};
diff -r 000000000000 -r 2c24602be78f lwasm/instab.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwasm/instab.h Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,58 @@
+/*
+instab.h
+Copyright © 2008 William Astle
+
+This file is part of LWASM.
+
+LWASM 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 3 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, see .
+
+
+Contains definitions for the instruction table
+*/
+
+#ifndef __instab_h_seen__
+#define __instab_h_seen__
+
+#include "lwasm.h"
+
+typedef struct
+{
+ char *opcode; /* the mneumonic */
+ int ops[4]; /* opcode values for up to four addr modes */
+ void (*parse)(asmstate_t *as, line_t *l, char **optr); /* parse operand for insn */
+ void (*resolve)(asmstate_t *as, line_t *l, int force); /* resolve instruction to code */
+ void (*emit)(asmstate_t *as, line_t *l); /* resolve instruction to code */
+ int flags; /* flag for this instruction */
+} instab_t;
+
+enum
+{
+ lwasm_insn_cond = 1, /* conditional instruction */
+ lwasm_insn_endm = 2, /* end of macro */
+ lwasm_insn_setsym = 4, /* insn sets symbol address */
+ lwasm_insn_is6309 = 8, /* insn is 6309 only */
+ lwasm_insn_struct = 16, /* insn allowed in a struct */
+ lwasm_insn_normal = 0
+};
+
+
+#define PARSEFUNC(fn) void (fn)(asmstate_t *as, line_t *l, char **p)
+#define RESOLVEFUNC(fn) void (fn)(asmstate_t *as, line_t *l, int force)
+#define EMITFUNC(fn) void (fn)(asmstate_t *as, line_t *l)
+
+#ifndef __instab_c_seen__
+extern instab_t instab[];
+#endif //__instab_c_seen__
+
+#endif //__instab_h_seen__
diff -r 000000000000 -r 2c24602be78f lwasm/list.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwasm/list.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,140 @@
+/*
+list.c
+
+Copyright © 2010 William Astle
+
+This file is part of LWTOOLS.
+
+LWTOOLS 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 3 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, see .
+*/
+
+#include
+#include
+
+#include
+#include
+
+#include "lwasm.h"
+#include "instab.h"
+
+void list_symbols(asmstate_t *as, FILE *of);
+
+/*
+Do listing
+*/
+void do_list(asmstate_t *as)
+{
+ line_t *cl;
+ FILE *of;
+ int i;
+
+ if (!(as -> flags & FLAG_LIST))
+ return;
+
+ if (as -> list_file)
+ of = fopen(as -> list_file, "w");
+ else
+ of = stdout;
+ if (!of)
+ {
+ fprintf(stderr, "Cannot open list file; list not generated\n");
+ return;
+ }
+ for (cl = as -> line_head; cl; cl = cl -> next)
+ {
+ if (cl -> len < 1)
+ {
+ if (cl -> soff >= 0)
+ {
+ fprintf(of, "%04X ", cl -> soff & 0xffff);
+ }
+ else if (cl -> dshow >= 0)
+ {
+ if (cl -> dsize == 1)
+ {
+ fprintf(of, " %02X ", cl -> dshow & 0xff);
+ }
+ else
+ {
+ fprintf(of, " %04X ", cl -> dshow & 0xff);
+ }
+ }
+ else if (cl -> dptr)
+ {
+ lw_expr_t te;
+ te = lw_expr_copy(cl -> dptr -> value);
+ as -> exportcheck = 1;
+ as -> csect = cl -> csect;
+ lwasm_reduce_expr(as, te);
+ as -> exportcheck = 0;
+ if (lw_expr_istype(te, lw_expr_type_int))
+ {
+ fprintf(of, " %04X ", lw_expr_intval(te) & 0xffff);
+ }
+ else
+ {
+ fprintf(of, " ???? ");
+ }
+ lw_expr_destroy(te);
+ }
+ else
+ {
+ fprintf(of, " ");
+ }
+ }
+ else
+ {
+ lw_expr_t te;
+ te = lw_expr_copy(cl -> addr);
+ as -> exportcheck = 1;
+ as -> csect = cl -> csect;
+ lwasm_reduce_expr(as, te);
+ as -> exportcheck = 0;
+// fprintf(of, "%s\n", lw_expr_print(te));
+ fprintf(of, "%04X ", lw_expr_intval(te) & 0xffff);
+ lw_expr_destroy(te);
+ for (i = 0; i < cl -> outputl && i < 8; i++)
+ {
+ fprintf(of, "%02X", cl -> output[i]);
+ }
+ for (; i < 8; i++)
+ {
+ fprintf(of, " ");
+ }
+ fprintf(of, " ");
+ }
+ /* the 34.34 below is deliberately chosen so that the start of the line text is at
+ a multiple of 8 from the start of the list line */
+ fprintf(of, "(%34.34s):%05d %s\n", cl -> linespec, cl -> lineno, cl -> ltext);
+ if (cl -> outputl > 8)
+ {
+ for (i = 8; i < cl -> outputl; i++)
+ {
+ if (i % 8 == 0)
+ {
+ if (i != 8)
+ fprintf(of, "\n ");
+ else
+ fprintf(of, " ");
+ }
+ fprintf(of, "%02X", cl -> output[i]);
+ }
+ if (i > 8)
+ fprintf(of, "\n");
+ }
+ }
+
+ if (as -> flags & FLAG_SYMBOLS)
+ list_symbols(as, of);
+}
diff -r 000000000000 -r 2c24602be78f lwasm/lwasm.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwasm/lwasm.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,866 @@
+/*
+lwasm.c
+
+Copyright © 2010 William Astle
+
+This file is part of LWTOOLS.
+
+LWTOOLS 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 3 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, see .
+*/
+
+#define ___lwasm_c_seen___
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include "lwasm.h"
+
+void lwasm_register_error(asmstate_t *as, line_t *l, const char *msg, ...);
+
+int lwasm_expr_exportable(asmstate_t *as, lw_expr_t expr)
+{
+ return 0;
+}
+
+int lwasm_expr_exportval(asmstate_t *as, lw_expr_t expr)
+{
+ return 0;
+}
+
+lw_expr_t lwasm_evaluate_var(char *var, void *priv)
+{
+ asmstate_t *as = (asmstate_t *)priv;
+ lw_expr_t e;
+ importlist_t *im;
+ struct symtabe *s;
+
+ s = lookup_symbol(as, as -> cl, var);
+ if (s)
+ {
+ e = lw_expr_build(lw_expr_type_special, lwasm_expr_syment, s);
+ return e;
+ }
+
+ // undefined here is undefied unless output is object
+ if (as -> output_format != OUTPUT_OBJ)
+ goto nomatch;
+
+ // check for import
+ for (im = as -> importlist; im; im = im -> next)
+ {
+ if (!strcmp(im -> symbol, var))
+ break;
+ }
+
+ // check for "undefined" to import automatically
+ if (!im && CURPRAGMA(as -> cl, PRAGMA_UNDEFEXTERN))
+ {
+ im = lw_alloc(sizeof(importlist_t));
+ im -> symbol = lw_strdup(var);
+ im -> next = as -> importlist;
+ as -> importlist = im;
+ }
+
+ if (!im)
+ goto nomatch;
+
+ e = lw_expr_build(lw_expr_type_special, lwasm_expr_import, im);
+ return e;
+
+nomatch:
+ if (as -> badsymerr)
+ {
+ lwasm_register_error(as, as -> cl, "Undefined symbol %s", var);
+ }
+ return NULL;
+}
+
+lw_expr_t lwasm_evaluate_special(int t, void *ptr, void *priv)
+{
+ switch (t)
+ {
+ case lwasm_expr_secbase:
+ {
+// sectiontab_t *s = priv;
+ asmstate_t *as = priv;
+ if (as -> exportcheck && ptr == as -> csect)
+ return lw_expr_build(lw_expr_type_int, 0);
+ return NULL;
+ }
+
+ case lwasm_expr_linelen:
+ {
+ line_t *cl = ptr;
+ if (cl -> len == -1)
+ return NULL;
+ return lw_expr_build(lw_expr_type_int, cl -> len);
+ }
+ break;
+
+ case lwasm_expr_lineaddr:
+ {
+ line_t *cl = ptr;
+ if (cl -> addr)
+ return lw_expr_copy(cl -> addr);
+ else
+ return NULL;
+ }
+
+ case lwasm_expr_syment:
+ {
+ struct symtabe *sym = ptr;
+ return lw_expr_copy(sym -> value);
+ }
+
+ case lwasm_expr_import:
+ {
+ return NULL;
+ }
+
+ case lwasm_expr_nextbp:
+ {
+ line_t *cl = ptr;
+ for (cl = cl -> next; cl; cl = cl -> next)
+ {
+ if (cl -> isbrpt)
+ break;
+ }
+ if (cl)
+ {
+ return lw_expr_copy(cl -> addr);
+ }
+ return NULL;
+ }
+
+ case lwasm_expr_prevbp:
+ {
+ line_t *cl = ptr;
+ for (cl = cl -> prev; cl; cl = cl -> prev)
+ {
+ if (cl -> isbrpt)
+ break;
+ }
+ if (cl)
+ {
+ return lw_expr_copy(cl -> addr);
+ }
+ return NULL;
+ }
+ }
+ return NULL;
+}
+
+void lwasm_register_error(asmstate_t *as, line_t *l, const char *msg, ...)
+{
+ lwasm_error_t *e;
+ va_list args;
+ char errbuff[1024];
+ int r;
+
+ if (!l)
+ return;
+
+ va_start(args, msg);
+
+ e = lw_alloc(sizeof(lwasm_error_t));
+
+ e -> next = l -> err;
+ l -> err = e;
+
+ as -> errorcount++;
+
+ r = vsnprintf(errbuff, 1024, msg, args);
+ e -> mess = lw_strdup(errbuff);
+
+ va_end(args);
+}
+
+void lwasm_register_warning(asmstate_t *as, line_t *l, const char *msg, ...)
+{
+ lwasm_error_t *e;
+ va_list args;
+ char errbuff[1024];
+ int r;
+
+ if (!l)
+ return;
+
+ va_start(args, msg);
+
+ e = lw_alloc(sizeof(lwasm_error_t));
+
+ e -> next = l -> err;
+ l -> err = e;
+
+ as -> errorcount++;
+
+ r = vsnprintf(errbuff, 1024, msg, args);
+ e -> mess = lw_strdup(errbuff);
+
+ va_end(args);
+}
+
+int lwasm_next_context(asmstate_t *as)
+{
+ int r;
+ r = as -> nextcontext;
+ as -> nextcontext++;
+ return r;
+}
+
+void lwasm_emit(line_t *cl, int byte)
+{
+ if (cl -> outputl < 0)
+ cl -> outputl = 0;
+
+ if (cl -> outputl == cl -> outputbl)
+ {
+ cl -> output = lw_realloc(cl -> output, cl -> outputbl + 8);
+ cl -> outputbl += 8;
+ }
+ cl -> output[cl -> outputl++] = byte & 0xff;
+
+ if (cl -> inmod)
+ {
+ asmstate_t *as = cl -> as;
+ // update module CRC
+ // this is a direct transliteration from the nitros9 asm source
+ // to C; it can, no doubt, be optimized for 32 bit processing
+ byte &= 0xff;
+
+ byte ^= (as -> crc)[0];
+ (as -> crc)[0] = (as -> crc)[1];
+ (as -> crc)[1] = (as -> crc)[2];
+ (as -> crc)[1] ^= (byte >> 7);
+ (as -> crc)[2] = (byte << 1);
+ (as -> crc)[1] ^= (byte >> 2);
+ (as -> crc)[2] ^= (byte << 6);
+ byte ^= (byte << 1);
+ byte ^= (byte << 2);
+ byte ^= (byte << 4);
+ if (byte & 0x80)
+ {
+ (as -> crc)[0] ^= 0x80;
+ (as -> crc)[2] ^= 0x21;
+ }
+ }
+}
+
+void lwasm_emitop(line_t *cl, int opc)
+{
+ if (opc > 0x100)
+ lwasm_emit(cl, opc >> 8);
+ lwasm_emit(cl, opc);
+}
+
+lw_expr_t lwasm_parse_term(char **p, void *priv)
+{
+ asmstate_t *as = priv;
+ int val;
+
+ if (!**p)
+ return NULL;
+
+ if (**p == '*' || (
+ **p == '.'
+ && !((*p)[1] >= 'A' && (*p)[1] <= 'Z')
+ && !((*p)[1] >= 'a' && (*p)[1] <= 'z')
+ && !((*p)[1] >= '0' && (*p)[1] <= '9')
+ ))
+ {
+ // special "symbol" for current line addr (*, .)
+ (*p)++;
+ return lw_expr_build(lw_expr_type_special, lwasm_expr_lineaddr, as -> cl);
+ }
+
+ // branch points
+ if (**p == '<')
+ {
+ (*p)++;
+ return lw_expr_build(lw_expr_type_special, lwasm_expr_prevbp, as -> cl);
+ }
+ if (**p == '>')
+ {
+ (*p)++;
+ return lw_expr_build(lw_expr_type_special, lwasm_expr_nextbp, as -> cl);
+ }
+
+ // double ascii constant
+ if (**p == '"')
+ {
+ int v;
+ (*p)++;
+ if (!**p)
+ return NULL;
+ if (!*((*p)+1))
+ return NULL;
+ v = (unsigned char)**p << 8 | (unsigned char)*((*p)+1);
+ (*p) += 2;
+ return lw_expr_build(lw_expr_type_int, v);
+ }
+
+ if (**p == '\'')
+ {
+ int v;
+
+ (*p)++;
+ if (!**p)
+ return NULL;
+
+ v = (unsigned char)**p;
+ (*p)++;
+ return lw_expr_build(lw_expr_type_int, v);
+ }
+
+ if (**p == '&')
+ {
+ // decimal constant
+ int v = 0;
+ (*p)++;
+
+ if (!strchr("0123456789", **p))
+ return NULL;
+
+ while (**p && strchr("0123456789", **p))
+ {
+ val = val * 10 + (**p - '0');
+ (*p)++;
+ }
+ return lw_expr_build(lw_expr_type_int, v);
+ }
+
+ if (**p == '%')
+ {
+ // binary constant
+ int v = 0;
+ (*p)++;
+
+ if (**p != '0' && **p != '1')
+ return NULL;
+
+ while (**p && (**p == '0' || **p == '1'))
+ {
+ val = val * 2 + (**p - '0');
+ (*p)++;
+ }
+ return lw_expr_build(lw_expr_type_int, v);
+ }
+
+ if (**p == '$')
+ {
+ // hexadecimal constant
+ int v = 0, v2;
+ (*p)++;
+ if (!strchr("0123456789abcdefABCDEF", **p))
+ return NULL;
+
+ while (**p && strchr("0123456789abcdefABCDEF", **p))
+ {
+ v2 = toupper(**p) - '0';
+ if (v2 > 9)
+ v2 -= 7;
+ v = v * 16 + v2;
+ (*p)++;
+ }
+ return lw_expr_build(lw_expr_type_int, v);
+ }
+
+ if (**p == '0' && (*((*p)+1) == 'x' || *((*p)+1) == 'X'))
+ {
+ // hexadecimal constant, C style
+ int v = 0, v2;
+ (*p)+=2;
+
+ if (!strchr("0123456789abcdefABCDEF", **p))
+ return NULL;
+
+ while (**p && strchr("0123456789abcdefABCDEF", **p))
+ {
+ v2 = toupper(**p) - '0';
+ if (v2 > 9)
+ v2 -= 7;
+ v = v * 16 + v2;
+ (*p)++;
+ }
+ return lw_expr_build(lw_expr_type_int, v);
+ }
+
+ if (**p == '@' && (*((*p)+1) >= '0' && *((*p)+1) <= '7'))
+ {
+ // octal constant
+ int v = 0;
+ (*p)++;
+
+ if (!strchr("01234567", **p))
+ return NULL;
+
+ while (**p && strchr("01234567", **p))
+ {
+ v = v * 8 + (**p - '0');
+ (*p)++;
+ }
+ return lw_expr_build(lw_expr_type_int, v);
+ }
+
+
+ // symbol or bare decimal or suffix constant here
+ do
+ {
+ int havedol = 0;
+ int l = 0;
+
+ while ((*p)[l] && strchr(SYMCHARS, (*p)[l]))
+ {
+ if ((*p)[l] == '$')
+ havedol = 1;
+ l++;
+ }
+ if (l == 0)
+ return NULL;
+
+ if ((*p)[l] == '{')
+ {
+ while ((*p)[l] && (*p)[l] != '}')
+ l++;
+ l++;
+ }
+
+ if (havedol || **p < '0' || **p > '9')
+ {
+ // have a symbol here
+ char *sym;
+ lw_expr_t term;
+
+ sym = lw_strndup(*p, l);
+ (*p) += l;
+ term = lw_expr_build(lw_expr_type_var, sym);
+ lw_free(sym);
+ return term;
+ }
+ } while (0);
+
+ if (!**p)
+ return NULL;
+
+ // we have a numeric constant here, either decimal or postfix base notation
+ {
+ int decval = 0, binval = 0, hexval = 0, octval = 0;
+ int valtype = 15; // 1 = bin, 2 = oct, 4 = dec, 8 = hex
+ int bindone = 0;
+ int val;
+ int dval;
+
+ while (1)
+ {
+ if (!**p || !strchr("0123456789ABCDEFabcdefqhoQHO", **p))
+ {
+ // we can legally be bin or decimal here
+ if (bindone)
+ {
+ // just finished a binary value
+ val = binval;
+ break;
+ }
+ else if (valtype & 4)
+ {
+ val = decval;
+ break;
+ }
+ else
+ {
+ // bad value
+ return NULL;
+ }
+ }
+
+ dval = toupper(**p);
+ (*p)++;
+
+ if (bindone)
+ {
+ // any characters past "B" means it is not binary
+ bindone = 0;
+ valtype &= 14;
+ }
+
+ switch (dval)
+ {
+ case 'Q':
+ case 'O':
+ if (valtype & 2)
+ {
+ val = octval;
+ valtype = -1;
+ break;
+ }
+ else
+ {
+ return NULL;
+ }
+ /* can't get here */
+
+ case 'H':
+ if (valtype & 8)
+ {
+ val = hexval;
+ valtype = -1;
+ break;
+ }
+ else
+ {
+ return NULL;
+ }
+ /* can't get here */
+
+ case 'B':
+ // this is a bit of a sticky one since B may be a
+ // hex number instead of the end of a binary number
+ // so it falls through to the digit case
+ if (valtype & 1)
+ {
+ // could still be binary of hex
+ bindone = 1;
+ valtype = 9;
+ }
+ /* fall through intented */
+
+ default:
+ // digit
+ dval -= '0';
+ if (dval > 9)
+ dval -= 7;
+ if (valtype & 8)
+ hexval = hexval * 16 + dval;
+ if (valtype & 4)
+ {
+ if (dval > 9)
+ valtype &= 11;
+ else
+ decval = decval * 10 + dval;
+ }
+ if (valtype & 2)
+ {
+ if (dval > 7)
+ valtype &= 13;
+ else
+ octval = octval * 8 + dval;
+ }
+ if (valtype & 1)
+ {
+ if (dval > 1)
+ valtype &= 14;
+ else
+ binval = binval * 2 + dval;
+ }
+ }
+ if (valtype == -1)
+ break;
+
+ // return if no more valid types
+ if (valtype == 0)
+ return NULL;
+
+ val = decval; // in case we fall through
+ }
+
+ // get here if we have a value
+ return lw_expr_build(lw_expr_type_int, val);
+ }
+ // can't get here
+}
+
+lw_expr_t lwasm_parse_expr(asmstate_t *as, char **p)
+{
+ lw_expr_t e;
+
+ e = lw_expr_parse(p, as);
+
+ return e;
+}
+
+int lwasm_reduce_expr(asmstate_t *as, lw_expr_t expr)
+{
+ lw_expr_simplify(expr, as);
+}
+
+void lwasm_save_expr(line_t *cl, int id, lw_expr_t expr)
+{
+ struct line_expr_s *e;
+
+ for (e = cl -> exprs; e; e = e -> next)
+ {
+ if (e -> id == id)
+ {
+ lw_expr_destroy(e -> expr);
+ e -> expr = expr;
+ return;
+ }
+ }
+
+ e = lw_alloc(sizeof(struct line_expr_s));
+ e -> expr = expr;
+ e -> id = id;
+ e -> next = cl -> exprs;
+ cl -> exprs = e;
+}
+
+lw_expr_t lwasm_fetch_expr(line_t *cl, int id)
+{
+ struct line_expr_s *e;
+
+ for (e = cl -> exprs; e; e = e -> next)
+ {
+ if (e -> id == id)
+ {
+ return e -> expr;
+ }
+ }
+ return NULL;
+}
+
+void skip_operand(char **p)
+{
+ for (; **p && !isspace(**p); (*p)++)
+ /* do nothing */ ;
+}
+
+int lwasm_emitexpr(line_t *l, lw_expr_t expr, int size)
+{
+ int v = 0;
+ int ol;
+
+ ol = l -> outputl;
+ if (ol == -1)
+ ol = 0;
+
+ if (lw_expr_istype(expr, lw_expr_type_int))
+ {
+ v = lw_expr_intval(expr);
+ }
+ // handle external/cross-section/incomplete references here
+ else
+ {
+ if (l -> as -> output_format == OUTPUT_OBJ)
+ {
+ reloctab_t *re;
+ lw_expr_t te;
+
+ if (size == 4)
+ {
+ // create a two part reference because lwlink doesn't
+ // support 32 bit references
+ lw_expr_t te2;
+ te = lw_expr_build(lw_expr_type_int, 0x10000);
+ te2 = lw_expr_build(lw_expr_type_oper, lw_expr_oper_divide, expr, te);
+ lw_expr_destroy(te);
+
+ re = lw_alloc(sizeof(reloctab_t));
+ re -> next = l -> csect -> reloctab;
+ l -> csect -> reloctab = re;
+ te = lw_expr_build(lw_expr_type_int, ol);
+ re -> offset = lw_expr_build(lw_expr_type_oper, lw_expr_oper_plus, l -> addr, te);
+ lw_expr_destroy(te);
+ lwasm_reduce_expr(l -> as, re -> offset);
+ re -> expr = te2;
+ re -> size = 2;
+
+ te = lw_expr_build(lw_expr_type_int, 0xFFFF);
+ te2 = lw_expr_build(lw_expr_type_oper, lw_expr_oper_bwand, expr, te);
+ lw_expr_destroy(te);
+
+ re = lw_alloc(sizeof(reloctab_t));
+ re -> next = l -> csect -> reloctab;
+ l -> csect -> reloctab = re;
+ te = lw_expr_build(lw_expr_type_int, ol + 2);
+ re -> offset = lw_expr_build(lw_expr_type_oper, lw_expr_oper_plus, l -> addr, te);
+ lw_expr_destroy(te);
+ lwasm_reduce_expr(l -> as, re -> offset);
+ re -> expr = te2;
+ re -> size = 2;
+ }
+ else
+ {
+ // add "expression" record to section table
+ re = lw_alloc(sizeof(reloctab_t));
+ re -> next = l -> csect -> reloctab;
+ l -> csect -> reloctab = re;
+ te = lw_expr_build(lw_expr_type_int, ol);
+ re -> offset = lw_expr_build(lw_expr_type_oper, lw_expr_oper_plus, l -> addr, te);
+ lw_expr_destroy(te);
+ lwasm_reduce_expr(l -> as, re -> offset);
+ re -> size = size;
+ re -> expr = lw_expr_copy(expr);
+ }
+ for (v = 0; v < size; v++)
+ lwasm_emit(l, 0);
+ return 0;
+ }
+ lwasm_register_error(l -> as, l, "Expression not fully resolved");
+ return -1;
+ }
+
+ switch (size)
+ {
+ case 4:
+ lwasm_emit(l, v >> 24);
+ lwasm_emit(l, v >> 16);
+ /* fallthrough intended */
+
+ case 2:
+ lwasm_emit(l, v >> 8);
+ /* fallthrough intended */
+
+ case 1:
+ lwasm_emit(l, v);
+ }
+
+ return 0;
+}
+
+int lwasm_lookupreg2(const char *regs, char **p)
+{
+ int rval = 0;
+
+ while (*regs)
+ {
+ if (toupper(**p) == *regs)
+ {
+ if (regs[1] == ' ' && !isalpha(*(*p + 1)))
+ break;
+ if (toupper(*(*p + 1)) == regs[1])
+ break;
+ }
+ regs += 2;
+ rval++;
+ }
+ if (!*regs)
+ return -1;
+ if (regs[1] == ' ')
+ (*p)++;
+ else
+ (*p) += 2;
+ return rval;
+}
+
+int lwasm_lookupreg3(const char *regs, char **p)
+{
+ int rval = 0;
+
+ while (*regs)
+ {
+ if (toupper(**p) == *regs)
+ {
+ if (regs[1] == ' ' && !isalpha(*(*p + 1)))
+ break;
+ if (toupper(*(*p + 1)) == regs[1])
+ {
+ if (regs[2] == ' ' && !isalpha(*(*p + 2)))
+ break;
+ if (toupper(*(*p + 2)) == regs[2])
+ break;
+ }
+ }
+ regs += 3;
+ rval++;
+ }
+ if (!*regs)
+ return -1;
+ if (regs[1] == ' ')
+ (*p)++;
+ else if (regs[2] == ' ')
+ (*p) += 2;
+ else
+ (*p) += 3;
+ return rval;
+}
+
+void lwasm_show_errors(asmstate_t *as)
+{
+ line_t *cl;
+ lwasm_error_t *e;
+
+ for (cl = as -> line_head; cl; cl = cl -> next)
+ {
+ if (!(cl -> err) && !(cl -> warn))
+ continue;
+ for (e = cl -> err; e; e = e -> next)
+ {
+ fprintf(stderr, "ERROR: %s\n", e -> mess);
+ }
+ for (e = cl -> warn; e; e = e -> next)
+ {
+ fprintf(stderr, "WARNING: %s\n", e -> mess);
+ }
+ fprintf(stderr, "%s:%05d %s\n\n", cl -> linespec, cl -> lineno, cl -> ltext);
+ }
+}
+
+/*
+this does any passes and other gymnastics that might be useful
+to see if an expression reduces early
+*/
+extern void do_pass3(asmstate_t *as);
+extern void do_pass4_aux(asmstate_t *as, int force);
+
+void lwasm_interim_reduce(asmstate_t *as)
+{
+ do_pass3(as);
+// do_pass4_aux(as, 0);
+}
+
+lw_expr_t lwasm_parse_cond(asmstate_t *as, char **p)
+{
+ lw_expr_t e;
+
+ debug_message(as, 250, "Parsing condition");
+ e = lwasm_parse_expr(as, p);
+ debug_message(as, 250, "COND EXPR: %s", lw_expr_print(e));
+
+ if (!e)
+ {
+ lwasm_register_error(as, as -> cl, "Bad expression");
+ return NULL;
+ }
+
+ /* we need to simplify the expression here */
+ debug_message(as, 250, "Doing interim reductions");
+ lwasm_interim_reduce(as);
+ debug_message(as, 250, "COND EXPR: %s", lw_expr_print(e));
+ debug_message(as, 250, "Reducing expression");
+ lwasm_reduce_expr(as, e);
+ debug_message(as, 250, "COND EXPR: %s", lw_expr_print(e));
+/* lwasm_reduce_expr(as, e);
+ debug_message(as, 250, "COND EXPR: %s", lw_expr_print(e));
+ lwasm_reduce_expr(as, e);
+ debug_message(as, 250, "COND EXPR: %s", lw_expr_print(e));
+ lwasm_reduce_expr(as, e);
+ debug_message(as, 250, "COND EXPR: %s", lw_expr_print(e));
+*/
+
+ lwasm_save_expr(as -> cl, 4242, e);
+
+ if (!lw_expr_istype(e, lw_expr_type_int))
+ {
+ debug_message(as, 250, "Non-constant expression");
+ lwasm_register_error(as, as -> cl, "Conditions must be constant on pass 1");
+ return NULL;
+ }
+ debug_message(as, 250, "Returning expression");
+ return e;
+}
diff -r 000000000000 -r 2c24602be78f lwasm/lwasm.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwasm/lwasm.h Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,317 @@
+/*
+lwasm.h
+
+Copyright © 2010 William Astle
+
+This file is part of LWTOOLS.
+
+LWTOOLS 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 3 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, see .
+*/
+
+#ifndef ___lwasm_h_seen___
+#define ___lwasm_h_seen___
+
+#include
+#include
+#include
+
+
+// these are allowed chars BELOW 0x80 for symbols
+// first is symbol start chars, second is anywhere in symbol
+#define SSYMCHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_@$"
+#define SYMCHARS SSYMCHARS ".?0123456789"
+
+typedef struct asmstate_s asmstate_t;
+
+enum
+{
+ lwasm_expr_linelen = 1, // length of ref'd line
+ lwasm_expr_lineaddr = 2, // addr of ref'd line
+ lwasm_expr_nextbp = 3, // next branch point
+ lwasm_expr_prevbp = 4, // previous branch point
+ lwasm_expr_syment = 5, // symbol table entry
+ lwasm_expr_import = 6, // symbol import entry
+ lwasm_expr_secbase = 7 // section base address
+};
+
+enum lwasm_output_e
+{
+ OUTPUT_DECB = 0, // DECB multirecord format
+ OUTPUT_RAW, // raw sequence of bytes
+ OUTPUT_OBJ, // proprietary object file format
+ OUTPUT_RAWREL, // raw bytes where ORG causes a SEEK in the file
+ OUTPUT_OS9 // os9 module target
+};
+
+enum lwasm_target_e
+{
+ TARGET_6309 = 0, // target 6309 CPU
+ TARGET_6809 // target 6809 CPU (no 6309 ops)
+};
+
+enum lwasm_flags_e
+{
+ FLAG_LIST = 0x0001,
+ FLAG_DEPEND = 0x0002,
+ FLAG_SYMBOLS = 0x004,
+ FLAG_NONE = 0
+};
+
+enum lwasm_pragmas_e
+{
+ PRAGMA_NONE = 0, // no pragmas in effect
+ PRAGMA_DOLLARNOTLOCAL = 0x0001, // dollar sign does not make a symbol local
+ PRAGMA_NOINDEX0TONONE = 0x0002, // do not change implicit 0,R to ,R
+ PRAGMA_UNDEFEXTERN = 0x0004, // undefined symbols are considered to be external
+ PRAGMA_CESCAPES = 0x0008, // allow C style escapes in fcc, fcs, fcn, etc.
+ PRAGMA_IMPORTUNDEFEXPORT = 0x0010, // imports symbol if undefined upon export
+ PRAGMA_PCASPCR = 0x0020 // treats ,PC as ,PCR instead of constant offset
+};
+
+
+enum
+{
+ section_flag_bss = 1, // BSS section
+ section_flag_none = 0 // no flags
+};
+
+typedef struct reloctab_s reloctab_t;
+struct reloctab_s
+{
+ lw_expr_t offset; // offset of relocation
+ int size; // size of relocation
+ lw_expr_t expr; // relocation expression
+ reloctab_t *next;
+};
+
+typedef struct sectiontab_s sectiontab_t;
+struct sectiontab_s
+{
+ char *name; // section name
+ int flags; // section flags;
+ lw_expr_t offset; // offset for next instance
+ int oblen; // size of section output
+ int obsize; // size of output buffer
+ unsigned char *obytes; // output buffer
+ reloctab_t *reloctab; // table of relocations
+ sectiontab_t *next;
+};
+
+typedef struct lwasm_error_s lwasm_error_t;
+struct lwasm_error_s
+{
+ char *mess; // actual error message
+ lwasm_error_t *next; // ptr to next error
+};
+
+struct line_expr_s
+{
+ lw_expr_t expr;
+ int id;
+ struct line_expr_s *next;
+};
+
+typedef struct line_s line_t;
+
+typedef struct exportlist_s exportlist_t;
+struct exportlist_s
+{
+ char *symbol; // symbol to export
+ struct symtabe *se; // symbol table entry
+ line_t *line; // line the export is on
+ exportlist_t *next; // next in the export list
+};
+
+typedef struct importlist_s importlist_t;
+struct importlist_s
+{
+ char *symbol; // symbol to import
+ importlist_t *next; // next in the import list
+};
+
+struct line_s
+{
+ lw_expr_t addr; // assembly address of the line
+ int len; // the "size" this line occupies (address space wise) (-1 if unknown)
+ int insn; // number of insn in insn table
+ int symset; // set if the line symbol was consumed by the instruction
+ char *sym; // symbol, if any, on the line
+ unsigned char *output; // output bytes
+ int outputl; // size of output
+ int outputbl; // size of output buffer
+ int dpval; // direct page value
+ lwasm_error_t *err; // list of errors
+ lwasm_error_t *warn; // list of errors
+ line_t *prev; // previous line
+ line_t *next; // next line
+ int inmod; // inside a module?
+ sectiontab_t *csect; // which section are we in?
+ struct line_expr_s *exprs; // expressions used during parsing
+ char *lstr; // string passed forward
+ int pb; // pass forward post byte
+ int lint; // pass forward integer
+ int lint2; // another pass forward integer
+ asmstate_t *as; // assembler state data ptr
+ int pragmas; // pragmas in effect for the line
+ int context; // the symbol context number
+ char *ltext; // line number
+ char *linespec; // line spec
+ int lineno; // line number
+ int soff; // struct offset (for listings)
+ int dshow; // data value to show (for listings)
+ int dsize; // set to 1 for 8 bit dshow value
+ int isbrpt; // set to 1 if this line is a branch point
+ struct symtabe *dptr; // symbol value to display
+};
+
+enum
+{
+ symbol_flag_set = 1, // symbol was used with "set"
+ symbol_flag_nocheck = 2, // do not check symbol characters
+ symbol_flag_none = 0 // no flags
+};
+
+struct symtabe
+{
+ char *symbol; // the name of the symbol
+ int context; // symbol context (-1 for global)
+ int version; // version of the symbol (for "set")
+ int flags; // flags for the symbol
+ sectiontab_t *section; // section the symbol is defined in
+ lw_expr_t value; // symbol value
+ struct symtabe *next; // next symbol in the table
+};
+
+typedef struct
+{
+ struct symtabe *head; // start of symbol table
+} symtab_t;
+
+typedef struct macrotab_s macrotab_t;
+struct macrotab_s
+{
+ char *name; // name of macro
+ char **lines; // macro lines
+ int numlines; // number lines in macro
+ macrotab_t *next; // next macro in list
+};
+
+typedef struct structtab_s structtab_t;
+typedef struct structtab_field_s structtab_field_t;
+
+struct structtab_field_s
+{
+ char *name; // structure field name - NULL for anonymous
+ int size; // structure field size
+ structtab_t *substruct; // sub structure if there is one
+ structtab_field_t *next; // next field entry
+};
+
+struct structtab_s
+{
+ char *name; // name of structure
+ int size; // number of bytes taken by struct
+ structtab_field_t *fields; // fields in the structure
+ structtab_t *next; // next structure
+};
+
+struct asmstate_s
+{
+ int output_format; // output format
+ int target; // assembly target
+ int debug_level; // level of debugging requested
+ FILE *debug_file; // FILE * to output debug messages to
+ int flags; // assembly flags
+ int pragmas; // pragmas currently in effect
+ int errorcount; // number of errors encountered
+ int inmacro; // are we in a macro?
+ int instruct; // are w in a structure?
+ int skipcond; // skipping a condition?
+ int skipcount; // depth of "skipping"
+ int skipmacro; // are we skipping in a macro?
+ int endseen; // have we seen an "end" pseudo?
+ int execaddr; // address from "end"
+ int inmod; // inside an os9 module?
+ unsigned char crc[3]; // crc accumulator
+ int badsymerr; // throw error on undef sym if set
+
+ line_t *line_head; // start of lines list
+ line_t *line_tail; // tail of lines list
+
+ line_t *cl; // current line pointer
+
+ sectiontab_t *csect; // current section
+
+ int context; // the current "context"
+ int nextcontext; // the next available context
+
+ symtab_t symtab; // meta data for the symbol table
+ macrotab_t *macros; // macro table
+ sectiontab_t *sections; // section table
+ exportlist_t *exportlist; // list of exported symbols
+ importlist_t *importlist; // list of imported symbols
+ char *list_file; // name of file to list to
+ char *output_file; // output file name
+ lw_stringlist_t input_files; // files to assemble
+ void *input_data; // opaque data used by the input system
+ lw_stringlist_t include_list; // include paths
+ lw_stack_t file_dir; // stack of the "current file" dir
+ lw_stack_t includelist;
+
+ structtab_t *structs; // defined structures
+ structtab_t *cstruct; // current structure
+
+ int exportcheck; // set if we need to collapse out the section base to 0
+};
+
+#ifndef ___symbol_c_seen___
+
+extern struct symtabe *register_symbol(asmstate_t *as, line_t *cl, char *sym, lw_expr_t value, int flags);
+extern struct symtabe *lookup_symbol(asmstate_t *as, line_t *cl, char *sym);
+
+#endif
+
+#ifndef ___lwasm_c_seen___
+
+extern void lwasm_register_error(asmstate_t *as, line_t *cl, const char *msg, ...);
+extern void lwasm_register_warning(asmstate_t *as, line_t *cl, const char *msg, ...);
+extern int lwasm_next_context(asmstate_t *as);
+extern void lwasm_emit(line_t *cl, int byte);
+extern void lwasm_emitop(line_t *cl, int opc);
+
+extern void lwasm_save_expr(line_t *cl, int id, lw_expr_t expr);
+extern lw_expr_t lwasm_fetch_expr(line_t *cl, int id);
+extern lw_expr_t lwasm_parse_expr(asmstate_t *as, char **p);
+extern int lwasm_emitexpr(line_t *cl, lw_expr_t expr, int s);
+
+extern void skip_operand(char **p);
+
+extern int lwasm_lookupreg2(const char *rlist, char **p);
+extern int lwasm_lookupreg3(const char *rlist, char **p);
+
+extern void lwasm_show_errors(asmstate_t *as);
+
+extern int lwasm_reduce_expr(asmstate_t *as, lw_expr_t expr);
+
+extern void debug_message(asmstate_t *as, int level, const char *fmt, ...);
+extern void dump_state(asmstate_t *as);
+
+extern lw_expr_t lwasm_parse_cond(asmstate_t *as, char **p);
+
+#endif
+
+#define OPLEN(op) (((op)>0xFF)?2:1)
+#define CURPRAGMA(l,p) (((l)->pragmas & (p)) ? 1 : 0)
+
+#endif /* ___lwasm_h_seen___ */
diff -r 000000000000 -r 2c24602be78f lwasm/macro.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwasm/macro.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,292 @@
+/*
+macro.c
+Copyright © 2008 William Astle
+
+This file is part of LWASM.
+
+LWASM 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 3 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, see .
+
+Contains stuff associated with macro processing
+*/
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include "lwasm.h"
+#include "input.h"
+#include "instab.h"
+
+PARSEFUNC(pseudo_parse_macro)
+{
+ macrotab_t *m;
+
+ l -> len = 0;
+
+ if (as -> skipcond)
+ {
+ as -> skipmacro = 1;
+ return;
+ }
+
+ if (as -> inmacro)
+ {
+ lwasm_register_error(as, l, "Attempt to define a macro inside a macro");
+ return;
+ }
+
+ if (!(l -> sym))
+ {
+ lwasm_register_error(as, l, "Missing macro name");
+ return;
+ }
+
+ for (m = as -> macros; m; m = m -> next)
+ {
+ if (!strcmp(m -> name, l -> sym))
+ break;
+ }
+ if (m)
+ {
+ lwasm_register_error(as, l, "Duplicate macro definition");
+ return;
+ }
+
+ m = lw_alloc(sizeof(macrotab_t));
+ m -> name = lw_strdup(l -> sym);
+ m -> next = as -> macros;
+ m -> lines = NULL;
+ m -> numlines = 0;
+ as -> macros = m;
+
+ while (**p && !isspace(**p))
+ (*p)++;
+
+ as -> inmacro = 1;
+}
+
+PARSEFUNC(pseudo_parse_endm)
+{
+ l -> len = 0;
+
+ if (as -> skipcond)
+ {
+ as -> skipmacro = 0;
+ return;
+ }
+
+ if (!as -> inmacro)
+ {
+ lwasm_register_error(as, l, "ENDM without MACRO");
+ return;
+ }
+
+ as -> inmacro = 0;
+
+ // a macro definition counts as a context break for local symbols
+ as -> context = lwasm_next_context(as);
+}
+
+// the current macro will ALWAYS be the first one in the table
+int add_macro_line(asmstate_t *as, char *optr)
+{
+ if (!as -> inmacro)
+ return 0;
+
+ as -> macros -> lines = lw_realloc(as -> macros -> lines, sizeof(char *) * (as -> macros -> numlines + 1));
+ as -> macros -> lines[as -> macros -> numlines] = lw_strdup(optr);
+ as -> macros -> numlines += 1;
+ return 1;
+}
+
+void macro_add_to_buff(char **buff, int *loc, int *len, char c)
+{
+ if (*loc == *len)
+ {
+ *buff = lw_realloc(*buff, *len + 32);
+ *len += 32;
+ }
+ (*buff)[(*loc)++] = c;
+}
+
+// this is just like a regular operation function
+/*
+macro args are referenced by "\n" where 1 <= n <= 9
+or by "\{n}"; a \ can be included by writing \\
+a comma separates argument but one can be included with "\,"
+whitespace ends argument list but can be included with "\ " or the like
+
+*/
+int expand_macro(asmstate_t *as, line_t *l, char **p, char *opc)
+{
+ int lc;
+ line_t *cl, *nl;
+ int oldcontext;
+ macrotab_t *m;
+
+ char **args = NULL; // macro arguments
+ int nargs = 0; // number of arguments
+
+ char *p2, *p3;
+
+ int bloc, blen;
+ char *linebuff;
+
+ for (m = as -> macros; m; m = m -> next)
+ {
+ if (!strcmp(opc, m -> name))
+ break;
+ }
+ // signal no macro expansion
+ if (!m)
+ return -1;
+
+ // save current symbol context for after macro expansion
+ oldcontext = as -> context;
+
+ cl = l;
+
+ as -> context = lwasm_next_context(as);
+
+ while (**p && !isspace(**p) && **p != ',')
+ {
+ p2 = *p;
+ while (*p2 && !isspace(*p2) && *p2 != ',')
+ {
+ if (*p2 == '\\')
+ {
+ if (p2[1])
+ p2++;
+ }
+ p2++;
+ }
+
+ // have arg here
+ args = lw_realloc(args, sizeof(char *) * (nargs + 1));
+ args[nargs] = lw_alloc(p2 - *p + 1);
+ args[nargs][p2 - *p] = '\0';
+ memcpy(args[nargs], *p, p2 - *p);
+ *p = p2;
+
+ // now collapse out "\" characters
+ for (p3 = p2 = args[nargs]; *p2; p2++, p3++)
+ {
+ if (*p2 == '\\' && p2[1])
+ {
+ p2++;
+ }
+ *p3 = *p2;
+ }
+ *p3 = '\0';
+
+ nargs++;
+ if (**p == ',')
+ (*p)++;
+ }
+
+
+ // now create a string for the macro
+ // and push it into the front of the input stack
+ bloc = blen = 0;
+ linebuff = NULL;
+
+ for (lc = 0; lc < m -> numlines; lc++)
+ {
+ for (p2 = m -> lines[lc]; *p2; p2++)
+ {
+ if (*p2 == '\\' && isdigit(p2[1]))
+ {
+ int n;
+
+ p2++;
+ n = *p2 - '0';
+ if (n == 0)
+ {
+ for (p3 = m -> name; *p3; p3++)
+ macro_add_to_buff(&linebuff, &bloc, &blen, *p3);
+ continue;
+ }
+ if (n < 1 || n > nargs)
+ continue;
+ for (p3 = args[n - 1]; *p3; p3++)
+ macro_add_to_buff(&linebuff, &bloc, &blen, *p3);
+ continue;
+ }
+ else if (*p2 == '{')
+ {
+ int n = 0, n2;
+ p2++;
+ while (*p2 && isdigit(*p2))
+ {
+ n2 = *p2 - '0';
+ if (n2 < 0 || n2 > 9)
+ n2 = 0;
+ n = n * 10 + n2;
+ p2++;
+ }
+ if (*p2 == '}')
+ p2++;
+
+ if (n == 0)
+ {
+ for (p3 = m -> name; *p3; p3++)
+ macro_add_to_buff(&linebuff, &bloc, &blen, *p3);
+ continue;
+ }
+ if (n < 1 || n > nargs)
+ continue;
+ for (p3 = args[n - 1]; *p3; p3++)
+ macro_add_to_buff(&linebuff, &bloc, &blen, *p3);
+ continue;
+ }
+ else
+ {
+ macro_add_to_buff(&linebuff, &bloc, &blen, *p2);
+ }
+ }
+
+ macro_add_to_buff(&linebuff, &bloc, &blen, '\n');
+
+ }
+
+ {
+ char ctcbuf[100];
+ char *p;
+ snprintf(ctcbuf, 100, "\001\001SETCONTEXT %d\n", oldcontext);
+ for (p = ctcbuf; *p; p++)
+ macro_add_to_buff(&linebuff, &bloc, &blen, *p);
+ }
+
+ // push the macro into the front of the stream
+ input_openstring(as, opc, linebuff);
+
+ lw_free(linebuff);
+
+ // clean up
+ if (args)
+ {
+ while (nargs)
+ {
+ lw_free(args[--nargs]);
+ }
+ lw_free(args);
+ }
+
+ // indicate a macro was expanded
+ return 0;
+}
diff -r 000000000000 -r 2c24602be78f lwasm/main.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwasm/main.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,268 @@
+/*
+main.c
+
+Copyright © 2010 William Astle
+
+This file is part of LWTOOLS.
+
+LWTOOLS 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 3 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, see .
+*/
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include "lwasm.h"
+#include "input.h"
+
+extern int parse_pragma_string(asmstate_t *as, char *str, int ignoreerr);
+
+/* command line option handling */
+const char *argp_program_version = "lwasm from " PACKAGE_STRING;
+const char *argp_program_bug_address = PACKAGE_BUGREPORT;
+char *program_name;
+
+static struct argp_option options[] =
+{
+ { "output", 'o', "FILE", 0, "Output to FILE"},
+ { "debug", 'd', "LEVEL", OPTION_ARG_OPTIONAL, "Set debug mode"},
+ { "format", 'f', "TYPE", 0, "Select output format: decb, raw, obj, os9"},
+ { "list", 'l', "FILE", OPTION_ARG_OPTIONAL, "Generate list [to FILE]"},
+ { "symbols", 's', 0, OPTION_ARG_OPTIONAL, "Generate symbol list in listing, no effect without --list"},
+ { "decb", 'b', 0, 0, "Generate DECB .bin format output, equivalent of --format=decb"},
+ { "raw", 'r', 0, 0, "Generate raw binary format output, equivalent of --format=raw"},
+ { "obj", 0x100, 0, 0, "Generate proprietary object file format for later linking, equivalent of --format=obj" },
+ { "depend", 0x101, 0, 0, "Output a dependency list to stdout; do not do any actual output though assembly is completed as usual" },
+ { "pragma", 'p', "PRAGMA", 0, "Set an assembler pragma to any value understood by the \"pragma\" pseudo op"},
+ { "6809", '9', 0, 0, "Set assembler to 6809 only mode" },
+ { "6309", '3', 0, 0, "Set assembler to 6309 mode (default)" },
+ { "includedir", 'I', "PATH", 0, "Add entry to include path" },
+ { 0 }
+};
+
+
+static error_t parse_opts(int key, char *arg, struct argp_state *state)
+{
+ asmstate_t *as = state -> input;
+
+ switch (key)
+ {
+ case 'I':
+ lw_stringlist_addstring(as -> include_list, arg);
+ break;
+
+ case 'o':
+ if (as -> output_file)
+ lw_free(as -> output_file);
+ as -> output_file = lw_strdup(arg);
+ break;
+
+ case 'd':
+ if (!arg)
+ as -> debug_level = 50;
+ else
+ as -> debug_level = atoi(arg);
+ break;
+
+ case 'l':
+ if (as -> list_file)
+ lw_free(as -> list_file);
+ if (!arg)
+ as -> list_file = NULL;
+ else
+ as -> list_file = lw_strdup(arg);
+ as -> flags |= FLAG_LIST;
+ break;
+
+ case 's':
+ as -> flags |= FLAG_SYMBOLS;
+ break;
+
+ case 'b':
+ as -> output_format = OUTPUT_DECB;
+ break;
+
+ case 'r':
+ as -> output_format = OUTPUT_RAW;
+ break;
+
+ case 0x100:
+ as -> output_format = OUTPUT_OBJ;
+ break;
+
+ case 0x101:
+ as -> flags |= FLAG_DEPEND;
+ break;
+
+ case 'f':
+ if (!strcasecmp(arg, "decb"))
+ as -> output_format = OUTPUT_DECB;
+ else if (!strcasecmp(arg, "raw"))
+ as -> output_format = OUTPUT_RAW;
+ else if (!strcasecmp(arg, "obj"))
+ as -> output_format = OUTPUT_OBJ;
+ else if (!strcasecmp(arg, "os9"))
+ {
+ as -> pragmas |= PRAGMA_DOLLARNOTLOCAL;
+ as -> output_format = OUTPUT_OS9;
+ }
+ else
+ {
+ fprintf(stderr, "Invalid output format: %s\n", arg);
+ exit(1);
+ }
+ break;
+
+ case 'p':
+ if (parse_pragma_string(as, arg, 0) == 0)
+ {
+ fprintf(stderr, "Unrecognized pragma string: %s\n", arg);
+ exit(1);
+ }
+ break;
+
+ case '9':
+ as -> target = TARGET_6809;
+ break;
+
+ case '3':
+ as -> target = TARGET_6309;
+ break;
+
+ case ARGP_KEY_END:
+ break;
+
+ case ARGP_KEY_ARG:
+ lw_stringlist_addstring(as -> input_files, arg);
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+static struct argp argp =
+{
+ options,
+ parse_opts,
+ " ",
+ "LWASM, a HD6309 and MC6809 cross-assembler"
+};
+
+/*
+main function; parse command line, set up assembler state, and run the
+assembler on the first file
+*/
+extern void do_pass1(asmstate_t *as);
+extern void do_pass2(asmstate_t *as);
+extern void do_pass3(asmstate_t *as);
+extern void do_pass4(asmstate_t *as);
+extern void do_pass5(asmstate_t *as);
+extern void do_pass6(asmstate_t *as);
+extern void do_pass7(asmstate_t *as);
+extern void do_output(asmstate_t *as);
+extern void do_list(asmstate_t *as);
+extern lw_expr_t lwasm_evaluate_special(int t, void *ptr, void *priv);
+extern lw_expr_t lwasm_evaluate_var(char *var, void *priv);
+extern lw_expr_t lwasm_parse_term(char **p, void *priv);
+
+struct passlist_s
+{
+ char *passname;
+ void (*fn)(asmstate_t *as);
+ int fordep;
+} passlist[] = {
+ { "parse", do_pass1, 1 },
+ { "symcheck", do_pass2 },
+ { "resolve1", do_pass3 },
+ { "resolve2", do_pass4 },
+ { "addressresolve", do_pass5 },
+ { "finalize", do_pass6 },
+ { "emit", do_pass7 },
+ { NULL, NULL }
+};
+
+
+int main(int argc, char **argv)
+{
+ int passnum;
+
+ /* assembler state */
+ asmstate_t asmstate = { 0 };
+ program_name = argv[0];
+
+ lw_expr_set_special_handler(lwasm_evaluate_special);
+ lw_expr_set_var_handler(lwasm_evaluate_var);
+ lw_expr_set_term_parser(lwasm_parse_term);
+
+ /* initialize assembler state */
+ asmstate.include_list = lw_stringlist_create();
+ asmstate.input_files = lw_stringlist_create();
+ asmstate.nextcontext = 1;
+
+ /* parse command line arguments */
+ argp_parse(&argp, argc, argv, 0, 0, &asmstate);
+
+ if (!asmstate.output_file)
+ {
+ asmstate.output_file = lw_strdup("a.out");
+ }
+
+ input_init(&asmstate);
+
+ for (passnum = 0; passlist[passnum].fn; passnum++)
+ {
+ if ((asmstate.flags & FLAG_DEPEND) && passlist[passnum].fordep == 0)
+ continue;
+ debug_message(&asmstate, 50, "Doing pass %d (%s)\n", passnum, passlist[passnum].passname);
+ (passlist[passnum].fn)(&asmstate);
+ debug_message(&asmstate, 50, "After pass %d (%s)\n", passnum, passlist[passnum].passname);
+ dump_state(&asmstate);
+
+ if (asmstate.errorcount > 0)
+ {
+ lwasm_show_errors(&asmstate);
+ exit(1);
+ }
+ }
+
+ if (asmstate.flags & FLAG_DEPEND)
+ {
+ // output dependencies
+ char *n;
+
+ while (n = lw_stack_pop(asmstate.includelist))
+ {
+ fprintf(stdout, "%s\n", n);
+ lw_free(n);
+ }
+ }
+ else
+ {
+ debug_message(&asmstate, 50, "Doing output");
+ do_output(&asmstate);
+ }
+
+ debug_message(&asmstate, 50, "Done assembly");
+
+ do_list(&asmstate);
+
+ exit(0);
+}
diff -r 000000000000 -r 2c24602be78f lwasm/os9.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwasm/os9.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,191 @@
+/*
+os9.c
+Copyright © 2009 William Astle
+
+This file is part of LWASM.
+
+LWASM 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 3 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, see .
+
+
+This file implements the various pseudo operations related to OS9 target
+*/
+#include
+#include
+#include
+#include
+
+#include
+
+#include "lwasm.h"
+#include "instab.h"
+
+
+// OS9 syscall
+PARSEFUNC(pseudo_parse_os9)
+{
+ lw_expr_t e;
+
+ if (as -> output_format != OUTPUT_OS9)
+ {
+ lwasm_register_error(as, l, "os9 directive only valid for OS9 target");
+ return;
+ }
+
+ // fetch immediate value
+ e = lwasm_parse_expr(as, p);
+ if (!e)
+ {
+ lwasm_register_error(as, l, "Bad operand");
+ return;
+ }
+ lwasm_save_expr(l, 0, e);
+ l -> len = 3;
+}
+
+EMITFUNC(pseudo_emit_os9)
+{
+ lw_expr_t e;
+
+ e = lwasm_fetch_expr(l, 0);
+
+ lwasm_emitop(l, 0x103f);
+ lwasm_emitexpr(l, e, 1);
+}
+
+PARSEFUNC(pseudo_parse_mod)
+{
+ lw_expr_t e;
+ int i;
+
+ if (as -> output_format != OUTPUT_OS9)
+ {
+ lwasm_register_error(as, l, "mod directive only valid for OS9 target");
+ return;
+ }
+
+ if (as -> inmod)
+ {
+ lwasm_register_error(as, l, "Already in a module!");
+ return;
+ }
+
+ // parse 6 expressions...
+ for (i = 0; i < 5; i++)
+ {
+ e = lwasm_parse_expr(as, p);
+ if (!e)
+ {
+ lwasm_register_error(as, l, "Bad operand");
+ return;
+ }
+
+ lwasm_save_expr(l, i, e);
+
+ if (**p != ',')
+ {
+ lwasm_register_error(as, l, "Bad operand");
+ return;
+ }
+ (*p)++;
+ }
+
+ e = lwasm_parse_expr(as, p);
+ if (!e)
+ {
+ lwasm_register_error(as, l, "Bad operand");
+ return;
+ }
+ lwasm_save_expr(l, 5, e);
+
+ l -> inmod = 1;
+
+ // we have an implicit ORG 0 with "mod"
+ lw_expr_destroy(l -> addr);
+ l -> addr = lw_expr_build(lw_expr_type_int, 0);
+
+ // init crc
+ as -> inmod = 1;
+}
+
+EMITFUNC(pseudo_emit_mod)
+{
+ lw_expr_t e1, e2, e3, e4;
+ int csum;
+
+ as -> crc[0] = 0xff;
+ as -> crc[1] = 0xff;
+ as -> crc[2] = 0xff;
+
+ // sync bytes
+ lwasm_emit(l, 0x87);
+ lwasm_emit(l, 0xcd);
+
+ // mod length
+ lwasm_emitexpr(l, e1 = lwasm_fetch_expr(l, 0), 2);
+
+ // name offset
+ lwasm_emitexpr(l, e2 = lwasm_fetch_expr(l, 1), 2);
+
+ // type
+ lwasm_emitexpr(l, e3 = lwasm_fetch_expr(l, 2), 1);
+
+ // flags/rev
+ lwasm_emitexpr(l, e4 = lwasm_fetch_expr(l, 3), 1);
+
+ // header check
+ csum = ~(0x87 ^ 0xCD ^(lw_expr_intval(e1) >> 8) ^ (lw_expr_intval(e1) & 0xff)
+ ^ (lw_expr_intval(e2) >> 8) ^ (lw_expr_intval(e2) & 0xff)
+ ^ lw_expr_intval(e3) ^ lw_expr_intval(e4));
+ lwasm_emit(l, csum);
+
+ // module type specific output
+ // note that these are handled the same for all so
+ // there need not be any special casing
+
+ // exec offset or fmgr name offset
+ lwasm_emitexpr(l, lwasm_fetch_expr(l, 4), 2);
+
+ // data size or drvr name offset
+ lwasm_emitexpr(l, lwasm_fetch_expr(l, 5), 2);
+}
+
+PARSEFUNC(pseudo_parse_emod)
+{
+ if (as -> output_format != OUTPUT_OS9)
+ {
+ lwasm_register_error(as, l, "emod directive only valid for OS9 target");
+ return;
+ }
+
+ if (!(as -> inmod))
+ {
+ lwasm_register_error(as, l, "not in a module!");
+ return;
+ }
+
+ as -> inmod = 0;
+}
+
+EMITFUNC(pseudo_emit_emod)
+{
+ unsigned char tcrc[3];
+
+ // don't mess with CRC!
+ tcrc[0] = as -> crc[0] ^ 0xff;
+ tcrc[1] = as -> crc[1] ^ 0xff;
+ tcrc[2] = as -> crc[2] ^ 0xff;
+ lwasm_emit(l, tcrc[0]);
+ lwasm_emit(l, tcrc[1]);
+ lwasm_emit(l, tcrc[2]);
+}
diff -r 000000000000 -r 2c24602be78f lwasm/output.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwasm/output.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,593 @@
+/*
+output.c
+Copyright © 2009, 2010 William Astle
+
+This file is part of LWASM.
+
+LWASM 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 3 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, see .
+
+
+Contains the code for actually outputting the assembled code
+*/
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include "lwasm.h"
+
+void write_code_raw(asmstate_t *as, FILE *of);
+void write_code_decb(asmstate_t *as, FILE *of);
+void write_code_rawrel(asmstate_t *as, FILE *of);
+void write_code_obj(asmstate_t *as, FILE *of);
+void write_code_os9(asmstate_t *as, FILE *of);
+
+// this prevents warnings about not using the return value of fwrite()
+#define writebytes(s, l, c, f) do { int r; r = fwrite((s), (l), (c), (f)); } while (0)
+
+void do_output(asmstate_t *as)
+{
+ FILE *of;
+
+ if (as -> errorcount > 0)
+ {
+ fprintf(stderr, "Not doing output due to assembly errors.\n");
+ return;
+ }
+
+ of = fopen(as -> output_file, "wb");
+ if (!of)
+ {
+ fprintf(stderr, "Cannot open '%s' for output", as -> output_file);
+ perror("");
+ return;
+ }
+
+ switch (as -> output_format)
+ {
+ case OUTPUT_RAW:
+ write_code_raw(as, of);
+ break;
+
+ case OUTPUT_DECB:
+ write_code_decb(as, of);
+ break;
+
+ case OUTPUT_RAWREL:
+ write_code_rawrel(as, of);
+ break;
+
+ case OUTPUT_OBJ:
+ write_code_obj(as, of);
+ break;
+
+ case OUTPUT_OS9:
+ write_code_os9(as, of);
+ break;
+
+ default:
+ fprintf(stderr, "BUG: unrecognized output format when generating output file\n");
+ fclose(of);
+ unlink(as -> output_file);
+ return;
+ }
+
+ fclose(of);
+}
+
+/*
+rawrel output treats an ORG directive as an offset from the start of the
+file. Undefined results will occur if an ORG directive moves the output
+pointer backward. This particular implementation uses "fseek" to handle
+ORG requests and to skip over RMBs.
+
+This simple brain damanged method simply does an fseek before outputting
+each instruction.
+*/
+void write_code_rawrel(asmstate_t *as, FILE *of)
+{
+ line_t *cl;
+
+ for (cl = as -> line_head; cl; cl = cl -> next)
+ {
+ if (cl -> outputl <= 0)
+ continue;
+
+ fseek(of, lw_expr_intval(cl -> addr), SEEK_SET);
+ writebytes(cl -> output, cl -> outputl, 1, of);
+ }
+}
+
+/*
+raw merely writes all the bytes directly to the file as is. ORG is just a
+reference for the assembler to handle absolute references. Multiple ORG
+statements will produce mostly useless results
+*/
+void write_code_raw(asmstate_t *as, FILE *of)
+{
+ line_t *cl;
+
+ for (cl = as -> line_head; cl; cl = cl -> next)
+ {
+ if (cl -> len > 0 && cl -> outputl == 0)
+ {
+ int i;
+ for (i = 0; i < cl -> len; i++)
+ writebytes("\0", 1, 1, of);
+ continue;
+ }
+ else if (cl -> outputl > 0)
+ writebytes(cl -> output, cl -> outputl, 1, of);
+ }
+}
+
+
+/*
+OS9 target also just writes all the bytes in order. No need for anything
+else.
+*/
+void write_code_os9(asmstate_t *as, FILE *of)
+{
+ line_t *cl;
+
+ for (cl = as -> line_head; cl; cl = cl -> next)
+ {
+ if (cl -> inmod == 0)
+ continue;
+ if (cl -> len > 0 && cl -> outputl == 0)
+ {
+ int i;
+ for (i = 0; i < cl -> len; i++)
+ writebytes("\0", 1, 1, of);
+ continue;
+ }
+ else if (cl -> outputl > 0)
+ writebytes(cl -> output, cl -> outputl, 1, of);
+ }
+}
+
+void write_code_decb(asmstate_t *as, FILE *of)
+{
+ long preambloc;
+ line_t *cl;
+ int blocklen = -1;
+ int nextcalc = -1;
+ unsigned char outbuf[5];
+ int caddr;
+
+ for (cl = as -> line_head; cl; cl = cl -> next)
+ {
+ if (cl -> outputl < 0)
+ continue;
+ caddr = lw_expr_intval(cl -> addr);
+ if (caddr != nextcalc && cl -> outputl > 0)
+ {
+ // need preamble here
+ if (blocklen > 0)
+ {
+ // update previous preamble if needed
+ fseek(of, preambloc, SEEK_SET);
+ outbuf[0] = (blocklen >> 8) & 0xFF;
+ outbuf[1] = blocklen & 0xFF;
+ writebytes(outbuf, 2, 1, of);
+ fseek(of, 0, SEEK_END);
+ }
+ blocklen = 0;
+ nextcalc = caddr;
+ outbuf[0] = 0x00;
+ outbuf[1] = 0x00;
+ outbuf[2] = 0x00;
+ outbuf[3] = (nextcalc >> 8) & 0xFF;
+ outbuf[4] = nextcalc & 0xFF;
+ preambloc = ftell(of) + 1;
+ writebytes(outbuf, 5, 1, of);
+ }
+ nextcalc += cl -> outputl;
+ writebytes(cl -> output, cl -> outputl, 1, of);
+ blocklen += cl -> outputl;
+ }
+ if (blocklen > 0)
+ {
+ fseek(of, preambloc, SEEK_SET);
+ outbuf[0] = (blocklen >> 8) & 0xFF;
+ outbuf[1] = blocklen & 0xFF;
+ writebytes(outbuf, 2, 1, of);
+ fseek(of, 0, SEEK_END);
+ }
+
+ // now write postamble
+ outbuf[0] = 0xFF;
+ outbuf[1] = 0x00;
+ outbuf[2] = 0x00;
+ outbuf[3] = (as -> execaddr >> 8) & 0xFF;
+ outbuf[4] = (as -> execaddr) & 0xFF;
+ writebytes(outbuf, 5, 1, of);
+}
+
+void write_code_obj_sbadd(sectiontab_t *s, unsigned char b)
+{
+ if (s -> oblen >= s -> obsize)
+ {
+ s -> obytes = lw_realloc(s -> obytes, s -> obsize + 128);
+ s -> obsize += 128;
+ }
+ s -> obytes[s -> oblen] = b;
+ s -> oblen += 1;
+}
+
+
+int write_code_obj_expraux(lw_expr_t e, void *of)
+{
+ int tt;
+ int v;
+ unsigned char buf[16];
+
+ tt = lw_expr_type(e);
+
+ switch (tt)
+ {
+ case lw_expr_type_oper:
+ buf[0] = 0x04;
+ switch (lw_expr_whichop(e))
+ {
+ case lw_expr_oper_plus:
+ buf[1] = 0x01;
+ break;
+
+ case lw_expr_oper_minus:
+ buf[1] = 0x02;
+ break;
+
+ case lw_expr_oper_times:
+ buf[1] = 0x03;
+ break;
+
+ case lw_expr_oper_divide:
+ buf[1] = 0x04;
+ break;
+
+ case lw_expr_oper_mod:
+ buf[1] = 0x05;
+ break;
+
+ case lw_expr_oper_intdiv:
+ buf[1] = 0x06;
+ break;
+
+ case lw_expr_oper_bwand:
+ buf[1] = 0x07;
+ break;
+
+ case lw_expr_oper_bwor:
+ buf[1] = 0x08;
+ break;
+
+ case lw_expr_oper_bwxor:
+ buf[1] = 0x09;
+ break;
+
+ case lw_expr_oper_and:
+ buf[1] = 0x0A;
+ break;
+
+ case lw_expr_oper_or:
+ buf[1] = 0x0B;
+ break;
+
+ case lw_expr_oper_neg:
+ buf[1] = 0x0C;
+ break;
+
+ case lw_expr_oper_com:
+ buf[1] = 0x0D;
+ break;
+
+ default:
+ buf[1] = 0xff;
+ }
+ writebytes(buf, 2, 1, of);
+ return 0;
+
+ case lw_expr_type_int:
+ v = lw_expr_intval(e);
+ buf[0] = 0x01;
+ buf[1] = (v >> 8) & 0xff;
+ buf[2] = v & 0xff;
+ writebytes(buf, 3, 1, of);
+ return 0;
+
+ case lw_expr_type_special:
+ v = lw_expr_specint(e);
+ switch (v)
+ {
+ case lwasm_expr_secbase:
+ {
+ // replaced with a synthetic symbol
+ sectiontab_t *se;
+ se = lw_expr_specptr(e);
+
+ writebytes("\x03\x02", 2, 1, of);
+ writebytes(se -> name, strlen(se -> name) + 1, 1, of);
+ return 0;
+ }
+ case lwasm_expr_import:
+ {
+ importlist_t *ie;
+ ie = lw_expr_specptr(e);
+ buf[0] = 0x02;
+ writebytes(buf, 1, 1, of);
+ writebytes(ie -> symbol, strlen(ie -> symbol) + 1, 1, of);
+ return 0;
+ }
+ case lwasm_expr_syment:
+ {
+ struct symtabe *se;
+ se = lw_expr_specptr(e);
+ buf[0] = 0x03;
+ writebytes(buf, 1, 1, of);
+ writebytes(se -> symbol, strlen(se -> symbol), 1, of);
+ if (se -> context != -1)
+ {
+ sprintf(buf, "\x01%d", se -> context);
+ writebytes(buf, strlen(buf), 1, of);
+ }
+ writebytes("", 1, 1, of);
+ return 0;
+ }
+ }
+
+ default:
+ // unrecognized term type - replace with integer 0
+// fprintf(stderr, "Unrecognized term type: %s\n", lw_expr_print(e));
+ buf[0] = 0x01;
+ buf[1] = 0x00;
+ buf[2] = 0x00;
+ writebytes(buf, 3, 1, of);
+ break;
+ }
+ return 0;
+}
+
+
+void write_code_obj(asmstate_t *as, FILE *of)
+{
+ line_t *l;
+ sectiontab_t *s;
+ reloctab_t *re;
+ exportlist_t *ex;
+ struct symtabe *se;
+
+ int i;
+ unsigned char buf[16];
+
+ // output the magic number and file header
+ // the 8 is NOT an error
+ writebytes("LWOBJ16", 8, 1, of);
+
+ // run through the entire system and build the byte streams for each
+ // section; at the same time, generate a list of "local" symbols to
+ // output for each section
+ // NOTE: for "local" symbols, we will append \x01 and the ascii string
+ // of the context identifier (so sym in context 1 would be "sym\x011"
+ // we can do this because the linker can handle symbols with any
+ // character other than NUL.
+ // also we will generate a list of incomplete references for each
+ // section along with the actual definition that will be output
+
+ // once all this information is generated, we will output each section
+ // to the file
+
+ // NOTE: we build everything in memory then output it because the
+ // assembler accepts multiple instances of the same section but the
+ // linker expects only one instance of each section in the object file
+ // so we need to collect all the various pieces of a section together
+ // (also, the assembler treated multiple instances of the same section
+ // as continuations of previous sections so we would need to collect
+ // them together anyway.
+
+ for (l = as -> line_head; l; l = l -> next)
+ {
+ if (l -> csect)
+ {
+ // we're in a section - need to output some bytes
+ if (l -> outputl > 0)
+ for (i = 0; i < l -> outputl; i++)
+ write_code_obj_sbadd(l -> csect, l -> output[i]);
+ else if (l -> outputl == 0 || l -> outputl == -1)
+ for (i = 0; i < l -> len; i++)
+ write_code_obj_sbadd(l -> csect, 0);
+ }
+ }
+
+ // run through the sections
+ for (s = as -> sections; s; s = s -> next)
+ {
+ // write the name
+ writebytes(s -> name, strlen(s -> name) + 1, 1, of);
+
+ // write the flags
+ if (s -> flags & section_flag_bss)
+ writebytes("\x01", 1, 1, of);
+
+ // indicate end of flags - the "" is NOT an error
+ writebytes("", 1, 1, of);
+
+ // now the local symbols
+
+ // a symbol for section base address
+ writebytes("\x02", 1, 1, of);
+ writebytes(s -> name, strlen(s -> name) + 1, 1, of);
+ // address 0; "\0" is not an error
+ writebytes("\0", 2, 1, of);
+ for (se = as -> symtab.head; se; se = se -> next)
+ {
+ lw_expr_t te;
+
+ debug_message(as, 200, "Consider symbol %s (%p) for export in section %p", se -> symbol, se -> section, s);
+
+ // ignore symbols not in this section
+ if (se -> section != s)
+ continue;
+
+ debug_message(as, 200, " In section");
+
+ if (se -> flags & symbol_flag_set)
+ continue;
+
+ debug_message(as, 200, " Not symbol_flag_set");
+
+ te = lw_expr_copy(se -> value);
+ debug_message(as, 200, " Value=%s", lw_expr_print(te));
+ as -> exportcheck = 1;
+ as -> csect = s;
+ lwasm_reduce_expr(as, te);
+ as -> exportcheck = 0;
+
+ debug_message(as, 200, " Value2=%s", lw_expr_print(te));
+
+ // don't output non-constant symbols
+ if (!lw_expr_istype(te, lw_expr_type_int))
+ {
+ lw_expr_destroy(te);
+ continue;
+ }
+
+ writebytes(se -> symbol, strlen(se -> symbol), 1, of);
+ if (se -> context >= 0)
+ {
+ writebytes("\x01", 1, 1, of);
+ sprintf(buf, "%d", se -> context);
+ writebytes(buf, strlen(buf), 1, of);
+ }
+ // the "" is NOT an error
+ writebytes("", 1, 1, of);
+
+ // write the address
+ buf[0] = (lw_expr_intval(te) >> 8) & 0xff;
+ buf[1] = lw_expr_intval(te) & 0xff;
+ writebytes(buf, 2, 1, of);
+ lw_expr_destroy(te);
+ }
+ // flag end of local symbol table - "" is NOT an error
+ writebytes("", 1, 1, of);
+
+ // now the exports -- FIXME
+ for (ex = as -> exportlist; ex; ex = ex -> next)
+ {
+ int eval;
+ lw_expr_t te;
+ line_t tl;
+
+ if (ex -> se == NULL)
+ continue;
+ if (ex -> se -> section != s)
+ continue;
+ te = lw_expr_copy(ex -> se -> value);
+ as -> csect = ex -> se -> section;
+ as -> exportcheck = 1;
+ tl.as = as;
+ as -> cl = &tl;
+ lwasm_reduce_expr(as, te);
+ as -> exportcheck = 0;
+ as -> cl = NULL;
+ if (!lw_expr_istype(te, lw_expr_type_int))
+ {
+ lw_expr_destroy(te);
+ continue;
+ }
+ eval = lw_expr_intval(te);
+ lw_expr_destroy(te);
+ writebytes(ex -> symbol, strlen(ex -> symbol) + 1, 1, of);
+ buf[0] = (eval >> 8) & 0xff;
+ buf[1] = eval & 0xff;
+ writebytes(buf, 2, 1, of);
+ }
+
+ // flag end of exported symbols - "" is NOT an error
+ writebytes("", 1, 1, of);
+
+ // FIXME - relocation table
+ for (re = s -> reloctab; re; re = re -> next)
+ {
+ int offset;
+ lw_expr_t te;
+ line_t tl;
+
+ tl.as = as;
+ as -> cl = &tl;
+ as -> csect = s;
+ as -> exportcheck = 1;
+
+ if (re -> expr == NULL)
+ {
+ // this is an error but we'll simply ignore it
+ // and not output this expression
+ continue;
+ }
+
+ // work through each term in the expression and output
+ // the proper equivalent to the object file
+ if (re -> size == 1)
+ {
+ // flag an 8 bit relocation (low 8 bits will be used)
+ buf[0] = 0xFF;
+ buf[1] = 0x01;
+ writebytes(buf, 2, 1, of);
+ }
+
+ te = lw_expr_copy(re -> offset);
+ lwasm_reduce_expr(as, te);
+ if (!lw_expr_istype(te, lw_expr_type_int))
+ {
+ lw_expr_destroy(te);
+ continue;
+ }
+ offset = lw_expr_intval(te);
+ lw_expr_destroy(te);
+
+ // output expression
+ lw_expr_testterms(re -> expr, write_code_obj_expraux, of);
+
+ // flag end of expressions
+ writebytes("", 1, 1, of);
+
+ // write the offset
+ buf[0] = (offset >> 8) & 0xff;
+ buf[1] = offset & 0xff;
+ writebytes(buf, 2, 1, of);
+ }
+
+ // flag end of incomplete references list
+ writebytes("", 1, 1, of);
+
+ // now blast out the code
+
+ // length
+ buf[0] = s -> oblen >> 8 & 0xff;
+ buf[1] = s -> oblen & 0xff;
+ writebytes(buf, 2, 1, of);
+
+ if (!(s -> flags & section_flag_bss))
+ {
+ writebytes(s -> obytes, s -> oblen, 1, of);
+ }
+ }
+
+ // flag no more sections
+ // the "" is NOT an error
+ writebytes("", 1, 1, of);
+}
diff -r 000000000000 -r 2c24602be78f lwasm/pass1.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwasm/pass1.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,316 @@
+/*
+pass1.c
+
+Copyright © 2010 William Astle
+
+This file is part of LWTOOLS.
+
+LWTOOLS 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 3 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, see .
+*/
+
+#include
+#include
+
+#include
+#include
+
+#include "lwasm.h"
+#include "instab.h"
+#include "input.h"
+
+extern int expand_macro(asmstate_t *as, line_t *l, char **p, char *opc);
+extern int expand_struct(asmstate_t *as, line_t *l, char **p, char *opc);
+
+/*
+pass 1: parse the lines
+
+line format:
+
+[] [ ]
+
+If is followed by a :, whitespace may precede the symbol
+
+A line may optionally start with a number which must not be preceded by
+white space and must be followed by a single whitespace character. After
+that whitespace character, the line is parsed as if it had no line number.
+
+*/
+void do_pass1(asmstate_t *as)
+{
+ char *line;
+ line_t *cl;
+ char *p1;
+ int stspace;
+ char *tok, *sym;
+ int opnum;
+ int lc = 1;
+ for (;;)
+ {
+ sym = NULL;
+ line = input_readline(as);
+ if (!line)
+ break;
+ if (line[0] == 1 && line[1] == 1)
+ {
+ // special internal directive
+ // these DO NOT appear in the output anywhere
+ // they are generated by the parser to pass information
+ // forward
+ for (p1 = line + 2; *p1 && !isspace(*p1); p1++)
+ /* do nothing */ ;
+ *p1++ = '\0';
+ if (!strcmp(line + 2, "SETCONTEXT"))
+ {
+ as -> context = strtol(p1, NULL, 10);
+ }
+ lw_free(line);
+ lc = 1;
+ continue;
+ }
+ debug_message(as, 75, "Read line: %s", line);
+
+ cl = lw_alloc(sizeof(line_t));
+ memset(cl, 0, sizeof(line_t));
+ cl -> outputl = -1;
+ cl -> linespec = lw_strdup(input_curspec(as));
+ cl -> prev = as -> line_tail;
+ cl -> insn = -1;
+ cl -> as = as;
+ cl -> inmod = as -> inmod;
+ cl -> csect = as -> csect;
+ cl -> pragmas = as -> pragmas;
+ cl -> context = as -> context;
+ cl -> ltext = lw_strdup(line);
+ cl -> soff = -1;
+ cl -> dshow = -1;
+ cl -> dsize = 0;
+ cl -> dptr = NULL;
+ cl -> isbrpt = 0;
+ as -> cl = cl;
+ if (!as -> line_tail)
+ {
+ as -> line_head = cl;
+ cl -> addr = lw_expr_build(lw_expr_type_int, 0);
+ }
+ else
+ {
+ lw_expr_t te;
+
+ cl -> lineno = as -> line_tail -> lineno + 1;
+ as -> line_tail -> next = cl;
+
+ // set the line address
+ te = lw_expr_build(lw_expr_type_special, lwasm_expr_linelen, cl -> prev);
+ cl -> addr = lw_expr_build(lw_expr_type_oper, lw_expr_oper_plus, cl -> prev -> addr, te);
+ lw_expr_destroy(te);
+ lwasm_reduce_expr(as, cl -> addr);
+// lw_expr_simplify(cl -> addr, as);
+
+ // carry DP value forward
+ cl -> dpval = cl -> prev -> dpval;
+
+ }
+ if (!lc && strcmp(cl -> linespec, cl -> prev -> linespec))
+ lc = 1;
+ if (lc)
+ {
+ cl -> lineno = 1;
+ lc = 0;
+ }
+ as -> line_tail = cl;
+ // blank lines don't count for anything
+ // except a local symbol context break
+ if (!*line)
+ {
+ as -> context = lwasm_next_context(as);
+ goto nextline;
+ }
+
+ // skip comments
+ // commends do not create a context break
+ if (*line == '*' || *line == ';' || *line == '#')
+ goto nextline;
+
+ p1 = line;
+ if (isdigit(*p1))
+ {
+ // skip line number
+ while (*p1 && isdigit(*p1))
+ p1++;
+ if (!*p1 && !isspace(*p1))
+ p1 = line;
+ else if (*p1 && !isspace(*p1))
+ p1 = line;
+ else if (*p1 && isspace(*p1))
+ p1++;
+ }
+
+ // blank line - context break
+ if (!*p1)
+ {
+ as -> context = lwasm_next_context(as);
+ goto nextline;
+ }
+
+ // comment - no context break
+ if (*p1 == '*' || *p1 == ';' || *p1 == '#')
+ goto nextline;
+
+ if (isspace(*p1))
+ {
+ for (; *p1 && isspace(*p1); p1++)
+ /* do nothing */ ;
+ stspace = 1;
+ }
+ else
+ stspace = 0;
+
+ if (*p1 == '*' || *p1 == ';' || *p1 == '#')
+ goto nextline;
+ if (!*p1)
+ {
+ // nothing but whitespace - context break
+ as -> context = lwasm_next_context(as);
+ goto nextline;
+ }
+
+ // find the end of the first token
+ for (tok = p1; *p1 && !isspace(*p1) && *p1 != ':' && *p1 != '='; p1++)
+ /* do nothing */ ;
+
+ if (*p1 == ':' || *p1 == '=' || stspace == 0)
+ {
+ // have a symbol here
+ sym = lw_strndup(tok, p1 - tok);
+ if (*p1 == ':')
+ p1++;
+ for (; *p1 && isspace(*p1); p1++)
+ /* do nothing */ ;
+
+ if (*p1 == '=')
+ {
+ tok = p1++;
+ }
+ else
+ {
+ for (tok = p1; *p1 && !isspace(*p1); p1++)
+ /* do nothing */ ;
+ }
+ }
+ if (sym && strcmp(sym, "!") == 0)
+ cl -> isbrpt = 1;
+ else if (sym)
+ cl -> sym = lw_strdup(sym);
+ cl -> symset = 0;
+
+ // tok points to the opcode for the line or NUL if none
+ if (*tok)
+ {
+ // look up operation code
+ sym = lw_strndup(tok, p1 - tok);
+ for (; *p1 && isspace(*p1); p1++)
+ /* do nothing */ ;
+
+ for (opnum = 0; instab[opnum].opcode; opnum++)
+ {
+ if (!strcasecmp(instab[opnum].opcode, sym))
+ break;
+ }
+
+ // p1 points to the start of the operand
+
+ // if we're inside a macro definition and not at ENDM,
+ // add the line to the macro definition and continue
+ if (as -> inmacro && !(instab[opnum].flags & lwasm_insn_endm))
+ {
+ add_macro_line(as, line);
+ goto linedone;
+ }
+
+ // if skipping a condition and the operation code doesn't
+ // operate within a condition (not a conditional)
+ // do nothing
+ if (as -> skipcond && !(instab[opnum].flags & lwasm_insn_cond))
+ goto linedone;
+
+ if (instab[opnum].opcode == NULL)
+ {
+ cl -> insn = -1;
+ if (*tok != ';' && *tok != '*')
+ {
+ // bad opcode; check for macro here
+ if (expand_macro(as, cl, &p1, sym) != 0)
+ {
+ // macro expansion failed
+ if (expand_struct(as, cl, &p1, sym) != 0)
+ {
+ // structure expansion failed
+ lwasm_register_error(as, cl, "Bad opcode");
+ }
+ }
+ }
+ }
+ else
+ {
+ cl -> insn = opnum;
+ // no parse func means operand doesn't matter
+ if (instab[opnum].parse)
+ {
+ if (as -> instruct == 0 || instab[opnum].flags & lwasm_insn_struct)
+ {
+ cl -> len = -1;
+ // call parse function
+ (instab[opnum].parse)(as, cl, &p1);
+
+ if (*p1 && !isspace(*p1))
+ {
+ // flag bad operand error
+ lwasm_register_error(as, cl, "Bad operand (%s)", p1);
+ }
+ }
+ else if (as -> instruct == 1)
+ {
+ lwasm_register_error(as, cl, "Bad operand (%s)", p1);
+ }
+ }
+ }
+ }
+
+ linedone:
+ lw_free(sym);
+
+ if (!as -> skipcond && !as -> inmacro)
+ {
+ if (cl -> sym && cl -> symset == 0)
+ {
+ debug_message(as, 50, "Register symbol %s: %s", cl -> sym, lw_expr_print(cl -> addr));
+
+ // register symbol at line address
+ if (!register_symbol(as, cl, cl -> sym, cl -> addr, symbol_flag_none))
+ {
+ // symbol error
+ // lwasm_register_error(as, cl, "Bad symbol '%s'", cl -> sym);
+ }
+ }
+ debug_message(as, 40, "Line address: %s", lw_expr_print(cl -> addr));
+ }
+
+ nextline:
+ lw_free(line);
+
+ // if we've hit the "end" bit, finish out
+ if (as -> endseen)
+ return;
+ }
+}
diff -r 000000000000 -r 2c24602be78f lwasm/pass2.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwasm/pass2.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,94 @@
+/*
+pass2.c
+
+Copyright © 2010 William Astle
+
+This file is part of LWTOOLS.
+
+LWTOOLS 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 3 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, see .
+*/
+
+#include
+#include
+
+#include
+#include
+
+#include "lwasm.h"
+#include "instab.h"
+
+/*
+pass 2: deal with undefined symbols and do a simplification pass
+on all the expressions. Handle PRAGMA_IMPORTUNDEFEXPORT
+
+*/
+void do_pass2(asmstate_t *as)
+{
+ line_t *cl;
+ exportlist_t *ex;
+ struct symtabe *s;
+ importlist_t *im;
+ struct line_expr_s *le;
+
+ // verify the export list
+ if (as -> output_format == OUTPUT_OBJ)
+ {
+ for (ex = as -> exportlist; ex; ex = ex -> next)
+ {
+ s = lookup_symbol(as, NULL, ex -> symbol);
+ if (!s)
+ {
+ if (CURPRAGMA(ex -> line, PRAGMA_IMPORTUNDEFEXPORT))
+ {
+ for (im = as -> importlist; im; im = im -> next)
+ {
+ if (!strcmp(ex -> symbol, im -> symbol))
+ break;
+ }
+ if (!im)
+ {
+ im = lw_alloc(sizeof(importlist_t));
+ im -> symbol = lw_strdup(ex -> symbol);
+ im -> next = as -> importlist;
+ as -> importlist = im;
+ }
+ }
+ else
+ {
+ // undefined export - register error
+ lwasm_register_error(as, ex -> line, "Undefined exported symbol");
+ }
+ }
+ ex -> se = s;
+ }
+ if (as -> errorcount > 0)
+ return;
+ }
+
+ // we want to throw errors on undefined symbols here
+ as -> badsymerr = 1;
+
+ // now do some reductions on expressions
+ for (cl = as -> line_head; cl; cl = cl -> next)
+ {
+ as -> cl = cl;
+
+ // simplify address
+ lwasm_reduce_expr(as, cl -> addr);
+
+ // simplify each expression
+ for (le = cl -> exprs; le; le = le -> next)
+ lwasm_reduce_expr(as, le -> expr);
+ }
+}
diff -r 000000000000 -r 2c24602be78f lwasm/pass3.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwasm/pass3.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,73 @@
+/*
+pass3.c
+
+Copyright © 2010 William Astle
+
+This file is part of LWTOOLS.
+
+LWTOOLS 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 3 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, see .
+*/
+
+#include
+#include
+
+#include
+#include
+
+#include "lwasm.h"
+#include "instab.h"
+
+/*
+Resolve1 Pass
+
+repeatedly resolve instruction sizes and line addresses
+until nothing more reduces
+
+*/
+void do_pass3(asmstate_t *as)
+{
+ int rc;
+ line_t *cl;
+ struct line_expr_s *le;
+
+ do
+ {
+ rc = 0;
+ for (cl = as -> line_head; cl; cl = cl -> next)
+ {
+ as -> cl = cl;
+
+ // simplify address
+ lwasm_reduce_expr(as, cl -> addr);
+
+ // simplify each expression
+ for (le = cl -> exprs; le; le = le -> next)
+ lwasm_reduce_expr(as, le -> expr);
+
+ if (cl -> len == -1)
+ {
+ // try resolving the instruction length
+ // but don't force resolution
+ if (cl -> insn >= 0 && instab[cl -> insn].resolve)
+ {
+ (instab[cl -> insn].resolve)(as, cl, 0);
+ if (cl -> len != -1)
+ rc++;
+ }
+ }
+ }
+ if (as -> errorcount > 0)
+ return;
+ } while (rc > 0);
+}
diff -r 000000000000 -r 2c24602be78f lwasm/pass4.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwasm/pass4.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,127 @@
+/*
+pass4.c
+
+Copyright © 2010 William Astle
+
+This file is part of LWTOOLS.
+
+LWTOOLS 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 3 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, see .
+*/
+
+#include
+#include
+
+#include
+#include
+
+#include "lwasm.h"
+#include "instab.h"
+
+/*
+Resolve2 Pass
+
+Force resolution of instruction sizes.
+
+*/
+void do_pass4_aux(asmstate_t *as, int force)
+{
+ int rc;
+ int cnt;
+ line_t *cl, *sl;
+ struct line_expr_s *le;
+
+ // first, count the number of unresolved instructions
+ for (cnt = 0, cl = as -> line_head; cl; cl = cl -> next)
+ {
+ if (cl -> len == -1)
+ cnt++;
+ }
+
+ sl = as -> line_head;
+ while (cnt > 0)
+ {
+ // find an unresolved instruction
+ for ( ; sl && sl -> len != -1; sl = sl -> next)
+ {
+ as -> cl = sl;
+ lwasm_reduce_expr(as, sl -> addr);
+
+ // simplify each expression
+ for (le = sl -> exprs; le; le = le -> next)
+ lwasm_reduce_expr(as, le -> expr);
+ }
+
+ // simplify address
+ as -> cl = sl;
+ lwasm_reduce_expr(as, sl -> addr);
+
+ // simplify each expression
+ for (le = sl -> exprs; le; le = le -> next)
+ lwasm_reduce_expr(as, le -> expr);
+
+
+ if (sl -> len == -1 && sl -> insn >= 0 && instab[sl -> insn].resolve)
+ {
+ (instab[sl -> insn].resolve)(as, sl, 1);
+ if (force && sl -> len == -1)
+ {
+ lwasm_register_error(as, sl, "Instruction failed to resolve.");
+ return;
+ }
+ }
+ cnt--;
+ if (cnt == 0)
+ return;
+
+ do
+ {
+ rc = 0;
+ for (cl = sl; cl; cl = cl -> next)
+ {
+ as -> cl = cl;
+
+ // simplify address
+ lwasm_reduce_expr(as, cl -> addr);
+
+ // simplify each expression
+ for (le = cl -> exprs; le; le = le -> next)
+ lwasm_reduce_expr(as, le -> expr);
+
+ if (cl -> len == -1)
+ {
+ // try resolving the instruction length
+ // but don't force resolution
+ if (cl -> insn >= 0 && instab[cl -> insn].resolve)
+ {
+ (instab[cl -> insn].resolve)(as, cl, 0);
+ if (cl -> len != -1)
+ {
+ rc++;
+ cnt--;
+ if (cnt == 0)
+ return;
+ }
+ }
+ }
+ }
+ if (as -> errorcount > 0)
+ return;
+ } while (rc > 0);
+ }
+}
+
+void do_pass4(asmstate_t *as)
+{
+ do_pass4_aux(as, 1);
+}
diff -r 000000000000 -r 2c24602be78f lwasm/pass5.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwasm/pass5.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,119 @@
+/*
+pass5.c
+
+Copyright © 2010 William Astle
+
+This file is part of LWTOOLS.
+
+LWTOOLS 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 3 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, see .
+*/
+
+#include
+#include
+
+#include
+#include
+
+#include "lwasm.h"
+#include "instab.h"
+
+/*
+AssignAddresses Pass
+
+Force resolution of all line addresses
+
+*/
+
+static int exprok_aux(lw_expr_t e, void *priv)
+{
+ asmstate_t *as = priv;
+
+ if (lw_expr_istype(e, lw_expr_type_int))
+ return 0;
+ if (lw_expr_istype(e, lw_expr_type_oper))
+ return 0;
+ if (lw_expr_istype(e, lw_expr_type_special) && as -> output_format == OUTPUT_OBJ)
+ {
+ int t;
+ t = lw_expr_specint(e);
+ if (t == lwasm_expr_secbase)
+ return 0;
+ }
+
+ return 1;
+}
+
+static int exprok(asmstate_t *as, lw_expr_t e)
+{
+ if (lw_expr_testterms(e, exprok_aux, as))
+ return 0;
+ return 1;
+}
+
+void do_pass5(asmstate_t *as)
+{
+ int rc;
+ int cnt;
+ int ocnt;
+ line_t *cl, *sl;
+ struct line_expr_s *le;
+
+ // first, count the number of non-constant addresses; do
+ // a reduction first on each one
+ for (cnt = 0, cl = as -> line_head; cl; cl = cl -> next)
+ {
+ as -> cl = cl;
+ lwasm_reduce_expr(as, cl -> addr);
+ if (!exprok(as, cl -> addr))
+ cnt++;
+ }
+
+ sl = as -> line_head;
+ while (cnt > 0)
+ {
+ ocnt = cnt;
+
+ // find an unresolved address
+ for ( ; sl && exprok(as, sl -> addr); sl = sl -> next)
+ /* do nothing */ ;
+
+ // simplify address
+ for (cl = sl; cl; cl = cl -> next)
+ {
+ as -> cl = sl;
+ lwasm_reduce_expr(as, sl -> addr);
+
+ if (exprok(as, cl -> addr))
+ {
+ if (0 == --cnt);
+ return;
+ }
+ }
+
+ if (cnt == ocnt)
+ break;
+ }
+
+ if (cnt)
+ {
+ // we have non-resolved line addresses here
+ for (cl = sl; cl; cl = cl -> next)
+ {
+ if (!exprok(as, cl -> addr))
+ {
+ lwasm_register_error(as, cl, "Cannot resolve line address");
+ }
+ }
+ }
+}
diff -r 000000000000 -r 2c24602be78f lwasm/pass6.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwasm/pass6.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,90 @@
+/*
+pass6.c
+
+Copyright © 2010 William Astle
+
+This file is part of LWTOOLS.
+
+LWTOOLS 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 3 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, see .
+*/
+
+#include
+#include
+
+#include
+#include
+
+#include "lwasm.h"
+#include "instab.h"
+
+/*
+Finalize Pass
+
+Reduce all expressions in a final pass.
+
+Observation:
+
+Everything should reduce as far as it is going to in a single pass
+because all line addresses are now constant (or section-base offset)
+*/
+
+static int exprok_aux(lw_expr_t e, void *priv)
+{
+ asmstate_t *as = priv;
+
+ if (lw_expr_istype(e, lw_expr_type_int))
+ return 0;
+
+ if (as -> output_format == OUTPUT_OBJ)
+ {
+ if (lw_expr_istype(e, lw_expr_type_oper))
+ return 0;
+ if (lw_expr_istype(e, lw_expr_type_special) && as -> output_format == OUTPUT_OBJ)
+ {
+ int t;
+ t = lw_expr_specint(e);
+ if (t == lwasm_expr_secbase || t == lwasm_expr_syment || t == lwasm_expr_import)
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static int exprok(asmstate_t *as, lw_expr_t e)
+{
+ if (lw_expr_testterms(e, exprok_aux, as))
+ return 0;
+ return 1;
+}
+
+
+void do_pass6(asmstate_t *as)
+{
+ line_t *cl;
+ struct line_expr_s *le;
+
+ for (cl = as -> line_head; cl; cl = cl -> next)
+ {
+ as -> cl = cl;
+ for (le = cl -> exprs; le; le = le -> next)
+ {
+ lwasm_reduce_expr(as, le -> expr);
+ if (!exprok(as, le -> expr))
+ {
+ lwasm_register_error(as, cl, "Invalid expression");
+ }
+ }
+ }
+}
diff -r 000000000000 -r 2c24602be78f lwasm/pass7.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwasm/pass7.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,51 @@
+/*
+pass7.c
+
+Copyright © 2010 William Astle
+
+This file is part of LWTOOLS.
+
+LWTOOLS 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 3 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, see .
+*/
+
+#include
+#include
+
+#include
+#include
+
+#include "lwasm.h"
+#include "instab.h"
+
+/*
+emit pass
+
+Generate object code
+*/
+void do_pass7(asmstate_t *as)
+{
+ line_t *cl;
+
+ for (cl = as -> line_head; cl; cl = cl -> next)
+ {
+ as -> cl = cl;
+ if (cl -> insn != -1)
+ {
+ if (instab[cl -> insn].emit)
+ {
+ (instab[cl -> insn].emit)(as, cl);
+ }
+ }
+ }
+}
diff -r 000000000000 -r 2c24602be78f lwasm/pragma.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwasm/pragma.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,124 @@
+/*
+pragma.c
+
+Copyright © 2010 William Astle
+
+This file is part of LWTOOLS.
+
+LWTOOLS 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 3 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, see .
+*/
+
+#include
+
+#include "lwasm.h"
+#include "instab.h"
+
+struct pragma_list
+{
+ const char *str;
+ int flag;
+};
+
+static const struct pragma_list set_pragmas[] =
+{
+ { "dollarnotlocal", PRAGMA_DOLLARNOTLOCAL },
+ { "noindex0tonone", PRAGMA_NOINDEX0TONONE },
+ { "undefextern", PRAGMA_UNDEFEXTERN },
+ { "cescapes", PRAGMA_CESCAPES },
+ { "importundefexport", PRAGMA_IMPORTUNDEFEXPORT },
+ { "pcaspcr", PRAGMA_PCASPCR },
+ { 0, 0 }
+};
+
+static const struct pragma_list reset_pragmas[] =
+{
+ { "nodollarnotlocal", PRAGMA_DOLLARNOTLOCAL },
+ { "index0tonone", PRAGMA_NOINDEX0TONONE },
+ { "noundefextern", PRAGMA_UNDEFEXTERN },
+ { "nocescapes", PRAGMA_CESCAPES },
+ { "noimportundefexport", PRAGMA_IMPORTUNDEFEXPORT },
+ { "nopcaspcr", PRAGMA_PCASPCR },
+ { 0, 0 }
+};
+
+int parse_pragma_string(asmstate_t *as, char *str, int ignoreerr)
+{
+ char *p;
+ int i;
+ const char *np = str;
+ int pragmas = as -> pragmas;
+
+ while (np)
+ {
+ p = lw_token(np, ',', &np);
+ for (i = 0; set_pragmas[i].str; i++)
+ {
+ if (!strcasecmp(p, set_pragmas[i].str))
+ {
+ pragmas |= set_pragmas[i].flag;
+ goto out;
+ }
+ }
+ for (i = 0; reset_pragmas[i].str; i++)
+ {
+ if (!strcasecmp(p, reset_pragmas[i].str))
+ {
+ pragmas &= ~(reset_pragmas[i].flag);
+ goto out;
+ }
+ }
+ /* unrecognized pragma here */
+ if (!ignoreerr)
+ {
+ lw_free(p);
+ return 0;
+ }
+ out:
+ lw_free(p);
+ }
+ as -> pragmas = pragmas;
+ return 1;
+}
+
+PARSEFUNC(pseudo_parse_pragma)
+{
+ char *ps, *t;
+
+ for (t = *p; *t && !isspace(*t); t++)
+ /* do nothing */ ;
+
+ ps = lw_strndup(*p, t - *p);
+ *p = t;
+
+ if (parse_pragma_string(as, ps, 0) == 0)
+ {
+ lwasm_register_error(as, l, "Unrecognized pragma string");
+ }
+ lw_free(ps);
+}
+
+PARSEFUNC(pseudo_parse_starpragma)
+{
+ char *ps, *t;
+
+ for (t = *p; *t && !isspace(*t); t++)
+ /* do nothing */ ;
+
+ ps = lw_strndup(*p, t - *p);
+ *p = t;
+
+ // *pragma must NEVER throw an error
+ parse_pragma_string(as, ps, 1);
+ lw_free(ps);
+}
diff -r 000000000000 -r 2c24602be78f lwasm/pseudo.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwasm/pseudo.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,1143 @@
+/*
+pseudo.c
+Copyright © 2010 William Astle
+
+This file is part of LWASM.
+
+LWASM 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 3 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, see .
+
+*/
+
+#include
+
+#include "lwasm.h"
+#include "instab.h"
+#include "input.h"
+
+#include "lw_string.h"
+
+extern void register_struct_entry(asmstate_t *as, line_t *l, int size, structtab_t *ss);
+
+// for "end"
+PARSEFUNC(pseudo_parse_end)
+{
+ lw_expr_t addr;
+
+ as -> endseen = 1;
+ l -> len = 0;
+
+ if (as -> output_format != OUTPUT_DECB)
+ {
+ skip_operand(p);
+ return;
+ }
+
+ if (!**p)
+ {
+ addr = lw_expr_build(lw_expr_type_int, 0);
+ }
+ else
+ {
+ addr = lwasm_parse_expr(as, p);
+ }
+ if (!addr)
+ {
+ lwasm_register_error(as, l, "Bad expression");
+ addr = lw_expr_build(lw_expr_type_int, 0);
+ }
+ lwasm_save_expr(l, 0, addr);
+}
+
+EMITFUNC(pseudo_emit_end)
+{
+ lw_expr_t addr;
+
+ addr = lwasm_fetch_expr(l, 0);
+
+ if (addr)
+ {
+ if (!lw_expr_istype(addr, lw_expr_type_int))
+ lwasm_register_error(as, l, "Exec address not constant!");
+ else
+ as -> execaddr = lw_expr_intval(addr);
+ }
+ as -> endseen = 1;
+}
+
+PARSEFUNC(pseudo_parse_fcb)
+{
+ int i = 0;
+ lw_expr_t e;
+
+ for (;;)
+ {
+ e = lwasm_parse_expr(as, p);
+ if (!e)
+ {
+ lwasm_register_error(as, l, "Bad expression (#%s)", i);
+ break;
+ }
+ lwasm_save_expr(l, i++, e);
+ if (**p != ',')
+ break;
+ (*p)++;
+ }
+
+ l -> len = i;
+}
+
+EMITFUNC(pseudo_emit_fcb)
+{
+ int i;
+ lw_expr_t e;
+ int v;
+
+ for (i = 0; i < l -> len; i++)
+ {
+ e = lwasm_fetch_expr(l, i);
+ lwasm_emitexpr(l, e, 1);
+ }
+}
+
+PARSEFUNC(pseudo_parse_fdb)
+{
+ int i = 0;
+ lw_expr_t e;
+
+ for (;;)
+ {
+ e = lwasm_parse_expr(as, p);
+ if (!e)
+ {
+ lwasm_register_error(as, l, "Bad expression (#%d)", i);
+ break;
+ }
+ lwasm_save_expr(l, i++, e);
+ if (**p != ',')
+ break;
+ (*p)++;
+ }
+
+ l -> len = i * 2;
+}
+
+EMITFUNC(pseudo_emit_fdb)
+{
+ int i;
+ lw_expr_t e;
+ int v;
+
+ for (i = 0; i < (l -> len)/2; i++)
+ {
+ e = lwasm_fetch_expr(l, i);
+ lwasm_emitexpr(l, e, 2);
+ }
+}
+
+PARSEFUNC(pseudo_parse_fqb)
+{
+ int i = 0;
+ lw_expr_t e;
+
+ for (;;)
+ {
+ e = lwasm_parse_expr(as, p);
+ if (!e)
+ {
+ lwasm_register_error(as, l, "Bad expression (#%s)", i);
+ break;
+ }
+ lwasm_save_expr(l, i++, e);
+ if (**p != ',')
+ break;
+ (*p)++;
+ }
+
+ l -> len = i * 4;
+}
+
+EMITFUNC(pseudo_emit_fqb)
+{
+ int i;
+ lw_expr_t e;
+ int v;
+
+ for (i = 0; i < (l -> len)/4; i++)
+ {
+ e = lwasm_fetch_expr(l, i);
+ lwasm_emitexpr(l, e, 4);
+ }
+}
+
+PARSEFUNC(pseudo_parse_fcc)
+{
+ char delim;
+ int i;
+
+ if (!**p)
+ {
+ lwasm_register_error(as, l, "Bad operand");
+ return;
+ }
+
+ delim = **p;
+ (*p)++;
+
+ for (i = 0; (*p)[i] && (*p)[i] != delim; i++)
+ /* do nothing */ ;
+
+ if ((*p)[i] != delim)
+ {
+ lwasm_register_error(as, l, "Bad operand");
+ return;
+ }
+
+ l -> lstr = lw_strndup(*p, i);
+ (*p) += i + 1;
+
+ l -> len = i;
+}
+
+EMITFUNC(pseudo_emit_fcc)
+{
+ int i;
+
+ for (i = 0; i < l -> len; i++)
+ lwasm_emit(l, l -> lstr[i]);
+}
+
+PARSEFUNC(pseudo_parse_fcs)
+{
+ char delim;
+ int i;
+
+ if (!**p)
+ {
+ lwasm_register_error(as, l, "Bad operand");
+ return;
+ }
+
+ delim = **p;
+ (*p)++;
+
+ for (i = 0; (*p)[i] && (*p)[i] != delim; i++)
+ /* do nothing */ ;
+
+ if ((*p)[i] != delim)
+ {
+ lwasm_register_error(as, l, "Bad operand");
+ return;
+ }
+
+ l -> lstr = lw_strndup(*p, i);
+ (*p) += i + 1;
+
+ l -> len = i;
+}
+
+EMITFUNC(pseudo_emit_fcs)
+{
+ int i;
+
+ for (i = 0; i < l -> len - 1; i++)
+ lwasm_emit(l, l -> lstr[i]);
+ lwasm_emit(l, l -> lstr[i] | 0x80);
+}
+
+PARSEFUNC(pseudo_parse_fcn)
+{
+ char delim;
+ int i;
+
+ if (!**p)
+ {
+ lwasm_register_error(as, l, "Bad operand");
+ return;
+ }
+
+ delim = **p;
+ (*p)++;
+
+ for (i = 0; (*p)[i] && (*p)[i] != delim; i++)
+ /* do nothing */ ;
+
+ if ((*p)[i] != delim)
+ {
+ lwasm_register_error(as, l, "Bad operand");
+ return;
+ }
+
+ l -> lstr = lw_strndup(*p, i);
+ (*p) += i + 1;
+
+ l -> len = i + 1;
+}
+
+EMITFUNC(pseudo_emit_fcn)
+{
+ int i;
+
+ for (i = 0; i < (l -> len - 1); i++)
+ lwasm_emit(l, l -> lstr[i]);
+ lwasm_emit(l, 0);
+}
+
+PARSEFUNC(pseudo_parse_rmb)
+{
+ lw_expr_t expr;
+
+ expr = lwasm_parse_expr(as, p);
+ if (!expr)
+ {
+ lwasm_register_error(as, l, "Bad expression");
+ }
+
+ l -> lint = 0;
+ if (as -> instruct)
+ {
+ lwasm_reduce_expr(as, expr);
+ if (!lw_expr_istype(expr, lw_expr_type_int))
+ {
+ lwasm_register_error(as, l, "Expression must be constant at parse time");
+ }
+ else
+ {
+ int e;
+ e = lw_expr_intval(expr);
+ register_struct_entry(as, l, e, NULL);
+ l -> len = 0;
+ l -> lint = 1;
+ l -> symset = 1;
+ }
+ }
+
+ lwasm_save_expr(l, 0, expr);
+}
+
+RESOLVEFUNC(pseudo_resolve_rmb)
+{
+ lw_expr_t expr;
+
+ if (l -> lint)
+ return;
+
+ if (l -> len >= 0)
+ return;
+
+ expr = lwasm_fetch_expr(l, 0);
+
+ if (lw_expr_istype(expr, lw_expr_type_int))
+ {
+ l -> len = lw_expr_intval(expr);
+ }
+}
+
+EMITFUNC(pseudo_emit_rmb)
+{
+ if (l -> lint)
+ return;
+
+ if (l -> len < 0)
+ lwasm_register_error(as, l, "Expression not constant");
+}
+
+PARSEFUNC(pseudo_parse_rmd)
+{
+ lw_expr_t expr;
+
+ l -> lint = 0;
+ expr = lwasm_parse_expr(as, p);
+ if (!expr)
+ {
+ lwasm_register_error(as, l, "Bad expression");
+ }
+
+ if (as -> instruct)
+ {
+ lwasm_reduce_expr(as, expr);
+ if (!lw_expr_istype(expr, lw_expr_type_int))
+ {
+ lwasm_register_error(as, l, "Expression must be constant at parse time");
+ }
+ else
+ {
+ int e;
+ e = lw_expr_intval(expr) * 2;
+ register_struct_entry(as, l, e, NULL);
+ l -> len = 0;
+ l -> symset = 1;
+ l -> lint = 1;
+ }
+ }
+ lwasm_save_expr(l, 0, expr);
+}
+
+RESOLVEFUNC(pseudo_resolve_rmd)
+{
+ lw_expr_t expr;
+
+ if (l -> lint)
+ return;
+
+ if (l -> len >= 0)
+ return;
+
+ expr = lwasm_fetch_expr(l, 0);
+
+ if (lw_expr_istype(expr, lw_expr_type_int))
+ {
+ l -> len = lw_expr_intval(expr) * 2;
+ }
+}
+
+EMITFUNC(pseudo_emit_rmd)
+{
+ if (l -> lint)
+ return;
+
+ if (l -> len < 0)
+ lwasm_register_error(as, l, "Expression not constant");
+}
+
+
+PARSEFUNC(pseudo_parse_rmq)
+{
+ lw_expr_t expr;
+
+ l -> lint = 0;
+ expr = lwasm_parse_expr(as, p);
+ if (!expr)
+ {
+ lwasm_register_error(as, l, "Bad expression");
+ }
+ if (as -> instruct)
+ {
+ lwasm_reduce_expr(as, expr);
+ if (!lw_expr_istype(expr, lw_expr_type_int))
+ {
+ lwasm_register_error(as, l, "Expression must be constant at parse time");
+ }
+ else
+ {
+ int e;
+ e = lw_expr_intval(expr) * 4;
+ register_struct_entry(as, l, e, NULL);
+ l -> len = 0;
+ l -> symset = 1;
+ l -> lint = 1;
+ }
+ }
+
+ lwasm_save_expr(l, 0, expr);
+}
+
+RESOLVEFUNC(pseudo_resolve_rmq)
+{
+ lw_expr_t expr;
+
+ if (l -> lint)
+ return;
+
+ if (l -> len >= 0)
+ return;
+
+ expr = lwasm_fetch_expr(l, 0);
+
+ if (lw_expr_istype(expr, lw_expr_type_int))
+ {
+ l -> len = lw_expr_intval(expr) * 4;
+ }
+}
+
+EMITFUNC(pseudo_emit_rmq)
+{
+ if (l -> lint)
+ return;
+
+ if (l -> len < 0)
+ lwasm_register_error(as, l, "Expression not constant");
+}
+
+
+PARSEFUNC(pseudo_parse_zmq)
+{
+ lw_expr_t expr;
+
+ expr = lwasm_parse_expr(as, p);
+ if (!expr)
+ {
+ lwasm_register_error(as, l, "Bad expression");
+ }
+
+ lwasm_save_expr(l, 0, expr);
+}
+
+RESOLVEFUNC(pseudo_resolve_zmq)
+{
+ lw_expr_t expr;
+
+ if (l -> len >= 0)
+ return;
+
+ expr = lwasm_fetch_expr(l, 0);
+
+ if (lw_expr_istype(expr, lw_expr_type_int))
+ {
+ l -> len = lw_expr_intval(expr) * 4;
+ }
+}
+
+EMITFUNC(pseudo_emit_zmq)
+{
+ int i;
+
+ if (l -> len < 0)
+ {
+ lwasm_register_error(as, l, "Expression not constant");
+ return;
+ }
+
+ for (i = 0; i < l -> len; i++)
+ lwasm_emit(l, 0);
+}
+
+
+PARSEFUNC(pseudo_parse_zmd)
+{
+ lw_expr_t expr;
+
+ expr = lwasm_parse_expr(as, p);
+ if (!expr)
+ {
+ lwasm_register_error(as, l, "Bad expression");
+ }
+
+ lwasm_save_expr(l, 0, expr);
+}
+
+RESOLVEFUNC(pseudo_resolve_zmd)
+{
+ lw_expr_t expr;
+
+ if (l -> len >= 0)
+ return;
+
+ expr = lwasm_fetch_expr(l, 0);
+
+ if (lw_expr_istype(expr, lw_expr_type_int))
+ {
+ l -> len = lw_expr_intval(expr) * 2;
+ }
+}
+
+EMITFUNC(pseudo_emit_zmd)
+{
+ int i;
+
+ if (l -> len < 0)
+ {
+ lwasm_register_error(as, l, "Expression not constant");
+ return;
+ }
+
+ for (i = 0; i < l -> len; i++)
+ lwasm_emit(l, 0);
+}
+
+PARSEFUNC(pseudo_parse_zmb)
+{
+ lw_expr_t expr;
+
+ expr = lwasm_parse_expr(as, p);
+ if (!expr)
+ {
+ lwasm_register_error(as, l, "Bad expression");
+ }
+
+ lwasm_save_expr(l, 0, expr);
+}
+
+RESOLVEFUNC(pseudo_resolve_zmb)
+{
+ lw_expr_t expr;
+
+ if (l -> len >= 0)
+ return;
+
+ expr = lwasm_fetch_expr(l, 0);
+
+ if (lw_expr_istype(expr, lw_expr_type_int))
+ {
+ l -> len = lw_expr_intval(expr);
+ }
+}
+
+EMITFUNC(pseudo_emit_zmb)
+{
+ int i;
+
+ if (l -> len < 0)
+ {
+ lwasm_register_error(as, l, "Expression not constant");
+ return;
+ }
+
+ for (i = 0; i < l -> len; i++)
+ lwasm_emit(l, 0);
+}
+
+PARSEFUNC(pseudo_parse_org)
+{
+ lw_expr_t e;
+
+ l -> len = 0;
+
+ e = lwasm_parse_expr(as, p);
+ if (!e)
+ {
+ lwasm_register_error(as, l, "Bad operand");
+ return;
+ }
+
+ lw_expr_destroy(l -> addr);
+ l -> addr = e;
+ l -> len = 0;
+}
+
+PARSEFUNC(pseudo_parse_equ)
+{
+ lw_expr_t e;
+
+ l -> len = 0;
+
+ if (!(l -> sym))
+ {
+ lwasm_register_error(as, l, "Missing symbol");
+ return;
+ }
+
+ e = lwasm_parse_expr(as, p);
+ if (!e)
+ {
+ lwasm_register_error(as, l, "Bad operand");
+ return;
+ }
+
+ register_symbol(as, l, l -> sym, e, symbol_flag_none);
+ l -> symset = 1;
+ l -> dptr = lookup_symbol(as, l, l -> sym);
+}
+
+PARSEFUNC(pseudo_parse_set)
+{
+ lw_expr_t e;
+
+ l -> len = 0;
+
+ if (!(l -> sym))
+ {
+ lwasm_register_error(as, l, "Missing symbol");
+ return;
+ }
+
+ e = lwasm_parse_expr(as, p);
+ if (!e)
+ {
+ lwasm_register_error(as, l, "Bad operand");
+ return;
+ }
+
+ register_symbol(as, l, l -> sym, e, symbol_flag_set);
+ l -> symset = 1;
+ l -> dptr = lookup_symbol(as, l, l -> sym);
+}
+
+PARSEFUNC(pseudo_parse_setdp)
+{
+ lw_expr_t e;
+
+ l -> len = 0;
+
+ if (as -> output_format == OUTPUT_OBJ)
+ {
+ lwasm_register_error(as, l, "SETDP not permitted for object target");
+ return;
+ }
+
+ e = lwasm_parse_expr(as, p);
+ if (!e)
+ {
+ lwasm_register_error(as, l, "Bad operand");
+ return;
+ }
+
+ if (!lw_expr_istype(e, lw_expr_type_int))
+ {
+ lwasm_register_error(as, l, "SETDP must be constant on pass 1");
+ return;
+ }
+ l -> dpval = lw_expr_intval(e) & 0xff;
+ l -> dshow = l -> dpval;
+ l -> dsize = 1;
+}
+
+PARSEFUNC(pseudo_parse_ifp1)
+{
+ l -> len = 0;
+
+ if (as -> skipcond && !(as -> skipmacro))
+ {
+ as -> skipcount++;
+ skip_operand(p);
+ return;
+ }
+
+ lwasm_register_warning(as, l, "IFP1 if is not supported; ignoring");
+
+}
+
+PARSEFUNC(pseudo_parse_ifp2)
+{
+ l -> len = 0;
+
+ if (as -> skipcond && !(as -> skipmacro))
+ {
+ as -> skipcount++;
+ skip_operand(p);
+ return;
+ }
+
+ lwasm_register_warning(as, l, "IFP2 if is not supported; ignoring");
+}
+
+PARSEFUNC(pseudo_parse_ifeq)
+{
+ lw_expr_t e;
+
+ l -> len = 0;
+
+ if (as -> skipcond && !(as -> skipmacro))
+ {
+ as -> skipcount++;
+ skip_operand(p);
+ return;
+ }
+
+ e = lwasm_parse_cond(as, p);
+ if (e && lw_expr_intval(e) != 0)
+ {
+ as -> skipcond = 1;
+ as -> skipcount = 1;
+ }
+}
+
+PARSEFUNC(pseudo_parse_ifne)
+{
+ lw_expr_t e;
+
+ l -> len = 0;
+
+ if (as -> skipcond && !(as -> skipmacro))
+ {
+ as -> skipcount++;
+ skip_operand(p);
+ return;
+ }
+
+ e = lwasm_parse_cond(as, p);
+ if (e && lw_expr_intval(e) == 0)
+ {
+ as -> skipcond = 1;
+ as -> skipcount = 1;
+ }
+}
+
+
+PARSEFUNC(pseudo_parse_ifgt)
+{
+ lw_expr_t e;
+
+ l -> len = 0;
+
+ if (as -> skipcond && !(as -> skipmacro))
+ {
+ as -> skipcount++;
+ skip_operand(p);
+ return;
+ }
+
+ e = lwasm_parse_cond(as, p);
+ if (e && lw_expr_intval(e) <= 0)
+ {
+ as -> skipcond = 1;
+ as -> skipcount = 1;
+ }
+}
+
+PARSEFUNC(pseudo_parse_ifge)
+{
+ lw_expr_t e;
+
+ l -> len = 0;
+
+ if (as -> skipcond && !(as -> skipmacro))
+ {
+ as -> skipcount++;
+ skip_operand(p);
+ return;
+ }
+
+ e = lwasm_parse_cond(as, p);
+ if (e && lw_expr_intval(e) < 0)
+ {
+ as -> skipcond = 1;
+ as -> skipcount = 1;
+ }
+}
+
+PARSEFUNC(pseudo_parse_iflt)
+{
+ lw_expr_t e;
+
+ l -> len = 0;
+
+ if (as -> skipcond && !(as -> skipmacro))
+ {
+ as -> skipcount++;
+ skip_operand(p);
+ return;
+ }
+
+ e = lwasm_parse_cond(as, p);
+ if (e && lw_expr_intval(e) >= 0)
+ {
+ as -> skipcond = 1;
+ as -> skipcount = 1;
+ }
+}
+
+PARSEFUNC(pseudo_parse_ifle)
+{
+ lw_expr_t e;
+
+ l -> len = 0;
+
+ if (as -> skipcond && !(as -> skipmacro))
+ {
+ as -> skipcount++;
+ skip_operand(p);
+ return;
+ }
+
+ e = lwasm_parse_cond(as, p);
+ if (e && lw_expr_intval(e) > 0)
+ {
+ as -> skipcond = 1;
+ as -> skipcount = 1;
+ }
+}
+
+PARSEFUNC(pseudo_parse_endc)
+{
+ l -> len = 0;
+ if (as -> skipcond && !(as -> skipmacro))
+ {
+ as -> skipcount--;
+ if (as -> skipcount <= 0)
+ as -> skipcond = 0;
+ }
+}
+
+PARSEFUNC(pseudo_parse_else)
+{
+ l -> len = 0;
+
+ if (as -> skipmacro)
+ return;
+
+ if (as -> skipcond)
+ {
+ if (as -> skipcount == 1)
+ {
+ as -> skipcount = 0;
+ as -> skipcond = 0;
+ }
+ return;
+ }
+ as -> skipcond = 1;
+ as -> skipcount = 1;
+}
+
+PARSEFUNC(pseudo_parse_ifdef)
+{
+ char *sym;
+ int i;
+ struct symtabe *s;
+
+ l -> len = 0;
+
+ if (as -> skipcond && !(as -> skipmacro))
+ {
+ as -> skipcount++;
+ skip_operand(p);
+ return;
+ }
+
+ for (i = 0; (*p)[i] && !isspace((*p)[i]); i++)
+ /* do nothing */ ;
+
+ sym = lw_strndup(*p, i);
+
+ s = lookup_symbol(as, l, sym);
+
+ lw_free(sym);
+
+ if (!s)
+ {
+ as -> skipcond = 1;
+ as -> skipcount = 1;
+ }
+}
+
+PARSEFUNC(pseudo_parse_ifndef)
+{
+ char *sym;
+ int i;
+ struct symtabe *s;
+
+ l -> len = 0;
+
+ if (as -> skipcond && !(as -> skipmacro))
+ {
+ as -> skipcount++;
+ skip_operand(p);
+ return;
+ }
+
+ for (i = 0; (*p)[i] && !isspace((*p)[i]); i++)
+ /* do nothing */ ;
+
+ sym = lw_strndup(*p, i);
+ (*p) += i;
+
+ s = lookup_symbol(as, l, sym);
+
+ lw_free(sym);
+
+ if (s)
+ {
+ as -> skipcond = 1;
+ as -> skipcount = 1;
+ }
+}
+
+PARSEFUNC(pseudo_parse_error)
+{
+ lwasm_register_error(as, l, "User error: %s", *p);
+ skip_operand(p);
+}
+
+PARSEFUNC(pseudo_parse_warning)
+{
+ lwasm_register_warning(as, l, "User warning: %s", *p);
+ skip_operand(p);
+}
+
+PARSEFUNC(pseudo_parse_includebin)
+{
+ char *fn, *p2;
+ int delim = 0;
+ FILE *fp;
+ long flen;
+
+ if (!**p)
+ {
+ lwasm_register_error(as, l, "Missing filename");
+ return;
+ }
+
+ if (**p == '"' || **p == '\'')
+ {
+ delim = **p;
+ (*p)++;
+
+ for (p2 = *p; *p2 && *p2 != delim; p2++)
+ /* do nothing */ ;
+ }
+ else
+ {
+ for (p2 = *p; *p2 && !isspace(*p2); p2++)
+ /* do nothing */ ;
+ }
+ fn = lw_strndup(*p, p2 - *p);
+
+ if (delim && **p)
+ (*p)++;
+
+ fp = input_open_standalone(as, fn);
+ if (!fp)
+ {
+ lwasm_register_error(as, l, "Cannot open file");
+ lw_free(fn);
+ return;
+ }
+
+ l -> lstr = fn;
+
+ fseek(fp, 0, SEEK_END);
+ flen = ftell(fp);
+ fclose(fp);
+
+ l -> len = flen;
+}
+
+EMITFUNC(pseudo_emit_includebin)
+{
+ FILE *fp;
+ int c;
+
+ fp = input_open_standalone(as, l -> lstr);
+ if (!fp)
+ {
+ lwasm_register_error(as, l, "Cannot open file (emit)!");
+ return;
+ }
+
+ for (;;)
+ {
+ c = fgetc(fp);
+ if (c == EOF)
+ {
+ fclose(fp);
+ return;
+ }
+ lwasm_emit(l, c);
+ }
+}
+
+PARSEFUNC(pseudo_parse_include)
+{
+ char *fn, *p2;
+ char *p3;
+ int delim = 0;
+
+ if (!**p)
+ {
+ lwasm_register_error(as, l, "Missing filename");
+ return;
+ }
+
+ if (**p == '"' || **p == '\'')
+ {
+ delim = **p;
+ (*p)++;
+
+ for (p2 = *p; *p2 && *p2 != delim; p2++)
+ /* do nothing */ ;
+ }
+ else
+ {
+ for (p2 = *p; *p2 && !isspace(*p2); p2++)
+ /* do nothing */ ;
+ }
+ fn = lw_strndup(*p, p2 - *p);
+ (*p) = p2;
+ if (delim && **p)
+ (*p)++;
+
+ 0 == asprintf(&p3, "include:%s", fn);
+ input_open(as, p3);
+ lw_free(p3);
+
+ l -> len = 0;
+}
+
+PARSEFUNC(pseudo_parse_align)
+{
+ lw_expr_t e;
+ if (!**p)
+ {
+ lwasm_register_error(as, l, "Bad operand");
+ return;
+ }
+
+ e = lwasm_parse_expr(as, p);
+
+ if (!e)
+ {
+ lwasm_register_error(as, l, "Bad operand");
+ return;
+ }
+
+ lwasm_save_expr(l, 0, e);
+
+ if (**p == ',')
+ {
+ e = lwasm_parse_expr(as, p);
+ }
+ else
+ {
+ e = lw_expr_build(lw_expr_type_int, 0);
+ }
+ if (!e)
+ {
+ lwasm_register_error(as, l, "Bad padding");
+ return;
+ }
+
+ lwasm_save_expr(l, 1, e);
+}
+
+RESOLVEFUNC(pseudo_resolve_align)
+{
+ lw_expr_t e;
+ int align;
+
+ e = lwasm_fetch_expr(l, 0);
+
+ if (lw_expr_istype(e, lw_expr_type_int))
+ {
+ align = lw_expr_intval(e);
+ if (align < 1)
+ {
+ lwasm_register_error(as, l, "Invalid alignment");
+ return;
+ }
+ }
+
+ if (lw_expr_istype(l -> addr, lw_expr_type_int))
+ {
+ int a;
+ a = lw_expr_intval(l -> addr);
+ if (a % align == 0)
+ {
+ l -> len = 0;
+ return;
+ }
+ l -> len = align - (a % align);
+ return;
+ }
+}
+
+EMITFUNC(pseudo_emit_align)
+{
+ lw_expr_t e;
+ int i;
+
+ e = lwasm_fetch_expr(l, 1);
+ for (i = 0; i < l -> len; i++)
+ {
+ lwasm_emitexpr(l, e, 1);
+ }
+}
diff -r 000000000000 -r 2c24602be78f lwasm/rules.make
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwasm/rules.make Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,10 @@
+dirname := $(dir $(lastword $(MAKEFILE_LIST)))
+
+lwasm_srcs_local := debug.c input.c insn_bitbit.c insn_gen.c insn_indexed.c \
+ insn_inh.c insn_logicmem.c insn_rel.c insn_rlist.c insn_rtor.c insn_tfm.c \
+ instab.c list.c lwasm.c macro.c main.c os9.c output.c pass1.c pass2.c \
+ pass3.c pass4.c pass5.c pass6.c pass7.c pragma.c pseudo.c section.c \
+ struct.c symbol.c
+
+lwasm_srcs := $(lwasm_srcs) $(addprefix $(dirname),$(lwasm_srcs_local))
+
diff -r 000000000000 -r 2c24602be78f lwasm/section.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwasm/section.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,351 @@
+/*
+section.c
+
+Copyright © 2010 William Astle
+
+This file is part of LWTOOLS.
+
+LWTOOLS 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 3 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, see .
+*/
+
+#include
+
+#include
+#include
+
+#include "lwasm.h"
+#include "instab.h"
+
+PARSEFUNC(pseudo_parse_section)
+{
+ char *p2;
+ char *sn;
+ char *opts = NULL;
+ sectiontab_t *s;
+
+ if (as -> output_format != OUTPUT_OBJ)
+ {
+ lwasm_register_error(as, l, "Cannot use sections unless using the object target");
+ return;
+ }
+
+ if (!**p)
+ {
+ lwasm_register_error(as, l, "Need section name");
+ return;
+ }
+
+ l -> len = 0;
+
+ if (as -> csect)
+ {
+ lw_expr_destroy(as -> csect -> offset);
+ as -> csect -> offset = lw_expr_copy(l -> addr);
+ as -> csect = NULL;
+ }
+
+ for (p2 = *p; *p2 && *p2 != ',' && !isspace(*p2); p2++)
+ /* do nothing */ ;
+
+ sn = lw_strndup(*p, p2 - *p);
+ *p = p2;
+
+ if (**p == ',')
+ {
+ // have opts
+ (*p)++;
+
+ for (p2 = *p; *p2 && !isspace(*p2); p2++)
+ /* do nothing */ ;
+
+ opts = lw_strndup(*p, p2 - *p);
+ *p = p2;
+ }
+
+ for (s = as -> sections; s; s = s -> next)
+ {
+ if (!strcmp(s -> name, sn))
+ break;
+ }
+ if (s && opts)
+ {
+ lwasm_register_warning(as, l, "Section flags can only be specified the first time; ignoring duplicate definition");
+ }
+ if (!s)
+ {
+ // create section data structure
+ s = lw_alloc(sizeof(sectiontab_t));
+ s -> oblen = 0;
+ s -> obsize = 0;
+ s -> obytes = NULL;
+ s -> name = lw_strdup(sn);
+ s -> offset = lw_expr_build(lw_expr_type_special, lwasm_expr_secbase, s);
+ s -> flags = section_flag_none;
+ s -> reloctab = NULL;
+ if (!strcasecmp(sn, "bss") || !strcasecmp(sn, ".bss"))
+ {
+ s -> flags |= section_flag_bss;
+ }
+ // parse options
+ if (opts)
+ {
+ // only one option ("bss" or "!bss")
+ if (!strcasecmp(opts, "bss"))
+ {
+ s -> flags |= section_flag_bss;
+ }
+ else if (!strcasecmp(opts, "!bss"))
+ {
+ s -> flags &= ~section_flag_bss;
+ }
+ else
+ {
+ lwasm_register_error(as, l, "Unrecognized section flag");
+ lw_free(sn);
+ lw_free(opts);
+ lw_free(s -> name);
+ lw_expr_destroy(s -> offset);
+ lw_free(s);
+ return;
+ }
+ }
+ s -> next = as -> sections;
+ as -> sections = s;
+ }
+
+ lw_expr_destroy(l -> addr);
+ l -> addr = lw_expr_copy(s -> offset);
+
+ as -> csect = s;
+ as -> context = lwasm_next_context(as);
+
+ l -> len = 0;
+
+ lw_free(opts);
+ lw_free(sn);
+}
+
+PARSEFUNC(pseudo_parse_endsection)
+{
+ if (as -> output_format != OUTPUT_OBJ)
+ {
+ lwasm_register_error(as, l, "Cannot use sections unless using the object target");
+ return;
+ }
+
+ l -> len = 0;
+
+ if (!(as -> csect))
+ {
+ lwasm_register_error(as, l, "ENDSECTION without SECTION");
+ return;
+ }
+
+ // save offset in case another instance of the section appears
+ lw_expr_destroy(as -> csect -> offset);
+ as -> csect -> offset = l -> addr;
+
+ // reset address to 0
+ l -> addr = lw_expr_build(lw_expr_type_int, 0);
+ as -> csect = NULL;
+
+ // end of section is a context break
+ as -> context = lwasm_next_context(as);
+
+ skip_operand(p);
+}
+
+PARSEFUNC(pseudo_parse_export)
+{
+ int after = 0;
+ char *sym = NULL;
+ exportlist_t *e;
+
+ if (as -> output_format != OUTPUT_OBJ)
+ {
+ lwasm_register_error(as, l, "EXPORT only supported for object target");
+ return;
+ }
+
+ l -> len = 0;
+
+ if (l -> sym)
+ {
+ sym = lw_strdup(l -> sym);
+ l -> symset = 1;
+ }
+
+ if (l -> sym)
+ {
+ skip_operand(p);
+ }
+
+again:
+ if (after || !sym)
+ {
+ char *p2;
+
+ after = 1;
+ for (p2 = *p; *p2 && *p2 != ',' && !isspace(*p2); p2++)
+ /* do nothing */ ;
+
+ sym = lw_strndup(*p, p2 - *p);
+ *p = p2;
+ }
+ if (!sym)
+ {
+ lwasm_register_error(as, l, "No symbol for EXPORT");
+ return;
+ }
+
+ // add the symbol to the "export" list (which will be resolved
+ // after the parse pass is complete
+ e = lw_alloc(sizeof(exportlist_t));
+ e -> next = as -> exportlist;
+ e -> symbol = lw_strdup(sym);
+ e -> line = l;
+ e -> se = NULL;
+ as -> exportlist = e;
+ lw_free(sym);
+
+ if (after && **p == ',')
+ {
+ (*p)++;
+ for (; **p && isspace(**p); (*p)++)
+ /* do nothing */ ;
+ goto again;
+ }
+}
+
+PARSEFUNC(pseudo_parse_extern)
+{
+ int after = 0;
+ char *sym = NULL;
+ importlist_t *e;
+
+ if (as -> output_format != OUTPUT_OBJ)
+ {
+ lwasm_register_error(as, l, "IMPORT only supported for object target");
+ return;
+ }
+
+ l -> len = 0;
+
+ if (l -> sym)
+ {
+ sym = lw_strdup(l -> sym);
+ l -> symset = 1;
+ }
+
+ if (l -> sym)
+ {
+ skip_operand(p);
+ }
+
+again:
+ if (after || !sym)
+ {
+ char *p2;
+
+ after = 1;
+ for (p2 = *p; *p2 && *p2 != ',' && !isspace(*p2); p2++)
+ /* do nothing */ ;
+
+ sym = lw_strndup(*p, p2 - *p);
+ *p = p2;
+ }
+ if (!sym)
+ {
+ lwasm_register_error(as, l, "No symbol for IMPORT");
+ return;
+ }
+
+ // add the symbol to the "export" list (which will be resolved
+ // after the parse pass is complete
+ e = lw_alloc(sizeof(importlist_t));
+ e -> next = as -> importlist;
+ e -> symbol = lw_strdup(sym);
+ as -> importlist = e;
+ lw_free(sym);
+
+ if (after && **p == ',')
+ {
+ (*p)++;
+ for (; **p && isspace(**p); (*p)++)
+ /* do nothing */ ;
+ goto again;
+ }
+}
+
+PARSEFUNC(pseudo_parse_extdep)
+{
+ int after = 0;
+ char *sym = NULL;
+ importlist_t *e;
+
+ if (as -> output_format != OUTPUT_OBJ)
+ {
+ lwasm_register_error(as, l, "EXTDEP only supported for object target");
+ return;
+ }
+
+ if (!as -> csect)
+ {
+ lwasm_register_error(as, l, "EXTDEP must be within a section");
+ return;
+ }
+
+ l -> len = 0;
+
+ if (l -> sym)
+ sym = lw_strdup(l -> sym);
+
+ if (l -> sym)
+ {
+ skip_operand(p);
+ }
+
+again:
+ if (after || !sym)
+ {
+ char *p2;
+
+ after = 1;
+ for (p2 = *p; *p2 && *p2 != ',' && !isspace(*p2); p2++)
+ /* do nothing */ ;
+
+ sym = lw_strndup(*p, p2 - *p);
+ }
+ if (!sym)
+ {
+ lwasm_register_error(as, l, "No symbol for EXTDEP");
+ return;
+ }
+
+ // create a zero-width dependency
+ {
+ lw_expr_t e;
+ e = lw_expr_build(lw_expr_type_int, 0);
+ lwasm_emitexpr(l, e, 0);
+ lw_expr_destroy(e);
+ }
+
+ if (after && **p == ',')
+ {
+ (*p)++;
+ for (; **p && isspace(**p); (*p)++)
+ /* do nothing */ ;
+ goto again;
+ }
+}
diff -r 000000000000 -r 2c24602be78f lwasm/struct.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwasm/struct.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,216 @@
+/*
+struct.c
+Copyright © 2010 William Astle
+
+This file is part of LWASM.
+
+LWASM 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 3 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, see .
+
+Contains stuff associated with structure processing
+*/
+
+#include
+
+#include
+#include
+
+#include "lwasm.h"
+#include "instab.h"
+
+PARSEFUNC(pseudo_parse_struct)
+{
+ structtab_t *s;
+
+ if (as -> instruct)
+ {
+ lwasm_register_error(as, l, "Attempt to define a structure inside a structure");
+ return;
+ }
+
+ if (l -> sym == NULL)
+ {
+ lwasm_register_error(as, l, "Structure definition with no effect - no symbol");
+ return;
+ }
+
+ for (s = as -> structs; s; s = s -> next)
+ {
+ if (!strcmp(s -> name, l -> sym))
+ break;
+ }
+
+ if (s)
+ {
+ lwasm_register_error(as, l, "Duplicate structure definition");
+ return;
+ }
+
+ as -> instruct = 1;
+
+ s = lw_alloc(sizeof(structtab_t));
+ s -> name = lw_strdup(l -> sym);
+ s -> next = as -> structs;
+ s -> fields = NULL;
+ s -> size = 0;
+ as -> structs = s;
+ as -> cstruct = s;
+
+ skip_operand(p);
+
+ l -> len = 0;
+ l -> symset = 1;
+}
+
+void pseudo_endstruct_aux(asmstate_t *as, line_t *l, structtab_field_t *e, const char *prefix, int *coff)
+{
+ char *symname = NULL;
+ lw_expr_t te1, te2;
+
+ while (e)
+ {
+ if (e -> name)
+ 0 == asprintf(&symname, "%s.%s", prefix, e -> name);
+ else
+ 0 == asprintf(&symname, "%s.____%d", prefix, *coff);
+
+ // register the symbol
+ te1 = lw_expr_build(lw_expr_type_int, *coff);
+ te2 = lw_expr_build(lw_expr_type_oper, lw_expr_oper_plus, te1, l -> addr);
+ register_symbol(as, l, symname, te2, symbol_flag_nocheck);
+ lw_expr_destroy(te2);
+ lw_expr_destroy(te1);
+
+ if (e -> substruct)
+ {
+ char *t;
+ 0 == asprintf(&t, "sizeof{%s}", symname);
+ te1 = lw_expr_build(lw_expr_type_int, e -> substruct -> size);
+ register_symbol(as, l, t, te1, symbol_flag_nocheck);
+ lw_expr_destroy(te1);
+ lw_free(t);
+ pseudo_endstruct_aux(as, l, e -> substruct -> fields, symname, coff);
+ }
+ else
+ {
+ *coff += e -> size;
+ }
+ e = e -> next;
+ }
+}
+
+
+PARSEFUNC(pseudo_parse_endstruct)
+{
+ char *t;
+ int coff = 0;
+ lw_expr_t te;
+
+ if (as -> instruct == 0)
+ {
+ lwasm_register_warning(as, l, "endstruct without struct");
+ skip_operand(p);
+ return;
+ }
+
+ 0 == asprintf(&t, "sizeof{%s}", as -> cstruct -> name);
+ te = lw_expr_build(lw_expr_type_int, as -> cstruct -> size);
+ register_symbol(as, l, t, te, symbol_flag_nocheck);
+ lw_expr_destroy(te);
+ lw_free(t);
+
+ l -> soff = as -> cstruct -> size;
+ as -> instruct = 0;
+
+ skip_operand(p);
+
+ pseudo_endstruct_aux(as, l, as -> cstruct -> fields, as -> cstruct -> name, &coff);
+
+ l -> len = 0;
+}
+
+void register_struct_entry(asmstate_t *as, line_t *l, int size, structtab_t *ss)
+{
+ structtab_field_t *e, *e2;
+
+ l -> soff = as -> cstruct -> size;
+ e = lw_alloc(sizeof(structtab_field_t));
+ e -> next = NULL;
+ e -> size = size;
+ if (l -> sym)
+ e -> name = lw_strdup(l -> sym);
+ else
+ e -> name = NULL;
+ e -> substruct = ss;
+ if (as -> cstruct -> fields)
+ {
+ for (e2 = as -> cstruct -> fields; e2 -> next; e2 = e2 -> next)
+ /* do nothing */ ;
+ e2 -> next = e;
+ }
+ else
+ {
+ as -> cstruct -> fields = e;
+ }
+ as -> cstruct -> size += size;
+}
+
+int expand_struct(asmstate_t *as, line_t *l, char **p, char *opc)
+{
+ structtab_t *s;
+ char *t;
+ lw_expr_t te;
+ int addr = 0;
+
+ debug_message(as, 200, "Checking for structure expansion: %s", opc);
+
+ for (s = as -> structs; s; s = s -> next)
+ {
+ if (!strcmp(opc, s -> name))
+ break;
+ }
+
+ if (!s)
+ return -1;
+
+ debug_message(as, 10, "Expanding structure: %s", opc);
+
+ if (!(l -> sym))
+ {
+ lwasm_register_error(as, l, "Cannot declare a structure without a symbol name.");
+ return;
+ }
+
+ l -> len = s -> size;
+
+ if (as -> instruct)
+ 0 == asprintf(&t, "sizeof(%s.%s}", as -> cstruct -> name, l -> sym);
+ else
+ 0 == asprintf(&t, "sizeof{%s}", l -> sym);
+ te = lw_expr_build(lw_expr_type_int, s -> size);
+ register_symbol(as, l, t, te, symbol_flag_nocheck);
+ lw_expr_destroy(te);
+ lw_free(t);
+
+ if (as -> instruct)
+ 0 == asprintf(&t, "%s.%s", as -> cstruct -> name, l -> sym);
+ else
+ t = lw_strdup(l -> sym);
+ pseudo_endstruct_aux(as, l, s -> fields, t, &addr);
+ lw_free(t);
+ l -> symset = 1;
+ if (as -> instruct)
+ register_struct_entry(as, l, s -> size, s);
+ return 0;
+}
+
diff -r 000000000000 -r 2c24602be78f lwasm/symbol.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwasm/symbol.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,326 @@
+/*
+symbol.c
+
+Copyright © 2010 William Astle
+
+This file is part of LWTOOLS.
+
+LWTOOLS 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 3 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, see .
+*/
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include "lwasm.h"
+
+struct symtabe *symbol_findprev(asmstate_t *as, struct symtabe *se)
+{
+ struct symtabe *se1, *se2;
+ int i;
+
+ for (se2 = NULL, se1 = as -> symtab.head; se1; se1 = se1 -> next)
+ {
+ debug_message(as, 200, "Sorting; looking at symbol %s (%p) for %s", se1 -> symbol, se1, se -> symbol);
+ /* compare se with se1 */
+ i = strcasecmp(se -> symbol, se1 -> symbol);
+
+ /* if the symbol sorts before se1, we just need to return */
+ if (i < 0)
+ return se2;
+
+ if (i == 0)
+ {
+ /* symbol name matches; compare other things */
+
+ /*if next version is greater than this one, return */
+ if (se -> version > se1 -> version)
+ return se2;
+ /* if next context is great than this one, return */
+ if (se -> context > se1 -> context)
+ return se2;
+
+ /* if section name is greater, return */
+ /* if se has no section but se1 does, we go first */
+ if (se -> section == NULL && se1 -> section != NULL)
+ return se2;
+ if (se -> section != NULL && se -> section != NULL)
+ {
+ /* compare section names and if se < se1, return */
+ i = strcasecmp(se -> section -> name, se1 -> section -> name);
+ if (i < 0)
+ return se2;
+ }
+ }
+
+ se2 = se1;
+ }
+ return se2;
+}
+
+struct symtabe *register_symbol(asmstate_t *as, line_t *cl, char *sym, lw_expr_t val, int flags)
+{
+ struct symtabe *se;
+ struct symtabe *sprev;
+ int islocal = 0;
+ int context = -1;
+ int version = -1;
+ char *cp;
+
+ debug_message(as, 200, "Register symbol %s (%02X), %s", sym, flags, lw_expr_print(val));
+
+ if (!(flags & symbol_flag_nocheck))
+ {
+ if (!sym || !*sym)
+ {
+ lwasm_register_error(as, cl, "Bad symbol (%s)", sym);
+ return NULL;
+ }
+ if (*sym < 0x80 && (!strchr(SSYMCHARS, *sym) && !strchr(sym + 1, '$') && !strchr(sym + 1, '@') && !strchr(sym + 1, '?')))
+ {
+ lwasm_register_error(as, cl, "Bad symbol (%s)", sym);
+ return NULL;
+ }
+
+ if ((*sym == '$' || *sym == '@') && (sym[1] >= '0' && sym[1] <= '9'))
+ {
+ lwasm_register_error(as, cl, "Bad symbol (%s)", sym);
+ return NULL;
+ }
+ }
+
+ for (cp = sym; *cp; cp++)
+ {
+ if (*cp == '@' || *cp == '?')
+ islocal = 1;
+ if (*cp == '$' && !(CURPRAGMA(cl, PRAGMA_DOLLARNOTLOCAL)))
+ islocal = 1;
+
+ // bad symbol
+ if (!(flags & symbol_flag_nocheck) && *cp < 0x80 && !strchr(SYMCHARS, *cp))
+ {
+ lwasm_register_error(as, cl, "Bad symbol (%s)", sym);
+ return NULL;
+ }
+ }
+
+ if (islocal)
+ context = cl -> context;
+
+ // first, look up symbol to see if it is already defined
+ for (se = as -> symtab.head; se; se = se -> next)
+ {
+ debug_message(as, 300, "Symbol add lookup: %p, %p", se, se -> next);
+ if (!strcmp(sym, se -> symbol))
+ {
+ if (se -> context != context)
+ continue;
+ if ((flags & symbol_flag_set) && (se -> flags & symbol_flag_set))
+ {
+ if (version < se -> version)
+ version = se -> version;
+ continue;
+ }
+ break;
+ }
+ }
+
+ if (se)
+ {
+ // multiply defined symbol
+ lwasm_register_error(as, cl, "Multiply defined symbol (%s)", sym);
+ return NULL;
+ }
+
+ if (flags & symbol_flag_set)
+ {
+ version++;
+ }
+
+ // symplify the symbol expression - replaces "SET" symbols with
+ // symbol table entries
+ lwasm_reduce_expr(as, val);
+
+ se = lw_alloc(sizeof(struct symtabe));
+ se -> context = context;
+ se -> version = version;
+ se -> flags = flags;
+ se -> value = lw_expr_copy(val);
+ se -> symbol = lw_strdup(sym);
+ se -> section = cl -> csect;
+ sprev = symbol_findprev(as, se);
+ if (!sprev)
+ {
+ debug_message(as, 200, "Adding symbol at head of symbol table");
+ se -> next = as -> symtab.head;
+ as -> symtab.head = se;
+ }
+ else
+ {
+ debug_message(as, 200, "Adding symbol in middle of symbol table");
+ se -> next = sprev -> next;
+ sprev -> next = se;
+ }
+ return se;
+}
+
+// for "SET" symbols, always returns the LAST definition of the
+// symbol. This works because the lwasm_reduce_expr() call in
+// register_symbol will ensure there are no lingering "var" references
+// to the set symbol anywhere in the symbol table; they will all be
+// converted to direct references
+// NOTE: this means that for a forward reference to a SET symbol,
+// the LAST definition will be the one used.
+// This arrangement also ensures that any reference to the symbol
+// itself inside a "set" definition will refer to the previous version
+// of the symbol.
+struct symtabe * lookup_symbol(asmstate_t *as, line_t *cl, char *sym)
+{
+ int local = 0;
+ struct symtabe *s, *s2;
+
+ // check if this is a local symbol
+ if (strchr(sym, '@') || strchr(sym, '?'))
+ local = 1;
+
+ if (cl && !CURPRAGMA(cl, PRAGMA_DOLLARNOTLOCAL) && strchr(sym, '$'))
+ local = 1;
+ if (!cl && !(as -> pragmas & PRAGMA_DOLLARNOTLOCAL) && strchr(sym, '$'))
+ local = 1;
+
+ // cannot look up local symbol in global context!!!!!
+ if (!cl && local)
+ return NULL;
+
+ for (s = as -> symtab.head, s2 = NULL; s; s = s -> next)
+ {
+ if (!strcmp(sym, s -> symbol))
+ {
+ if (local && s -> context != cl -> context)
+ continue;
+
+ if (s -> flags & symbol_flag_set)
+ {
+ // look for highest version of symbol
+ if (s -> version > s2 -> version)
+ s2 = s;
+ continue;
+ }
+ break;
+ }
+ }
+ if (!s && s2)
+ s = s2;
+
+ return s;
+}
+
+struct listinfo
+{
+ sectiontab_t *sect;
+ asmstate_t *as;
+ int complex;
+};
+
+int list_symbols_test(lw_expr_t e, void *p)
+{
+ struct listinfo *li = p;
+
+ if (li -> complex)
+ return 0;
+
+ if (lw_expr_istype(e, lw_expr_type_special))
+ {
+ if (lw_expr_specint(e) == lwasm_expr_secbase)
+ {
+ if (li -> sect)
+ {
+ li -> complex = 1;
+ }
+ else
+ {
+ li -> sect = lw_expr_specptr(e);
+ }
+ }
+ }
+ return 0;
+}
+
+void list_symbols(asmstate_t *as, FILE *of)
+{
+ struct symtabe *s;
+ lw_expr_t te;
+ struct listinfo li;
+
+ li.as = as;
+
+ fprintf(of, "\nSymbol Table:\n");
+
+ for (s = as -> symtab.head; s; s = s -> next)
+ {
+ lwasm_reduce_expr(as, s -> value);
+ fputc('[', of);
+ if (s -> flags & symbol_flag_set)
+ fputc('S', of);
+ else
+ fputc(' ', of);
+ if (as -> output_format == OUTPUT_OBJ)
+ {
+ if (lw_expr_istype(s -> value, lw_expr_type_int))
+ fputc('c', of);
+ else
+ fputc('s', of);
+ }
+ if (s -> context < 0)
+ fputc('G', of);
+ else
+ fputc('L', of);
+
+ fputc(']', of);
+ fputc(' ', of);
+ fprintf(of, "%-32s ", s -> symbol);
+
+ te = lw_expr_copy(s -> value);
+ li.complex = 0;
+ li.sect = NULL;
+ lw_expr_testterms(te, list_symbols_test, &li);
+ if (li.sect)
+ {
+ as -> exportcheck = 1;
+ as -> csect = li.sect;
+ lwasm_reduce_expr(as, te);
+ as -> exportcheck = 0;
+ }
+
+ if (lw_expr_istype(te, lw_expr_type_int))
+ {
+ fprintf(of, "%04X", lw_expr_intval(te));
+ if (li.sect)
+ {
+ fprintf(of, " (%s)", li.sect -> name);
+ }
+ fprintf(of, "\n");
+ }
+ else
+ {
+ fprintf(of, "<>\n");
+// fprintf(of, "%s\n", lw_expr_print(s -> value));
+ }
+ lw_expr_destroy(te);
+ }
+}
diff -r 000000000000 -r 2c24602be78f lwlib/lw_alloc.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwlib/lw_alloc.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,66 @@
+/*
+lw_alloc.c
+
+Copyright © 2010 William Astle
+
+This file is part of LWTOOLS.
+
+LWTOOLS 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 3 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, see .
+*/
+
+#include
+
+#define ___lw_alloc_c_seen___
+#include "lw_alloc.h"
+
+void lw_free(void *P)
+{
+ if (P)
+ free(P);
+}
+
+void *lw_alloc(int size)
+{
+ void *r;
+
+ r = malloc(size);
+ if (!r)
+ {
+ abort();
+ }
+ return r;
+}
+
+void *lw_realloc(void *P, int S)
+{
+ void *r;
+
+ if (!P)
+ {
+ return lw_alloc(S);
+ }
+
+ if (!S)
+ {
+ lw_free(P);
+ return NULL;
+ }
+
+ r = realloc(P, S);
+ if (!r)
+ {
+ abort();
+ }
+ return r;
+}
diff -r 000000000000 -r 2c24602be78f lwlib/lw_alloc.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwlib/lw_alloc.h Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,36 @@
+/*
+lw_alloc.h
+
+Copyright © 2010 William Astle
+
+This file is part of LWTOOLS.
+
+LWTOOLS 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 3 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, see .
+*/
+
+#ifndef ___lw_alloc_h_seen___
+#define ___lw_alloc_h_seen___
+
+
+#ifdef ___lw_alloc_c_seen___
+
+#else /* def ___lw_alloc_c_seen___ */
+
+extern void lw_free(void *P);
+extern void *lw_alloc(int S);
+extern void *lw_realloc(void *P, int S);
+
+#endif /* def ___lw_alloc_c_seen___ */
+
+#endif /* ___lw_alloc_h_seen___ */
\ No newline at end of file
diff -r 000000000000 -r 2c24602be78f lwlib/lw_error.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwlib/lw_error.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,46 @@
+/*
+lw_error.c
+
+Copyright © 2010 William Astle
+
+This file is part of LWTOOLS.
+
+LWTOOLS 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 3 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, see .
+*/
+
+#define ___lw_error_c_seen___
+#include "lw_error.h"
+
+#include
+#include
+#include
+
+static void (*lw_error_func)(const char *fmt, ...) = NULL;
+
+void lw_error(const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ if (lw_error_func)
+ (*lw_error_func)(fmt, args);
+ else
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ exit(1);
+}
+
+void lw_error_setfunc(void (*f)(const char *fmt, ...))
+{
+ lw_error_func = f;
+}
diff -r 000000000000 -r 2c24602be78f lwlib/lw_error.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwlib/lw_error.h Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,34 @@
+/*
+lw_error.h
+
+Copyright © 2010 William Astle
+
+This file is part of LWTOOLS.
+
+LWTOOLS 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 3 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, see .
+*/
+
+#ifndef ___lw_error_h_seen___
+#define ___lw_error_h_seen___
+
+
+#ifdef ___lw_error_c_seen___
+
+#else /* def ___lw_error_c_seen___ */
+
+extern void lw_error(const char *fmt, ...);
+extern void lw_error_setfunc(void (*f)(const char *fmt, ...));
+#endif /* def ___lw_error_c_seen___ */
+
+#endif /* ___lw_error_h_seen___ */
diff -r 000000000000 -r 2c24602be78f lwlib/lw_expr.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwlib/lw_expr.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,1273 @@
+/*
+lwexpr.c
+
+Copyright © 2010 William Astle
+
+This file is part of LWTOOLS.
+
+LWTOOLS 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 3 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, see .
+*/
+
+#include
+#include
+#include
+
+#define ___lw_expr_c_seen___
+#include "lw_alloc.h"
+#include "lw_expr.h"
+#include "lw_error.h"
+#include "lw_string.h"
+
+static lw_expr_fn_t *evaluate_special = NULL;
+static lw_expr_fn2_t *evaluate_var = NULL;
+static lw_expr_fn3_t *parse_term = NULL;
+
+/* Q&D to break out of infinite recursion */
+static int level = 0;
+static int bailing = 0;
+
+int lw_expr_istype(lw_expr_t e, int t)
+{
+ if (e -> type == t)
+ return 1;
+ return 0;
+}
+
+int lw_expr_intval(lw_expr_t e)
+{
+ if (e -> type == lw_expr_type_int)
+ return e -> value;
+ return -1;
+}
+
+int lw_expr_whichop(lw_expr_t e)
+{
+ if (e -> type == lw_expr_type_oper)
+ return e -> value;
+ return -1;
+}
+
+int lw_expr_specint(lw_expr_t e)
+{
+ if (e -> type == lw_expr_type_special)
+ return e -> value;
+ return -1;
+}
+
+void lw_expr_set_term_parser(lw_expr_fn3_t *fn)
+{
+ parse_term = fn;
+}
+
+void lw_expr_set_special_handler(lw_expr_fn_t *fn)
+{
+ evaluate_special = fn;
+}
+
+void lw_expr_set_var_handler(lw_expr_fn2_t *fn)
+{
+ evaluate_var = fn;
+}
+
+lw_expr_t lw_expr_create(void)
+{
+ lw_expr_t r;
+
+ r = lw_alloc(sizeof(struct lw_expr_priv));
+ r -> operands = NULL;
+
+ return r;
+}
+
+void lw_expr_destroy(lw_expr_t E)
+{
+ struct lw_expr_opers *o;
+ if (!E)
+ return;
+ while (E -> operands)
+ {
+ o = E -> operands;
+ E -> operands = o -> next;
+ lw_expr_destroy(o -> p);
+ lw_free(o);
+ }
+ if (E -> type == lw_expr_type_var)
+ lw_free(E -> value2);
+ lw_free(E);
+}
+
+/* actually duplicates the entire expression */
+void lw_expr_add_operand(lw_expr_t E, lw_expr_t O);
+lw_expr_t lw_expr_copy(lw_expr_t E)
+{
+ lw_expr_t r, t;
+ struct lw_expr_opers *o;
+
+ r = lw_alloc(sizeof(struct lw_expr_priv));
+ *r = *E;
+ r -> operands = NULL;
+
+ if (E -> type == lw_expr_type_var)
+ r -> value2 = lw_strdup(E -> value2);
+ for (o = E -> operands; o; o = o -> next)
+ {
+ lw_expr_add_operand(r, o -> p);
+ }
+
+ return r;
+}
+
+void lw_expr_add_operand(lw_expr_t E, lw_expr_t O)
+{
+ struct lw_expr_opers *o, *t;
+
+ o = lw_alloc(sizeof(struct lw_expr_opers));
+ o -> p = lw_expr_copy(O);
+ o -> next = NULL;
+ for (t = E -> operands; t && t -> next; t = t -> next)
+ /* do nothing */ ;
+
+ if (t)
+ t -> next = o;
+ else
+ E -> operands = o;
+}
+
+lw_expr_t lw_expr_build_aux(int exprtype, va_list args)
+{
+ lw_expr_t r;
+ int t;
+ void *p;
+
+ lw_expr_t te1, te2;
+
+ r = lw_expr_create();
+
+ switch (exprtype)
+ {
+ case lw_expr_type_int:
+ t = va_arg(args, int);
+ r -> type = lw_expr_type_int;
+ r -> value = t;
+ break;
+
+ case lw_expr_type_var:
+ p = va_arg(args, char *);
+ r -> type = lw_expr_type_var;
+ r -> value2 = lw_strdup(p);
+ break;
+
+ case lw_expr_type_special:
+ t = va_arg(args, int);
+ p = va_arg(args, char *);
+ r -> type = lw_expr_type_special;
+ r -> value = t;
+ r -> value2 = p;
+ break;
+
+ case lw_expr_type_oper:
+ t = va_arg(args, int);
+ te1 = va_arg(args, lw_expr_t);
+ if (t != lw_expr_oper_com && t != lw_expr_oper_neg)
+ te2 = va_arg(args, lw_expr_t);
+ else
+ te2 = NULL;
+
+ r -> type = lw_expr_type_oper;
+ r -> value = t;
+ lw_expr_add_operand(r, te1);
+ if (te2)
+ lw_expr_add_operand(r, te2);
+ break;
+
+ default:
+ lw_error("Invalid expression type specified to lw_expr_build");
+ }
+
+ return r;
+}
+
+lw_expr_t lw_expr_build(int exprtype, ...)
+{
+ va_list args;
+ lw_expr_t r;
+
+ va_start(args, exprtype);
+ r = lw_expr_build_aux(exprtype, args);
+ va_end(args);
+ return r;
+}
+
+void lw_expr_print_aux(lw_expr_t E, char **obuf, int *buflen, int *bufloc)
+{
+ struct lw_expr_opers *o;
+ int c = 0;
+ char buf[256];
+
+ if (!E)
+ {
+ strcpy(buf, "(NULL)");
+ return;
+ }
+ for (o = E -> operands; o; o = o -> next)
+ {
+ c++;
+ lw_expr_print_aux(o -> p, obuf, buflen, bufloc);
+ }
+
+ switch (E -> type)
+ {
+ case lw_expr_type_int:
+ if (E -> value < 0)
+ snprintf(buf, 256, "-%#x ", -(E -> value));
+ else
+ snprintf(buf, 256, "%#x ", E -> value);
+ break;
+
+ case lw_expr_type_var:
+ snprintf(buf, 256, "V(%s) ", (char *)(E -> value2));
+ break;
+
+ case lw_expr_type_special:
+ snprintf(buf, 256, "S(%d,%p) ", E -> value, E -> value2);
+ break;
+
+ case lw_expr_type_oper:
+ snprintf(buf, 256, "[%d]", c);
+ switch (E -> value)
+ {
+ case lw_expr_oper_plus:
+ strcat(buf, "+ ");
+ break;
+
+ case lw_expr_oper_minus:
+ strcat(buf, "- ");
+ break;
+
+ case lw_expr_oper_times:
+ strcat(buf, "* ");
+ break;
+
+ case lw_expr_oper_divide:
+ strcat(buf, "/ ");
+ break;
+
+ case lw_expr_oper_mod:
+ strcat(buf, "% ");
+ break;
+
+ case lw_expr_oper_intdiv:
+ strcat(buf, "\\ ");
+ break;
+
+ case lw_expr_oper_bwand:
+ strcat(buf, "BWAND ");
+ break;
+
+ case lw_expr_oper_bwor:
+ strcat(buf, "BWOR ");
+ break;
+
+ case lw_expr_oper_bwxor:
+ strcat(buf, "BWXOR ");
+ break;
+
+ case lw_expr_oper_and:
+ strcat(buf, "AND ");
+ break;
+
+ case lw_expr_oper_or:
+ strcat(buf, "OR ");
+ break;
+
+ case lw_expr_oper_neg:
+ strcat(buf, "NEG ");
+ break;
+
+ case lw_expr_oper_com:
+ strcat(buf, "COM ");
+ break;
+
+ default:
+ strcat(buf, "OPER ");
+ break;
+ }
+ break;
+ default:
+ snprintf(buf, 256, "ERR ");
+ break;
+ }
+
+ c = strlen(buf);
+ if (*bufloc + c >= *buflen)
+ {
+ *buflen += 128;
+ *obuf = lw_realloc(*obuf, *buflen);
+ }
+ strcpy(*obuf + *bufloc, buf);
+ *bufloc += c;
+}
+
+char *lw_expr_print(lw_expr_t E)
+{
+ static char *obuf = NULL;
+ static int obufsize = 0;
+
+ int obufloc = 0;
+
+ lw_expr_print_aux(E, &obuf, &obufsize, &obufloc);
+
+ return obuf;
+}
+
+/*
+Return:
+nonzero if expressions are the same (identical pointers or matching values)
+zero if expressions are not the same
+
+*/
+int lw_expr_compare(lw_expr_t E1, lw_expr_t E2)
+{
+ struct lw_expr_opers *o1, *o2;
+
+ if (E1 == E2)
+ return 1;
+
+ if (!E1 || !E2)
+ return 0;
+
+ if (!(E1 -> type == E2 -> type && E1 -> value == E2 -> value))
+ return 0;
+
+ if (E1 -> type == lw_expr_type_var)
+ {
+ if (!strcmp(E1 -> value2, E2 -> value2))
+ return 1;
+ else
+ return 0;
+ }
+
+ if (E1 -> type == lw_expr_type_special)
+ {
+ if (E1 -> value2 == E2 -> value2)
+ return 1;
+ else
+ return 0;
+ }
+
+ for (o1 = E1 -> operands, o2 = E2 -> operands; o1 && o2; o1 = o1 -> next, o2 = o2 -> next)
+ if (lw_expr_compare(o1 -> p, o2 -> p) == 0)
+ return 0;
+ if (o1 || o2)
+ return 0;
+
+ return 1;
+}
+
+/* return true if E is an operator of type oper */
+int lw_expr_isoper(lw_expr_t E, int oper)
+{
+ if (E -> type == lw_expr_type_oper && E -> value == oper)
+ return 1;
+ return 0;
+}
+
+
+void lw_expr_simplify_sortconstfirst(lw_expr_t E)
+{
+ struct lw_expr_opers *o;
+
+ if (E -> type != lw_expr_type_oper)
+ return;
+ if (E -> value != lw_expr_oper_times && E -> value != lw_expr_oper_plus)
+ return;
+
+ for (o = E -> operands; o; o = o -> next)
+ {
+ if (o -> p -> type == lw_expr_type_oper && (o -> p -> value == lw_expr_oper_times || o -> p -> value == lw_expr_oper_plus))
+ lw_expr_simplify_sortconstfirst(o -> p);
+ }
+
+ for (o = E -> operands; o; o = o -> next)
+ {
+ if (o -> p -> type == lw_expr_type_int && o != E -> operands)
+ {
+ struct lw_expr_opers *o2;
+ for (o2 = E -> operands; o2 -> next != o; o2 = o2 -> next)
+ /* do nothing */ ;
+ o2 -> next = o -> next;
+ o -> next = E -> operands;
+ E -> operands = o;
+ o = o2;
+ }
+ }
+}
+
+void lw_expr_sortoperandlist(struct lw_expr_opers **o)
+{
+// fprintf(stderr, "lw_expr_sortoperandlist() not yet implemented\n");
+}
+
+// return 1 if the operand lists match, 0 if not
+// may re-order the argument lists
+int lw_expr_simplify_compareoperandlist(struct lw_expr_opers **ol1, struct lw_expr_opers **ol2)
+{
+ struct lw_expr_opers *o1, *o2;
+
+ lw_expr_sortoperandlist(ol1);
+ lw_expr_sortoperandlist(ol2);
+
+ for (o1 = *ol1, o2 = *ol2; o1 && o2; o1 = o1 -> next, o2 = o2 -> next)
+ {
+ if (!lw_expr_compare(o1 -> p, o2 -> p))
+ return 0;
+ }
+ if (o1 || o2)
+ return 0;
+ return 1;
+}
+
+int lw_expr_simplify_isliketerm(lw_expr_t e1, lw_expr_t e2)
+{
+ // first term is a "times"
+ if (e1 -> type == lw_expr_type_oper && e1 -> value == lw_expr_oper_times)
+ {
+ // second term is a "times"
+ if (e2 -> type == lw_expr_type_oper && e2 -> value == lw_expr_oper_times)
+ {
+ // both times - easy check
+ struct lw_expr_opers *o1, *o2;
+ for (o1 = e1 -> operands; o1; o1 = o1 -> next)
+ if (o1 -> p -> type != lw_expr_type_int)
+ break;
+
+ for (o2 = e2 -> operands; o2; o2 = o2 -> next)
+ if (o2 -> p -> type != lw_expr_type_int)
+ break;
+
+ if (lw_expr_simplify_compareoperandlist(&o1, &o2))
+ return 1;
+ return 0;
+ }
+
+ // not a times - have to assume it's the operand list
+ // with a "1 *" in front if it
+ if (!e1 -> operands -> next)
+ return 0;
+ if (e1 -> operands -> next -> next)
+ return 0;
+ if (!lw_expr_compare(e1 -> operands -> next -> p, e2))
+ return 0;
+ return 1;
+ }
+
+ // e1 is not a times
+ if (e2 -> type == lw_expr_type_oper && e2 -> value == lw_expr_oper_times)
+ {
+ // e2 is a times
+ if (e2 -> operands -> next -> next)
+ return 0;
+ if (!lw_expr_compare(e1, e2 -> operands -> next -> p))
+ return 0;
+ return 1;
+ }
+
+ // neither are times
+ if (!lw_expr_compare(e1, e2))
+ return 0;
+ return 1;
+}
+
+int lw_expr_contains(lw_expr_t E, lw_expr_t E1)
+{
+ struct lw_expr_opers *o;
+
+ // NULL expr contains nothing :)
+ if (!E)
+ return 0;
+
+ if (E1 -> type != lw_expr_type_var && E1 -> type != lw_expr_type_special)
+ return 0;
+
+ if (lw_expr_compare(E, E1))
+ return 1;
+
+ for (o = E -> operands; o; o = o -> next)
+ {
+ if (lw_expr_contains(o -> p, E1))
+ return 1;
+ }
+ return 0;
+}
+
+void lw_expr_simplify_l(lw_expr_t E, void *priv);
+
+void lw_expr_simplify_go(lw_expr_t E, void *priv)
+{
+ struct lw_expr_opers *o;
+
+ // replace subtraction with O1 + -1(O2)...
+ // needed for like term collection
+ if (E -> type == lw_expr_type_oper && E -> value == lw_expr_oper_minus)
+ {
+ for (o = E -> operands -> next; o; o = o -> next)
+ {
+ lw_expr_t e1, e2;
+
+ e2 = lw_expr_build(lw_expr_type_int, -1);
+ e1 = lw_expr_build(lw_expr_type_oper, lw_expr_oper_times, e2, o -> p);
+ lw_expr_destroy(o -> p);
+ lw_expr_destroy(e2);
+ o -> p = e1;
+ }
+ E -> value = lw_expr_oper_plus;
+ }
+
+ // turn "NEG" into -1(O) - needed for like term collection
+ if (E -> type == lw_expr_type_oper && E -> value == lw_expr_oper_neg)
+ {
+ lw_expr_t e1;
+
+ E -> value = lw_expr_oper_times;
+ e1 = lw_expr_build(lw_expr_type_int, -1);
+ lw_expr_add_operand(E, e1);
+ lw_expr_destroy(e1);
+ }
+
+again:
+ // try to resolve non-constant terms to constants here
+ if (E -> type == lw_expr_type_special && evaluate_special)
+ {
+ lw_expr_t te;
+
+ te = evaluate_special(E -> value, E -> value2, priv);
+ if (lw_expr_contains(te, E))
+ lw_expr_destroy(te);
+ if (te)
+ {
+ for (o = E -> operands; o; o = o -> next)
+ lw_expr_destroy(o -> p);
+ if (E -> type == lw_expr_type_var)
+ lw_free(E -> value2);
+ *E = *te;
+ E -> operands = NULL;
+
+ if (te -> type == lw_expr_type_var)
+ E -> value2 = lw_strdup(te -> value2);
+ for (o = te -> operands; o; o = o -> next)
+ {
+ lw_expr_add_operand(E, lw_expr_copy(o -> p));
+ }
+ lw_expr_destroy(te);
+ goto again;
+ }
+ return;
+ }
+
+ if (E -> type == lw_expr_type_var && evaluate_var)
+ {
+ lw_expr_t te;
+
+ te = evaluate_var(E -> value2, priv);
+ if (lw_expr_contains(te, E))
+ lw_expr_destroy(te);
+ else if (te)
+ {
+ for (o = E -> operands; o; o = o -> next)
+ lw_expr_destroy(o -> p);
+ if (E -> type == lw_expr_type_var)
+ lw_free(E -> value2);
+ *E = *te;
+ E -> operands = NULL;
+
+ if (te -> type == lw_expr_type_var)
+ E -> value2 = lw_strdup(te -> value2);
+ for (o = te -> operands; o; o = o -> next)
+ {
+ lw_expr_add_operand(E, lw_expr_copy(o -> p));
+ }
+ lw_expr_destroy(te);
+ goto again;
+ }
+ return;
+ }
+
+ // non-operators have no simplification to do!
+ if (E -> type != lw_expr_type_oper)
+ return;
+
+ // merge plus operations
+ if (E -> value == lw_expr_oper_plus)
+ {
+ lw_expr_t e2;
+
+ tryagainplus:
+ for (o = E -> operands; o; o = o -> next)
+ {
+ if (o -> p -> type == lw_expr_type_oper && o -> p -> value == lw_expr_oper_plus)
+ {
+ struct lw_expr_opers *o2, *o3;
+ // we have a + operation - bring operands up
+
+ for (o2 = E -> operands; o2 && o2 -> next != o; o2 = o2 -> next)
+ /* do nothing */ ;
+ if (o2)
+ o2 -> next = o -> p -> operands;
+ else
+ E -> operands = o -> p -> operands;
+ for (o2 = o -> p -> operands; o2 -> next; o2 = o2 -> next)
+ /* do nothing */ ;
+ o2 -> next = o -> next;
+ o -> p -> operands = NULL;
+ lw_expr_destroy(o -> p);
+ lw_free(o);
+ goto tryagainplus;
+ }
+ }
+ }
+
+ // merge times operations
+ if (E -> value == lw_expr_oper_times)
+ {
+ lw_expr_t e2;
+
+ tryagaintimes:
+ for (o = E -> operands; o; o = o -> next)
+ {
+ if (o -> p -> type == lw_expr_type_oper && o -> p -> value == lw_expr_oper_times)
+ {
+ struct lw_expr_opers *o2, *o3;
+ // we have a + operation - bring operands up
+
+ for (o2 = E -> operands; o2 && o2 -> next != o; o2 = o2 -> next)
+ /* do nothing */ ;
+ if (o2)
+ o2 -> next = o -> p -> operands;
+ else
+ E -> operands = o -> p -> operands;
+ for (o2 = o -> p -> operands; o2 -> next; o2 = o2 -> next)
+ /* do nothing */ ;
+ o2 -> next = o -> next;
+ o -> p -> operands = NULL;
+ lw_expr_destroy(o -> p);
+ lw_free(o);
+ goto tryagaintimes;
+ }
+ }
+ }
+
+ // simplify operands
+ for (o = E -> operands; o; o = o -> next)
+ lw_expr_simplify_l(o -> p, priv);
+
+ for (o = E -> operands; o; o = o -> next)
+ {
+ if (o -> p -> type != lw_expr_type_int)
+ break;
+ }
+
+ if (!o)
+ {
+ // we can do the operation here!
+ int tr = -42424242;
+
+ switch (E -> value)
+ {
+ case lw_expr_oper_neg:
+ tr = -(E -> operands -> p -> value);
+ break;
+
+ case lw_expr_oper_com:
+ tr = ~(E -> operands -> p -> value);
+ break;
+
+ case lw_expr_oper_plus:
+ tr = E -> operands -> p -> value;
+ for (o = E -> operands -> next; o; o = o -> next)
+ tr += o -> p -> value;
+ break;
+
+ case lw_expr_oper_minus:
+ tr = E -> operands -> p -> value;
+ for (o = E -> operands -> next; o; o = o -> next)
+ tr -= o -> p -> value;
+ break;
+
+ case lw_expr_oper_times:
+ tr = E -> operands -> p -> value;
+ for (o = E -> operands -> next; o; o = o -> next)
+ tr *= o -> p -> value;
+ break;
+
+ case lw_expr_oper_divide:
+ tr = E -> operands -> p -> value / E -> operands -> next -> p -> value;
+ break;
+
+ case lw_expr_oper_mod:
+ tr = E -> operands -> p -> value % E -> operands -> next -> p -> value;
+ break;
+
+ case lw_expr_oper_intdiv:
+ tr = E -> operands -> p -> value / E -> operands -> next -> p -> value;
+ break;
+
+ case lw_expr_oper_bwand:
+ tr = E -> operands -> p -> value & E -> operands -> next -> p -> value;
+ break;
+
+ case lw_expr_oper_bwor:
+ tr = E -> operands -> p -> value | E -> operands -> next -> p -> value;
+ break;
+
+ case lw_expr_oper_bwxor:
+ tr = E -> operands -> p -> value ^ E -> operands -> next -> p -> value;
+ break;
+
+ case lw_expr_oper_and:
+ tr = E -> operands -> p -> value && E -> operands -> next -> p -> value;
+ break;
+
+ case lw_expr_oper_or:
+ tr = E -> operands -> p -> value || E -> operands -> next -> p -> value;
+ break;
+
+ }
+
+ while (E -> operands)
+ {
+ o = E -> operands;
+ E -> operands = o -> next;
+ lw_expr_destroy(o -> p);
+ lw_free(o);
+ }
+ E -> type = lw_expr_type_int;
+ E -> value = tr;
+ return;
+ }
+
+ if (E -> value == lw_expr_oper_plus)
+ {
+ lw_expr_t e1;
+ int cval = 0;
+
+ e1 = lw_expr_create();
+ e1 -> operands = E -> operands;
+ E -> operands = 0;
+
+ for (o = e1 -> operands; o; o = o -> next)
+ {
+ if (o -> p -> type == lw_expr_type_int)
+ cval += o -> p -> value;
+ else
+ lw_expr_add_operand(E, o -> p);
+ }
+ lw_expr_destroy(e1);
+ if (cval)
+ {
+ e1 = lw_expr_build(lw_expr_type_int, cval);
+ lw_expr_add_operand(E, e1);
+ lw_expr_destroy(e1);
+ }
+ }
+
+ if (E -> value == lw_expr_oper_times)
+ {
+ lw_expr_t e1;
+ int cval = 1;
+
+ e1 = lw_expr_create();
+ e1 -> operands = E -> operands;
+ E -> operands = 0;
+
+ for (o = e1 -> operands; o; o = o -> next)
+ {
+ if (o -> p -> type == lw_expr_type_int)
+ cval *= o -> p -> value;
+ else
+ lw_expr_add_operand(E, o -> p);
+ }
+ lw_expr_destroy(e1);
+ if (cval != 1)
+ {
+ e1 = lw_expr_build(lw_expr_type_int, cval);
+ lw_expr_add_operand(E, e1);
+ lw_expr_destroy(e1);
+ }
+ }
+
+ if (E -> value == lw_expr_oper_times)
+ {
+ for (o = E -> operands; o; o = o -> next)
+ {
+ if (o -> p -> type == lw_expr_type_int && o -> p -> value == 0)
+ {
+ // one operand of times is 0, replace operation with 0
+ while (E -> operands)
+ {
+ o = E -> operands;
+ E -> operands = o -> next;
+ lw_expr_destroy(o -> p);
+ lw_free(o);
+ }
+ E -> type = lw_expr_type_int;
+ E -> value = 0;
+ return;
+ }
+ }
+ }
+
+ // sort "constants" to the start of each operand list for + and *
+ if (E -> value == lw_expr_oper_plus || E -> value == lw_expr_oper_times)
+ lw_expr_simplify_sortconstfirst(E);
+
+ // look for like terms and collect them together
+ if (E -> value == lw_expr_oper_plus)
+ {
+ struct lw_expr_opers *o2;
+ for (o = E -> operands; o; o = o -> next)
+ {
+ // skip constants
+ if (o -> p -> type == lw_expr_type_int)
+ continue;
+
+ // we have a term to match
+ // (o -> p) is first term
+ for (o2 = o -> next; o2; o2 = o2 -> next)
+ {
+ lw_expr_t e1, e2;
+
+ if (o2 -> p -> type == lw_expr_type_int)
+ continue;
+
+ if (lw_expr_simplify_isliketerm(o -> p, o2 -> p))
+ {
+ int coef, coef2;
+
+ // we have a like term here
+ // do something about it
+ if (o -> p -> type == lw_expr_type_oper && o -> p -> value == lw_expr_oper_times)
+ {
+ if (o -> p -> operands -> p -> type == lw_expr_type_int)
+ coef = o -> p -> operands -> p -> value;
+ else
+ coef = 1;
+ }
+ else
+ coef = 1;
+ if (o2 -> p -> type == lw_expr_type_oper && o2 -> p -> value == lw_expr_oper_times)
+ {
+ if (o2 -> p -> operands -> p -> type == lw_expr_type_int)
+ coef2 = o2 -> p -> operands -> p -> value;
+ else
+ coef2 = 1;
+ }
+ else
+ coef2 = 1;
+ coef += coef2;
+ e1 = lw_expr_create();
+ e1 -> type = lw_expr_type_oper;
+ e1 -> value = lw_expr_oper_times;
+ if (coef != 1)
+ {
+ e2 = lw_expr_build(lw_expr_type_int, coef);
+ lw_expr_add_operand(e1, e2);
+ lw_expr_destroy(e2);
+ }
+ lw_expr_destroy(o -> p);
+ o -> p = e1;
+ for (o = o2 -> p -> operands; o; o = o -> next)
+ {
+ if (o -> p -> type == lw_expr_type_int)
+ continue;
+ lw_expr_add_operand(e1, o -> p);
+ }
+ lw_expr_destroy(o2 -> p);
+ o2 -> p = lw_expr_build(lw_expr_type_int, 0);
+ goto again;
+ }
+ }
+ }
+ }
+
+
+ if (E -> value == lw_expr_oper_plus)
+ {
+ int c = 0, t = 0;
+ for (o = E -> operands; o; o = o -> next)
+ {
+ t++;
+ if (!(o -> p -> type == lw_expr_type_int && o -> p -> value == 0))
+ {
+ c++;
+ }
+ }
+ if (c == 1)
+ {
+ lw_expr_t r;
+ // find the value and "move it up"
+ while (E -> operands)
+ {
+ o = E -> operands;
+ if (o -> p -> type != lw_expr_type_int || o -> p -> value != 0)
+ {
+ r = lw_expr_copy(o -> p);
+ }
+ E -> operands = o -> next;
+ lw_expr_destroy(o -> p);
+ lw_free(o);
+ }
+ *E = *r;
+ return;
+ }
+ else if (c == 0)
+ {
+ // replace with 0
+ while (E -> operands)
+ {
+ o = E -> operands;
+ E -> operands = o -> next;
+ lw_expr_destroy(o -> p);
+ lw_free(o);
+ }
+ E -> type = lw_expr_type_int;
+ E -> value = 0;
+ return;
+ }
+ else if (c != t)
+ {
+ // collapse out zero terms
+ struct lw_expr_opers *o2;
+
+ for (o = E -> operands; o; o = o -> next)
+ {
+ if (o -> p -> type == lw_expr_type_int && o -> p -> value == 0)
+ {
+ if (o == E -> operands)
+ {
+ E -> operands = o -> next;
+ lw_expr_destroy(o -> p);
+ lw_free(o);
+ o = E -> operands;
+ }
+ else
+ {
+ for (o2 = E -> operands; o2 -> next == o; o2 = o2 -> next)
+ /* do nothing */ ;
+ o2 -> next = o -> next;
+ lw_expr_destroy(o -> p);
+ lw_free(o);
+ o = o2;
+ }
+ }
+ }
+ }
+ return;
+ }
+
+ /* handle times - expand the terms - only with exactly two operands */
+ if (E -> value == lw_expr_oper_times)
+ {
+ lw_expr_t t1;
+ lw_expr_t E2;
+ lw_expr_t E3;
+ if (E -> operands && E -> operands -> next && !(E -> operands -> next -> next))
+ {
+ if (E -> operands -> p -> type == lw_expr_type_int)
+ {
+ /* TIMES */
+ E2 = E -> operands -> next -> p;
+ E3 = E -> operands -> p;
+ if (E2 -> type == lw_expr_type_oper && E2 -> value == lw_expr_oper_plus)
+ {
+ lw_free(E -> operands -> next);
+ lw_free(E -> operands);
+ E -> operands = NULL;
+ E -> value = lw_expr_oper_plus;
+
+ for (o = E2 -> operands; o; o = o -> next)
+ {
+ t1 = lw_expr_build(lw_expr_type_oper, lw_expr_oper_times, E3, o -> p);
+ lw_expr_add_operand(E, t1);
+ }
+
+ lw_expr_destroy(E2);
+ lw_expr_destroy(E3);
+ }
+ }
+ else if (E -> operands -> next -> p -> type == lw_expr_type_int)
+ {
+ /* TIMES */
+ E2 = E -> operands -> p;
+ E3 = E -> operands -> next -> p;
+ if (E2 -> type == lw_expr_type_oper && E2 -> value == lw_expr_oper_plus)
+ {
+ lw_free(E -> operands -> next);
+ lw_free(E -> operands);
+ E -> operands = NULL;
+ E -> value = lw_expr_oper_plus;
+
+ for (o = E2 -> operands; o; o = o -> next)
+ {
+ t1 = lw_expr_build(lw_expr_type_oper, lw_expr_oper_times, E3, o -> p);
+ lw_expr_add_operand(E, t1);
+ }
+
+ lw_expr_destroy(E2);
+ lw_expr_destroy(E3);
+ }
+ }
+ }
+ }
+}
+
+void lw_expr_simplify_l(lw_expr_t E, void *priv)
+{
+ lw_expr_t te;
+ int c;
+
+ (level)++;
+ // bail out if the level gets too deep
+ if (level >= 500 || bailing)
+ {
+ bailing = 1;
+ level--;
+ if (level == 0)
+ bailing = 0;
+ return;
+ }
+ do
+ {
+ te = lw_expr_copy(E);
+ lw_expr_simplify_go(E, priv);
+ c = 0;
+ if (lw_expr_compare(te, E) == 0)
+ c = 1;
+ lw_expr_destroy(te);
+ }
+ while (c);
+ (level)--;
+}
+
+void lw_expr_simplify(lw_expr_t E, void *priv)
+{
+ lw_expr_simplify_l(E, priv);
+}
+
+/*
+
+The following two functions are co-routines which evaluate an infix
+expression. lw_expr_parse_term checks for unary prefix operators then, if
+none found, passes the string off the the defined helper function to
+determine what the term really is. It also handles parentheses.
+
+lw_expr_parse_expr evaluates actual expressions with infix operators. It
+respects the order of operations.
+
+The end of an expression is determined by the presence of any of the
+following conditions:
+
+1. a NUL character
+2. a whitespace character
+3. a )
+4. a ,
+5. any character that is not recognized as a term
+
+lw_expr_parse_term returns NULL if there is no term (end of expr, etc.)
+
+lw_expr_parse_expr returns NULL if there is no expression or on a syntax
+error.
+
+*/
+
+lw_expr_t lw_expr_parse_expr(char **p, void *priv, int prec);
+
+lw_expr_t lw_expr_parse_term(char **p, void *priv)
+{
+ lw_expr_t term, term2;
+
+eval_next:
+ if (!**p || isspace(**p) || **p == ')' || **p == ']')
+ return NULL;
+
+ // parentheses
+ if (**p == '(')
+ {
+ (*p)++;
+ term = lw_expr_parse_expr(p, priv, 0);
+ if (**p != ')')
+ {
+ lw_expr_destroy(term);
+ return NULL;
+ }
+ (*p)++;
+ return term;
+ }
+
+ // unary +
+ if (**p == '+')
+ {
+ (*p)++;
+ goto eval_next;
+ }
+
+ // unary - (prec 200)
+ if (**p == '-')
+ {
+ (*p)++;
+ term = lw_expr_parse_expr(p, priv, 200);
+ if (!term)
+ return NULL;
+
+ term2 = lw_expr_build(lw_expr_type_oper, lw_expr_oper_neg, term);
+ lw_expr_destroy(term);
+ return term2;
+ }
+
+ // unary ^ or ~ (complement, prec 200)
+ if (**p == '^' || **p == '~')
+ {
+ (*p)++;
+ term = lw_expr_parse_expr(p, priv, 200);
+ if (!term)
+ return NULL;
+
+ term2 = lw_expr_build(lw_expr_type_oper, lw_expr_oper_com, term);
+ lw_expr_destroy(term);
+ return term2;
+ }
+
+ // non-operator - pass to caller
+ return parse_term(p, priv);
+}
+
+lw_expr_t lw_expr_parse_expr(char **p, void *priv, int prec)
+{
+ static const struct operinfo
+ {
+ int opernum;
+ char *operstr;
+ int operprec;
+ } operators[] =
+ {
+ { lw_expr_oper_plus, "+", 100 },
+ { lw_expr_oper_minus, "-", 100 },
+ { lw_expr_oper_times, "*", 150 },
+ { lw_expr_oper_divide, "/", 150 },
+ { lw_expr_oper_mod, "%", 150 },
+ { lw_expr_oper_intdiv, "\\", 150 },
+
+ { lw_expr_oper_and, "&&", 25 },
+ { lw_expr_oper_or, "||", 25 },
+
+ { lw_expr_oper_bwand, "&", 50 },
+ { lw_expr_oper_bwor, "|", 50 },
+ { lw_expr_oper_bwxor, "^", 50 },
+
+ { lw_expr_oper_none, "", 0 }
+ };
+
+ int opern, i;
+ lw_expr_t term1, term2, term3;
+
+ if (!**p || isspace(**p) || **p == ')' || **p == ',' || **p == ']')
+ return NULL;
+
+ term1 = lw_expr_parse_term(p, priv);
+ if (!term1)
+ return NULL;
+
+eval_next:
+ if (!**p || isspace(**p) || **p == ')' || **p == ',' || **p == ']')
+ return term1;
+
+ // expecting an operator here
+ for (opern = 0; operators[opern].opernum != lw_expr_oper_none; opern++)
+ {
+ for (i = 0; (*p)[i] && operators[opern].operstr[i] && ((*p)[i] == operators[opern].operstr[i]); i++)
+ /* do nothing */;
+ if (operators[opern].operstr[i] == '\0')
+ break;
+ }
+
+ if (operators[opern].opernum == lw_expr_oper_none)
+ {
+ // unrecognized operator
+ lw_expr_destroy(term1);
+ return NULL;
+ }
+
+ // operator number is in opern, length of oper in i
+
+ // logic:
+ // if the precedence of this operation is <= to the "prec" flag,
+ // we simply return without advancing the input pointer; the operator
+ // will be evaluated again in the enclosing function call
+ if (operators[opern].operprec <= prec)
+ return term1;
+
+ // logic:
+ // we have a higher precedence operator here so we will advance the
+ // input pointer to the next term and let the expression evaluator
+ // loose on it after which time we will push our operator onto the
+ // stack and then go on with the expression evaluation
+ (*p) += i;
+
+ // evaluate next expression(s) of higher precedence
+ term2 = lw_expr_parse_expr(p, priv, operators[opern].operprec);
+ if (!term2)
+ {
+ lw_expr_destroy(term1);
+ return NULL;
+ }
+
+ // now create operator
+ term3 = lw_expr_build(lw_expr_type_oper, operators[opern].opernum, term1, term2);
+ lw_expr_destroy(term1);
+ lw_expr_destroy(term2);
+
+ // the new "expression" is the next "left operand"
+ term1 = term3;
+
+ // continue evaluating
+ goto eval_next;
+}
+
+lw_expr_t lw_expr_parse(char **p, void *priv)
+{
+ return lw_expr_parse_expr(p, priv, 0);
+}
+
+int lw_expr_testterms(lw_expr_t e, lw_expr_testfn_t *fn, void *priv)
+{
+ struct lw_expr_opers *o;
+ int r;
+
+ for (o = e -> operands; o; o = o -> next)
+ {
+ r = lw_expr_testterms(o -> p, fn, priv);
+ if (r)
+ return r;
+ }
+ return (fn)(e, priv);
+}
+
+int lw_expr_type(lw_expr_t e)
+{
+ return e -> type;
+}
+
+void *lw_expr_specptr(lw_expr_t e)
+{
+ return e -> value2;
+}
diff -r 000000000000 -r 2c24602be78f lwlib/lw_expr.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwlib/lw_expr.h Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,115 @@
+/*
+lwexpr.h
+
+Copyright © 2010 William Astle
+
+This file is part of LWTOOLS.
+
+LWTOOLS 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 3 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, see .
+*/
+
+#ifndef ___lw_expr_h_seen___
+#define ___lw_expr_h_seen___
+
+#include
+
+enum
+{
+ lw_expr_type_oper, // operator term
+ lw_expr_type_int, // integer
+ lw_expr_type_var, // a "variable" (string for the name)
+ lw_expr_type_special // a "special" reference (user defined)
+};
+
+enum
+{
+ lw_expr_oper_plus = 1, // addition
+ lw_expr_oper_minus, // subtraction
+ lw_expr_oper_times, // multiplication
+ lw_expr_oper_divide, // division
+ lw_expr_oper_mod, // modulus
+ lw_expr_oper_intdiv, // integer division
+ lw_expr_oper_bwand, // bitwise and
+ lw_expr_oper_bwor, // bitwise or
+ lw_expr_oper_bwxor, // bitwise xor
+ lw_expr_oper_and, // boolean and
+ lw_expr_oper_or, // boolean or
+ lw_expr_oper_neg, // unary negation, 2's complement
+ lw_expr_oper_com, // unary 1's complement
+ lw_expr_oper_none = 0
+};
+
+#ifdef ___lw_expr_c_seen___
+
+typedef struct lw_expr_priv * lw_expr_t;
+
+struct lw_expr_opers
+{
+ lw_expr_t p;
+ struct lw_expr_opers *next;
+};
+
+struct lw_expr_priv
+{
+ int type; // type of term
+ int value; // integer value
+ void *value2; // misc pointer value
+ struct lw_expr_opers *operands; // ptr to list of operands (for operators)
+};
+
+typedef lw_expr_t lw_expr_fn_t(int t, void *ptr, void *priv);
+typedef lw_expr_t lw_expr_fn2_t(char *var, void *priv);
+typedef lw_expr_t lw_expr_fn3_t(char **p, void *priv);
+typedef int lw_expr_testfn_t(lw_expr_t e, void *priv);
+
+#else /* def ___lw_expr_c_seen___ */
+
+typedef void * lw_expr_t;
+
+extern lw_expr_t lwexpr_create(void);
+extern void lw_expr_destroy(lw_expr_t E);
+extern lw_expr_t lw_expr_copy(lw_expr_t E);
+extern void lw_expr_add_operand(lw_expr_t E, lw_expr_t O);
+extern lw_expr_t lw_expr_build(int exprtype, ...);
+extern char *lw_expr_print(lw_expr_t E);
+extern int lw_expr_compare(lw_expr_t E1, lw_expr_t E2);
+extern void lw_expr_simplify(lw_expr_t E, void *priv);
+
+typedef lw_expr_t lw_expr_fn_t(int t, void *ptr, void *priv);
+typedef lw_expr_t lw_expr_fn2_t(char *var, void *priv);
+typedef lw_expr_t lw_expr_fn3_t(char **p, void *priv);
+
+extern void lw_expr_set_special_handler(lw_expr_fn_t *fn);
+extern void lw_expr_set_var_handler(lw_expr_fn2_t *fn);
+extern void lw_expr_set_term_parser(lw_expr_fn3_t *fn);
+
+extern lw_expr_t lw_expr_parse(char **p, void *priv);
+extern int lw_expr_istype(lw_expr_t e, int t);
+extern int lw_expr_intval(lw_expr_t e);
+extern int lw_expr_specint(lw_expr_t e);
+extern void *lw_expr_specptr(lw_expr_t e);
+extern int lw_expr_whichop(lw_expr_t e);
+
+extern int lw_expr_type(lw_expr_t e);
+
+typedef int lw_expr_testfn_t(lw_expr_t e, void *priv);
+
+// run a function on all terms in an expression; if the function
+// returns non-zero for any term, return non-zero, else return
+// zero
+extern int lw_expr_testterms(lw_expr_t e, lw_expr_testfn_t *fn, void *priv);
+
+#endif /* def ___lw_expr_c_seen___ */
+
+#endif /* ___lw_expr_h_seen___ */
diff -r 000000000000 -r 2c24602be78f lwlib/lw_stack.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwlib/lw_stack.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,78 @@
+/*
+lw_stack.c
+
+Copyright © 2010 William Astle
+
+This file is part of LWTOOLS.
+
+LWTOOLS 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 3 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, see .
+*/
+
+#define ___lw_stack_c_seen___
+#include "lw_stack.h"
+#include "lw_alloc.h"
+
+/* this is technically valid but dubious */
+#define NULL 0
+
+lw_stack_t lw_stack_create(void (*freefn)(void *d))
+{
+ lw_stack_t S;
+
+ S = lw_alloc(sizeof(lw_stack_t));
+ S -> head = NULL;
+ S -> freefn = freefn;
+ return S;
+}
+
+void *lw_stack_pop(lw_stack_t S)
+{
+ if (S -> head)
+ {
+ void *ret, *r2;
+
+ ret = S -> head -> data;
+ r2 = S -> head;
+ S -> head = S -> head -> next;
+ lw_free(r2);
+ return ret;
+ }
+ return NULL;
+}
+
+void lw_stack_destroy(lw_stack_t S)
+{
+ void *d;
+
+ while (d = lw_stack_pop(S))
+ (S->freefn)(d);
+ lw_free(S);
+}
+
+void *lw_stack_top(lw_stack_t S)
+{
+ if (S -> head)
+ return S -> head -> data;
+ return NULL;
+}
+
+void lw_stack_push(lw_stack_t S, void *item)
+{
+ struct lw_stack_node_priv *t;
+
+ t = lw_alloc(sizeof(struct lw_stack_node_priv));
+ t -> next = S -> head;
+ S -> head = t;
+ t -> data = item;
+}
diff -r 000000000000 -r 2c24602be78f lwlib/lw_stack.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwlib/lw_stack.h Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,53 @@
+/*
+lw_stack.h
+
+Copyright © 2010 William Astle
+
+This file is part of LWTOOLS.
+
+LWTOOLS 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 3 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, see .
+*/
+
+#ifndef ___lw_stack_h_seen___
+#define ___lw_stack_h_seen___
+
+
+#ifdef ___lw_stack_c_seen___
+
+struct lw_stack_node_priv
+{
+ void *data;
+ struct lw_stack_node_priv *next;
+};
+
+struct lw_stack_priv
+{
+ struct lw_stack_node_priv *head;
+ void (*freefn)(void *d);
+};
+
+typedef struct lw_stack_priv * lw_stack_t;
+
+#else /* def ___lw_stack_c_seen___ */
+
+typedef void * lw_stack_t;
+extern lw_stack_t lw_stack_create(void (*freefn)(void *d));
+extern void lw_stack_destroy(lw_stack_t S);
+extern void *lw_stack_top(lw_stack_t S);
+extern void *lw_stack_pop(lw_stack_t S);
+extern void lw_stack_push(lw_stack_t S, void *item);
+
+#endif /* def ___lw_stack_c_seen___ */
+
+#endif /* ___lw_stack_h_seen___ */
diff -r 000000000000 -r 2c24602be78f lwlib/lw_string.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwlib/lw_string.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,83 @@
+/*
+lw_string.c
+
+Copyright © 2010 William Astle
+
+This file is part of LWTOOLS.
+
+LWTOOLS 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 3 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, see .
+*/
+
+#include
+#include
+
+#define ___lw_string_c_seen___
+#include "lw_alloc.h"
+#include "lw_string.h"
+
+char *lw_strdup(const char *s)
+{
+ char *r;
+
+ if (!s)
+ s = "(null)";
+
+ r = lw_alloc(strlen(s) + 1);
+ strcpy(r, s);
+ return r;
+}
+
+char *lw_strndup(const char *s, int len)
+{
+ char *r;
+ int sl;
+
+ sl = strlen(s);
+ if (sl > len)
+ sl = len;
+
+ r = lw_alloc(sl + 1);
+ memmove(r, s, sl);
+ r[sl] = '\0';
+ return r;
+}
+
+char *lw_token(const char *s, int sep, const char **ap)
+{
+ const char *p;
+ char *r;
+
+ if (!s)
+ return NULL;
+
+ p = strchr(s, sep);
+ if (!p)
+ {
+ if (ap)
+ *ap = NULL;
+ return lw_strdup(s);
+ }
+
+ r = lw_alloc(p - s + 1);
+ strncpy(r, (char *)s, p - s);
+ r[p - s] = '\0';
+
+ if (ap)
+ {
+ while (*p && *p == sep)
+ p++;
+ *ap = p;
+ }
+ return r;
+}
diff -r 000000000000 -r 2c24602be78f lwlib/lw_string.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwlib/lw_string.h Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,36 @@
+/*
+lw_string.h
+
+Copyright © 2010 William Astle
+
+This file is part of LWTOOLS.
+
+LWTOOLS 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 3 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, see .
+*/
+
+#ifndef ___lw_string_h_seen___
+#define ___lw_string_h_seen___
+
+
+#ifdef ___lw_string_c_seen___
+
+#else /* def ___lw_string_c_seen___ */
+
+extern char *lw_strdup(const char *s);
+extern char *lw_strndup(const char *s, int len);
+extern char *lw_token(const char *s, int sep, const char **ap);
+
+#endif /* def ___lw_string_c_seen___ */
+
+#endif /* ___lw_string_h_seen___ */
\ No newline at end of file
diff -r 000000000000 -r 2c24602be78f lwlib/lw_stringlist.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwlib/lw_stringlist.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,102 @@
+/*
+lw_stringlist.c
+
+Copyright © 2010 William Astle
+
+This file is part of LWTOOLS.
+
+LWTOOLS 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 3 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, see .
+*/
+
+#include
+
+#define ___lw_stringlist_c_seen___
+#include "lw_stringlist.h"
+#include "lw_string.h"
+#include "lw_alloc.h"
+
+lw_stringlist_t lw_stringlist_create(void)
+{
+ lw_stringlist_t s;
+
+
+ s = lw_alloc(sizeof(struct lw_stringlist_priv));
+ s -> strings = NULL;
+ s -> nstrings = 0;
+ s -> cstring = 0;
+
+ return s;
+}
+
+void lw_stringlist_destroy(lw_stringlist_t S)
+{
+ if (S)
+ {
+ int i;
+ for (i = 0; i < S -> nstrings; i++)
+ {
+ lw_free(S -> strings[i]);
+ }
+ lw_free(S);
+ }
+}
+
+void lw_stringlist_addstring(lw_stringlist_t S, char *str)
+{
+ S -> strings = lw_realloc(S -> strings, sizeof(char *) * (S -> nstrings + 1));
+ S -> strings[S -> nstrings] = lw_strdup(str);
+ S -> nstrings++;
+}
+
+void lw_stringlist_reset(lw_stringlist_t S)
+{
+ S -> cstring = 0;
+}
+
+char *lw_stringlist_current(lw_stringlist_t S)
+{
+ if (S -> cstring >= S -> nstrings)
+ return NULL;
+ return S -> strings[S -> cstring];
+}
+
+char *lw_stringlist_next(lw_stringlist_t S)
+{
+ S -> cstring++;
+ return lw_stringlist_current(S);
+}
+
+int lw_stringlist_nstrings(lw_stringlist_t S)
+{
+ return S -> nstrings;
+}
+
+lw_stringlist_t lw_stringlist_copy(lw_stringlist_t S)
+{
+ lw_stringlist_t r;
+
+ r = lw_alloc(sizeof(lw_stringlist_t));
+ r -> nstrings = S -> nstrings;
+ if (S -> nstrings)
+ {
+ int i;
+
+ r -> strings = lw_alloc(sizeof(char *) * S -> nstrings);
+ for (i = 0; i < S -> nstrings; i++)
+ {
+ r -> strings[i] = lw_strdup(S -> strings[i]);
+ }
+ }
+ return r;
+}
diff -r 000000000000 -r 2c24602be78f lwlib/lw_stringlist.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwlib/lw_stringlist.h Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,50 @@
+/*
+lw_stringlist.h
+
+Copyright © 2010 William Astle
+
+This file is part of LWTOOLS.
+
+LWTOOLS 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 3 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, see .
+*/
+
+#ifndef ___lw_stringlist_h_seen___
+#define ___lw_stringlist_h_seen___
+
+
+#ifdef ___lw_stringlist_c_seen___
+
+struct lw_stringlist_priv
+{
+ char **strings;
+ int nstrings;
+ int cstring;
+};
+typedef struct lw_stringlist_priv * lw_stringlist_t;
+
+#else /* def ___lw_stringlist_c_seen___ */
+
+typedef void * lw_stringlist_t;
+extern lw_stringlist_t lw_stringlist_create(void);
+extern void lw_stringlist_destroy(lw_stringlist_t S);
+extern void lw_stringlist_addstring(lw_stringlist_t S, char *str);
+extern void lw_stringlist_reset(lw_stringlist_t S);
+extern char *lw_stringlist_current(lw_stringlist_t S);
+extern char *lw_stringlist_next(lw_stringlist_t S);
+extern int lw_stringlist_nstrings(lw_stringlist_t S);
+extern lw_stringlist_t lw_stringlist_copy(lw_stringlist_t S);
+
+#endif /* def ___lw_stringlist_c_seen___ */
+
+#endif /* ___lw_stringlist_h_seen___ */
diff -r 000000000000 -r 2c24602be78f lwlib/rules.make
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwlib/rules.make Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,6 @@
+dirname := $(dir $(lastword $(MAKEFILE_LIST)))
+
+lwlib_srcs_local := lw_alloc.c lw_error.c lw_expr.c lw_stack.c \
+ lw_string.c lw_stringlist.c
+
+lwlib_srcs := $(lwlib_srcs) $(addprefix $(dirname),$(lwlib_srcs_local))
diff -r 000000000000 -r 2c24602be78f lwlink/expr.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwlink/expr.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,369 @@
+/*
+expr.c
+Copyright © 2009 William Astle
+
+This file is part of LWLINK.
+
+LWLINK 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 3 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, see .
+*/
+
+/*
+This file contains the actual expression evaluator
+*/
+
+#define __expr_c_seen__
+
+#include
+#include
+#include
+
+#include "expr.h"
+#include "util.h"
+
+lw_expr_stack_t *lw_expr_stack_create(void)
+{
+ lw_expr_stack_t *s;
+
+ s = lw_malloc(sizeof(lw_expr_stack_t));
+ s -> head = NULL;
+ s -> tail = NULL;
+ return s;
+}
+
+void lw_expr_stack_free(lw_expr_stack_t *s)
+{
+ while (s -> head)
+ {
+ s -> tail = s -> head;
+ s -> head = s -> head -> next;
+ lw_expr_term_free(s -> tail -> term);
+ lw_free(s -> tail);
+ }
+ lw_free(s);
+}
+
+lw_expr_stack_t *lw_expr_stack_dup(lw_expr_stack_t *s)
+{
+ lw_expr_stack_node_t *t;
+ lw_expr_stack_t *s2;
+
+ s2 = lw_expr_stack_create();
+ for (t = s -> head; t; t = t -> next)
+ {
+ lw_expr_stack_push(s2, t -> term);
+ }
+ return s2;
+}
+
+void lw_expr_term_free(lw_expr_term_t *t)
+{
+ if (t)
+ {
+ if (t -> term_type == LW_TERM_SYM)
+ lw_free(t -> symbol);
+ lw_free(t);
+ }
+}
+
+lw_expr_term_t *lw_expr_term_create_oper(int oper)
+{
+ lw_expr_term_t *t;
+
+ t = lw_malloc(sizeof(lw_expr_term_t));
+ t -> term_type = LW_TERM_OPER;
+ t -> value = oper;
+ return t;
+}
+
+lw_expr_term_t *lw_expr_term_create_int(int val)
+{
+ lw_expr_term_t *t;
+
+ t = lw_malloc(sizeof(lw_expr_term_t));
+ t -> term_type = LW_TERM_INT;
+ t -> value = val;
+ return t;
+}
+
+lw_expr_term_t *lw_expr_term_create_sym(char *sym, int symtype)
+{
+ lw_expr_term_t *t;
+
+ t = lw_malloc(sizeof(lw_expr_term_t));
+ t -> term_type = LW_TERM_SYM;
+ t -> symbol = lw_strdup(sym);
+ t -> value = symtype;
+ return t;
+}
+
+lw_expr_term_t *lw_expr_term_dup(lw_expr_term_t *t)
+{
+ switch (t -> term_type)
+ {
+ case LW_TERM_INT:
+ return lw_expr_term_create_int(t -> value);
+
+ case LW_TERM_OPER:
+ return lw_expr_term_create_oper(t -> value);
+
+ case LW_TERM_SYM:
+ return lw_expr_term_create_sym(t -> symbol, t -> value);
+
+ default:
+ exit(1);
+ }
+// can't get here
+}
+
+void lw_expr_stack_push(lw_expr_stack_t *s, lw_expr_term_t *t)
+{
+ lw_expr_stack_node_t *n;
+
+ if (!s)
+ {
+ exit(1);
+ }
+
+ n = lw_malloc(sizeof(lw_expr_stack_node_t));
+ n -> next = NULL;
+ n -> prev = s -> tail;
+ n -> term = lw_expr_term_dup(t);
+
+ if (s -> head)
+ {
+ s -> tail -> next = n;
+ s -> tail = n;
+ }
+ else
+ {
+ s -> head = n;
+ s -> tail = n;
+ }
+}
+
+lw_expr_term_t *lw_expr_stack_pop(lw_expr_stack_t *s)
+{
+ lw_expr_term_t *t;
+ lw_expr_stack_node_t *n;
+
+ if (!(s -> tail))
+ return NULL;
+
+ n = s -> tail;
+ s -> tail = n -> prev;
+ if (!(n -> prev))
+ {
+ s -> head = NULL;
+ }
+
+ t = n -> term;
+ n -> term = NULL;
+
+ lw_free(n);
+
+ return t;
+}
+
+/*
+take an expression stack s and scan for operations that can be completed
+
+return -1 on error, 0 on no error
+
+possible errors are: division by zero or unknown operator
+
+theory of operation:
+
+scan the stack for an operator which has two constants preceding it (binary)
+or 1 constant preceding it (unary) and if found, perform the calculation
+and replace the operator and its operands with the result
+
+repeat the scan until no futher simplications are found or if there are no
+further operators or only a single term remains
+
+*/
+int lw_expr_reval(lw_expr_stack_t *s, lw_expr_stack_t *(*sfunc)(char *sym, int stype, void *state), void *state)
+{
+ lw_expr_stack_node_t *n, *n2;
+ lw_expr_stack_t *ss;
+ int c;
+
+next_iter_sym:
+ // resolve symbols
+ // symbols that do not resolve to an expression are left alone
+ for (c = 0, n = s -> head; n; n = n -> next)
+ {
+ if (n -> term -> term_type == LW_TERM_SYM)
+ {
+ ss = sfunc(n -> term -> symbol, n -> term -> value, state);
+ if (ss)
+ {
+ c++;
+ // splice in the result stack
+ if (n -> prev)
+ {
+ n -> prev -> next = ss -> head;
+ }
+ else
+ {
+ s -> head = ss -> head;
+ }
+ ss -> head -> prev = n -> prev;
+ ss -> tail -> next = n -> next;
+ if (n -> next)
+ {
+ n -> next -> prev = ss -> tail;
+ }
+ else
+ {
+ s -> tail = ss -> tail;
+ }
+ lw_expr_term_free(n -> term);
+ lw_free(n);
+ n = ss -> tail;
+
+ ss -> head = NULL;
+ ss -> tail = NULL;
+ lw_expr_stack_free(ss);
+ }
+ }
+ }
+ if (c)
+ goto next_iter_sym;
+
+next_iter:
+ // a single term
+ if (s -> head == s -> tail)
+ return 0;
+
+ // search for an operator
+ for (n = s -> head; n; n = n -> next)
+ {
+ if (n -> term -> term_type == LW_TERM_OPER)
+ {
+ if (n -> term -> value == LW_OPER_NEG
+ || n -> term -> value == LW_OPER_COM
+ )
+ {
+ // unary operator
+ if (n -> prev && n -> prev -> term -> term_type == LW_TERM_INT)
+ {
+ // a unary operator we can resolve
+ // we do the op then remove the term "n" is pointing at
+ if (n -> term -> value == LW_OPER_NEG)
+ {
+ n -> prev -> term -> value = -(n -> prev -> term -> value);
+ }
+ else if (n -> term -> value == LW_OPER_COM)
+ {
+ n -> prev -> term -> value = ~(n -> prev -> term -> value);
+ }
+ n -> prev -> next = n -> next;
+ if (n -> next)
+ n -> next -> prev = n -> prev;
+ else
+ s -> tail = n -> prev;
+
+ lw_expr_term_free(n -> term);
+ lw_free(n);
+ break;
+ }
+ }
+ else
+ {
+ // binary operator
+ if (n -> prev && n -> prev -> prev && n -> prev -> term -> term_type == LW_TERM_INT && n -> prev -> prev -> term -> term_type == LW_TERM_INT)
+ {
+ // a binary operator we can resolve
+ switch (n -> term -> value)
+ {
+ case LW_OPER_PLUS:
+ n -> prev -> prev -> term -> value += n -> prev -> term -> value;
+ break;
+
+ case LW_OPER_MINUS:
+ n -> prev -> prev -> term -> value -= n -> prev -> term -> value;
+ break;
+
+ case LW_OPER_TIMES:
+ n -> prev -> prev -> term -> value *= n -> prev -> term -> value;
+ break;
+
+ case LW_OPER_DIVIDE:
+ if (n -> prev -> term -> value == 0)
+ return -1;
+ n -> prev -> prev -> term -> value /= n -> prev -> term -> value;
+ break;
+
+ case LW_OPER_MOD:
+ if (n -> prev -> term -> value == 0)
+ return -1;
+ n -> prev -> prev -> term -> value %= n -> prev -> term -> value;
+ break;
+
+ case LW_OPER_INTDIV:
+ if (n -> prev -> term -> value == 0)
+ return -1;
+ n -> prev -> prev -> term -> value /= n -> prev -> term -> value;
+ break;
+
+ case LW_OPER_BWAND:
+ n -> prev -> prev -> term -> value &= n -> prev -> term -> value;
+ break;
+
+ case LW_OPER_BWOR:
+ n -> prev -> prev -> term -> value |= n -> prev -> term -> value;
+ break;
+
+ case LW_OPER_BWXOR:
+ n -> prev -> prev -> term -> value ^= n -> prev -> term -> value;
+ break;
+
+ case LW_OPER_AND:
+ n -> prev -> prev -> term -> value = (n -> prev -> term -> value && n -> prev -> prev -> term -> value) ? 1 : 0;
+ break;
+
+ case LW_OPER_OR:
+ n -> prev -> prev -> term -> value = (n -> prev -> term -> value || n -> prev -> prev -> term -> value) ? 1 : 0;
+ break;
+
+ default:
+ // return error if unknown operator!
+ return -1;
+ }
+
+ // now remove the two unneeded entries from the stack
+ n -> prev -> prev -> next = n -> next;
+ if (n -> next)
+ n -> next -> prev = n -> prev -> prev;
+ else
+ s -> tail = n -> prev -> prev;
+
+ lw_expr_term_free(n -> term);
+ lw_expr_term_free(n -> prev -> term);
+ lw_free(n -> prev);
+ lw_free(n);
+ break;
+ }
+ }
+ }
+ }
+ // note for the terminally confused about dynamic memory and pointers:
+ // n will not be NULL even after the lw_free calls above so
+ // this test will still work (n will be a dangling pointer)
+ // (n will only be NULL if we didn't find any operators to simplify)
+ if (n)
+ goto next_iter;
+
+ return 0;
+}
diff -r 000000000000 -r 2c24602be78f lwlink/expr.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwlink/expr.h Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,108 @@
+/*
+expr.h
+Copyright © 2009 William Astle
+
+This file is part of LWLINK.
+
+LWLINK 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 3 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, see .
+*/
+
+/*
+Definitions for expression evaluator
+*/
+
+#ifndef __expr_h_seen__
+#define __expr_h_seen__
+
+#ifndef __expr_c_seen__
+#define __expr_E__ extern
+#else
+#define __expr_E__
+#endif
+
+// term types
+#define LW_TERM_NONE 0
+#define LW_TERM_OPER 1 // an operator
+#define LW_TERM_INT 2 // 32 bit signed integer
+#define LW_TERM_SYM 3 // symbol reference
+
+// operator types
+#define LW_OPER_NONE 0
+#define LW_OPER_PLUS 1 // +
+#define LW_OPER_MINUS 2 // -
+#define LW_OPER_TIMES 3 // *
+#define LW_OPER_DIVIDE 4 // /
+#define LW_OPER_MOD 5 // %
+#define LW_OPER_INTDIV 6 // \ (don't end line with \)
+#define LW_OPER_BWAND 7 // bitwise AND
+#define LW_OPER_BWOR 8 // bitwise OR
+#define LW_OPER_BWXOR 9 // bitwise XOR
+#define LW_OPER_AND 10 // boolean AND
+#define LW_OPER_OR 11 // boolean OR
+#define LW_OPER_NEG 12 // - unary negation (2's complement)
+#define LW_OPER_COM 13 // ^ unary 1's complement
+
+
+// term structure
+typedef struct lw_expr_term_s
+{
+ int term_type; // type of term (see above)
+ char *symbol; // name of a symbol
+ int value; // value of the term (int) or operator number (OPER)
+} lw_expr_term_t;
+
+// type for an expression evaluation stack
+typedef struct lw_expr_stack_node_s lw_expr_stack_node_t;
+struct lw_expr_stack_node_s
+{
+ lw_expr_term_t *term;
+ lw_expr_stack_node_t *prev;
+ lw_expr_stack_node_t *next;
+};
+
+typedef struct lw_expr_stack_s
+{
+ lw_expr_stack_node_t *head;
+ lw_expr_stack_node_t *tail;
+} lw_expr_stack_t;
+
+__expr_E__ void lw_expr_term_free(lw_expr_term_t *t);
+__expr_E__ lw_expr_term_t *lw_expr_term_create_oper(int oper);
+__expr_E__ lw_expr_term_t *lw_expr_term_create_sym(char *sym, int symtype);
+__expr_E__ lw_expr_term_t *lw_expr_term_create_int(int val);
+__expr_E__ lw_expr_term_t *lw_expr_term_dup(lw_expr_term_t *t);
+
+__expr_E__ void lw_expr_stack_free(lw_expr_stack_t *s);
+__expr_E__ lw_expr_stack_t *lw_expr_stack_create(void);
+__expr_E__ lw_expr_stack_t *lw_expr_stack_dup(lw_expr_stack_t *s);
+
+__expr_E__ void lw_expr_stack_push(lw_expr_stack_t *s, lw_expr_term_t *t);
+__expr_E__ lw_expr_term_t *lw_expr_stack_pop(lw_expr_stack_t *s);
+
+// simplify expression
+__expr_E__ int lw_expr_reval(lw_expr_stack_t *s, lw_expr_stack_t *(*sfunc)(char *sym, int symtype, void *state), void *state);
+
+// useful macros
+// is the expression "simple" (one term)?
+#define lw_expr_is_simple(s) ((s) -> head == (s) -> tail)
+
+// is the expression constant?
+#define lw_expr_is_constant(s) (lw_expr_is_simple(s) && (!((s) -> head) || (s) -> head -> term -> term_type == LW_TERM_INT))
+
+// get the constant value of an expression or 0 if not constant
+#define lw_expr_get_value(s) (lw_expr_is_constant(s) ? ((s) -> head ? (s) -> head -> term -> value : 0) : 0)
+
+#undef __expr_E__
+
+#endif // __expr_h_seen__
diff -r 000000000000 -r 2c24602be78f lwlink/link.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwlink/link.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,460 @@
+/*
+link.c
+Copyright © 2009 William Astle
+
+This file is part of LWLINK.
+
+LWLINK 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 3 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, see .
+
+
+Resolve section and symbol addresses; handle incomplete references
+*/
+
+#include
+#include
+
+#include "expr.h"
+#include "lwlink.h"
+#include "util.h"
+
+struct section_list *sectlist = NULL;
+int nsects = 0;
+static int nforced = 0;
+
+void check_section_name(char *name, int *base, fileinfo_t *fn)
+{
+ int sn;
+
+ if (fn -> forced == 0)
+ return;
+
+ for (sn = 0; sn < fn -> nsections; sn++)
+ {
+ if (!strcmp(name, fn -> sections[sn].name))
+ {
+ // we have a match
+ sectlist = lw_realloc(sectlist, sizeof(struct section_list) * (nsects + 1));
+ sectlist[nsects].ptr = &(fn -> sections[sn]);
+
+ fn -> sections[sn].processed = 1;
+ fn -> sections[sn].loadaddress = *base;
+ *base += fn -> sections[sn].codesize;
+ nsects++;
+ }
+ }
+ for (sn = 0; sn < fn -> nsubs; sn++)
+ {
+ check_section_name(name, base, fn -> subs[sn]);
+ }
+}
+
+void add_matching_sections(char *name, int yesflags, int noflags, int *base);
+void check_section_flags(int yesflags, int noflags, int *base, fileinfo_t *fn)
+{
+ int sn;
+
+ if (fn -> forced == 0)
+ return;
+
+ for (sn = 0; sn < fn -> nsections; sn++)
+ {
+ // ignore if the noflags tell us to
+ if (noflags && (fn -> sections[sn].flags & noflags))
+ continue;
+ // ignore unless the yesflags tell us not to
+ if (yesflags && (fn -> sections[sn].flags & yesflags == 0))
+ continue;
+ // ignore it if already processed
+ if (fn -> sections[sn].processed)
+ continue;
+
+ // we have a match - now collect *all* sections of the same name!
+ add_matching_sections(fn -> sections[sn].name, 0, 0, base);
+
+ // and then continue looking for sections
+ }
+ for (sn = 0; sn < fn -> nsubs; sn++)
+ {
+ check_section_flags(yesflags, noflags, base, fn -> subs[sn]);
+ }
+}
+
+
+
+void add_matching_sections(char *name, int yesflags, int noflags, int *base)
+{
+ int fn;
+ if (name)
+ {
+ // named section
+ // look for all instances of a section by the specified name
+ // and resolve base addresses and add to the list
+ for (fn = 0; fn < ninputfiles; fn++)
+ {
+ check_section_name(name, base, inputfiles[fn]);
+ }
+ }
+ else
+ {
+ // wildcard section
+ // named section
+ // look for all instances of a section by the specified name
+ // and resolve base addresses and add to the list
+ for (fn = 0; fn < ninputfiles; fn++)
+ {
+ check_section_flags(yesflags, noflags, base, inputfiles[fn]);
+ }
+ }
+}
+
+// work out section load order and resolve base addresses for each section
+// make a list of sections to load in order
+void resolve_sections(void)
+{
+ int laddr = 0;
+ int ln, sn, fn;
+
+ for (ln = 0; ln < linkscript.nlines; ln++)
+ {
+ if (linkscript.lines[ln].loadat >= 0)
+ laddr = linkscript.lines[ln].loadat;
+ add_matching_sections(linkscript.lines[ln].sectname, linkscript.lines[ln].yesflags, linkscript.lines[ln].noflags, &laddr);
+
+ if (linkscript.lines[ln].sectname)
+ {
+ }
+ else
+ {
+ // wildcard section
+ // look for all sections not yet processed that match flags
+
+ int f = 0;
+ int fn0, sn0;
+ char *sname;
+
+ // named section
+ // look for all instances of a section by the specified name
+ // and resolve base addresses and add to the list
+ for (fn0 = 0; fn0 < ninputfiles; fn0++)
+ {
+ for (sn0 = 0; sn0 < inputfiles[fn0] -> nsections; sn0++)
+ {
+ // ignore if the "no flags" bit says to
+ if (linkscript.lines[ln].noflags && (inputfiles[fn0] -> sections[sn0].flags & linkscript.lines[ln].noflags))
+ continue;
+ // ignore unless the yes flags tell us not to
+ if (linkscript.lines[ln].yesflags && (inputfiles[fn0] -> sections[sn0].flags & linkscript.lines[ln].yesflags == 0))
+ continue;
+ if (inputfiles[fn0] -> sections[sn0].processed == 0)
+ {
+ sname = inputfiles[fn0] -> sections[sn0].name;
+ for (fn = 0; fn < ninputfiles; fn++)
+ {
+ for (sn = 0; sn < inputfiles[fn] -> nsections; sn++)
+ {
+ if (!strcmp(sname, inputfiles[fn] -> sections[sn].name))
+ {
+ // we have a match
+ sectlist = lw_realloc(sectlist, sizeof(struct section_list) * (nsects + 1));
+ sectlist[nsects].ptr = &(inputfiles[fn] -> sections[sn]);
+
+ inputfiles[fn] -> sections[sn].processed = 1;
+ if (!f && linkscript.lines[ln].loadat >= 0)
+ {
+ f = 1;
+ sectlist[nsects].forceaddr = 1;
+ laddr = linkscript.lines[ln].loadat;
+ }
+ else
+ {
+ sectlist[nsects].forceaddr = 0;
+ }
+ inputfiles[fn] -> sections[sn].loadaddress = laddr;
+ laddr += inputfiles[fn] -> sections[sn].codesize;
+ nsects++;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // theoretically, all the base addresses are set now
+}
+
+lw_expr_stack_t *find_external_sym_recurse(char *sym, fileinfo_t *fn)
+{
+ int sn;
+ lw_expr_stack_t *r;
+ lw_expr_term_t *term;
+ symtab_t *se;
+ int val;
+
+ for (sn = 0; sn < fn -> nsections; sn++)
+ {
+ for (se = fn -> sections[sn].exportedsyms; se; se = se -> next)
+ {
+ if (!strcmp(sym, se -> sym))
+ {
+ if (!(fn -> forced))
+ {
+ fn -> forced = 1;
+ nforced = 1;
+ }
+ val = se -> offset + fn -> sections[sn].loadaddress;
+ r = lw_expr_stack_create();
+ term = lw_expr_term_create_int(val & 0xffff);
+ lw_expr_stack_push(r, term);
+ lw_expr_term_free(term);
+ return r;
+ }
+ }
+ }
+
+ for (sn = 0; sn < fn -> nsubs; sn++)
+ {
+ r = find_external_sym_recurse(sym, fn -> subs[sn]);
+ if (r)
+ {
+ if (!(fn -> forced))
+ {
+ nforced = 1;
+ fn -> forced = 1;
+ }
+ return r;
+ }
+ }
+ return NULL;
+}
+
+// resolve all incomplete references now
+// anything that is unresolvable at this stage will throw an error
+// because we know the load address of every section now
+lw_expr_stack_t *resolve_sym(char *sym, int symtype, void *state)
+{
+ section_t *sect = state;
+ lw_expr_term_t *term;
+ int val = 0, i, fn;
+ lw_expr_stack_t *s;
+ symtab_t *se;
+ fileinfo_t *fp;
+
+ if (symtype == 1)
+ {
+ // local symbol
+ if (!sym)
+ {
+ val = sect -> loadaddress;
+ goto out;
+ }
+
+ // start with this section
+ for (se = sect -> localsyms; se; se = se -> next)
+ {
+ if (!strcmp(se -> sym, sym))
+ {
+ val = se -> offset + sect -> loadaddress;
+ goto out;
+ }
+ }
+ // not in this section - check all sections in this file
+ for (i = 0; i < sect -> file -> nsections; i++)
+ {
+ for (se = sect -> file -> sections[i].localsyms; se; se = se -> next)
+ {
+ if (!strcmp(se -> sym, sym))
+ {
+ val = se -> offset + sect -> file -> sections[i].loadaddress;
+ goto out;
+ }
+ }
+ }
+ // not found
+ symerr = 1;
+ fprintf(stderr, "Local symbol %s not found in %s:%s\n", sanitize_symbol(sym), sect -> file -> filename, sect -> name);
+ goto outerr;
+ }
+ else
+ {
+ // external symbol
+ // read all files in order until found (or not found)
+ if (sect)
+ {
+ for (fp = sect -> file; fp; fp = fp -> parent)
+ {
+ s = find_external_sym_recurse(sym, fp);
+ if (s)
+ return s;
+ }
+ }
+
+ for (fn = 0; fn < ninputfiles; fn++)
+ {
+ s = find_external_sym_recurse(sym, inputfiles[fn]);
+ if (s)
+ return s;
+ }
+ if (sect)
+ {
+ fprintf(stderr, "External symbol %s not found in %s:%s\n", sanitize_symbol(sym), sect -> file -> filename, sect -> name);
+ }
+ else
+ {
+ fprintf(stderr, "External symbol %s not found\n", sym);
+ }
+ symerr = 1;
+ goto outerr;
+ }
+ fprintf(stderr, "Shouldn't ever get here!!!\n");
+ exit(88);
+out:
+ s = lw_expr_stack_create();
+ term = lw_expr_term_create_int(val & 0xffff);
+ lw_expr_stack_push(s, term);
+ lw_expr_term_free(term);
+ return s;
+outerr:
+ return NULL;
+}
+
+void resolve_references(void)
+{
+ int sn;
+ reloc_t *rl;
+ int rval;
+
+ // resolve entry point if required
+ // this must resolve to an *exported* symbol and will resolve to the
+ // first instance of that symbol
+ if (linkscript.execsym)
+ {
+ lw_expr_stack_t *s;
+
+ s = resolve_sym(linkscript.execsym, 0, NULL);
+ if (!s)
+ {
+ fprintf(stderr, "Cannot resolve exec address '%s'\n", linkscript.execsym);
+ symerr = 1;
+ }
+ else
+ {
+ linkscript.execaddr = lw_expr_get_value(s);
+ lw_expr_stack_free(s);
+ }
+ }
+
+ for (sn = 0; sn < nsects; sn++)
+ {
+ for (rl = sectlist[sn].ptr -> incompletes; rl; rl = rl -> next)
+ {
+ // do a "simplify" on the expression
+ rval = lw_expr_reval(rl -> expr, resolve_sym, sectlist[sn].ptr);
+
+ // is it constant? error out if not
+ if (rval != 0 || !lw_expr_is_constant(rl -> expr))
+ {
+ fprintf(stderr, "Incomplete reference at %s:%s+%02X\n", sectlist[sn].ptr -> file -> filename, sectlist[sn].ptr -> name, rl -> offset);
+ symerr = 1;
+ }
+ else
+ {
+ // put the value into the relocation address
+ rval = lw_expr_get_value(rl -> expr);
+ if (rl -> flags & RELOC_8BIT)
+ {
+ sectlist[sn].ptr -> code[rl -> offset] = rval & 0xff;
+ }
+ else
+ {
+ sectlist[sn].ptr -> code[rl -> offset] = (rval >> 8) & 0xff;
+ sectlist[sn].ptr -> code[rl -> offset + 1] = rval & 0xff;
+ }
+ }
+ }
+ }
+
+ if (symerr)
+ exit(1);
+}
+
+/*
+This is just a pared down version of the algo for resolving references.
+*/
+void resolve_files(void)
+{
+ int sn;
+ int fn;
+ reloc_t *rl;
+ lw_expr_stack_t *te;
+
+ int rval;
+
+ // resolve entry point if required
+ // this must resolve to an *exported* symbol and will resolve to the
+ // first instance of that symbol
+ if (linkscript.execsym)
+ {
+ lw_expr_stack_t *s;
+
+ s = resolve_sym(linkscript.execsym, 0, NULL);
+ if (!s)
+ {
+ fprintf(stderr, "Cannot resolve exec address '%s'\n", sanitize_symbol(linkscript.execsym));
+ symerr = 1;
+ }
+ }
+
+ do
+ {
+ nforced = 0;
+ for (fn = 0; fn < ninputfiles; fn++)
+ {
+ if (inputfiles[fn] -> forced == 0)
+ continue;
+
+ for (sn = 0; sn < inputfiles[fn] -> nsections; sn++)
+ {
+ for (rl = inputfiles[fn] -> sections[sn].incompletes; rl; rl = rl -> next)
+ {
+ // do a "simplify" on the expression
+ te = lw_expr_stack_dup(rl -> expr);
+ rval = lw_expr_reval(te, resolve_sym, &(inputfiles[fn] -> sections[sn]));
+
+ // is it constant? error out if not
+ if (rval != 0 || !lw_expr_is_constant(te))
+ {
+ fprintf(stderr, "Incomplete reference at %s:%s+%02X\n", inputfiles[fn] -> filename, inputfiles[fn] -> sections[sn].name, rl -> offset);
+ symerr = 1;
+ }
+ lw_expr_stack_free(te);
+ }
+ }
+ }
+ }
+ while (nforced == 1);
+
+ if (symerr)
+ exit(1);
+
+ // theoretically, all files referenced by other files now have "forced" set to 1
+ for (fn = 0; fn < ninputfiles; fn++)
+ {
+ if (inputfiles[fn] -> forced == 1)
+ continue;
+
+ fprintf(stderr, "Warning: %s (%d) does not resolve any symbols\n", inputfiles[fn] -> filename, fn);
+ }
+}
diff -r 000000000000 -r 2c24602be78f lwlink/lwlink.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwlink/lwlink.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,142 @@
+/*
+lwlink.c
+Copyright © 2009 William Astle
+
+This file is part of LWLINK.
+
+LWLINK 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 3 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, see .
+
+
+
+*/
+
+#define __lwlink_c_seen__
+
+#include
+#include
+#include
+#include
+#include
+
+#include "lwlink.h"
+#include "util.h"
+
+int debug_level = 0;
+int outformat = OUTPUT_DECB;
+char *outfile = NULL;
+char *scriptfile = NULL;
+int symerr = 0;
+char *map_file = NULL;
+
+fileinfo_t **inputfiles = NULL;
+int ninputfiles = 0;
+
+int nlibdirs = 0;
+char **libdirs = NULL;
+
+int nscriptls = 0;
+char **scriptls = NULL;
+
+void add_input_file(char *fn)
+{
+ inputfiles = lw_realloc(inputfiles, sizeof(fileinfo_t *) * (ninputfiles + 1));
+ inputfiles[ninputfiles] = lw_malloc(sizeof(fileinfo_t));
+ memset(inputfiles[ninputfiles], 0, sizeof(fileinfo_t));
+ inputfiles[ninputfiles] -> forced = 1;
+ inputfiles[ninputfiles++] -> filename = lw_strdup(fn);
+}
+
+void add_input_library(char *libname)
+{
+ inputfiles = lw_realloc(inputfiles, sizeof(fileinfo_t *) * (ninputfiles + 1));
+ inputfiles[ninputfiles] = lw_malloc(sizeof(fileinfo_t));
+ memset(inputfiles[ninputfiles], 0, sizeof(fileinfo_t));
+ inputfiles[ninputfiles] -> islib = 1;
+ inputfiles[ninputfiles] -> forced = 0;
+ inputfiles[ninputfiles++] -> filename = lw_strdup(libname);
+}
+
+void add_library_search(char *libdir)
+{
+ libdirs = lw_realloc(libdirs, sizeof(char*) * (nlibdirs + 1));
+ libdirs[nlibdirs] = lw_strdup(libdir);
+ nlibdirs++;
+}
+
+void add_section_base(char *sectspec)
+{
+ char *base;
+ int baseaddr;
+ char *t;
+ int l;
+
+ base = strchr(sectspec, '=');
+ if (!base)
+ {
+ l = strlen(sectspec);
+ baseaddr = 0;
+ }
+ else
+ {
+ baseaddr = strtol(base + 1, NULL, 16);
+ l = base - sectspec;
+ *base = '\0';
+ }
+ baseaddr = baseaddr & 0xffff;
+
+ t = lw_malloc(l + 25);
+ sprintf(t, "section %s load %04X", sectspec, baseaddr);
+ if (base)
+ *base = '=';
+
+ scriptls = lw_realloc(scriptls, sizeof(char *) * (nscriptls + 1));
+ scriptls[nscriptls++] = t;
+}
+
+char *sanitize_symbol(char *symbol)
+{
+ static char symbuf[2048];
+ char *sym = symbol;
+ char *tp = symbuf;
+
+ for (; *sym; sym++)
+ {
+ int c1 = *sym;
+ if (c1 == '\\')
+ {
+ *tp++ = '\\';
+ *tp++ = '\\';
+ continue;
+ }
+ if (c1 < 32 || c1 > 126)
+ {
+ int c;
+ *tp++ = '\\';
+ c = c1 >> 4;
+ c += 48;
+ if (c > 57)
+ c += 7;
+ *tp++ = c;
+ c = c1 & 15;
+ c += 48;
+ if (c > 57)
+ c += 7;
+ *tp++ = c;
+ continue;
+ }
+ *tp++ = c1;
+ }
+ *tp = 0;
+ return symbuf;
+}
diff -r 000000000000 -r 2c24602be78f lwlink/lwlink.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwlink/lwlink.h Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,156 @@
+/*
+lwlink.h
+Copyright © 2009 William Astle
+
+This file is part of LWLINK.
+
+LWLINK 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 3 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, see .
+
+Contains the main defs used by the linker
+*/
+
+
+#ifndef __lwlink_h_seen__
+#define __lwlink_h_seen__
+
+#include "expr.h"
+
+#define OUTPUT_DECB 0 // DECB multirecord format
+#define OUTPUT_RAW 1 // raw sequence of bytes
+#define OUTPUT_LWEX0 2 // LWOS LWEX binary version 0
+
+typedef struct symtab_s symtab_t;
+struct symtab_s
+{
+ unsigned char *sym; // symbol name
+ int offset; // local offset
+// int realval; // resolved value
+ symtab_t *next; // next symbol
+};
+
+#define RELOC_NORM 0 // all default (16 bit)
+#define RELOC_8BIT 1 // only use the low 8 bits for the reloc
+typedef struct reloc_s reloc_t;
+struct reloc_s
+{
+ int offset; // where in the section
+ int flags; // flags for the relocation
+ lw_expr_stack_t *expr; // the expression to calculate it
+ reloc_t *next; // ptr to next relocation
+};
+
+typedef struct fileinfo_s fileinfo_t;
+
+#define SECTION_BSS 1
+typedef struct
+{
+ unsigned char *name; // name of the section
+ int flags; // section flags
+ int codesize; // size of the code
+ unsigned char *code; // pointer to the code
+ int loadaddress; // the actual load address of the section
+ int processed; // was the section processed yet?
+
+ symtab_t *localsyms; // local symbol table
+ symtab_t *exportedsyms; // exported symbols table
+
+ reloc_t *incompletes; // table of incomplete references
+
+ fileinfo_t *file; // the file we are in
+} section_t;
+
+struct fileinfo_s
+{
+ char *filename;
+ unsigned char *filedata;
+ long filesize;
+ section_t *sections;
+ int nsections;
+ int islib; // set to true if the file is a "-l" option
+
+ int forced; // set to true if the file is a "forced" include
+
+ // "sub" files (like in archives or libraries)
+ int nsubs;
+ fileinfo_t **subs;
+ fileinfo_t *parent;
+};
+
+struct section_list
+{
+ section_t *ptr; // ptr to section structure
+ int forceaddr; // was this force to an address by the link script?
+};
+
+#ifndef __link_c_seen__
+extern struct section_list *sectlist;
+extern int nsects;
+#endif
+
+
+#ifndef __lwlink_c_seen__
+
+extern int debug_level;
+extern int outformat;
+extern char *outfile;
+extern int ninputfiles;
+extern fileinfo_t **inputfiles;
+extern char *scriptfile;
+
+extern int nlibdirs;
+extern char **libdirs;
+
+extern int nscriptls;
+extern char **scriptls;
+
+extern int symerr;
+
+extern char *map_file;
+
+#define __lwlink_E__ extern
+#else
+#define __lwlink_E__
+#endif // __lwlink_c_seen__
+
+__lwlink_E__ void add_input_file(char *fn);
+__lwlink_E__ void add_input_library(char *fn);
+__lwlink_E__ void add_library_search(char *fn);
+__lwlink_E__ void add_section_base(char *fn);
+__lwlink_E__ char *sanitize_symbol(char *sym);
+
+#undef __lwlink_E__
+
+struct scriptline_s
+{
+ char *sectname; // name of section, NULL for wildcard
+ int loadat; // address to load at (or -1)
+ int noflags; // flags to NOT have
+ int yesflags; // flags to HAVE
+};
+
+typedef struct
+{
+ int nlines; // number of lines in the script
+ struct scriptline_s *lines; // the parsed script lines (section)
+ int padsize; // the size to pad to, -1 for none
+ char *execsym; // entry point symbol
+ int execaddr; // execution address (entry point)
+ int stacksize; // stack size
+} linkscript_t;
+
+#ifndef __script_c_seen__
+extern linkscript_t linkscript;
+#endif
+
+#endif //__lwlink_h_seen__
diff -r 000000000000 -r 2c24602be78f lwlink/main.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwlink/main.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,194 @@
+/*
+main.c
+Copyright © 2009 William Astle
+
+This file is part of LWLINK.
+
+LWLINK 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 3 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, see .
+
+
+Implements the program startup code
+
+*/
+
+#include
+#include
+#include
+#include
+#include
+
+#include "lwlink.h"
+
+char *program_name;
+
+// command line option handling
+const char *argp_program_version = "LWLINK from " PACKAGE_STRING;
+const char *argp_program_bug_address = PACKAGE_BUGREPORT;
+
+static error_t parse_opts(int key, char *arg, struct argp_state *state)
+{
+ switch (key)
+ {
+ case 'o':
+ // output
+ outfile = arg;
+ break;
+
+ case 's':
+ // script file
+ scriptfile = arg;
+ break;
+
+ case 'd':
+ // debug
+ debug_level++;
+ break;
+
+ case 'b':
+ // decb output
+ outformat = OUTPUT_DECB;
+ break;
+
+ case 'r':
+ // raw binary output
+ outformat = OUTPUT_RAW;
+ break;
+
+ case 'f':
+ // output format
+ if (!strcasecmp(arg, "decb"))
+ outformat = OUTPUT_DECB;
+ else if (!strcasecmp(arg, "raw"))
+ outformat = OUTPUT_RAW;
+ else if (!strcasecmp(arg, "lwex0") || !strcasecmp(arg, "lwex"))
+ outformat = OUTPUT_LWEX0;
+ else
+ {
+ fprintf(stderr, "Invalid output format: %s\n", arg);
+ exit(1);
+ }
+ break;
+ case ARGP_KEY_END:
+ // done; sanity check
+ if (!outfile)
+ outfile = "a.out";
+ break;
+
+ case 'l':
+ add_input_library(arg);
+ break;
+
+ case 'L':
+ add_library_search(arg);
+ break;
+
+ case 0x100:
+ add_section_base(arg);
+ break;
+
+ case 'm':
+ map_file = arg;
+ break;
+
+ case ARGP_KEY_ARG:
+ add_input_file(arg);
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+static struct argp_option options[] =
+{
+ { "output", 'o', "FILE", 0,
+ "Output to FILE"},
+ { "debug", 'd', 0, 0,
+ "Set debug mode"},
+ { "format", 'f', "TYPE", 0,
+ "Select output format: decb, raw, lwex"},
+ { "decb", 'b', 0, 0,
+ "Generate DECB .bin format output, equivalent of --format=decb"},
+ { "raw", 'r', 0, 0,
+ "Generate raw binary format output, equivalent of --format=raw"},
+ { "script", 's', "FILE", 0,
+ "Specify the linking script (overrides the built in defaults)"},
+ { "library", 'l', "LIBSPEC", 0,
+ "Read library libLIBSPEC.a from the search path" },
+ { "library-path", 'L', "DIR", 0,
+ "Add DIR to the library search path" },
+ { "section-base", 0x100, "SECT=BASE", 0,
+ "Load section SECT at BASE" },
+ { "map", 'm', "FILE", 0,
+ "Output informaiton about the link" },
+ { 0 }
+};
+
+static struct argp argp =
+{
+ options,
+ parse_opts,
+ " ...",
+ "LWLINK, a HD6309 and MC6809 cross-linker"
+};
+
+extern void read_files(void);
+extern void setup_script(void);
+extern void resolve_files(void);
+extern void resolve_sections(void);
+extern void resolve_references(void);
+extern void do_output(void);
+extern void display_map(void);
+
+// main function; parse command line, set up assembler state, and run the
+// assembler on the first file
+int main(int argc, char **argv)
+{
+ program_name = argv[0];
+
+ argp_parse(&argp, argc, argv, 0, 0, NULL);
+ if (ninputfiles == 0)
+ {
+ fprintf(stderr, "No input files\n");
+ exit(1);
+ }
+
+ unlink(outfile);
+
+ // handle the linker script
+ setup_script();
+
+ // read the input files
+ read_files();
+
+ // trace unresolved references and determine which non-forced
+ // objects must be included
+ resolve_files();
+
+ // resolve section bases and section order
+ resolve_sections();
+
+ // resolve incomplete references
+ resolve_references();
+
+ // do the actual output
+ do_output();
+
+ // display/output the link map
+ if (map_file)
+ display_map();
+
+ exit(0);
+}
diff -r 000000000000 -r 2c24602be78f lwlink/map.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwlink/map.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,113 @@
+/*
+map.c
+Copyright © 2009 William Astle
+
+This file is part of LWLINK.
+
+LWLINK 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 3 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, see .
+
+
+Output information about the linking process
+*/
+
+#include
+#include
+#include
+
+#include "lwlink.h"
+#include "util.h"
+
+struct symliste
+{
+ char *name;
+ char *fn;
+ int addr;
+ int ext;
+ struct symliste *next;
+};
+
+void display_map(void)
+{
+ FILE *of;
+ int sn;
+ int std = 0;
+ struct symliste *slist = NULL;
+ struct symliste *ce, *pe, *ne;
+ symtab_t *sym;
+ int i;
+
+ if (!strcmp(map_file, "-"))
+ {
+ std = 1;
+ of = stdout;
+ }
+ else
+ {
+ of = fopen(map_file, "w");
+ if (!of)
+ {
+ fprintf(stderr, "Cannot open map file - using stdout\n");
+ std = 1;
+ of = stdout;
+ }
+ }
+
+ // display section list
+ for (sn = 0; sn < nsects; sn++)
+ {
+ fprintf(of, "Section: %s (%s) load at %04X, length %04X\n",
+ sanitize_symbol(sectlist[sn].ptr -> name),
+ sectlist[sn].ptr -> file -> filename,
+ sectlist[sn].ptr -> loadaddress,
+ sectlist[sn].ptr -> codesize
+ );
+ }
+
+ // generate a sorted list of symbols and display it
+ for (sn = 0; sn < nsects; sn++)
+ {
+ for (sym = sectlist[sn].ptr -> localsyms; sym; sym = sym -> next)
+ {
+ for (pe = NULL, ce = slist; ce; ce = ce -> next)
+ {
+ i = strcmp(ce -> name, sym -> sym);
+ if (i == 0)
+ {
+ i = strcmp(ce -> fn, sectlist[sn].ptr -> file -> filename);
+ }
+ if (i > 0)
+ break;
+ pe = ce;
+ }
+ ne = lw_malloc(sizeof(struct symliste));
+ ne -> ext = 0;
+ ne -> addr = sym -> offset + sectlist[sn].ptr -> loadaddress;
+ ne -> next = ce;
+ ne -> name = sym -> sym;
+ ne -> fn = sectlist[sn].ptr -> file -> filename;
+ if (pe)
+ pe -> next = ne;
+ else
+ slist = ne;
+ }
+ }
+
+ for (ce = slist; ce; ce = ce -> next)
+ {
+ fprintf(of, "Symbol: %s (%s) = %04X\n", sanitize_symbol(ce -> name), ce -> fn, ce -> addr);
+ }
+
+ if (!std)
+ fclose(of);
+}
diff -r 000000000000 -r 2c24602be78f lwlink/objdump.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwlink/objdump.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,346 @@
+/*
+objdump.c
+Copyright © 2009 William Astle
+
+This file is part of LWLINK
+
+LWLINK 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 3 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, see .
+
+
+A standalone program to dump an object file in a text form to stdout
+
+*/
+#include
+#include
+
+#include "util.h"
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+void read_lwobj16v0(unsigned char *filedata, long filesize);
+char *program_name;
+
+char *string_cleanup(char *sym)
+{
+ static char symbuf[4096];
+ int optr = 0;
+ while (*sym)
+ {
+ if (*sym < 33 || *sym > 126)
+ {
+ int c;
+ symbuf[optr++] = '\\';
+ c = *sym >> 4;
+ c+= 48;
+ if (c > 57)
+ c += 7;
+ symbuf[optr++] = c;
+ c = *sym & 15;
+ c += 48;
+ if (c > 57)
+ c += 7;
+ symbuf[optr++] = c;
+ }
+ else if (*sym == '\\')
+ {
+ symbuf[optr++] = '\\';
+ symbuf[optr++] = '\\';
+ }
+ else
+ {
+ symbuf[optr++] = *sym;
+ }
+ sym++;
+ }
+ symbuf[optr] = '\0';
+ return symbuf;
+}
+
+/*
+The logic of reading the entire file into memory is simple. All the symbol
+names in the file are NUL terminated strings and can be used directly without
+making additional copies.
+*/
+int main(int argc, char **argv)
+{
+ int i;
+ long size;
+ FILE *f;
+ long bread;
+ unsigned char *filedata;
+
+ program_name = argv[0];
+ if (argc != 2)
+ {
+ fprintf(stderr, "Must specify exactly one input file.\n");
+ exit(1);
+ }
+
+ f = fopen(argv[1], "rb");
+ if (!f)
+ {
+ fprintf(stderr, "Can't open file %s:", argv[1]);
+ perror("");
+ exit(1);
+ }
+ fseek(f, 0, SEEK_END);
+ size = ftell(f);
+ rewind(f);
+
+ filedata = lw_malloc(size);
+
+ bread = fread(filedata, 1, size, f);
+ if (bread < size)
+ {
+ fprintf(stderr, "Short read on file %s (%ld/%ld):", argv[1], bread, size);
+ perror("");
+ exit(1);
+ }
+
+ fclose(f);
+
+ if (!memcmp(filedata, "LWOBJ16", 8))
+ {
+ // read v0 LWOBJ16 file
+ read_lwobj16v0(filedata, size);
+ }
+ else
+ {
+ fprintf(stderr, "%s: unknown file format\n", argv[1]);
+ exit(1);
+ }
+ exit(0);
+}
+
+// this macro is used to bail out if we run off the end of the file data
+// while parsing - it keeps the code below cleaner
+#define NEXTBYTE() do { cc++; if (cc > filesize) { fprintf(stderr, "***invalid file format\n"); exit(1); } } while (0)
+// this macro is used to refer to the current byte in the stream
+#define CURBYTE() (filedata[cc < filesize ? cc : filesize - 1])
+// this one will leave the input pointer past the trailing NUL
+#define CURSTR() read_lwobj16v0_str(&cc, &filedata, filesize)
+unsigned char *read_lwobj16v0_str(long *cc1, unsigned char **filedata1, long filesize)
+{
+ int cc = *cc1;
+ unsigned char *filedata = *filedata1;
+ unsigned char *fp;
+ fp = &CURBYTE();
+ while (CURBYTE())
+ NEXTBYTE();
+ NEXTBYTE();
+ *cc1 = cc;
+ *filedata1 = filedata;
+ return fp;
+}
+// the function below can be switched to dealing with data coming from a
+// source other than an in-memory byte pool by adjusting the input data
+// in "fn" and the above two macros
+void read_lwobj16v0(unsigned char *filedata, long filesize)
+{
+ unsigned char *fp;
+ long cc;
+ int val;
+ int bss;
+
+ static char *opernames[] = {
+ "?",
+ "PLUS",
+ "MINUS",
+ "TIMES",
+ "DIVIDE",
+ "MOD",
+ "INTDIV",
+ "BWAND",
+ "BWOR",
+ "BWXOR",
+ "AND",
+ "OR",
+ "NEG",
+ "COM"
+ };
+ static const int numopers = 13;
+
+ // start reading *after* the magic number
+ cc = 8;
+
+ while (1)
+ {
+ bss = 0;
+
+ // bail out if no more sections
+ if (!(CURBYTE()))
+ break;
+
+ fp = CURSTR();
+
+ printf("SECTION %s\n", fp);
+
+ // read flags
+ while (CURBYTE())
+ {
+ switch (CURBYTE())
+ {
+ case 0x01:
+ printf(" FLAG: BSS\n");
+ bss = 1;
+ break;
+
+ default:
+ printf(" FLAG: %02X (unknown)\n", CURBYTE());
+ break;
+ }
+ NEXTBYTE();
+ }
+ // skip NUL terminating flags
+ NEXTBYTE();
+
+ printf(" Local symbols:\n");
+ // now parse the local symbol table
+ while (CURBYTE())
+ {
+ fp = CURSTR();
+
+ // fp is the symbol name
+ val = (CURBYTE()) << 8;
+ NEXTBYTE();
+ val |= (CURBYTE());
+ NEXTBYTE();
+ // val is now the symbol value
+
+ printf(" %s=%04X\n", string_cleanup(fp), val);
+
+ }
+ // skip terminating NUL
+ NEXTBYTE();
+
+ printf(" Exported symbols\n");
+
+ // now parse the exported symbol table
+ while (CURBYTE())
+ {
+ fp = CURSTR();
+
+ // fp is the symbol name
+ val = (CURBYTE()) << 8;
+ NEXTBYTE();
+ val |= (CURBYTE());
+ NEXTBYTE();
+ // val is now the symbol value
+
+ printf(" %s=%04X\n", string_cleanup(fp), val);
+ }
+ // skip terminating NUL
+ NEXTBYTE();
+
+ // now parse the incomplete references and make a list of
+ // external references that need resolution
+ printf(" Incomplete references\n");
+ while (CURBYTE())
+ {
+ printf(" (");
+ // parse the expression
+ while (CURBYTE())
+ {
+ int tt = CURBYTE();
+ NEXTBYTE();
+ switch (tt)
+ {
+ case 0x01:
+ // 16 bit integer
+ tt = CURBYTE() << 8;
+ NEXTBYTE();
+ tt |= CURBYTE();
+ NEXTBYTE();
+ // normalize for negatives...
+ if (tt > 0x7fff)
+ tt -= 0x10000;
+ printf(" I16=%d", tt);
+ break;
+
+ case 0x02:
+ // external symbol reference
+ printf(" ES=%s", string_cleanup(CURSTR()));
+ break;
+
+ case 0x03:
+ // internal symbol reference
+ printf(" IS=%s", string_cleanup(CURSTR()));
+ break;
+
+ case 0x04:
+ // operator
+ if (CURBYTE() > 0 && CURBYTE() <= numopers)
+ printf(" OP=%s", opernames[CURBYTE()]);
+ else
+ printf(" OP=?");
+ NEXTBYTE();
+ break;
+
+ case 0x05:
+ // section base reference (NULL internal reference is
+ // the section base address
+ printf(" SB");
+ break;
+
+ case 0xFF:
+ // section flags
+ printf(" FLAGS=%02X", CURBYTE());
+ NEXTBYTE();
+ break;
+
+ default:
+ printf(" ERR");
+ }
+ }
+ // skip the NUL
+ NEXTBYTE();
+
+ // fetch the offset
+ val = CURBYTE() << 8;
+ NEXTBYTE();
+ val |= CURBYTE() & 0xff;
+ NEXTBYTE();
+ printf(" ) @ %04X\n", val);
+ }
+ // skip the NUL terminating the relocations
+ NEXTBYTE();
+
+ // now set code location and size and verify that the file
+ // contains data going to the end of the code (if !SECTION_BSS)
+ val = CURBYTE() << 8;
+ NEXTBYTE();
+ val |= CURBYTE();
+ NEXTBYTE();
+
+ printf(" CODE %04X bytes", val);
+
+ // skip the code if we're not in a BSS section
+ if (!bss)
+ {
+ int i;
+ for (i = 0; i < val; i++)
+ {
+ if (! (i % 16))
+ {
+ printf("\n %04X ", i);
+ }
+ printf("%02X", CURBYTE());
+ NEXTBYTE();
+ }
+ }
+ printf("\n");
+ }
+}
diff -r 000000000000 -r 2c24602be78f lwlink/output.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwlink/output.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,215 @@
+/*
+output.c
+Copyright © 2009 William Astle
+
+This file is part of LWLINK.
+
+LWLINK 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 3 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, see .
+
+
+Actually output the binary
+*/
+
+#include
+#include
+#include
+
+#include "lwlink.h"
+
+// this prevents warnings about not using the return value of fwrite()
+// and, theoretically, can be replaced with a function that handles things
+// better in the future
+#define writebytes(s, l, c, f) do { int r; r = fwrite((s), (l), (c), (f)); } while (0)
+
+void do_output_decb(FILE *of);
+void do_output_raw(FILE *of);
+void do_output_lwex0(FILE *of);
+
+void do_output(void)
+{
+ FILE *of;
+
+ of = fopen(outfile, "wb");
+ if (!of)
+ {
+ fprintf(stderr, "Cannot open output file %s: ", outfile);
+ perror("");
+ exit(1);
+ }
+
+ switch (outformat)
+ {
+ case OUTPUT_DECB:
+ do_output_decb(of);
+ break;
+
+ case OUTPUT_RAW:
+ do_output_raw(of);
+ break;
+
+ case OUTPUT_LWEX0:
+ do_output_lwex0(of);
+ break;
+
+ default:
+ fprintf(stderr, "Unknown output format doing output!\n");
+ exit(111);
+ }
+
+ fclose(of);
+}
+
+void do_output_decb(FILE *of)
+{
+ int sn, sn2;
+ int cloc, olen;
+ unsigned char buf[5];
+
+ for (sn = 0; sn < nsects; sn++)
+ {
+ if (sectlist[sn].ptr -> flags & SECTION_BSS)
+ {
+ // no output for a BSS section
+ continue;
+ }
+ if (sectlist[sn].ptr -> codesize == 0)
+ {
+ // don't generate output for a zero size section
+ continue;
+ }
+
+ // calculate the length of this output block
+ cloc = sectlist[sn].ptr -> loadaddress;
+ olen = 0;
+ for (sn2 = sn; sn2 < nsects; sn2++)
+ {
+ // ignore BSS sections
+ if (sectlist[sn2].ptr -> flags & SECTION_BSS)
+ continue;
+ // ignore zero length sections
+ if (sectlist[sn2].ptr -> codesize == 0)
+ continue;
+ if (cloc != sectlist[sn2].ptr -> loadaddress)
+ break;
+ olen += sectlist[sn2].ptr -> codesize;
+ cloc += sectlist[sn2].ptr -> codesize;
+ }
+
+ // write a preamble
+ buf[0] = 0x00;
+ buf[1] = olen >> 8;
+ buf[2] = olen & 0xff;
+ buf[3] = sectlist[sn].ptr -> loadaddress >> 8;
+ buf[4] = sectlist[sn].ptr -> loadaddress & 0xff;
+ writebytes(buf, 1, 5, of);
+ for (; sn < sn2; sn++)
+ {
+ if (sectlist[sn].ptr -> flags & SECTION_BSS)
+ continue;
+ if (sectlist[sn].ptr -> codesize == 0)
+ continue;
+ writebytes(sectlist[sn].ptr -> code, 1, sectlist[sn].ptr -> codesize, of);
+ }
+ sn--;
+ }
+ // write a postamble
+ buf[0] = 0xff;
+ buf[1] = 0x00;
+ buf[2] = 0x00;
+ buf[3] = linkscript.execaddr >> 8;
+ buf[4] = linkscript.execaddr & 0xff;
+ writebytes(buf, 1, 5, of);
+}
+
+void do_output_raw(FILE *of)
+{
+ int nskips = 0; // used to output blanks for BSS inline
+ int sn;
+
+ for (sn = 0; sn < nsects; sn++)
+ {
+ if (sectlist[sn].ptr -> flags & SECTION_BSS)
+ {
+ // no output for a BSS section
+ nskips += sectlist[sn].ptr -> codesize;
+ continue;
+ }
+ while (nskips > 0)
+ {
+ // the "" is not an error - it turns into a single NUL byte!
+ writebytes("", 1, 1, of);
+ nskips--;
+ }
+ writebytes(sectlist[sn].ptr -> code, 1, sectlist[sn].ptr -> codesize, of);
+ }
+}
+
+void do_output_lwex0(FILE *of)
+{
+ int nskips = 0; // used to output blanks for BSS inline
+ int sn;
+ int codedatasize = 0;
+ unsigned char buf[32];
+
+ // calculate items for the file header
+ for (sn = 0; sn < nsects; sn++)
+ {
+ if (sectlist[sn].ptr -> flags & SECTION_BSS)
+ {
+ // no output for a BSS section
+ nskips += sectlist[sn].ptr -> codesize;
+ continue;
+ }
+ codedatasize += nskips;
+ nskips = 0;
+ codedatasize += sectlist[sn].ptr -> codesize;
+ }
+
+ // output the file header
+ buf[0] = 'L';
+ buf[1] = 'W';
+ buf[2] = 'E';
+ buf[3] = 'X';
+ buf[4] = 0; // version 0
+ buf[5] = 0; // low stack
+ buf[6] = linkscript.stacksize / 256;
+ buf[7] = linkscript.stacksize & 0xff;
+ buf[8] = nskips / 256;
+ buf[9] = nskips & 0xff;
+ buf[10] = codedatasize / 256;
+ buf[11] = codedatasize & 0xff;
+ buf[12] = linkscript.execaddr / 256;
+ buf[13] = linkscript.execaddr & 0xff;
+ memset(buf + 14, 0, 18);
+
+ writebytes(buf, 1, 32, of);
+ // output the data
+ // NOTE: disjoint load addresses will not work correctly!!!!!
+ for (sn = 0; sn < nsects; sn++)
+ {
+ if (sectlist[sn].ptr -> flags & SECTION_BSS)
+ {
+ // no output for a BSS section
+ nskips += sectlist[sn].ptr -> codesize;
+ continue;
+ }
+ while (nskips > 0)
+ {
+ // the "" is not an error - it turns into a single NUL byte!
+ writebytes("", 1, 1, of);
+ nskips--;
+ }
+ writebytes(sectlist[sn].ptr -> code, 1, sectlist[sn].ptr -> codesize, of);
+ }
+}
diff -r 000000000000 -r 2c24602be78f lwlink/readfiles.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwlink/readfiles.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,423 @@
+/*
+readfiles.c
+Copyright © 2009 William Astle
+
+This file is part of LWLINK.
+
+LWLINK 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 3 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, see .
+
+
+Reads input files
+
+*/
+
+#include
+#include
+#include
+#include
+#include
+
+#include "lwlink.h"
+#include "util.h"
+
+void read_lwobj16v0(fileinfo_t *fn);
+void read_lwar1v(fileinfo_t *fn);
+
+/*
+The logic of reading the entire file into memory is simple. All the symbol
+names in the file are NUL terminated strings and can be used directly without
+making additional copies.
+*/
+void read_file(fileinfo_t *fn)
+{
+ if (!memcmp(fn -> filedata, "LWOBJ16", 8))
+ {
+ // read v0 LWOBJ16 file
+ read_lwobj16v0(fn);
+ }
+ else if (!memcmp(fn -> filedata, "LWAR1V", 6))
+ {
+ // archive file
+ read_lwar1v(fn);
+ }
+ else
+ {
+ fprintf(stderr, "%s: unknown file format\n", fn -> filename);
+ exit(1);
+ }
+}
+
+void read_files(void)
+{
+ int i;
+ long size;
+ FILE *f;
+ long bread;
+ for (i = 0; i < ninputfiles; i++)
+ {
+ if (inputfiles[i] -> islib)
+ {
+ char *tf;
+ int s;
+ int j;
+
+ f = NULL;
+
+ for (j = 0; j < nlibdirs; j++)
+ {
+ s = strlen(libdirs[j]) + 7 + strlen(inputfiles[i] -> filename);
+ tf = lw_malloc(s + 1);
+ sprintf(tf, "%s/lib%s.a", libdirs[j], inputfiles[i] -> filename);
+ f = fopen(tf, "rb");
+ if (!f)
+ {
+ free(tf);
+ continue;
+ }
+ free(tf);
+ break;
+ }
+ if (!f)
+ {
+ fprintf(stderr, "Can't open library: -l%s\n", inputfiles[i] -> filename);
+ exit(1);
+ }
+ }
+ else
+ {
+ f = fopen(inputfiles[i] -> filename, "rb");
+ if (!f)
+ {
+ fprintf(stderr, "Can't open file %s:", inputfiles[i] -> filename);
+ perror("");
+ exit(1);
+ }
+ }
+ fseek(f, 0, SEEK_END);
+ size = ftell(f);
+ rewind(f);
+
+ inputfiles[i] -> filedata = lw_malloc(size);
+ inputfiles[i] -> filesize = size;
+
+ bread = fread(inputfiles[i] -> filedata, 1, size, f);
+ if (bread < size)
+ {
+ fprintf(stderr, "Short read on file %s (%ld/%ld):", inputfiles[i] -> filename, bread, size);
+ perror("");
+ exit(1);
+ }
+
+ fclose(f);
+
+ read_file(inputfiles[i]);
+ }
+}
+
+// this macro is used to bail out if we run off the end of the file data
+// while parsing - it keeps the code below cleaner
+#define NEXTBYTE() do { cc++; if (cc > fn -> filesize) { fprintf(stderr, "%s: invalid file format\n", fn -> filename); exit(1); } } while (0)
+// this macro is used to refer to the current byte in the stream
+#define CURBYTE() (fn -> filedata[cc < fn -> filesize ? cc : fn -> filesize - 1])
+// this one will leave the input pointer past the trailing NUL
+#define CURSTR() read_lwobj16v0_str(&cc, fn)
+unsigned char *read_lwobj16v0_str(long *cc1, fileinfo_t *fn)
+{
+ int cc = *cc1;
+ unsigned char *fp;
+ fp = &CURBYTE();
+ while (CURBYTE())
+ NEXTBYTE();
+ NEXTBYTE();
+ *cc1 = cc;
+ return fp;
+}
+// the function below can be switched to dealing with data coming from a
+// source other than an in-memory byte pool by adjusting the input data
+// in "fn" and the above two macros
+
+void read_lwobj16v0(fileinfo_t *fn)
+{
+ unsigned char *fp;
+ long cc;
+ section_t *s;
+ int val;
+ symtab_t *se;
+
+ // start reading *after* the magic number
+ cc = 8;
+
+ // init data
+ fn -> sections = NULL;
+ fn -> nsections = 0;
+
+ while (1)
+ {
+// NEXTBYTE();
+ // bail out if no more sections
+ if (!(CURBYTE()))
+ break;
+
+ fp = CURSTR();
+
+ // we now have a section name in fp
+ // create new section entry
+ fn -> sections = lw_realloc(fn -> sections, sizeof(section_t) * (fn -> nsections + 1));
+ s = &(fn -> sections[fn -> nsections]);
+ fn -> nsections += 1;
+
+ s -> localsyms = NULL;
+ s -> flags = 0;
+ s -> codesize = 0;
+ s -> name = fp;
+ s -> loadaddress = 0;
+ s -> localsyms = NULL;
+ s -> exportedsyms = NULL;
+ s -> incompletes = NULL;
+ s -> processed = 0;
+ s -> file = fn;
+
+ // read flags
+ while (CURBYTE())
+ {
+ switch (CURBYTE())
+ {
+ case 0x01:
+ s -> flags |= SECTION_BSS;
+ break;
+
+ default:
+ fprintf(stderr, "%s (%s): unrecognized section flag %02X\n", fn -> filename, s -> name, (int)(CURBYTE()));
+ exit(1);
+ }
+ NEXTBYTE();
+ }
+ // skip NUL terminating flags
+ NEXTBYTE();
+
+ // now parse the local symbol table
+ while (CURBYTE())
+ {
+ fp = CURSTR();
+
+ // fp is the symbol name
+ val = (CURBYTE()) << 8;
+ NEXTBYTE();
+ val |= (CURBYTE());
+ NEXTBYTE();
+ // val is now the symbol value
+
+ // create symbol table entry
+ se = lw_malloc(sizeof(symtab_t));
+ se -> next = s -> localsyms;
+ s -> localsyms = se;
+ se -> sym = fp;
+ se -> offset = val;
+ }
+ // skip terminating NUL
+ NEXTBYTE();
+
+ // now parse the exported symbol table
+ while (CURBYTE())
+ {
+ fp = CURSTR();
+
+ // fp is the symbol name
+ val = (CURBYTE()) << 8;
+ NEXTBYTE();
+ val |= (CURBYTE());
+ NEXTBYTE();
+ // val is now the symbol value
+
+ // create symbol table entry
+ se = lw_malloc(sizeof(symtab_t));
+ se -> next = s -> exportedsyms;
+ s -> exportedsyms = se;
+ se -> sym = fp;
+ se -> offset = val;
+ }
+ // skip terminating NUL
+ NEXTBYTE();
+
+ // now parse the incomplete references and make a list of
+ // external references that need resolution
+ while (CURBYTE())
+ {
+ reloc_t *rp;
+ lw_expr_term_t *term;
+
+ // we have a reference
+ rp = lw_malloc(sizeof(reloc_t));
+ rp -> next = s -> incompletes;
+ s -> incompletes = rp;
+ rp -> offset = 0;
+ rp -> expr = lw_expr_stack_create();
+ rp -> flags = RELOC_NORM;
+
+ // parse the expression
+ while (CURBYTE())
+ {
+ int tt = CURBYTE();
+ NEXTBYTE();
+ switch (tt)
+ {
+ case 0xFF:
+ // a flag specifier
+ tt = CURBYTE();
+ rp -> flags = tt;
+ NEXTBYTE();
+ term = NULL;
+ break;
+
+ case 0x01:
+ // 16 bit integer
+ tt = CURBYTE() << 8;
+ NEXTBYTE();
+ tt |= CURBYTE();
+ NEXTBYTE();
+ // normalize for negatives...
+ if (tt > 0x7fff)
+ tt -= 0x10000;
+ term = lw_expr_term_create_int(tt);
+ break;
+
+ case 0x02:
+ // external symbol reference
+ term = lw_expr_term_create_sym(CURSTR(), 0);
+ break;
+
+ case 0x03:
+ // internal symbol reference
+ term = lw_expr_term_create_sym(CURSTR(), 1);
+ break;
+
+ case 0x04:
+ // operator
+ term = lw_expr_term_create_oper(CURBYTE());
+ NEXTBYTE();
+ break;
+
+ case 0x05:
+ // section base reference (NULL internal reference is
+ // the section base address
+ term = lw_expr_term_create_sym(NULL, 1);
+ break;
+
+ default:
+ fprintf(stderr, "%s (%s): bad relocation expression (%02X)\n", fn -> filename, s -> name, tt);
+ exit(1);
+ }
+ if (term)
+ {
+ lw_expr_stack_push(rp -> expr, term);
+ lw_expr_term_free(term);
+ }
+ }
+ // skip the NUL
+ NEXTBYTE();
+
+ // fetch the offset
+ rp -> offset = CURBYTE() << 8;
+ NEXTBYTE();
+ rp -> offset |= CURBYTE() & 0xff;
+ NEXTBYTE();
+ }
+ // skip the NUL terminating the relocations
+ NEXTBYTE();
+
+ // now set code location and size and verify that the file
+ // contains data going to the end of the code (if !SECTION_BSS)
+ s -> codesize = CURBYTE() << 8;
+ NEXTBYTE();
+ s -> codesize |= CURBYTE();
+ NEXTBYTE();
+
+ s -> code = &(CURBYTE());
+
+ // skip the code if we're not in a BSS section
+ if (!(s -> flags & SECTION_BSS))
+ {
+ int i;
+ for (i = 0; i < s -> codesize; i++)
+ NEXTBYTE();
+ }
+ }
+}
+
+/*
+Read an archive file - this will create a "sub" record and farm out the
+parsing of the sub files to the regular file parsers
+
+The archive file format consists of the 6 byte magic number followed by a
+series of records as follows:
+
+- NUL terminated file name
+- 32 bit file length in big endian order
+- the file data
+
+An empty file name indicates the end of the file.
+
+*/
+void read_lwar1v(fileinfo_t *fn)
+{
+ unsigned long cc = 6;
+ unsigned long flen;
+ unsigned long l;
+ for (;;)
+ {
+ if (cc >= fn -> filesize || !(fn -> filedata[cc]))
+ return;
+
+ for (l = cc; cc < fn -> filesize && fn -> filedata[cc]; cc++)
+ /* do nothing */ ;
+
+ cc++;
+
+ if (cc >= fn -> filesize)
+ {
+ fprintf(stderr, "Malformed archive file %s.\n", fn -> filename);
+ exit(1);
+ }
+
+ if (cc + 4 > fn -> filesize)
+ return;
+
+ flen = (fn -> filedata[cc++] << 24);
+ flen |= (fn -> filedata[cc++] << 16);
+ flen |= (fn -> filedata[cc++] << 8);
+ flen |= (fn -> filedata[cc++]);
+
+ if (flen == 0)
+ return;
+
+ if (cc + flen > fn -> filesize)
+ {
+ fprintf(stderr, "Malformed archive file %s.\n", fn -> filename);
+ exit(1);
+ }
+
+ // add the "sub" input file
+ fn -> subs = lw_realloc(fn -> subs, sizeof(fileinfo_t *) * (fn -> nsubs + 1));
+ fn -> subs[fn -> nsubs] = lw_malloc(sizeof(fileinfo_t));
+ memset(fn -> subs[fn -> nsubs], 0, sizeof(fileinfo_t));
+ fn -> subs[fn -> nsubs] -> filedata = fn -> filedata + cc;
+ fn -> subs[fn -> nsubs] -> filesize = flen;
+ fn -> subs[fn -> nsubs] -> filename = lw_strdup(fn -> filedata + l);
+ fn -> subs[fn -> nsubs] -> parent = fn;
+ fn -> subs[fn -> nsubs] -> forced = fn -> forced;
+ read_file(fn -> subs[fn -> nsubs]);
+ fn -> nsubs++;
+ cc += flen;
+ }
+}
diff -r 000000000000 -r 2c24602be78f lwlink/rules.make
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwlink/rules.make Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,8 @@
+dirname := $(dir $(lastword $(MAKEFILE_LIST)))
+
+lwlink_srcs_local := main.c lwlink.c util.c readfiles.c expr.c script.c link.c output.c map.c
+lwobjdump_srcs_local := objdump.c util.c
+
+
+lwlink_srcs := $(lwlink_srcs) $(addprefix $(dirname),$(lwlink_srcs_local))
+lwobjdump_srcs := $(lwobjdump_srcs) $(addprefix $(dirname),$(lwobjdump_srcs_local))
diff -r 000000000000 -r 2c24602be78f lwlink/script.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwlink/script.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,295 @@
+/*
+script.c
+Copyright © 2009 William Astle
+
+This file is part of LWLINK.
+
+LWLINK 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 3 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, see .
+
+
+Read and parse linker scripts
+*/
+
+#include
+#include
+#include
+#include
+
+#include "lwlink.h"
+#include "util.h"
+
+// the built-in DECB target linker script
+static char *decb_script =
+ "section init load 2000\n"
+ "section code\n"
+ "section *,!bss\n"
+ "section *,bss\n"
+ "entry 2000\n"
+ ;
+
+// the built-in RAW target linker script
+static char *raw_script =
+ "section init load 0000\n"
+ "section code\n"
+ "section *,!bss\n"
+ "section *,bss\n"
+ ;
+
+static char *lwex0_script =
+ "section init load 0100\n"
+ "section .text\n"
+ "section .data\n"
+ "section *,!bss\n"
+ "section *,bss\n"
+ "entry __start\n"
+ "stacksize 0100\n" // default 256 byte stack
+ ;
+
+// the "simple" script
+static char *simple_script =
+ "section *,!bss\n"
+ "section *,bss\n"
+ ;
+
+linkscript_t linkscript = { 0, NULL, -1 };
+
+void setup_script()
+{
+ char *script, *oscript;
+ long size;
+
+ // read the file if needed
+ if (scriptfile)
+ {
+ FILE *f;
+ long bread;
+
+ f = fopen(scriptfile, "rb");
+ if (!f)
+ {
+ fprintf(stderr, "Can't open file %s:", scriptfile);
+ perror("");
+ exit(1);
+ }
+ fseek(f, 0, SEEK_END);
+ size = ftell(f);
+ rewind(f);
+
+ script = lw_malloc(size + 2);
+
+ bread = fread(script, 1, size, f);
+ if (bread < size)
+ {
+ fprintf(stderr, "Short read on file %s (%ld/%ld):", scriptfile, bread, size);
+ perror("");
+ exit(1);
+ }
+ fclose(f);
+
+ script[size] = '\n';
+ script[size + 1] = '\0';
+ }
+ else
+ {
+ // fetch defaults based on output mode
+ switch (outformat)
+ {
+ case OUTPUT_RAW:
+ script = raw_script;
+ break;
+
+ case OUTPUT_DECB:
+ script = decb_script;
+ break;
+
+ case OUTPUT_LWEX0:
+ script = lwex0_script;
+ break;
+
+ default:
+ script = simple_script;
+ break;
+ }
+
+ size = strlen(script);
+ if (nscriptls)
+ {
+ char *rscript;
+ int i;
+ // prepend the "extra" script lines
+ for (i = 0; i < nscriptls; i++)
+ size += strlen(scriptls[i]) + 1;
+
+ rscript = lw_malloc(size + 1);
+ oscript = rscript;
+ for (i = 0; i < nscriptls; i++)
+ {
+ oscript += sprintf(oscript, "%s\n", scriptls[i]);
+ }
+ strcpy(oscript, script);
+ script = rscript;
+ }
+ }
+
+ if (outformat == OUTPUT_LWEX0)
+ linkscript.stacksize = 0x100;
+
+ oscript = script;
+ // now parse the script file
+ while (*script)
+ {
+ char *ptr, *ptr2, *line;
+
+ for (ptr = script; *ptr && *ptr != '\n' && *ptr != '\r'; ptr++)
+ /* do nothing */ ;
+
+ line = lw_malloc(ptr - script + 1);
+ memcpy(line, script, ptr - script);
+ line[ptr - script] = '\0';
+
+ // skip line terms
+ for (script = ptr + 1; *script == '\n' || *script == '\r'; script++)
+ /* do nothing */ ;
+
+ // ignore leading whitespace
+ for (ptr = line; *ptr && isspace(*ptr); ptr++)
+ /* do nothing */ ;
+
+ // ignore blank lines
+ if (!*ptr)
+ continue;
+
+ for (ptr = line; *ptr && !isspace(*ptr); ptr++)
+ /* do nothing */ ;
+
+ // now ptr points to the char past the first word
+ // NUL it out
+ if (*ptr)
+ *ptr++ = '\0';
+
+ // skip spaces after the first word
+ for ( ; *ptr && isspace(*ptr); ptr++)
+ /* do nothing */ ;
+
+ if (!strcmp(line, "pad"))
+ {
+ // padding
+ // parse the hex number and stow it
+ linkscript.padsize = strtol(ptr, NULL, 16);
+ if (linkscript.padsize < 0)
+ linkscript.padsize = 0;
+ }
+ else if (!strcmp(line, "stacksize"))
+ {
+ // stack size for targets that support it
+ // parse the hex number and stow it
+ linkscript.padsize = strtol(ptr, NULL, 16);
+ if (linkscript.stacksize < 0)
+ linkscript.stacksize = 0x100;
+ }
+ else if (!strcmp(line, "entry"))
+ {
+ int eaddr;
+
+ eaddr = strtol(ptr, &ptr2, 16);
+ if (*ptr2)
+ {
+ linkscript.execaddr = -1;
+ linkscript.execsym = lw_strdup(ptr);
+ }
+ else
+ {
+ linkscript.execaddr = eaddr;
+ linkscript.execsym = NULL;
+ }
+ }
+ else if (!strcmp(line, "section"))
+ {
+ // section
+ // parse out the section name and flags
+ for (ptr2 = ptr; *ptr2 && !isspace(*ptr2); ptr2++)
+ /* do nothing */ ;
+
+ if (*ptr2)
+ *ptr2++ = '\0';
+
+ while (*ptr2 && isspace(*ptr2))
+ ptr2++;
+
+ // ptr now points to the section name and flags and ptr2
+ // to the first non-space character following
+
+ // then look for "load " clause
+ if (*ptr2)
+ {
+ if (!strncmp(ptr2, "load", 4))
+ {
+ ptr2 += 4;
+ while (*ptr2 && isspace(*ptr2))
+ ptr2++;
+
+ }
+ else
+ {
+ fprintf(stderr, "%s: bad script\n", scriptfile);
+ exit(1);
+ }
+ }
+
+ // now ptr2 points to the load address if there is one
+ // or NUL if not
+ linkscript.lines = lw_realloc(linkscript.lines, sizeof(struct scriptline_s) * (linkscript.nlines + 1));
+
+ linkscript.lines[linkscript.nlines].noflags = 0;
+ linkscript.lines[linkscript.nlines].yesflags = 0;
+ if (*ptr2)
+ linkscript.lines[linkscript.nlines].loadat = strtol(ptr2, NULL, 16);
+ else
+ linkscript.lines[linkscript.nlines].loadat = -1;
+ for (ptr2 = ptr; *ptr2 && *ptr2 != ','; ptr2++)
+ /* do nothing */ ;
+ if (*ptr2)
+ {
+ *ptr2++ = '\0';
+ if (!strcmp(ptr2, "!bss"))
+ {
+ linkscript.lines[linkscript.nlines].noflags = SECTION_BSS;
+ }
+ else if (!strcmp(ptr2, "bss"))
+ {
+ linkscript.lines[linkscript.nlines].yesflags = SECTION_BSS;
+ }
+ else
+ {
+ fprintf(stderr, "%s: bad script\n", scriptfile);
+ exit(1);
+ }
+ }
+ if (ptr[0] == '*' && ptr[1] == '\0')
+ linkscript.lines[linkscript.nlines].sectname = NULL;
+ else
+ linkscript.lines[linkscript.nlines].sectname = lw_strdup(ptr);
+ linkscript.nlines++;
+ }
+ else
+ {
+ fprintf(stderr, "%s: bad script\n", scriptfile);
+ exit(1);
+ }
+ lw_free(line);
+ }
+
+ if (scriptfile || nscriptls)
+ lw_free(oscript);
+}
diff -r 000000000000 -r 2c24602be78f lwlink/util.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwlink/util.c Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,86 @@
+/*
+util.c
+Copyright © 2009 William Astle
+
+This file is part of LWLINK.
+
+LWLINK 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 3 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, see .
+*/
+
+/*
+Utility functions
+*/
+
+#define __util_c_seen__
+#include
+#include
+#include
+#include
+
+#include "util.h"
+
+void *lw_malloc(int size)
+{
+ void *ptr;
+
+ ptr = malloc(size);
+ if (!ptr)
+ {
+ // bail out; memory allocation error
+ fprintf(stderr, "lw_malloc(): Memory allocation error\n");
+ exit(1);
+ }
+ return ptr;
+}
+
+void *lw_realloc(void *optr, int size)
+{
+ void *ptr;
+
+ if (size == 0)
+ {
+ lw_free(optr);
+ return;
+ }
+
+ ptr = realloc(optr, size);
+ if (!ptr)
+ {
+ fprintf(stderr, "lw_realloc(): memory allocation error\n");
+ exit(1);
+ }
+}
+
+void lw_free(void *ptr)
+{
+ if (ptr)
+ free(ptr);
+}
+
+char *lw_strdup(const char *s)
+{
+ char *d;
+
+ if (!s)
+ return NULL;
+
+ d = strdup(s);
+ if (!d)
+ {
+ fprintf(stderr, "lw_strdup(): memory allocation error\n");
+ exit(1);
+ }
+
+ return d;
+}
diff -r 000000000000 -r 2c24602be78f lwlink/util.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lwlink/util.h Wed Jan 19 22:27:17 2011 -0700
@@ -0,0 +1,44 @@
+/*
+util.h
+Copyright © 2009 William Astle
+
+This file is part of LWLINK.
+
+LWLINK 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 3 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, see .
+*/
+
+/*
+Utility functions
+*/
+
+#ifndef __util_h_seen__
+#define __util_h_seen__
+
+#ifndef __util_c_seen__
+#define __util_E__ extern
+#else
+#define __util_E__
+#endif
+
+// allocate memory
+__util_E__ void *lw_malloc(int size);
+__util_E__ void lw_free(void *ptr);
+__util_E__ void *lw_realloc(void *optr, int size);
+
+// string stuff
+__util_E__ char *lw_strdup(const char *s);
+
+#undef __util_E__
+
+#endif // __util_h_seen__