From dfbf66ea398ead2670cb30390fb8303dda2ca3ed Mon Sep 17 00:00:00 2001
From: Godzil If you use Windows or TI calculators you don't need to build GTC yourself as
+there are already precompiled versions available. If you use Unix-like operating systems (Linux, Mac OS X...) you will have to
+follow these instructions to build GTC yourself. You should need no special package apart from GNU make and a C/C++ compiler to
+build GTC. On Windows you will need Cygwin. Just type (replace By default GTC will be installed in The above instructions are designed to only recompile platform-dependent files
+and as such have minimal dependencies. If you want to modify precompiled data such as the precompiled headers you will
+need extra packages like Perl and possibly Ruby. The Makefiles follow these conventions: All Makefiles are designed to be safely used with parallel compilation.
+ The computer version of GTC has a number of options available on the command-line. They are all listed here. Please note that currently, these options are not available for the FlashApp version. To compile a file named This will create files named You can modify the behaviour of GTC with command-line options (or command-line switches). Their position on the command-line does not matter. For example, if you want to use the Or, equivalently: See below for a complete list of options. By default, By default, calculator executables are stored in the By default, It is in the philosophy of GTC to have default options as sensible as possible, so optimization options are kept to a bare minimum. Furthermore, optimizations are always enabled. This switch will make your program much smaller and very slightly faster, at the expense of a short loading time (usually less than half a second). However note that because it adds an unpacker to your program, it will make very small programs (less than 3-4 kilobytes) larger, so it should not be used in this case. It has the same effect as defining the It can be an interesting way to work around AMS's program size limit for AMS version 2.0x, because a program that exceeds the size limit when uncompressed can be compressed to a size below the limit. Not an option per se, but a way to indicate that all arguments after GTC is composed of three separate parts: the GTC compiler, the GTC IDE and the
+GTC standard library. You are free to use these parts separately or in
+combination. You can redistribute or modify GTC freely for non-commercial use, as long as
+you also redistribute the modified source and comply with the licenses of the
+components you choose to distribute: you cannot redistribute the GTC standard
+library if you fail to comply with the terms of the GNU General Public
+License, version 2 (GPL). In addition you may redistribute the GTC standard
+library under the terms of the GPL license, without restriction on commercial
+use. Excluding the standard library, the main author of GTC is Paul Froissart,
+however GTC would not have been possible without building upon the work of
+the following contributors. The GTC standard library is a simple recompilation of old versions of the TIGCC
+library, adapted for usage of a different calling convention. As such it is
+licensed under the terms of the GNU General Public License, with an
+exception allowing linking of the library with external programs, and
+redistribution of the linked programs notwithstanding the provisions of the
+GPL. The TIGCC library was written by Zeljko Juric, Thomas Nussbaumer, Sebastian
+Reichelt, Kevin Kofler and other contributors to the
+ TIGCC project. The GTC compiler is based on the 68000 and i386 C compiler III.1 by Christoph
+van Wuellen (1989-1991), itself based on the 68000 compiler by Matthew Brandt
+(1984-1986). The The code to import Some people provided significant help without contributing code to the project. Thanks to Olivier Armand for his FlashAppy patch: since TI has stopped signing
+Flash applications this is absolutely vital to GTC. Thanks to vince from the Ti-Fr team for his generous hosting. Thanks to all the testers who helped uncover bugs. You will find the latest versions and online documentation on the GTC website: Please use the feedback form to submit bugs or
+comments.
+ You will find GTC supports a number of extensions, designed to take advantage of the TI platform, or simply to maintain compatibility with existing programs. See Generalized Lvalues. Note however that weird constructs like See Compound Literals (Cast Constructors). There is some difference in the handling of static storage duration though, see Differences between GTC and TIGCC. See Designated Initializers, but in GTC this only works for array types. See Specifying Attributes of Functions, however not all of the specifiers are meaningful in GTC. It is sometimes convenient to include binary files directly into your program, for example when using sprites. The You can use The first declaration creates an array of 16 shorts containing the hexadecimal numbers provided.
+The second declaration creates an array of 16 shorts whose representation in memory will be the same as Note that for the sake of portability, GTC allows you to program in assembly, with a syntax very close to that of a68k. In fact, it is powerful enough to write full assembly programs using only GTC! You can insert assembly code at the global level, for example: This creates an assembly function named To use such a function in C code, you need to prototype it: This tells GTC that your function takes a You can also insert assembly code within a function. This has the advantage over global assembly functions to eliminate the overhead associated with a function call. This functions turns off the calculator when An You must separate different declarations either: The behaviour of GTC is indeed very close to that of The most notable difference is perhaps that, where After execution of Note the In this example, Because What's most interesting in all this is that the C library required no modification whatsoever to allow using ROM calls in such a way: ROM calls are not defined twice, and there isn't even a conditional statement acting differently inside This is an operator reserved to operands of instructions in The reason why this operator exists is simple: assembly and C each have different arithmetic rules. For example, if you have the following code: then, while in C So when you write: then, as you would expect from assembly code, This works with But GTC allows you to do much more: you may want to access information that requires access to the full typing system of C, not just the addresses of different objects.
+The way you can access this typing system is by the then GTC goes one step further, by automatically enclosing Here both The prefix This is not very useful in normal C code, but it can be useful in conjunction with other GTC extensions, mainly This could be because you do not have enough free RAM (more than 100kb is recommended), but if you have enough RAM it is probably because the function abc is too large to fit in the memory of the calculator. You will need to split into smaller functions to avoid the error. Another reason could be that you have a It all depends on what features your program uses. Here is a list of porting issues: Additionally, you may run into these little behaviour differences: This list may not be exhaustive, but I will be happy to hear about any problems you might have that are not mentioned in this list. You should not have much trouble compiling GTC programs with TIGCC as GTC was designed to introduce as few incompatibilities as possible. However, if you use low-level features like assembly you might run into some problems: The traditional (and popular) assembler for TI calculators. It is currently
+distributed as part of TIGCC.Building GTC
+Building the binaries
+./configure && make && sudo make installmake with make -j to take advantage of multiprocessor systems)./usr/local. If you want to install it in
+a different directory (for example if you don't have administrator rights), use
+the following command:./configure --prefix $HOME/my_directory && make installRebuilding a modified GTC
+Notes for developers
+
+make clean cleans up intermediary files, but not final files.
+make distclean cleans up intermediary files and any platform-dependent
+ files.
+make scratchclean cleans up everything that can be rebuilt. Note: use
+ with care, as if you don't have the right tools installed you are not going
+ to be able to rebuild GTC.
+GTC Command-line options
+
+
+
+
+
+
+
+
Basic usage
Invocation
+hello.c, open a command-line prompt in the folder where hello.c is stored, and type:
+gtc hello.c
+
+hello.89z, hello.9xz and hello.v2z (or only some of those, if your program is specific to a calculator model). You can now run them after sending them to your calculator or to an emulator.Adding options
+-o switch to create files named somename.89z, somename.9xz and somename.v2z, you can type:
+gtc hello.c -o somename
+
+
+gtc -o somename hello.c
+
+List of all options
Options affecting output
-o switch
+gtc hello.c foo.c bar.c results in an executable named hello.89z or hello.v2z. You can specify other names with this switch, for example gtc hello.c foo.c bar.c -o somename will instead create an executable named somename.89z or somename.v2z.--folder switch
+main folder. You can store them in the folder somefold with the switch --folder=somefold.--output switch
+gtc hello.c -o somename results in an executable named somename.89z; the name of the program on the calculator will thus be somename(). You can change this with the switch --output=myprog: gtc hello.c -o somename --output=myprog creates an executable named somename.89z containing a program whose name on the calculator will be myprog().Preprocessor options
Optimization options
+-exe switch
+EXE_OUT preprocessor symbol.Other options
-- separator
+-- are really filenames and not command-line switches.
+For example gtc -DHELLO hello.c -- foo.c -file-with-dashes-.c will compile the 3 files hello.c, foo.c and -file-with-dashes-.c, with the single option -DHELLO. Without -- the file -file-with-dashes-.c would have been understood as an (invalid) command-line option.
+Information
+
+
+Credits and licensing
+Standard library
+Compiler core
+Compression routines
+-exe mode is based on the PuCrunch algorithm written by Pasi Albert Ojala, and adapted for use on TI calculators by Thomas Nussbaumer.Object file import
+.o files is based on obj2ti written by Julien Muchembled and further modified by Sebastian Reichelt and Kevin Kofler.Thanks
+Contact
+GTC examples
+GTC Extensions
+
+
+
+
+
GNU extensions
+
+Generalized Lvalues
+(a,b)+=5 are rejected by GTC -- commas are not considered legal lvalues.Compound Literals (Cast Constructors)
+Designated Initializers
+Specifying Attributes of Functions
+GTC-specific extensions
incbin directive
+incbin directives allows you to do just that, without having to convert your data to a decimal or hexadecimal header (which can be memory-consuming on a TI).Using
incbin to declare a C array
+incbin to initialize the contents of a C array:
+// The following declares a sprite using normal C initializers
+short sprite1[] = {
+ 0xFFFF, 0x8008, 0x8008, 0xFFFF,
+ 0xFF00, 0x8800, 0x8800, 0x8800,
+ 0x00FF, 0x0088, 0x0088, 0x0088,
+ 0xFFFF, 0x8008, 0x8008, 0xFFFF,
+};
+
+// The following declares a sprite using
+incbin,
+// reading the contents from the file sprite.bin
+short sprite2[] = incbin "sprite.bin";
+sprite.bin.import_binary can be a useful
+alternative, although there are several caveats: you will have to manually
+declare the size of the array if sizeof is to be used, and you cannot use it
+to declare a static array inside a function.asm{} statement
+Inserting an
asm{} statement in the codeGlobal
asm{} statements
+
+asm {
+add_3_and_multiply_by_5:
+ add.w #3,d0
+ mulu #5,d0
+ rts
+};
+
+add_3_and_multiply_by_5 that takes an input argument in d0, adds 3 to it, multiplies it by 5, and returns the result in d0.
+short add_3_and_multiply_by_5(short x);
+
+short named x as an input, and outputs a short. Because of the calling convention, x will be placed in d0: see default calling convention for more information on where input arguments to assembly functions will be located.Inline
asm{} statements
+
+void do_something(char *command) {
+ if (!strcmp(command,"off"))
+ asm { trap #4 };
+ else
+ printf("unknown command!\n");
+}
+
+command is "off", by calling trap #4.Structure of an
asm{} statement
+asm{} statement is comprised of a set of declarations between the outer { and } braces.
+A declaration can be:
+moveq #123,d0 my_function: dc.w 123,456,789 or incbin "data.bin" ;) -- however you should absolutely avoid doing this outside #define, as the behaviour may change some day
+asm{} interpretation rules
+a68k. Like a68k, GTC tries to optimize instructions when it is possible, for example add.w #3,d0 will be optimized to addq.w #3,d0. Like a68k, you don't need to add a : after label names: however, while with a68k you can only do so if the label is placed on the first char of the line, with GTC you can do so any time as long as the label does not correspond to an assembly instruction.a68k uses specific commands like equ and equr to define macros, GTC simply uses the C preprocessor. This is very powerful, as it allows you to define constants just once and reuse them in C code. You can also use normal C conditionals like #if or #ifdef, making conditional compilation easier.
+You can also interface your code with C much more easily, for example you have access to the sizeof operator:
+int table[] = { 1,2,3,4 };
+
+asm {
+negate_table:
+ lea table,a0
+ moveq #sizeof(table)/2-1,d0
+\loop
+ neg.w (a0)+
+ dbra d0,\loop
+ rts
+};
+
+negate_table, table will be equal to { -1,-2,-3,-4 }.\ in \loop: this means that the label is local. However, this notion differs slightly from that of a68k: while the label is only valid between the surrounding two global labels in a68k, the label is valid throughout the asm{} statement in GTC. It is often more convenient, as this example shows:
+asm {
+\return_with_error
+ moveq #-1,d0
+ rts
+my_function:
+ addq.w #5,d0
+ bmi.s \return_with_error
+ tst.w d1
+ bmi.s \return_with_error
+ ... very long code (longer than 128 bytes) ...
+ rts
+};
+
+\return_with_error is placed before my_function because it allows the branches to \return_with_error to be short branches (bmi.s, 2 bytes) rather than long branches (bmi.w, 4 bytes). If GTC followed the rules of a68k, then it would require \return_with_error to be a global, which can be inconvenient if you have lots of these. Instead, it allows you to structurally divide your program in logical asm{} blocks.Extra features of
asm{} statements
+asm{} statements rely on the C compiler architecture of GTC, there are lots of nice features, for example:
+#define USE_KERNEL
+#include <std.h>
+asm {
+_main:
+ pea "Hello, world!"(pc)
+ jsr ST_helpMsg
+ addq.l #4,a7
+ rts
+};
+
+asm{} code and inside C code!
+This is possible because the assembler was able to interpret the C construct corresponding to ST_helpMsg.asm{} special operator: __c__
+asm{} statements.
+int table[] = { 1,2,3,4 };
+
+table+2 will designate the address of table[2] (the number 3), in assembly table+2 will designate the address of table[0] plus 2 bytes, which happens to be the address of table[1].
+asm {
+load_address:
+ lea table+2(pc),a0
+ rts
+};
+
+table+2 corresponds to the address given by assembly arithmetic rules.#define statements too:
+asm {
+load_address:
+#define my_item table+2
+ lea my_item(pc),a0
+ rts
+};
+
+__c__ operator: if you write
+asm {
+load_address:
+ lea __c__(table+2)(pc),a0
+ rts
+};
+
+table+2 will not be interpreted according to assembly rules, but according to C rules: that is, __c__(table+2) is the adress of table[2].#defines written as part of C code in the __c__ operator:
+int table[] = { 1,2,3,4 };
+#define third_item &table[2] // note: table+2 would give the same results
+
+int *c_load_address() {
+ return third_item;
+}
+
+asm {
+load_address:
+ lea third_item(pc),a0
+ rts
+};
+
+c_load_address() and load_address() do the same thing, without ever having to define third_item twice!@@ prefix
+@@ can be prepended to any identifier to prevent it from being expanded by the preprocessor.
+For example, @@MY_SYMBOL will expand to MY_SYMBOL even if MY_SYMBOL has been #defined to expand to 0x1234.asm{} statements and pre-compiled headers.Frequently Asked Questions
+Common issues
(on-calc) I keep getting errors such as "
not enough memory to compile function abc"
+#define with a large body, or a very
+large number of global declarations. This shouldn't be a problem for most
+programs, but if you think you are in this case, you can try to solve it with #undef or by creating a precompiled header.Differences between GTC and TIGCC
How can I port my program from TIGCC to GTC?
+
+long long support: GTC does not support them, if you use them you will have to rewrite your code to use two longs instead. In many cases it's very easy to port.
+asm() vs asm{}: the assembly syntax is different between GTC and TIGCC. However if you are familiar with a68k you will be able to use GTC's syntax in no time.
+float/double support: currently, GTC does not support floats. If your program uses floats, then unless you think you can get rid of them (e.g. if you are only using them for sines and cosines, you can use a pre-computed table instead), you're basically stuck and should definitely continue using TIGCC (unless you're willing to go down to the assembly level). Sorry.
+
+
+int *f(int *dest,int x) {
+ memcpy(dest,(int[4]){x,x+1,x+2},8);
+ return dest;
+}
+
+is not accepted by GTC because the array constructed is not constant (x is not known at compile time). But you can rewrite it to use a temporary array instead:
+
+int *f(int *dest,int x) {
+ int temp[4] = {x,x+1,x+2};
+ memcpy(dest,temp,8);
+ return dest;
+}
+
+regparm(2,1) convention, while TIGCC uses the stkparm convention. This is only a problem if you have written assembly functions yourself; in this case, you have to specify the calling convention you use in the prototype, e.g.:
+
+asm {
+upper_8_bits:
+ move.b 4(a7),d0
+ rts
+};
+char upper_8_bits(long x);
+
+would become
+
+asm {
+upper_8_bits:
+ move.b 4(a7),d0
+ rts
+};
+char upper_8_bits(long x) __attribute__((stkparm));
+
+How can I make sure my GTC program can be compiled with TIGCC too?
+
+asm {
+turn_calculator_off:
+ trap #4
+ rts
+};
+
+into this more portable program:
+
+#ifdef __GTC__
+/* assembly code using GTC's
+asm{} syntax */
+asm {
+turn_calculator_off:
+ trap #4
+ rts
+};
+#else
+/* assembly code using TIGCC's asm() syntax */
+asm("
+turn_calculator_off:
+ trap #4
+ rts
+");
+#endif
+regparm.
+Glossary
+
+a68k
+
GTC is a C compiler to create programs for the TI-89/TI-92+/V200 calculators. You can choose to run the compiler either on a computer (cross-compilation) or directly on a TI calculator (on-calc compilation). +You can download GTC here.
+Warning: the Windows version does not have a graphical interface yet, so +you should only use it if you know how to run programs from the command line.
+Please note this is preliminary documentation. Some important topics are +missing, and you may find broken links.
+General information:
+ +Getting started:
+General TI programming documentation:
+GTC-specific documentation:
++ GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details typeshow w'. + This is free software, and you are welcome to redistribute it + under certain conditions; typeshow c' for details. + +The hypothetical commandsshow w' andshow c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other thanshow w' andshow c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. +
Sorry, this entry has not been written yet!
You must first install FlashAppy on your calculator. Note that like all ROM +patches, you will not be able to send your modified calculator ROM image to +other calculators. Neither the authors of GTC nor the author of FlashAppy can +be held responsible for any damage that could occur during or after this +process. However, we are not aware of any case where a calculator was damaged +by FlashAppy.
+You only need to install FlashAppy once: you won't need to reinstall it after a +reset or after upgrading to a newer version of GTC. On the other hand if you +install an AMS update you will need to reinstall FlashAppy afterwards.
+Legal notice: the .89t/.9xt/.v2t and .89y/.9xy/.v2y files in the bin-89/92p/v200 directories are subject to the GNU General Public License, which grants you a number of rights. You may choose not to install them, but this will prevent you from using the TIGCC Library.
Once FlashAppy is installed, send all the files in the bin-89, bin-92p or bin-v200 directory (depending on the model) to your calculator, and archive
+them all.
Check that the GTC flashapp was properly transferred by entering the Var-Link +screen and pressing F7: you should see GTC appear in the list. Otherwise, the +transfer failed: make sure that FlashAppy is installed and that you have enough +Archive memory.
+To create a test source file, create a directory named source, create an
+empty text file inside that directory named hello with the TI text editor,
+and archive it with the Var-Link screen.
Now you can run the IDE by typing gtc\gtc_ide() and open the file named hello.
Type in the following code:
+
+#include <tigcclib.h>
+
+void _main() {
+ ST_helpMsg("Hello world!");
+}
+
+Now press the F5 key. This should bring up a compilation dialog, which should +close after a few seconds (if not, you may not have installed GTC properly: +make sure FlashAppy is correctly installed, that everything is archived, and +that you have enough RAM).
+Once the compilation is over you can exit the IDE and run your program by +typing
++outbin() ++
It should display the text Hello world! in the status line. If it worked,
+congratulations! You now have a working C compiler on your calculator.
Here is a small subset of the key commands supported by GTC IDE:
+Also, GTC IDE supports keyboard shortcuts that the standard text editor +doesn't: for example, you can press Shift-2nd-Right (press Shift and 2nd, +then press Right while still holding Shift and 2nd) to highlight the text from +the cursor to the end of the line. Likewise you can press Shift-2nd-Down to +highlight a whole screen of text, or Shift-Diamond-Down to select until the +end of the file. These shortcuts come in particularly handy when selecting +large amounts of text.
+main\outbin() to a kbdprgm like kbdprgm9 so that you can
+ quickly run a freshly compiled program by typing Diamond-9 in the Home
+ screen.
+zheader. You should not delete stdhead or keywords if you want to
+ compile programs designed for the TIGCC library.
+A calling convention specifies where arguments to a function are placed, and where the function places its return value. +You shouldn't worry about it, unless you are an assembly programmer trying to call assembly functions from C code or vice-versa.
+regparm)Unless otherwise specified, GTC uses the most efficient calling convention, regparm.
+Basically, it consists of placing as many arguments as possible into a small set of registers for maximum efficiency, and when they are all used, place the remaining arguments on the stack, which is less efficient.
More precisely, here is the specific algorithm for placing arguments:
+a, from left to right
+d0,d1,d2,a0,a1} are already used by other arguments
+a on the stack
+d0,d1,d2} unused and one of {a0,a1} unused
+a's type is a pointer
+a in the next free address register
+a in the next free data register
+a0,a1} is unused
+a in the next free address register
+a in the next free data register
+Here is how the placement of an argument is done:
+a in the next free data register:
+a in d0 if it is unused
+a in d1 if it is unused
+a in d2 a in the next free address register:
+a in a0 if it is unused
+a in a1 a on the stack:
+stkparm Here is the algorithm for placing the return value:
+a0 d0 struct or a union d0 (not the address!)
+Note that regparm requires the function to have a fixed number of arguments: otherwise, for variable-argument functions, no arguments are placed in registers, and the stkparm convention is used instead.
Note that TIGCC uses the same algorithm, as long as you specify the function attribute __attribute__((regparm(2,1))).
You can also use a different set of variables than d0-d2/a0-a1 thanks to the regparm function attribute, but it is not recommended.
stkparm)The stkparm convention is less efficient, but is useful because it is the one used internally by AMS. It is also much simpler to describe.
The arguments are pushed one after the other onto the stack, starting from the rightmost argument. chars and unsigned chars should be widened to an int before being pushed.
+
Warning: the Windows version does not have a graphical interface yet, so +you should only use it if you know how to run programs from the command line.
+Legal notice: the Include directory is subject to the GNU General Public License, which grants you a number of rights. You may choose not to install it, but it will prevent you from using the TIGCC Library.
To install GTC just extract gtc.exe and the Include directory to any
+directory. You should add that directory to your Windows path (Control Panel →
+System → Advanced → Environment Variables, and modify the PATH variable).
Now you can invoke gtc on the command-line, for more information see GTC
+Command-line options.
+
') { + getch(); + lastst = pointsto; + } else + lastst = minus; + break; + case '*': + getch(); + if (lastch == '=') { + getch(); + lastst = astimes; + } else + lastst = star; + break; + case '/': + getch(); + if (lastch == '=') { + getch(); + lastst = asdivide; + /*} else if (lastch == '*') { + getch(); + for (;;) { + if (lastch == '*') { + getch(); + if (lastch == '/') { + getch(); + goto restart; + } + } else getch(); + } + } else if (lastch == '/') { + getch(); + for (;;) { + if (lastch == '\n') { + getch(); + goto restart; + } else getch(); + }*/ + } else + lastst = divide; + break; + case '^': + getch(); + if (lastch == '=') { + getch(); + lastst = asuparrow; + } else + lastst = uparrow; + break; + case ';': + getch(); + lastst = semicolon; + break; + case ':': + getch(); + lastst = colon; + break; + case '=': + getch(); + if (lastch == '=') { + getch(); + lastst = eq; + } else + lastst = assign; + break; + case '>': + getch(); + if (lastch == '=') { + getch(); + lastst = geq; + } else if (lastch == '>') { + getch(); + if (lastch == '=') { + getch(); + lastst = asrshift; + } else + lastst = rshift; + } else + lastst = gt; + break; + case '<': + getch(); + if (lastch == '=') { + getch(); + lastst = leq; + } else if (lastch == '<') { + getch(); + if (lastch == '=') { + getch(); + lastst = aslshift; + } else + lastst = lshift; + } else + lastst = lt; + break; + case '\'': + getch(); + ival = getsch(0); /* get a string char */ + if (lastch != '\'') + error(ERR_SYNTAX); + else + getch(); + lastst = iconst; + break; + case '\"': + if (forbid!=sconst) { + getch_in_string=1; + getch(); + for (i = 0; ; ++i) { + if ((j = getsch(1)) IS_INVALID) + break; + if (i < MAX_STRLEN) + laststr[i] = j; + } + getch_in_string=0; + /* + * Attention: laststr may contain zeroes! + */ + if (i > MAX_STRLEN) { + i = MAX_STRLEN; + uwarn("string constant too long"); + } + lstrlen = i; + laststr[i] = 0; + } + lastst = sconst; + break; + case '!': + getch(); + if (lastch == '=') { + getch(); + lastst = neq; + } else + lastst = not; + break; + case '%': + getch(); + if (lastch == '=') { + getch(); + lastst = asmodop; + } else + lastst = modop; + break; + case '~': + getch(); + lastst = compl; + break; + case '.': + getch(); + if (isdigit(lastch)) { +#ifndef NOFLOAT + rval = 0; + getfrac(); +#endif + lastst = rconst; + if (lastch=='e' || lastch=='E') { + getch(); +#ifndef NOFLOAT + getexp(); +#endif + } + } else if (lastch=='.') { + getch(); + if (lastch!='.') error(ERR_SYNTAX); + getch(); + lastst = dots; + } else + lastst = dot; + break; + case ',': + getch(); + lastst = comma; + break; + case '&': + getch(); + if (lastch == '&') { + lastst = land; + getch(); + } else if (lastch == '=') { + lastst = asand; + getch(); + } else + lastst = and; + break; + case '|': + getch(); + if (lastch == '|') { + lastst = lor; + getch(); + } else if (lastch == '=') { + lastst = asor; + getch(); + } else + lastst = or; + break; + case '(': + getch(); +#ifdef ASM +#ifdef OLD_AMODE_INPUT + if (asm_xflag + && ((lastch=='p' && *lptr=='c') + || (lastch=='s' && *lptr=='p') + || (lastch=='a' && *lptr>='0' && *lptr<='7')) + && (lptr[1]==')' || lptr[1]==',')) + lastst = kw_offs_end; + else +#else + if (asm_xflag + && ((lastch=='p' && *lptr=='c') + || (lastch=='s' && *lptr=='p') + || (lastch=='a' && *lptr>='0' && *lptr<='7')) + && (lptr[1]==')' || lptr[1]==',')) + lastst_flag=1; + else lastst_flag=0; +#endif +#endif + lastst = openpa; + break; + case ')': + getch(); + lastst = closepa; + break; + case '[': + getch(); + lastst = openbr; + break; + case ']': + getch(); + lastst = closebr; + break; + case '{': + getch(); + lastst = begin; + break; + case '}': + getch(); + lastst = end; + break; + case '?': + getch(); + lastst = hook; + break; + case '#': + getch(); + // TODO: rewrite the following (disabled because not ANSI-compliant) + /*getsym(); + if (lastst==id) { + SYM *sp; + if (mac_sp!=&mac_stk[MAX_MAC_NUM] && + (sp = search(lastid, lastcrc, (HTABLE *)*mac_sp))) { + char c,*q=sp->value.s; char buf[MAX_STRLEN],*bp; int i; + lastst=sconst; + bp=buf; + *bp++='"'; + i=MAX_STRLEN-1-2; + do { + if (!(c=*q++)) break; + if (c=='"') { *bp++='\\'; *bp++='"'; } + else *bp++=c; + } while (i--); + *bp++='"'; + lptr-=bp-buf+1; + memcpy(lptr,buf,bp-buf); + getch(); + } else error(ERR_UNDEFINED); + } else if (lastst==lconst||lastst==iconst||lastst==uconst) { + char buf[MAX_STRLEN],*bp; + lastst=sconst; + bp=buf; + *bp++='"'; + sprintf(bp,"%ld",ival); + bp+=strlen(bp); + *bp++='"'; + lptr-=bp-buf+1; + memcpy(lptr,buf,bp-buf); + getch(); + } else error(ERR_IDEXPECT); + getsym();*/ +#ifdef ASM + if (asm_flag) { + lastst = sharp; + break; + } else { +#endif + error(ERR_ILLCHAR); + goto restart; /* get a real token */ +#ifdef ASM + } +#endif +/* if (lastst==iconst || lastst==lconst || lastst==uconst) { + lastst=sconst; + if (forbid!=lastst) sprintf(laststr,"%ld",ival); + else { + char b[20]; int n; + sprintf(b,"%ld",ival); + lptr-=1+(n=strlen(b)); + strncpy(lptr,b,n); + lptr[n]='"'; + } + } else error(ERR_INTEGER);*/ + break; +#ifdef ASM + case '\\': + if (asm_flag) { + if (forbid==(lastst=id)) return; + getch(); + if (getid((int)'\\')) goto restart; + } else { + getch(); + error(ERR_ILLCHAR); + goto restart; /* get a real token */ + } + break; +#endif + case '@': + getch(); + if (lastch=='@') { + getch(); + if (isbegidch(lastch)) { + if (forbid==(lastst=id)) return; + getrawid(); + break; + } + } + /* otherwise fall through */ + default: + getch(); + error(ERR_ILLCHAR); + goto restart; /* get a real token */ + } + if (lastst == id) { + searchkw(); +//#ifdef OLD_MACRO + if (lastst == kw_eval) { + struct enode *ep; + getsym(); + needpunc(openpa); + if (!expression(&ep)) error(ERR_EXPREXPECT); + if (lastst!=closepa) needpunc(closepa); + opt0(&ep); + if (ep->nodetype==en_icon) { + lastst=lconst; + ival=ep->v.i; +#ifndef NOFLOAT + } else if (ep->nodetype==en_fcon) { + lastst=rconst; + rval=ep->v.f; +#endif + } else error(ERR_CONSTEXPECT); + } +#ifdef ASM + else if (asm_flag && lastst == id) { + if (!lastid[2]) { + if (lastid[1]>='0' && lastid[1]<='7') { + lastreg=lastid[1]-'0'; // we don't care if we set lastreg even if + if (lastid[0]=='d') // lastst is an id + lastst=kw_dreg; // (for example 'z6' will set lastreg to 6) + else if (lastid[0]=='a') + lastst=kw_areg; + } else if (lastid[1]=='p' && lastid[0]=='s') + lastst=kw_areg,lastreg=7; + } + asm_searchkw(); + } +#endif +#if defined(PCH) && !defined(MEXP_SUPPORTS_PCH) + if (lastst==id && !(lastsp = search(lastid, lastcrc, &lsyms)) + && !(lastsp = search(lastid, lastcrc, &gsyms))) { +#if 0 + int n=pchnum; + while (n--) { + unsigned char *p0=pchdata[n],*tab=pchtab[n],*tabp,*p,c,*q; + TI_SHORT *extTab=(TI_SHORT *)(p0+w2s(pchhead[n]->ext_off)); + int z=PCH_HEAD_SIZE; + do { + p=p0+z; q=lastid; + while ((c=*p++) && c==*q++); + if (!c && !*q) { + tabp=&tab[(p[4]<<8)+p[5]]; + if (*tabp) /* really quit, because it would be a mess */ + goto pch_done; /* if we scanned other files for this ID ;) */ + if (pchload(p+6,tabp,p0,extTab)) goto restart; + else { + lastsp = gsearch(lastid, lastcrc); + goto pch_done; + } + } + if (c) while (*p++); + if (c0) goto restart; + else if (n<0) lastsp = gsearch(lastid, lastcrc); +#endif + } +#else + if (lastst==id && !(lastsp = search(lastid, lastcrc, &lsyms))) + lastsp = search(lastid, lastcrc, &gsyms); +#endif + } +/* if (global_flag) + if (lastst==id && !strcmp(lastid,"pos")) + bkpt();*/ +/* if (lineid==0x51) + bkpt();*/ +} + +int getcache(enum(e_sym) f) { + enum(e_sym) my_st=lastst; + int my_flag=lastst_flag; + int my_line=lineid,my_prev=prevlineid; + if (cached_sym!=-1) return (cached_sym==f); + cached_sym=-2; // tell getcache not to put anything into cache + forbid=f; + getsym(); + cached_sym=lastst; + cached_flag=lastst_flag; + cached_lineid=my_line; + lastst=my_st; + lastst_flag=my_flag; + lineid=my_line; + prevlineid=my_prev; + forbid=-1; + if (cached_sym==f) cached_sym=-1; + return (cached_sym==-1); +/* enum(e_sym) my_st=lastst,cached=cached_sym; + if ((int)cached_sym2 IS_VALID) return (cached_sym2==f); + cached_sym=-1; // prevent getsym from caching :) + forbid=f; + getsym(); + forbid=-1; + if ((int)cached IS_VALID) { + if ((int)cached_sym2 IS_VALID) fatal("CACHE"); + cached_sym2=lastst; + cached_sym=cached; + lastst=my_st; + if (cached_sym2==f) cached_sym2=-1; + return (cached_sym2==f); + } else { + cached_sym=lastst; + lastst=my_st; + if (cached_sym==f) cached_sym=-1; + return (cached_sym==f); + }*/ +} + +void needpunc(enum(e_sym) p) { + if (lastst == p) + getsym(); + else + uerr(ERR_PUNCT, + p==semicolon?';': + (p==begin?'{': + (p==end?'}': + (p==openpa?'(': + (p==closepa?')': + (p==hook?'?': + (p==comma?',': + (p==closebr?']':' ')))))))); +} + +extern unsigned char sizeof_flag; +extern unsigned char id_are_zero; +void do_compile() { + /* parser initialization */ + sizeof_flag=0; id_are_zero=0; + flags=flags_basegtc; +#ifdef SPEED_OPT + speed_opt_value = default_speed_opt_value; +#endif + /* lexical analyzer / preprocessor initialization */ + initsym(); + /* compilation itself */ + compile(); +} +#ifdef PCH +void closepch() { +#ifdef REQ_MGT + { + FILE *req_file=NULL; + int i,needs_req=0; + for (i=pchnum;i--;) + if (pchrequired[i] && strcmp(pchname[i],"stdhead")) + needs_req++; + if (needs_req) { + char buf[sizeof("[Req_v1]\n")+1]; + char temp[5000]; + *temp=0; + req_file=fopen(proj_file,"r"); + if (req_file) { + while (!feof(req_file)) { + fgets(buf,sizeof("[Req_v1]\n"),req_file); + strcat(temp,buf); + if (!strcmp(buf,"[Req_v1]\n")) { + needs_req=0; + break; + } + } + fclose(req_file); + } + req_file=fopen(proj_file,"w"); + if (!req_file) fatal("Could not open project file."); + fputs(temp,req_file); + if (needs_req) + fputs("[Req_v1]\n",req_file); + needs_req=1; + } +#endif + /* close PCH files */ + while (pchnum) { + pchnum--; +#ifdef REQ_MGT + if (pchrequired[pchnum] && needs_req) + fprintf(req_file,"%s\n",pchname[pchnum]); +#endif + fclose(pchfile[pchnum]); + } +#ifdef REQ_MGT + if (needs_req) + fclose(req_file); + } +#endif +} +#endif +// vim:ts=4:sw=4 diff --git a/gtc/src/gtdevcomm.c b/gtc/src/gtdevcomm.c new file mode 100644 index 0000000..286014f --- /dev/null +++ b/gtc/src/gtdevcomm.c @@ -0,0 +1,43 @@ +/* + * GTools C compiler + * ================= + * source file : + * (on-calc) communication with the GT-Dev IDE + * + * Copyright 2001-2004 Paul Froissart. + * Credits to Christoph van Wuellen and Matthew Brandt. + * All commercial rights reserved. + * + * This compiler may be redistributed as long there is no + * commercial interest. The compiler must not be redistributed + * without its full sources. This notice must stay intact. + */ + +#include "GtDevComm.h" + +extern int has_error; + +char *in_file CGLOB,*out_file CGLOB; +Msg_Callback_t msg_process CGLOB; +Progr_Callback_t progr_process CGLOB; +#include "identity.h" +void _gtdevmain(void); +int Compile(char *in,char *out,Msg_Callback_t _msg_process,Progr_Callback_t _progr_process) { + void *old_a5=bssdata; + int res; + bssdata=malloc(BSS_SIZE); + if (!bssdata) return; + memset(bssdata,0,BSS_SIZE); + in_file=in; out_file=out; + msg_process=_msg_process; + progr_process=_progr_process; + _gtdevmain(); + bssdata=identity(bssdata); + if (!bssdata) + return 2; + res=has_error; + free(bssdata); + bssdata=old_a5; + return res; +} +// vim:ts=4:sw=4 diff --git a/gtc/src/gtdevcomm.h b/gtc/src/gtdevcomm.h new file mode 100644 index 0000000..2a201fb --- /dev/null +++ b/gtc/src/gtdevcomm.h @@ -0,0 +1,44 @@ +/* + * GTools C compiler + * ================= + * source file : + * (on-calc) communication with the GT-Dev IDE + * + * Copyright 2001-2004 Paul Froissart. + * Credits to Christoph van Wuellen and Matthew Brandt. + * All commercial rights reserved. + * + * This compiler may be redistributed as long there is no + * commercial interest. The compiler must not be redistributed + * without its full sources. This notice must stay intact. + */ + +#ifndef __GTDEVCOMM_H +#define __GTDEVCOMM_H + +//#include "E:\Paul\89\Ti-GCC\Projects\GT-Dev\SecureCommDef.h" +#include "securecommdef.h" + +#define ET_FATAL -2 +#define ET_WARNING -1 +#define ET_ERROR 0 +#define ET_INTERNAL_WARNING 1 +#define ET_INTERNAL_FAILURE 2 +#define et_isinternal(x) ((x)>0) +#define et_iserror(x) !((x)&1) +#if __TIGCC_BETA__*100+__TIGCC_MINOR__>=94 +#define CALLBACK __ATTR_TIOS_CALLBACK__ +#else +#define CALLBACK +#endif +typedef void (CALLBACK*Msg_Callback_t)(char *message,int err_type,char *func,char *file,int line,int chr); +//typedef _Msg_Callback_t *Msg_Callback_t; +#define MAX_PROGRESS 65535 +typedef void (CALLBACK*Progr_Callback_t)(char *func,char *file,unsigned int fprogress); +//typedef _Progr_Callback_t *Progr_Callback_t; + +extern char *in_file,*out_file; +extern Msg_Callback_t msg_process; +extern Progr_Callback_t progr_process; +#endif +// vim:ts=4:sw=4 diff --git a/gtc/src/gtpack/gtpack.c b/gtc/src/gtpack/gtpack.c new file mode 100644 index 0000000..99530f8 --- /dev/null +++ b/gtc/src/gtpack/gtpack.c @@ -0,0 +1,2259 @@ +/****************************************************************************** +* +* A variant of ttpack designed to output XPak compressed data. +* +* ----------------------------------------------------------------------------- +* +* original project name: TIGCC Tools Suite +* file name: ttpack.c +* initial date: 14/08/2000 +* authors: albert@cs.tut.fi +* thomas.nussbaumer@gmx.net +* Paul Froissart +* description: packing program +* +* ----------------------------------------------------------------------------- +* +* based on code from Pasi 'Albert' Ojala, albert@cs.tut.fi +* +* heavily reduced to fit to the needs by thomas.nussbaumer@gmx.net +* +* modified to fit XPak's compression format +* +******************************************************************************/ + +#include+#include +#include +#include +#include +#include + +//#define ONCALC_PACKER_EMU +//#define EVEN_LZ // allow only LZ sequences with the same parity +//#define NEW_RANGE // LZhuf-like range coding +//#define X_STATS +#define NO_XVERBOSE +//#define ZRANGE +//#define ZRANGE_FAST + +#include "tt.h" // generic defines +#include "ttversion.h" // tigcc tools suite version info +#include "revtools.h" // used for id displaying +#include "ttunpack.h" // errorcodes definition +#include "packhead.h" // compressed header definition + +#define CVS_FILE_REVISION "$Revision: 1.4 $" + +#define FIXF_MACHMASK 0xff +#define FIXF_WRAP 256 +#define FIXF_DLZ 512 + + +#define F_VERBOSE (1<<0) +#define F_STATS (1<<1) +#define F_AUTO (1<<2) +#define F_NOOPT (1<<3) +#define F_AUTOEX (1<<4) +#define F_TEXTINPUT (1<<5) +#define F_TEXTOUTPUT (1<<6) +#define F_NORLE (1<<9) +#define F_ERROR (1<<15) + +#ifndef min +#define min(a,b) ((a 1..127 */ +#else +#define LRANGE 6144 /* packer() emulation */ +#endif +#ifdef NEW_RANGE +#undef LRANGE +#define LRANGE 4096 +#endif +#ifdef ZRANGE +#undef LRANGE +#define LRANGE 6144 +#endif +#define MAXLZLEN (2< 1..127 */ +#define DEFAULT_LZLEN LRANGE + + + +unsigned short *rle, *elr, *lzlen, *lzpos; +unsigned short *lzlen2, *lzpos2; +int *length, inlen; +unsigned char *indata, *mode, *newesc; +unsigned short *backSkip; + + +enum MODE { + LITERAL = 0, + LZ77 = 1, + RLE = 2, + DLZ = 3, + MMARK = 4 +}; + +int lzopt = 0; + + +int maxGamma = 7; +int reservedBytes = 2; +int escBits = 2; +int escMask = 0xc0; +int extraLZPosBits = 0; +int rleUsed = 31; + + +/* +//============================================================================= +// outputs usage information of this tool +//============================================================================= +void PrintUsage() { + fprintf(stderr, "Usage: ttpack [- ] \n" \ + " -hti treat input as hex textinput\n" \ + " -hto generate hex textoutput\n" \ + " -fdelta use delta-lz77 -- shortens some files\n" \ + " e force escape bits\n" \ + " r restrict lz search range\n" \ + " n no RLE/LZ length optimization\n" \ + " s full statistics\n" \ + " v verbose\n" \ + " p force extralzposbits\n" \ + " m max len 5..7 (2*2^5..2*2^7)\n"); +} +*/ + +/* +//============================================================================= +// the packing code +//============================================================================= +int SavePack(int flags,int type, unsigned char *data, int size, char *target, + int start, int escape, unsigned char *rleValues, + int endAddr, int extraLZPosBits,int memStart, int memEnd) +{ + FILE *fp = NULL; + + int i; + + if (!data) return 10; + if (!target) fp = stdout; + + if ((type & FIXF_MACHMASK) == 0) { + // Save without decompressor + + if (fp || (fp = fopen(target, "wb"))) { + PackedHeader cth; + RLEEntries re; + + cth.origsize_lo = inlen & 0xff; + cth.origsize_hi = (inlen >> 8); + #ifndef COMPACT + cth.magic1 = MAGIC_CHAR1; + cth.magic2 = MAGIC_CHAR2; + cth.compsize_lo = (size + rleUsed + sizeof(PackedHeader)) & 0xff; + cth.compsize_hi = (size + rleUsed + sizeof(PackedHeader)) >> 8; + #else + #ifndef OLD_HDR + memcpy(cth.magic,"GTPk",4); + cth.compsize_lo = (size + rleUsed + sizeof(PackedHeader)) & 0xff; + cth.compsize_hi = (size + rleUsed + sizeof(PackedHeader)) >> 8; + #endif + #endif + cth.esc1 = (escape >> (8-escBits)); + //cth.notused3 + //cth.notused4 + cth.esc2 = escBits; + #if !defined(COMPACT) || defined(OLD_HDR) + cth.gamma1 = maxGamma + 1; + cth.gamma2 = (1 << maxGamma); + #endif + cth.extralz = extraLZPosBits; + //cth.notused1 = 0xff; + //cth.notused2 = 0xff; + cth.rleentries = rleUsed; + + for(i=0; i >= 1; + + if (!bitMask) { +#ifndef NO_XVERBOSE + printf("[%02x]\n",(int)(unsigned char)outBuffer[outPointer]); +#endif + bitMask = 0x80; + outPointer++; + } +} + + + +int lenValue[256]; + +//-------------------------------------------- +// why not initializing value lenValue[0] ???? +//-------------------------------------------- +//============================================================================= +// +//============================================================================= +#if K_GAMMA-1 +void InitValueLen() { + int i,h; + + for (i=1; i<256; i++) { + int count = 0; + + if (i<2) count = 0; /* 1 */ + else if (i<4) count = 1; /* 2-3 */ + else if (i<8) count = 2; /* 4-7 */ + else if (i<16) count = 3; /* 8-15 */ + else if (i<32) count = 4; /* 16-31 */ + else if (i<64) count = 5; /* 32-63 */ + else if (i<128) count = 6; /* 64-127 */ + else if (i<256) count = 7; /* 128-255 */ + +// lenValue[i] = (count>>1)+count+2; + switch (count) { + case 0: h=1; break; + case 1: if (i==2) h=1; else h=2; break; + case 2: h=4; break; + case 3: h=5; break; + case 4: h=6; break; + case 5: h=7; break; + case 6: h=8; break; + case 7: h=9; break; + } + lenValue[i]=h+count; + } +} +#else +void InitValueLen() { + int i; + + // could be heavily optimized, but isn't necessary + for (i=1; i<256; i++) { + int count = 0; + + if (i<2) count = 0; /* 1 */ + else if (i<4) count = 1; /* 2-3 */ + else if (i<8) count = 2; /* 4-7 */ + else if (i<16) count = 3; /* 8-15 */ + else if (i<32) count = 4; /* 16-31 */ + else if (i<64) count = 5; /* 32-63 */ + else if (i<128) count = 6; /* 64-127 */ + else if (i<256) count = 7; /* 128-255 */ + + lenValue[i] = 2*count; + /*if (count 1) { + bits = (bits<<1) | (value & 1); /* is reversed compared to value */ + value >>= 1; + count++; + PutBit(1); + } + /*if (count same as value */ + bits >>= 1; + } +#endif +} + +#ifdef NEW_RANGE +unsigned char p_len[64] = { + 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 +}; + +unsigned char p_code[64] = { + 0x00, 0x20, 0x30, 0x40, 0x50, 0x58, 0x60, 0x68, + 0x70, 0x78, 0x80, 0x88, 0x90, 0x94, 0x98, 0x9C, + 0xA0, 0xA4, 0xA8, 0xAC, 0xB0, 0xB4, 0xB8, 0xBC, + 0xC0, 0xC2, 0xC4, 0xC6, 0xC8, 0xCA, 0xCC, 0xCE, + 0xD0, 0xD2, 0xD4, 0xD6, 0xD8, 0xDA, 0xDC, 0xDE, + 0xE0, 0xE2, 0xE4, 0xE6, 0xE8, 0xEA, 0xEC, 0xEE, + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, + 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF +}; +//============================================================================= +// +//============================================================================= +void PutRange(int c) { + int i; + + /* output upper 6 bits with encoding */ + i = c >> 6; + PutNBits((unsigned)p_code[i] >> (8-p_len[i]), p_len[i]); + + /* output lower 6 bits directly */ + PutNBits((c & 0x3f), 6); +} +#endif + +int gainedEscaped = 0; +int gainedRle = 0, gainedSRle = 0, gainedLRle = 0; +int gainedLz = 0, gainedRlecode = 0; +int gainedDLz = 0, timesDLz = 0; + +int timesEscaped = 0, timesNormal = 0; +int timesRle = 0, timesSRle = 0, timesLRle = 0; +int timesLz = 0; + +int lenStat[8][4]; + //0: + //1: + //2: SRLE + //3: RLE byte + //4: + +//============================================================================= +// +//============================================================================= +int OutputNormal(int *esc, unsigned char *data, int newesc) { + timesNormal++; + if ((data[0] & escMask) == *esc) { + PutNBits((*esc>>(8-escBits)), escBits); /* escBits>=0 */ + PutBit(0); + PutBit(1); + PutBit(0); + + *esc = newesc; + PutNBits((*esc>>(8-escBits)), escBits); /* escBits>=0 */ + PutNBits(data[0], 8-escBits); + + gainedEscaped += escBits + 3; + timesEscaped++; + return 1; + } + PutNBits(data[0], 8); + return 0; +} + + +//============================================================================= +// +//============================================================================= +void OutputEof(int *esc) { + /* EOF marker */ + PutNBits((*esc>>(8-escBits)), escBits); /* escBits>=0 */ + PutValue(3); /* >2 */ + PutValue((2< >3)); + + gainedRlecode -= LenValue(32+(data>>3)) + 3; + + PutNBits(data, 3); + + lenStat[5][3]++; +} + + +unsigned char rleLen[256]; + + +//============================================================================= +// +//============================================================================= +void InitRleLen() { + int i; + + for (i=0; i<256; i++) rleLen[i] = LenValue(32 + 0) + 3; + for (i=1; i<32; i++) rleLen[rleValues[i]] = LenValue(i); +} + +#define LenRleByte(d) (rleLen[d]) + + +//============================================================================= +// +//============================================================================= +int LenRle(int len, int data) { + int out = 0; + + do { + if (len == 1) { + out += escBits + 3 + 8; + len = 0; + } + else if (len <= (1< >8)+1) + LenRleByte(data); + len -= tmp; + } + } while (len); + return out; +} + + +//============================================================================= +// +//============================================================================= +int OutputRle(int *esc, unsigned char *data, int rlelen) { + int len = rlelen, tmp; + + while (len) { + if (len >= 2 && len <= (1< = 3 || IsShortRleByte(*data))) { + /* Short RLE */ + if (len==2) lenStat[0][2]++; + else if (len<=4) lenStat[1][2]++; + else if (len<=8) lenStat[2][2]++; + else if (len<=16) lenStat[3][2]++; + else if (len<=32) lenStat[4][2]++; + else if (len<=64) lenStat[5][2]++; + else if (len<=128) lenStat[6][2]++; + else if (len<=256) lenStat[6][2]++; + + PutNBits((*esc>>(8-escBits)), escBits); /* escBits>=0 */ + PutBit(0); + PutBit(1); + PutBit(1); + PutValue(len-1); + PutRleByte(*data); + + tmp = 8*len -escBits -3 -LenValue(len-1) -LenRleByte(*data); + gainedRle += tmp; + gainedSRle += tmp; + + timesRle++; + timesSRle++; + return 0; + } + if (len<3) { + while (len--) + OutputNormal(esc, data, *esc); + return 0; + } + + if (len <= maxrlelen) { + /* Run-length encoding */ + PutNBits((*esc>>(8-escBits)), escBits); /* escBits>=0 */ + + PutBit(0); + PutBit(1); + PutBit(1); + + PutValue((1< >(8-maxGamma))); + + PutNBits((len-1), 8-maxGamma); + PutValue(((len-1)>>8) + 1); + PutRleByte(*data); + + tmp = 8*len -escBits -3 -maxGamma -8 -LenValue(((len-1)>>8)+1) + -LenRleByte(*data); + gainedRle += tmp; + gainedLRle += tmp; + + timesRle++; + timesLRle++; + return 0; + } + + /* Run-length encoding */ + PutNBits((*esc>>(8-escBits)), escBits); /* escBits>=0 */ + + PutBit(0); + PutBit(1); + PutBit(1); + + PutValue((1< >(8-maxGamma))); + + PutNBits((maxrlelen-1) & 0xff, 8-maxGamma); + PutValue(((maxrlelen-1)>>8)+1); + PutRleByte(*data); + + tmp = 8*maxrlelen -escBits -3 -maxGamma -8 + -LenValue(((maxrlelen-1)>>8)+1) -LenRleByte(*data); + gainedRle += tmp; + gainedLRle += tmp; + timesRle++; + timesLRle++; + len -= maxrlelen; + data += maxrlelen; + } + return 0; +} + + +#ifdef ZRANGE +char zrlen[96]={ + 0, + 2,2,2,2, + 3,3,3,3, + 4,4,4,4,4,4,4,4, + 5,5,5,5,5,5,5,5, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 +}; +#define ZrLen(p) (zrlen[((p)-1)>>6]) +#endif + + +//============================================================================= +// +//============================================================================= +int LenLz(int lzlen, int lzpos) { +#ifdef EVEN_LZ + if (lzpos&1) return 100000; +#endif + if (lzlen==2) { +#if !defined(ZRANGE) || defined(ZRANGE_FAST) +#ifdef EVEN_LZ + if (lzpos <= 256) return escBits + 2 + 7; +#else + if (lzpos <= 256) return escBits + 2 + 8; +#endif + else return 100000; +#else + if (lzpos <= 64) return escBits + 2 + 7; + else if (lzpos <= 128) return escBits + 2 + 8; + else if (lzpos <= 256) return escBits + 2 + 9; + else return 100000; +#endif + } + +#ifdef ZRANGE + return escBits + 8 + ZrLen(lzpos) + LenValue(lzlen-1); +#else +#ifdef EVEN_LZ + return escBits + 7 + extraLZPosBits + +#else + return escBits + 8 + extraLZPosBits + +#endif + LenValue(((lzpos-1)>>(8+extraLZPosBits))+1) + + LenValue(lzlen-1); +#endif +} + +#ifdef X_STATS +#define XS_NUM (LRANGE/64+1) +int lzstats[16][XS_NUM]; +int lzstatlong[XS_NUM]; +#endif + +//============================================================================= +// +//============================================================================= +int OutputLz(int *esc, int lzlen, int lzpos, char *data, int curpos) { +#ifdef X_STATS + if (lzlen<=16) + lzstats[lzlen-1][(lzpos-1)>>6]++; + else + lzstatlong[(lzpos-1)>>6]++; +#endif + if (lzlen==2) lenStat[0][1]++; + else if (lzlen<=4) lenStat[1][1]++; + else if (lzlen<=8) lenStat[2][1]++; + else if (lzlen<=16) lenStat[3][1]++; + else if (lzlen<=32) lenStat[4][1]++; + else if (lzlen<=64) lenStat[5][1]++; + else if (lzlen<=128) lenStat[6][1]++; + else if (lzlen<=256) lenStat[7][1]++; + + if (lzlen >= 2 && lzlen <= maxlzlen) { + int tmp; + + PutNBits((*esc>>(8-escBits)), escBits); /* escBits>=0 */ + + tmp = ((lzpos-1)>>(8+extraLZPosBits))+2; + if (tmp==2) lenStat[0][0]++; + else if (tmp<=4) lenStat[1][0]++; + else if (tmp<=8) lenStat[2][0]++; + else if (tmp<=16) lenStat[3][0]++; + else if (tmp<=32) lenStat[4][0]++; + else if (tmp<=64) lenStat[5][0]++; + else if (tmp<=128) lenStat[6][0]++; + else if (tmp<=256) lenStat[6][0]++; + + if (lzlen==2) { + PutValue(lzlen-1); + PutBit(0); + if (lzpos > 256) fprintf(stderr,"Error at %d: lzpos too long (%d) for lzlen==2\n",curpos, lzpos); +#ifdef ZRANGE +#ifdef ZRANGE_FAST + PutNBits(((lzpos-1) & 0xff) ^ 0xff, 8); +#else + { + int x=lzpos-1; + switch (x>>6) { + case 0: PutNBits(x,7); break; // x=0b00****** => 0****** + case 1: PutNBits(x+64,8); break; // x=0b01****** => 10****** + case 2: PutNBits(x+256,9); break; // x=0b10****** => 110****** + case 3: PutNBits(x+256,9); break; // x=0b11****** => 111****** + } + } +#endif +#endif + } + else { +#ifdef ZRANGE + PutValue(lzlen-1); +/* PutNBits(0,ZrLen(lzpos)); + PutNBits(0,8);*/ + { + int x=~(lzpos-1),u=(x+64)>>8; + switch (ZrLen(lzpos)) { +/*u=0*/ case 0: PutNBits(x,8); break; +/*u=-1*/ case 2: PutNBits(0x1,2); PutNBits(x,8); break; +/*u=-2*/ case 3: PutNBits(0x0,2); PutNBits(x,8); PutNBits(0x0,1); break; +/*u=-4..-3*/ case 4: PutNBits(0x0,2); PutNBits(x,8); PutNBits(0x2+(u&1),2); break; +/*u=-6..-5*/ case 5: PutNBits(0x2,2); PutNBits(x,8); PutNBits(0x0+(u&1),3); break; +/*u=-12..-7*/ case 6: PutNBits(0x2,2); PutNBits(x,8); PutNBits(0x4+((u+(12&7))&7),4); break; +/*u=-24..-13*/ case 7: PutNBits(0x2,2); PutNBits(x,8); PutNBits(0x14+((u+(24&15))&15),5); break; + } + } +#else +#ifdef X_STATS + PutValue(lzlen-1); +// PutNBits(0,1+3); + PutNBits(0,3); +#else + PutValue(lzlen-1); +#ifndef NEW_RANGE + PutValue( ((lzpos-1) >> (8+extraLZPosBits)) +1); + PutNBits( ((lzpos-1) >> 8), extraLZPosBits); +#endif +#endif +#endif + } +// PutNBits(0xFF, 8); +#ifndef ZRANGE +#ifndef NEW_RANGE +#ifdef EVEN_LZ + PutNBits((((lzpos-1) & 0xff) ^ 0xff) >> 1, 7); + if (lzpos&1) fprintf(stderr, "Error: odd lzpos\n"); +#else + PutNBits(((lzpos-1) & 0xff) ^ 0xff, 8); +#endif +#else + PutRange(lzpos-1); +#endif +#endif + + gainedLz += 8*lzlen -LenLz(lzlen, lzpos); + timesLz++; + return 3; + } + fprintf(stderr, "Error: lzlen too short/long (%d)\n", lzlen); + return lzlen; +} + + + +/* Non-recursive version */ +/* NOTE! IMPORTANT! the "length" array length must be inlen+1 */ + +//============================================================================= +// +//============================================================================= +int OptimizeLength(int optimize) { + int i; + + length[inlen] = 0; /* one off the end, our 'target' */ + for (i=inlen-1; i>=0; i--) { + int r1 = 8 + length[i+1], r2, r3; + +/* if (i<=0x40b1 && !(i&((1<<0)-1))) + printf("");*/ + if (!lzlen[i] && !rle[i] && (!lzlen2 || !lzlen2[i])) { + length[i] = r1; + mode[i] = LITERAL; + continue; + } + + /* If rle>maxlzlen, skip to the start of the rle-maxlzlen.. */ + if (rle[i] > maxlzlen && elr[i] > 1) { + int z = elr[i]; + + i -= elr[i]; + + r2 = LenRle(rle[i], indata[i]) + length[i+ rle[i]]; + if (optimize) { + int ii, mini = rle[i], minv = r2; + + int bot = rle[i] - (1< =bot; ii--) { + int v = LenRle(ii, indata[i]) + length[i + ii]; + if (v < minv) { + minv = v; + mini = ii; + } + } + if (minv != r2) { + lzopt += r2 - minv; + rle[i] = mini; + r2 = minv; + } + } + length[i] = r2; + mode[i] = RLE; + + for (; z>=0; z--) { + length[i+z] = r2; + mode[i+z] = RLE; + } + continue; + } + r3 = r2 = r1 + 1000; /* r3 >= r2 > r1 */ + + if (rle[i]) { + r2 = LenRle(rle[i], indata[i]) + length[i+ rle[i]]; + + if (optimize) { + int ii, mini = rle[i], minv = r2; + + /* Check only the original length and all shorter + lengths that are power of two. + + Does not really miss many 'minimums' this way, + at least not globally.. + + Makes the assumption that the Elias Gamma Code is + used, i.e. values of the form 2^n are 'optimal' */ + ii = 2; + while (rle[i] > ii) { + int v = LenRle(ii, indata[i]) + length[i + ii]; + if (v < minv) { + minv = v; + mini = ii; + } + ii <<= 1; + } + if (minv != r2) { + lzopt += r2 - minv; + rle[i] = mini; + r2 = minv; + } + } + } + if (lzlen[i]) { + r3 = LenLz(lzlen[i], lzpos[i]) + length[i + lzlen[i]]; + + if (optimize && lzlen[i]>2) { + int ii, mini = lzlen[i], minv = r3; + int topLen = LenLz(lzlen[i], lzpos[i]) + - LenValue(lzlen[i]-1); + + /* Check only the original length and all shorter + lengths that are power of two. + + Does not really miss many 'minimums' this way, + at least not globally.. + + Makes the assumption that the Elias Gamma Code is + used, i.e. values of the form 2^n are 'optimal' */ + ii = 4; + while (lzlen[i] > ii) { + int v = topLen + LenValue(ii-1) + length[i + ii]; + if (v < minv) { + minv = v; + mini = ii; + } + ii <<= 1; + } + /* + Note: + 2-byte optimization checks are no longer done + with the rest, because the equation gives too long + code lengths for 2-byte matches if extraLzPosBits>0. + */ + /* Two-byte rescan/check */ + if (backSkip[i] && backSkip[i] <= 256) { +#ifdef EVEN_LZ + if (backSkip[i]&1) { + int j=backSkip[i]; + while (j && (j&1)) + j=backSkip[j]; + if (j && j<=256) { + int v = LenLz(2, j) + length[i + 2]; + + if (v < minv) { + minv = v; + mini = 2; + lzlen[i] = mini; + r3 = minv; + lzpos[i] = j; + } + } + } else { +#endif + /* There are previous occurrances (near enough) */ + int v = LenLz(2, (int)backSkip[i]) + length[i + 2]; + + if (v < minv) { + minv = v; + mini = 2; + lzlen[i] = mini; + r3 = minv; + lzpos[i] = (int)backSkip[i]; + } +#ifdef EVEN_LZ + } +#endif + } + if (minv != r3 && minv < r2) { + lzopt += r3 - minv; + lzlen[i] = mini; + r3 = minv; + } + } + } + + if (r2 <= r1) { + if (r2 <= r3) { + length[i] = r2; + mode[i] = RLE; + } + else { + length[i] = r3; + mode[i] = LZ77; + } + } + else { + if (r3 <= r1) { + length[i] = r3; + mode[i] = LZ77; + } + else { + length[i] = r1; + mode[i] = LITERAL; + } + } + if (lzlen2 && lzlen2[i] > 3) { + r3 = escBits + 2*maxGamma + 16 + LenValue(lzlen2[i]-1) + length[i + lzlen2[i]]; + //r3 = LenDLz(lzlen2[i], lzpos2[i]) + length[i + lzlen2[i]]; + if (r3 < length[i]) { + length[i] = r3; + mode[i] = DLZ; + } + } + } + return length[0]; +} + + +/* + The algorithm in the OptimizeEscape() works as follows: + 1) Only unpacked bytes are processed, they are marked + with MMARK. We proceed from the end to the beginning. + Variable A (old/new length) is updated. + 2) At each unpacked byte, one and only one possible + escape matches. A new escape code must be selected + for this case. The optimal selection is the one which + provides the shortest number of escapes to the end + of the file, + i.e. A[esc] = 1+min(A[0], A[1], .. A[states-1]). + For other states A[esc] = A[esc]; + If we change escape in this byte, the new escape is + the one with the smallest value in A. + 3) The starting escape is selected from the possibilities + and mode 0 is restored to all mode 3 locations. + + */ + +//============================================================================= +// +//============================================================================= +int OptimizeEscape(int *startEscape, int *nonNormal) { + int i, /*j,*/ states = (1< 256) { + fprintf(stderr, "Escape optimize: only 256 states (%d)!\n",states); + return 0; + } + + /* Mark those bytes that are actually outputted */ + for (i=0; i =0; i--) { + /* Using a table to skip non-normal bytes does not help.. */ + if (mode[i] == MMARK) { + int k = (indata[i] >> esc8); + + /* Change the tag values back to normal */ + mode[i] = LITERAL; + + /* + k are the matching bytes, + minv is the minimum value, + minp is the minimum index + */ + + newesc[i] = (minp << esc8); + a[k] = minv + 1; + b[k] = b[minp] + 1; + if (k==minp) { + /* Minimum changed -> need to find a new minimum */ + /* a[k] may still be the minimum */ + minv++; + for (k=states-1; k>=0; k--) { + if (a[k] < minv) { + minv = a[k]; + minp = k; + /* + There may be others, but the first one that + is smaller than the old minimum is equal to + any other new minimum. + */ + break; + } + } + } + } + } + + /* Select the best value for the initial escape */ + if (startEscape) { + i = inlen; /* make it big enough */ + for (j=states-1; j>=0; j--) { + if (a[j] <= i) { + *startEscape = (j << esc8); + i = a[j]; + } + } + } + if (nonNormal) + *nonNormal = other; + return b[startEscape ? (*startEscape>>esc8) : 0]; +#else + { + /* this fairly simple (but efficient) algo comes from GTPk */ + char esc_used[256]; + int esc_rem=states-1; + int lastesc=-1,escaped=0; + int k; + memset(esc_used,0,256); + for (i=0; i > esc8); + + mode[i] = LITERAL; + + if (!esc_used[k] && !esc_rem--) { + memset(esc_used,0,256); + esc_rem=states-1; + escaped++; + if (lastesc>=0) newesc[lastesc] = (k << esc8); + else if (startEscape) *startEscape = (k << esc8); + lastesc=i; + } else { + esc_used[k]=1; + } + } + } + for (k=0;;k++) { + if (!esc_used[k]) { + if (lastesc>=0) newesc[lastesc] = (k << esc8); + else if (startEscape) *startEscape = (k << esc8); + break; + } + } + newesc[0] = *startEscape; + if (nonNormal) + *nonNormal = other; + return escaped; + } +#endif +} + + +//============================================================================= +// Initialize the RLE byte code table according to all RLE's found so far O(n) +//============================================================================= +void InitRle(int flags) { + int p, mr, mv, i; + + for (i=1; i<32; i++) { + mr = -1; + mv = 0; + + for (p=0; p<256; p++) { + if (rleHist[p] > mv) { + mv = rleHist[p]; + mr = p; + } + } + if (mr>=0) { + rleValues[i] = mr; + rleHist[mr] = -1; + } else + break; + } + InitRleLen(); +} + + +//============================================================================= +// Initialize the RLE byte code table according to RLE's actually used O(n) +//============================================================================= +void OptimizeRle(int flags) { + int p, mr, mv, i; + + if ((flags & F_NORLE)) { + rleUsed = 0; + return; + } + if (flags & F_STATS) fprintf(stderr, "RLE Byte Code Re-Tune, RLE Ranks:\n"); + + for (p=0; p<256; p++) rleHist[p] = 0; + + for (p=0; p mv) { + mv = rleHist[p]; + mr = p; + } + } + if (mr>=0) { + rleValues[i] = mr; + if (flags & F_STATS) { + fprintf(stderr, " %2d.0x%02x %-3d ", i, mr, mv); + if (!((i - 1) % 6)) fprintf(stderr, "\n"); + } + rleHist[mr] = -1; + } + else { + break; + } + } + rleUsed = i-1; + if (rleUsed) + for (;i<32;i++) + rleValues[i]=rleValues[i-1]; + + if (flags & F_STATS) + if (((i - 1) % 6)!=1) fprintf(stderr, "\n"); + InitRleLen(); +} + + +int outlen; + +//============================================================================= +// +//============================================================================= +int PackLz77(int lzsz, int flags, int *startEscape,int endAddr, int memEnd, int type) +{ + int i, j, p, headerSize; + int escape; + unsigned char *hashValue; + unsigned char *a; + int k; + + unsigned short *lastPair; + + int rescan = 0; + +#ifndef NO_XVERBOSE + int vescape; +#endif + + + + if (lzsz < 0 || lzsz > lrange) { + fprintf(stderr, "LZ range must be from 0 to %d (was %d). Set to %d.\n", + lrange, lzsz, lrange); + lzsz = lrange; + } + if (lzsz > 65535) { + fprintf(stderr, + "LZ range must be from 0 to 65535 (was %d). Set to 65535.\n", + lzsz); + lzsz = 65535; + } + if (!lzsz) fprintf(stderr, "Warning: zero LZ range. Only RLE packing used.\n"); + + InitRleLen(); + length = (int *)calloc(sizeof(int), inlen + 1); + mode = (unsigned char *)calloc(sizeof(unsigned char), inlen); + rle = (unsigned short *)calloc(sizeof(unsigned short), inlen); + elr = (unsigned short *)calloc(sizeof(unsigned short), inlen); + lzlen = (unsigned short *)calloc(sizeof(unsigned short), inlen); + lzpos = (unsigned short *)calloc(sizeof(unsigned short), inlen); + if ((type & FIXF_DLZ)) { + lzlen2 = (unsigned short *)calloc(sizeof(unsigned short), inlen); + lzpos2 = (unsigned short *)calloc(sizeof(unsigned short), inlen); + } + else { + lzlen2 = lzpos2 = NULL; + } + newesc = (unsigned char *)calloc(sizeof(unsigned char), inlen); + backSkip = (unsigned short *)calloc(sizeof(unsigned short), inlen); + hashValue = (unsigned char *)malloc(inlen); + lastPair = (unsigned short *)calloc(sizeof(unsigned short), 256*256); + + /* error checking */ + if (!length || !mode || !rle || !elr || !lzlen || !lzpos || !newesc || + !lastPair || !backSkip + || ((type & FIXF_DLZ) && (!lzlen2 || !lzpos2)) + || !hashValue) + { + fprintf(stderr, "Memory allocation failed!\n"); + goto errorexit; + } + + i = 0; + j = 0; + a = indata + inlen; + for (p=inlen-1; p>=0; p--) { + k = j; + j = i; + i = *--a; /* Only one read per position */ + hashValue[p] = i*3 + j*5 + k*7; /* 7.95 % */ + } + + /* Detect all RLE and LZ77 jump possibilities */ + for (p=0; p =2) { + rleHist[indata[p]]++; + + for (i=rlelen-1; i>=0; i--) { + rle[p+i] = rlelen-i; + elr[p+i] = i; /* For RLE backward skipping */ + } + + } + } + + /* check LZ77 code */ + if (p+rle[p]+1 =0 && i>=bot) { + /* Got a 2-byte match at least */ + maxval = 2; + maxpos = p-i; + + /* + A..AB rlep # of A's, B is something else.. + + Search for bytes that are in p + (rlep-1), i.e. + the last rle byte ('A') and the non-matching one + ('B'). When found, check if the rle in the compare + position (i) is long enough (i.e. the same number + of A's at p and i-rlep+1). + + There are dramatically less matches for AB than for + AA, so we get a huge speedup with this approach. + We are still guaranteed to find the most recent + longest match there is. + */ + + i = (int)lastPair[(indata[p+(rlep-1)]<<8) | indata[p+rlep]] -1; + while (i>=bot /* && i>=rlep-1 */) { /* bot>=rlep-1, i>=bot ==> i>=rlep-1 */ + + /* Equal number of A's ? */ + if (!(rlep-1) || rle[i-(rlep-1)]==rlep) { /* 'head' matches */ + /* rlep==1 ==> (rlep-1)==0 */ + /* ivanova.run: 443517 rlep==1, + 709846 rle[i+1-rlep]==rlep */ + + /* + Check the hash values corresponding to the last + two bytes of the currently longest match and + the first new matching(?) byte. If the hash + values don't match, don't bother to check the + data itself. + */ + if ( + hashValue[i+maxval-rlep-1] == hashCompare + ) { + unsigned char *a = indata + i+2; /* match */ + unsigned char *b = indata + p+rlep-1+2;/* curpos */ + int topindex = inlen-(p+rlep-1); + + /* the 2 first bytes ARE the same.. */ + j = 2; + while (j < topindex && *a++==*b++) + j++; + + if (j + rlep-1 > maxval) { + int tmplen = j+rlep-1, tmppos = p-i+rlep-1; + + if (tmplen > maxlzlen) + tmplen = maxlzlen; + + /* Accept only versions that really are shorter */ + if (tmplen*8 - LenLz(tmplen, tmppos) > + maxval*8 - LenLz(maxval, maxpos)) { + maxval = tmplen; + maxpos = tmppos; + hashCompare = hashValue[p+maxval-2]; + } + if (maxval == maxlzlen) + break; + } + } + } + if (!backSkip[i]) + break; /* No previous occurrances (near enough) */ + i -= (int)backSkip[i]; + } + + /* + If there is 'A' in the previous position also, + RLE-like LZ77 is possible, although rarely + shorter than real RLE. + */ + if (p && rle[p-1] > maxval) { + maxval = rle[p-1] - 1; + maxpos = 1; + } + /* + Last, try to find as long as possible match + for the RLE part only. + */ + if (maxval < maxlzlen && rlep > maxval) { + bot = p - lzsz; + if (bot < 0) + bot = 0; + + /* Note: indata[p] == indata[p+1] */ + i = (int)lastPair[indata[p]*257] -1; + while (/* i>= rlep-2 &&*/ i>=bot) { + if (elr[i] + 2 > maxval) { + maxval = min(elr[i] + 2, rlep); + maxpos = p - i + (maxval-2); + if(maxval == rlep) + break; /* Got enough */ + } + i -= elr[i]; + if (!backSkip[i]) + break; /* No previous occurrances (near enough) */ + i -= (int)backSkip[i]; + } + } + if (p+maxval > inlen) { + fprintf(stderr,"Error @ %d, lzlen %d, pos %d - exceeds inlen\n",p, maxval, maxpos); + maxval = inlen - p; + } + if (maxpos<=256 || maxval > 2) { + if (maxpos < 0) fprintf(stderr, "Error @ %d, lzlen %d, pos %d\n",p, maxval, maxpos); + lzlen[p] = (maxval =0 && i>=bot) { + maxval = 2; + maxpos = p-i; + + /* + A..AB rlep # of A's, B is something else.. + + Search for bytes that are in p + (rlep-1), i.e. + the last rle byte ('A') and the non-matching one + ('B'). When found, check if the rle in the compare + position (i) is long enough (i.e. the same number + of A's at p and i-rlep+1). + + There are dramatically less matches for AB than for + AA, so we get a huge speedup with this approach. + We are still guaranteed to find the most recent + longest match there is. + */ + + i = (int)lastPair[(((indata[p+(rlep-1)] + rot) & 0xff)<<8) | + ((indata[p+rlep] + rot) & 0xff)] -1; + while (i>=bot /* && i>=rlep-1 */) { /* bot>=rlep-1, i>=bot ==> i>=rlep-1 */ + + /* Equal number of A's ? */ + if (!(rlep-1) || rle[i-(rlep-1)]==rlep) { /* 'head' matches */ + /* rlep==1 ==> (rlep-1)==0 */ + /* ivanova.run: 443517 rlep==1, + 709846 rle[i+1-rlep]==rlep */ + + /* + Check the hash values corresponding to the last + two bytes of the currently longest match and + the first new matching(?) byte. If the hash + values don't match, don't bother to check the + data itself. + */ + if (indata[i+maxval-rlep+1] == valueCompare) { + unsigned char *a = indata + i+2; /* match */ + unsigned char *b = indata + p+rlep-1+2;/* curpos */ + int topindex = inlen-(p+rlep-1); + + /* the 2 first bytes ARE the same.. */ + j = 2; + while (j < topindex && *a++==((*b++ + rot) & 0xff)) + j++; + + if (j + rlep-1 > maxval) { + int tmplen = j+rlep-1, tmppos = p-i+rlep-1; + + if (tmplen > maxlzlen) + tmplen = maxlzlen; + + /* Accept only versions that really are shorter */ + if (tmplen*8 - LenLz(tmplen, tmppos) > + maxval*8 - LenLz(maxval, maxpos)) { + maxval = tmplen; + maxpos = tmppos; + + valueCompare = (indata[p+maxval] + rot) & 0xff; + } + if (maxval == maxlzlen) + break; + } + } + } + if (!backSkip[i]) + break; /* No previous occurrances (near enough) */ + i -= (int)backSkip[i]; + } + + if (p+maxval > inlen) { + fprintf(stderr,"Error @ %d, lzlen %d, pos %d - exceeds inlen\n",p, maxval, maxpos); + maxval = inlen - p; + } + if (maxval > 3 && maxpos <= 256 && + (maxval > lzlen2[p] || + (maxval == lzlen2[p] && maxpos < lzpos2[p]))) { + if (maxpos < 0) + fprintf(stderr, "Error @ %d, lzlen %d, pos %d\n",p, maxval, maxpos); + lzlen2[p] = (maxval p || ptr > 0xffff) + ptr = 0; + + backSkip[p] = ptr; + lastPair[index] = p+1; + } + } + if ((flags & F_NORLE)) { + for (p=1; p lzlen[p]) { + lzlen[p] = (rle[p] >escBits) & 0xff; + + /* Find the optimum path for selected escape bits (no optimize) */ + OptimizeLength(0); + + /* Optimize the escape selections for this path & escBits */ + escaped = OptimizeEscape(&escape, &other); + + /* Compare value: bits lost for escaping -- bits lost for prefix */ + c = (escBits+3)*escaped + other*escBits; + if (flags & F_STATS) { + fprintf(stderr, " %d:%d", escBits, c); + fflush(stderr); /* for SAS/C */ + } + if (c < mv) { + mb = escBits; + mv = c; + } else { + /* minimum found */ + break; + } + if (escBits==4 && (flags & F_STATS)) fprintf(stderr, "\n"); + } + if (mb==1) { /* Minimum was 1, check 0 */ + int escaped; + + escBits = 0; + escMask = 0; + + /* Find the optimum path for selected escape bits (no optimize) */ + OptimizeLength(0); + /* Optimize the escape selections for this path & escBits */ + escaped = OptimizeEscape(&escape, NULL); + + if ((flags & F_STATS)) { + fprintf(stderr, " %d:%d", escBits, 3*escaped); + fflush(stderr); /* for SAS/C */ + } + if (3*escaped < mv) { + mb = 0; + /* mv = 3*escaped; */ + } + } + if ((flags & F_STATS)) fprintf(stderr, "\n"); + + if (flags & F_VERBOSE) fprintf(stderr, "Selected %d-bit escapes\n", mb); + escBits = mb; + escMask = (0xff00>>escBits) & 0xff; + } + + + if (!(flags & F_NOOPT)) { + if (flags & F_VERBOSE) { + fprintf(stderr, "Optimizing LZ77 and RLE lengths..."); + fflush(stderr); + } + } + + /* Find the optimum path (optimize) */ + OptimizeLength((flags & F_NOOPT)?0:1); + if (flags & F_STATS) { + if (!(flags & F_NOOPT)) fprintf(stderr, " gained %d units.\n", lzopt/8); + } + else { + //fprintf(stderr, "\n"); + } + + if (1 || (flags & F_AUTOEX)) { + long lzstat[5] = {0,0,0,0,0}, i, cur = 0, old = extraLZPosBits; + + if (flags & F_VERBOSE) { + fprintf(stderr, "Selecting LZPOS LO length.. "); + fflush(stderr); + } + + for (p=0; p > 8)+1 > (1< (1< (1<<(maxGamma-1))) { + if (rle[p] <= (1< 10) { + if (flags & F_VERBOSE) fprintf(stderr,"Note: Using option -m%d you may get better results.\n",maxGamma+1); + } + if (maxGamma > 5 && stat[0] + stat[1] + stat[3] < 4) { + if (flags & F_VERBOSE) fprintf(stderr,"Note: Using option -m%d you may get better results.\n",maxGamma-1); + } + } + + /* Optimize the escape selections */ + OptimizeEscape(&escape, NULL); + if (startEscape) *startEscape = escape; + OptimizeRle(flags); /* Retune the RLE selections */ + +#ifdef NO_XVERBOSE + if (flags & F_VERBOSE) { + int oldEscape = escape; + if (flags & F_VERBOSE) printf("normal RLE LZLEN LZPOS(absolute)\n\n"); + + for (p=0; p "); + j += lzlen2[p]; + } else + printf(" "); + if (lzpos2) { + if (flags & F_VERBOSE) printf(" %04x*%03d*+%02x", lzpos2[p], lzlen2[p],(indata[p] - indata[p-lzpos2[p]]) & 0xff); + } + if (flags & F_VERBOSE) printf(" 001 %03d %03d %04x(%04x) %02x %s\n", + rle[p],lzlen[p],lzpos[p],p-lzpos[p],indata[p], + (mode[p] & MMARK)?"#":" "); + break; + case MMARK | LITERAL: + case LITERAL: + if (flags & F_VERBOSE) { + if (j==p) printf(">"); + else printf(" "); + + if (lzpos2) { + printf(" %04x %03d +%02x", lzpos2[p], lzlen2[p], + (indata[p] - indata[p-lzpos2[p]]) & 0xff); + } + } + if (j==p) { + if (flags & F_VERBOSE) { + printf("*001* %03d %03d %04x(%04x) %02x %s %02x", + rle[p], lzlen[p], lzpos[p], p-lzpos[p], indata[p], + (mode[p] & MMARK)?"#":" ", newesc[p]); + } + if ((indata[p] & escMask) == escape) { + escape = newesc[p]; + if (flags & F_VERBOSE) printf(""); + } + if (flags & F_VERBOSE) printf("\n"); + j += 1; + } else { + if (flags & F_VERBOSE) printf("*001* %03d %03d %04x(%04x) %02x %s %02x\n", + rle[p], lzlen[p], lzpos[p], p-lzpos[p], indata[p], + (mode[p] & MMARK)?"#":" ", newesc[p]); + } + break; + case MMARK | LZ77: + case LZ77: + if (j==p) { + if (flags & F_VERBOSE) printf(">"); + j += lzlen[p]; + } else + if (flags & F_VERBOSE) printf(" "); + if (lzpos2) { + if (flags & F_VERBOSE) printf(" %04x %03d +%02x", lzpos2[p], lzlen2[p], + (indata[p] - indata[p-lzpos2[p]]) & 0xff); + } + if (flags & F_VERBOSE) printf(" 001 %03d *%03d* %04x(%04x) %02x %s\n", + rle[p], lzlen[p], lzpos[p], p-lzpos[p], indata[p], + (mode[p] & MMARK)?"#":" "); + break; + case MMARK | RLE: + case RLE: + if (j==p) { + if (flags & F_VERBOSE) printf(">"); + j += rle[p]; + } else + if (flags & F_VERBOSE) printf(" "); + if (lzpos2) { + if (flags & F_VERBOSE) printf(" %04x %03d +%02x", lzpos2[p], lzlen2[p], + (indata[p] - indata[p-lzpos2[p]]) & 0xff); + } + if (flags & F_VERBOSE) printf(" 001 *%03d* %03d %04x(%04x) %02x %s\n", + rle[p], lzlen[p], lzpos[p], p-lzpos[p], indata[p], + (mode[p] & MMARK)?"#":" "); + break; + default: + j++; + break; + } + mode[p] &= ~MMARK; + } + escape = oldEscape; + } +#endif + +#ifndef NO_XVERBOSE + if (flags & F_VERBOSE) { + for (p=0; p "); + j += lzlen2[p]; + } else + printf(" "); + if (lzpos2) { + if (flags & F_VERBOSE) printf(" %04x*%03d*+%02x", lzpos2[p], lzlen2[p],(indata[p] - indata[p-lzpos2[p]]) & 0xff); + } + if (flags & F_VERBOSE) printf(" 001 %03d %03d %04x(%04x) %02x %s\n", + rle[p],lzlen[p],lzpos[p],p-lzpos[p],indata[p], + (mode[p] & MMARK)?"#":" "); + break; + case MMARK | LITERAL: + case LITERAL: + if (flags & F_VERBOSE) { + if (j==p) printf(">"); + else printf(" "); + + if (lzpos2) { + printf(" %04x %03d +%02x", lzpos2[p], lzlen2[p], + (indata[p] - indata[p-lzpos2[p]]) & 0xff); + } + } + if (j==p) { + if (flags & F_VERBOSE) { + printf("*001* %03d %03d %04x(%04x) %02x %s %02x", + rle[p], lzlen[p], lzpos[p], p-lzpos[p], indata[p], + (mode[p] & MMARK)?"#":" ", newesc[p]); + } + if ((indata[p] & escMask) == vescape) { + vescape = newesc[p]; + if (flags & F_VERBOSE) printf(""); + } + if (flags & F_VERBOSE) printf("\n"); + j += 1; + } else { + if (flags & F_VERBOSE) printf("*001* %03d %03d %04x(%04x) %02x %s %02x\n", + rle[p], lzlen[p], lzpos[p], p-lzpos[p], indata[p], + (mode[p] & MMARK)?"#":" ", newesc[p]); + } + break; + case MMARK | LZ77: + case LZ77: + if (j==p) { + if (flags & F_VERBOSE) printf(">"); + j += lzlen[p]; + } else + if (flags & F_VERBOSE) printf(" "); + if (lzpos2) { + if (flags & F_VERBOSE) printf(" %04x %03d +%02x", lzpos2[p], lzlen2[p], + (indata[p] - indata[p-lzpos2[p]]) & 0xff); + } + if (flags & F_VERBOSE) printf(" 001 %03d *%03d* %04x(%04x) %02x %s\n", + rle[p], lzlen[p], lzpos[p], p-lzpos[p], indata[p], + (mode[p] & MMARK)?"#":" "); + break; + case MMARK | RLE: + case RLE: + if (j==p) { + if (flags & F_VERBOSE) printf(">"); + j += rle[p]; + } else + if (flags & F_VERBOSE) printf(" "); + if (lzpos2) { + if (flags & F_VERBOSE) printf(" %04x %03d +%02x", lzpos2[p], lzlen2[p], + (indata[p] - indata[p-lzpos2[p]]) & 0xff); + } + if (flags & F_VERBOSE) printf(" 001 *%03d* %03d %04x(%04x) %02x %s\n", + rle[p], lzlen[p], lzpos[p], p-lzpos[p], indata[p], + (mode[p] & MMARK)?"#":" "); + break; + default: + j++; + break; + } + mode[p] &= ~MMARK; + } +#endif + switch (mode[p]) { + case LITERAL: /* normal */ + length[p] = outPointer; + + OutputNormal(&escape, indata+p, newesc[p]); + p++; + break; + + case DLZ: + for (i=0; i >(8-escBits)), escBits); + PutValue(lzlen2[p]-1); + PutValue((2< 2 && lzlen[p] > rle[p]) { + int bot = p - lzpos[p] + 1, i; + unsigned short rlep = rle[p]; + + if (!rlep) + rlep = 1; + if (bot < 0) + bot = 0; + bot += (rlep-1); + + i = p - (int)backSkip[p]; + while (i>=bot /* && i>=rlep-1 */) { + /* Equal number of A's ? */ + if (rlep==1 || rle[i-rlep+1]==rlep) { /* 'head' matches */ + unsigned char *a = indata + i+1; /* match */ + unsigned char *b = indata + p+rlep-1+1; /* curpos */ + int topindex = inlen-(p+rlep-1); + + j = 1; + while (j < topindex && *a++==*b++) + j++; + + if (j + rlep-1 >= lzlen[p]) { + int tmppos = p-i+rlep-1; +#ifdef EVEN_LZ + if (!(tmppos&1)) { +#endif + + rescan += + LenLz(lzlen[p], lzpos[p]) - + LenLz(lzlen[p], tmppos); +#ifdef EVEN_LZ + if (tmppos&1) + fprintf(stderr,"Error: misalign in tmppos\n"); +#endif + lzpos[p] = tmppos; + break; +#ifdef EVEN_LZ + } +#endif + } + } + if (!backSkip[i]) + break; /* No previous occurrances (near enough) */ + i -= (int)backSkip[i]; + } + } + + for (i=0; i = 'a' && c <= 'f') return c - 'a' + 10; + if (c >= '0' && c <= '9') return c - '0'; + return NO_HEX_CHARACTER; +} + + +//============================================================================= +// converts hex text into binary +//============================================================================= +int ConvertText2Bin(unsigned char* ib,int origlen) { + int pos; + int cnt = 0; + int searchforendofline = 0; + int len_after_convert = 0; + unsigned char val = 0; + unsigned char actual; + + len_after_convert = 0; + for (pos = 0; pos < origlen;pos++) { + if (searchforendofline) { + if (ib[pos] == '\n') searchforendofline = 0; + continue; + } + if (ib[pos] == '/') { + cnt = 0; + if (pos < origlen-1 && ib[pos+1] == '/') searchforendofline = 1; + continue; + } + + actual = hex2int(ib[pos]); + if (actual == NO_HEX_CHARACTER) { + cnt = 0; + continue; + } + if (cnt == 0) { + val = actual*16; + cnt++; + } + else { + val += actual; + cnt=0; + ib[len_after_convert++] = val; + } + } + return(len_after_convert); +} + +void *GTPackDo(void *buf,unsigned short *buflen) { + int startEscape; + char *ptr; + +// unsigned long timeused = clock(); + + lrange = LRANGE; + maxlzlen = MAXLZLEN; + maxrlelen = MAXRLELEN; + + InitValueLen(); + + indata = buf; + inlen = *buflen; + PackLz77(lrange, F_AUTO|F_AUTOEX, &startEscape, 1234, 12345, 0); + free(indata); + { + int i; + PackedHeader cth; + RLEEntries re; + + cth.origsize_lo = inlen & 0xff; + cth.origsize_hi = (inlen >> 8); + memcpy(cth.magic,"GTPk",4); + cth.compsize_lo = (outlen + rleUsed + sizeof(PackedHeader)) & 0xff; + cth.compsize_hi = (outlen + rleUsed + sizeof(PackedHeader)) >> 8; + cth.esc1 = (startEscape >> (8-escBits)); + cth.esc2 = escBits; + cth.extralz = extraLZPosBits; + cth.rleentries = rleUsed; + + for(i=0; i > (8-escBits) +// unsigned char notused3; +// unsigned char notused4; + unsigned char esc2; // escBits + unsigned char gamma1; // maxGamma + 1 + unsigned char gamma2; // (1< > (8-escBits) + unsigned char extralz; // extraLZPosBits + unsigned char rleentries; // rleUsed +} PackedHeader; +#endif + + +#define GetUnPackedSize(p) (unsigned int)((p)->origsize_lo | ((p)->origsize_hi << 8)) +#define IsPacked(p) ((p)->magic1 == MAGIC_CHAR1 && (p)->magic2 == MAGIC_CHAR2) + + +typedef struct { + unsigned char value[MAX_RLE_ENTRIES]; +} RLEEntries; + + +#endif + + +//############################################################################# +//###################### NO MORE FAKES BEYOND THIS LINE ####################### +//############################################################################# +// +//============================================================================= +// Revision History +//============================================================================= +// +// $Log: packhead.h,v $ +// Revision 1.4 2005/08/04 21:27:43 Paul Froissart +// adapted for XPak +// +// Revision 1.3 2000/08/20 15:24:28 Thomas Nussbaumer +// macros to get unpacked size and to check if packed added +// +// Revision 1.2 2000/08/16 23:08:55 Thomas Nussbaumer +// magic characters changed to TP ... t(igcc tools) p(acked file) +// +// Revision 1.1 2000/08/14 22:49:57 Thomas Nussbaumer +// initial version +// +// diff --git a/gtc/src/gtpack/revtools.h b/gtc/src/gtpack/revtools.h new file mode 100644 index 0000000..e0b5dea --- /dev/null +++ b/gtc/src/gtpack/revtools.h @@ -0,0 +1,108 @@ +/****************************************************************************** +* +* project name: TIGCC Tools Suite +* file name: revtools.h +* initial date: 23/08/2000 +* author: thomas.nussbaumer@gmx.net +* description: macros for automatic handling of version number output +* which is in sync with the CVS version number +* +* examine one of the pctools source codes to see how it works ;-) +* +* [NO CVS ID HERE BY INTENTION] +* +******************************************************************************/ + +//----------------------------------------------------------------------------- +// [Usage] +// +// (1) include this file into your tool +// +// +// (2) AFTER (!!) all includes put the following lines into your source code: +// +// #ifdef CVS_FILE_REVISION +// #undef CVS_FILE_REVISION +// #endif +// ---------------------------------------------------------------------------- +// DON'T EDIT THE NEXT REVISION BY HAND! THIS IS DONE AUTOMATICALLY BY THE +// CVS SYSTEM !!! +// ---------------------------------------------------------------------------- +// #define CVS_FILE_REVISION "$Revision$" +// +// It must be placed AFTER (!!) all includes otherwise the macros may be +// expanded wrong where you use them. For example: if you have added the above +// lines at the top of your file and include afterwards a file which does +// the same, the version of the included file will be used further due to the +// #undef CVS_FILE_REVISION. Everything clear? +// +// +// (3) to output the cvs revision number you can now to a simple: +// +// printf(CVSREV_PRINTPARAMS) +// +// if your file has, for example, the revision 1.3 the following string will +// be printed: v1.03 +// +// the prefix before the subversion is used to get equal-sized output strings +// for mainversions between 1 ... 9 and subversion between 1 .. 99 +// +// if your program leaves that range and you need to have equal-sized output +// strings you have to implement it by your own by using the +// CVSREV_MAIN and CVSREV_SUB macros which returns the main and sub versions +// as plain integers. if there is something wrong with your revision string +// CVSREV_MAIN and/or CVSREV_SUB will deliver 0, which is no valid CVS main +// or subversion number. +// +// i will suggest that you use the CVS system. its simple to handle, keeps +// track of your revisions and their history and with the smart macros below +// you haven't to worry anymore about the version output strings of your +// program. if you want a special version number you can force CVS at every +// time to give this version number to your program (0 is not allowed as +// main and subversion number - thats the only pity) +// +// within this tools suite every tool will use the automatic version handling +// but the tool suite version number itself will be handled "by hand". +// this number shouldn't change that quickly as with the tools. +// +//----------------------------------------------------------------------------- +#ifndef __REV_TOOLS_H__ +#define __REV_TOOLS_H__ +#include +#include +#include + +//----------------------------------------------------------------------------- +// just used internally +//----------------------------------------------------------------------------- +#define CVS_TRUNC_PREFIX ((strlen((CVS_FILE_REVISION))<=11) ? 0 : (CVS_FILE_REVISION+11)) +#define CVS_FIND_COMMA (strchr(CVS_TRUNC_PREFIX,'.')) +#define CVSREV_MAIN (int)(!(CVS_TRUNC_PREFIX) ? 0 : atoi(CVS_TRUNC_PREFIX)) +#define CVSREV_SUB (int)(!(CVS_TRUNC_PREFIX) ? 0 : (!(CVS_FIND_COMMA) ? 0 : atoi(CVS_FIND_COMMA+1))) + +//----------------------------------------------------------------------------- +// NOTE: THE FOLLOWING MACRO WILL ONLY HANDLE MAIN VERSION < 10 AT CONSTANT +// LENGTH !!! +// (subversions from 1 .. 99 are mapped to 01 .. 99) +// +// the following macro may be used to setup a printf(),sprintf() or fprintf() +// call +//----------------------------------------------------------------------------- +#define CVSREV_PRINTPARAMS "v%d.%02d",CVSREV_MAIN,CVSREV_SUB + + +#define PRINT_ID(name) fprintf(stderr,"\n");fprintf(stderr, name" ");\ + fprintf(stderr,CVSREV_PRINTPARAMS);\ + fprintf(stderr," - TIGCC Tools Suite v"TTV_MAIN TTV_SUB"\n" \ + "(c) thomas.nussbaumer@gmx.net " TTV_DATE"\n\n"); + + + + + + +#endif + +//############################################################################# +//###################### NO MORE FAKES BEYOND THIS LINE ####################### +//############################################################################# diff --git a/gtc/src/gtpack/tt.h b/gtc/src/gtpack/tt.h new file mode 100644 index 0000000..c29a180 --- /dev/null +++ b/gtc/src/gtpack/tt.h @@ -0,0 +1,48 @@ +/****************************************************************************** +* +* project name: TIGCC Tools Suite +* file name: tt.h +* initial date: 13/08/2000 +* author: thomas.nussbaumer@gmx.net +* description: generic definitions for TIGCC Tools Suite +* +* $Id: tt.h,v 1.3 2000/08/23 20:29:43 Thomas Nussbaumer Exp $ +* +******************************************************************************/ + +#ifndef __TT_H__ +#define __TT_H__ + +#define CALC_TI89 0 +#define CALC_TI92P 1 + +#define SIGNATURE_TI89 "**TI89**" +#define SIGNATURE_TI92P "**TI92P*" + +#define DEFAULT_FOLDER "main" + +#define DEFAULT_ITEMS_PER_LINE 10 + +#endif + +//############################################################################# +//###################### NO MORE FAKES BEYOND THIS LINE ####################### +//############################################################################# +// +//============================================================================= +// Revision History +//============================================================================= +// +// $Log: tt.h,v $ +// Revision 1.3 2000/08/23 20:29:43 Thomas Nussbaumer +// added a 'P' to the TI92p definitions +// +// Revision 1.2 2000/08/23 01:04:41 Thomas Nussbaumer +// corrected signature of TI92p +// +// Revision 1.1 2000/08/13 20:24:16 Thomas Nussbaumer +// initial version +// +// +// +// diff --git a/gtc/src/gtpack/ttunpack.h b/gtc/src/gtpack/ttunpack.h new file mode 100644 index 0000000..5dcc0bd --- /dev/null +++ b/gtc/src/gtpack/ttunpack.h @@ -0,0 +1,49 @@ +/****************************************************************************** +* +* project name: TIGCC Tools Suite +* file name: ttunpack.h +* initial date: 14/08/2000 +* author: thomas.nussbaumer@gmx.net +* description: defines of errorcodes of decompression routine and its +* declaration +* $Id: ttunpack.h,v 1.2 2000/08/20 15:26:21 Thomas Nussbaumer Exp $ +* +******************************************************************************/ + +#ifndef __TTUNPACK_H__ +#define __TTUNPACK_H__ + +#define K_GAMMA 1 +#define M_GAMMA 0 + +#define ERRPCK_OKAY 0 +#define ERRPCK_NOESCFOUND 248 +#define ERRPCK_ESCBITS 249 +#define ERRPCK_MAXGAMMA 250 +#define ERRPCK_EXTRALZP 251 +#define ERRPCK_NOMAGIC 252 +#define ERRPCK_OUTBUFOVERRUN 253 +#define ERRPCK_LZPOSUNDERRUN 254 + +int _tt_Decompress(unsigned char *src, unsigned char *dest); +#define UnPack _tt_Decompress + +#endif + + +//############################################################################# +//###################### NO MORE FAKES BEYOND THIS LINE ####################### +//############################################################################# +// +//============================================================================= +// Revision History +//============================================================================= +// +// $Log: ttunpack.h,v $ +// Revision 1.2 2000/08/20 15:26:21 Thomas Nussbaumer +// prefix of unpack routine (_tt_) corrected +// +// Revision 1.1 2000/08/14 22:49:57 Thomas Nussbaumer +// initial version +// +// diff --git a/gtc/src/gtpack/ttversion.h b/gtc/src/gtpack/ttversion.h new file mode 100644 index 0000000..404feba --- /dev/null +++ b/gtc/src/gtpack/ttversion.h @@ -0,0 +1,53 @@ +/****************************************************************************** +* +* project name: TIGCC Tools Suite +* file name: ttversion.h +* initial date: 13/08/2000 +* author: thomas.nussbaumer@gmx.net +* description: TIGCC Tools Suite version definitions +* +* $Id: ttversion.h,v 1.7 2000/10/01 14:59:22 Thomas Nussbaumer Exp $ +* +******************************************************************************/ + +#ifndef __TTVERSION_H__ +#define __TTVERSION_H__ + +#define TTV_MAIN "0.95" +#define TTV_SUB "" +#define TTV_DATE "01/10/2000" + +#endif + +//############################################################################# +//###################### NO MORE FAKES BEYOND THIS LINE ####################### +//############################################################################# +// +//============================================================================= +// Revision History +//============================================================================= +// +// $Log: ttversion.h,v $ +// Revision 1.7 2000/10/01 14:59:22 Thomas Nussbaumer +// generic commit +// +// Revision 1.6 2000/08/27 23:52:39 Thomas Nussbaumer +// forcing version to 0.41 +// +// Revision 1.5 2000/08/23 20:31:37 Thomas Nussbaumer +// next version step +// +// Revision 1.4 2000/08/23 01:05:59 Thomas Nussbaumer +// next version step +// +// Revision 1.3 2000/08/16 23:09:15 Thomas Nussbaumer +// version actualized to 0.15 +// +// Revision 1.2 2000/08/13 20:26:12 Thomas Nussbaumer +// version now 0.10 (preview release) +// +// Revision 1.1 2000/08/13 16:02:13 Thomas Nussbaumer +// initial version +// +// +// diff --git a/gtc/src/identity.h b/gtc/src/identity.h new file mode 100644 index 0000000..acf588a --- /dev/null +++ b/gtc/src/identity.h @@ -0,0 +1,22 @@ +/* + * GTools C compiler + * ================= + * source file : + * (on-calc) volatilizing a value + * + * Copyright 2001-2004 Paul Froissart. + * Credits to Christoph van Wuellen and Matthew Brandt. + * All commercial rights reserved. + * + * This compiler may be redistributed as long there is no + * commercial interest. The compiler must not be redistributed + * without its full sources. This notice must stay intact. + */ + +#ifndef __IDENTITY +#define __IDENTITY +void *identity(void *x) { + return x; +} +#endif +// vim:ts=4:sw=4 diff --git a/gtc/src/init.c b/gtc/src/init.c new file mode 100644 index 0000000..bc8d03d --- /dev/null +++ b/gtc/src/init.c @@ -0,0 +1,434 @@ +/* + * GTools C compiler + * ================= + * source file : + * initialisations + * + * Copyright 2001-2004 Paul Froissart. + * Credits to Christoph van Wuellen and Matthew Brandt. + * All commercial rights reserved. + * + * This compiler may be redistributed as long there is no + * commercial interest. The compiler must not be redistributed + * without its full sources. This notice must stay intact. + */ + +#include "define.h" +_FILE(__FILE__) +#include "c.h" +#include "expr.h" +#include "gen.h" +#define USE_MEMMGT +#include "cglbdec.h" + +long inittype(TYP *,TYP **); +static long initstruct(TYP *,TYP **), initarray(TYP *,TYP **), initunion(TYP *,TYP **); +static int initchar(), initshort(), initlong(), initpointer(); +#ifndef NOFLOAT +static int initfloat(); +#ifdef DOUBLE +static int initdouble(); +#endif +#endif +static struct enode *constexpr(); +extern TYP *copy_type(TYP *s); + +TYP *copy_type_global(TYP *tp) { + TYP *tp2; + temp_local++; + global_flag++; + tp2=copy_type(tp); + global_flag--; + temp_local--; + return tp2; +} + +void doinit(struct sym *sp, int align) { + nl(); + if (lastst != assign) + genstorage(sp, align); + else { + struct slit *strtab_old=strtab; + int glob = global_flag; + int no_locblk = !locblk; +/* if (lineid>=0x100) + bkpt();*/ + strtab = 0; + global_flag = 0; + tmp_use(); + temp_local++; + global_strings++; + dseg(); /* select data segment */ + put_align(align); +#ifndef AS + if (sp->storage_class == sc_static) + put_label((unsigned int) sp->value.i); + else + g_strlab(sp->name); +#else +#ifdef PC +#define gnu_hook(x,y) ((x)?(x):(y)) +#else +#define gnu_hook(x,y) ((x)?:(y)) +#endif + if (sp->storage_class == sc_static) { + extern int glblabel; + put_label(gnu_hook(sp->value.splab,sp->value.splab=nxtglabel())); + } else + put_label(splbl(sp)); +#endif + getsym(); + (void) inittype(sp->tp,&sp->tp); +/* if (strtab) + bkpt();*/ + if (strtab) + dumplits(); + global_strings--; + temp_local--; + tmp_free(); /* just in case, but shouldn't get used because of temp_local */ + if (no_locblk && locblk) + rel_local(); + global_flag = glob; + strtab = strtab_old; + } +} + +long inittype(TYP *tp,TYP **tpp) { + int brace_seen = 0; + long nbytes; + if (lastst == begin) { + brace_seen = 1; + getsym(); + } + switch (tp->type) { + case bt_char: + case bt_uchar: + nbytes = initchar(); + break; + case bt_short: + case bt_ushort: + nbytes = initshort(); + break; + case bt_pointer: + if (tp->val_flag) + nbytes = initarray(tp,tpp); + else { + nbytes = initpointer(); + } + break; + case bt_ulong: + case bt_long: + nbytes = initlong(); + break; +#ifndef NOFLOAT + case bt_float: + nbytes = initfloat(); + break; +#ifdef DOUBLE + case bt_double: + nbytes = initdouble(); + break; +#endif +#endif + case bt_struct: + nbytes = initstruct(tp,tpp); + break; + case bt_union: + nbytes = initunion(tp,tpp); + break; + default: + error(ERR_NOINIT); + nbytes = 0; + } + if (brace_seen) + needpunc(end); + return nbytes; +} + +/*void modf_btp(TYP *new_btp,TYP *tp) { + tp=copy_type(tp); + tp->btp=new_btp; + modf(tp,modfp); +}*/ + +extern unsigned int pos; +static long initarray(TYP *tp,TYP **tpp) { + long nbytes; + char *p; + int len; +#ifdef AS + unsigned int max_pos=pos; +#endif +// tmp_use(); + nbytes = 0; + if (lastst == sconst && (tp->btp->type == bt_char || + tp->btp->type == bt_uchar)) { + len = lstrlen; + nbytes = len; + p = laststr; + while (len--) + genbyte(*p++); + if (!tp->size) /* if tp->size!=0, then the padding stuff takes care of it */ + genbyte(0), nbytes++; + while (nbytes < tp->size) + genbyte(0), nbytes++; + getsym(); /* skip sconst */ + } else if (lastst == kw_incbin) { + FILE *fp; int size; +#ifndef PC + unsigned char type; +#endif +/* getsym(); + if (lastst!=sconst) + error(ERR_SYNTAX);*/ + skipspace(); + if (lastch!='"') + error(ERR_SYNTAX); + getch(); + getidstr(); + if (lastch!='"') + error(ERR_SYNTAX); + getch(); + getsym(); + fp=fopen(lastid,"rb"); + if (!fp) + uerr(ERR_CANTOPEN,lastid); +#ifdef PC + p=malloc(100000); + size=fread(p,1,100000,fp); +#else + p=*(char **)fp; + size=*(unsigned short *)p; + type=p[size+1]; + if (type==0xF3 || type==0xE0) size--; + else if (type==0xF8) { size--; do size--; while (p[size+1]); } +#endif + if (tp->size && size>tp->size) size=tp->size; + nbytes=size; + while (size--) genbyte(*p++); + while (nbytes size) { + genbyte(0); + nbytes++; + } + } else if (lastst == end) + goto pad; + else { + int i,additional,size; + for (i=0;;) { + additional=0; + if (lastst == openbr) { + getsym(); { + int j=intexpr(); + long diff=tp->btp->size*(j-i); + if (lastst == dots) { + getsym(); + additional=intexpr()-j; + } + if (lastst != closebr) error(ERR_SYNTAX); + else { + getsym(); + if (lastst == assign) getsym(); + if (i =0) { + nbytes += (size=inittype(tp->btp,NULL)); i++; +#ifdef AS + while (additional--) rewrite(size), nbytes+=size, i++; +#endif + } + #ifdef AS + if (pos>max_pos) max_pos=pos; + #endif + if (lastst == comma) + getsym(); + if (lastst == end || lastst == semicolon) { + pad: + #ifdef AS + if (pos size) { + genbyte(0); + nbytes++; + } + break; + } + if (tp->size > 0 && nbytes >= tp->size) + break; + } + } +#if 0 + if (tp->size == 0) + tp->size = nbytes; + if (nbytes > tp->size) + error(ERR_INITSIZE); +#else + if (tp->size && nbytes > tp->size) + error(ERR_INITSIZE); + if (tp->size != nbytes && tpp) + /* fix the symbol's size, unless tpp=0 (item of a struct/union or array) */ + tp = copy_type_global(tp), + *tpp = tp, + tp->size = nbytes; // we need this for the 'sizeof' operator... +#endif +// tmp_free(); + return nbytes; +} + +static long initunion(TYP *tp,TYP **tpp) { + struct sym *sp; + long nbytes; + + int brace_seen = 0; + if (lastst == begin) { + brace_seen = 1; + getsym(); + } + + sp = tp->lst.head; +/* + * Initialize the first branch + */ + if (sp == 0) + return 0; + nbytes = inittype(sp->tp,NULL); + while (nbytes < tp->size) { + genbyte(0); + nbytes++; + } + + if (tp->size != nbytes && tpp) + tp = copy_type_global(tp), + *tpp = tp, + tp->size = nbytes; // we need this for the 'sizeof' operator... + + if (brace_seen) + needpunc(end); +} + +static long initstruct(TYP *tp,TYP **tpp) { + struct sym *sp; + long nbytes; + nbytes = 0; + sp = tp->lst.head; /* start at top of symbol table */ + if (lastst != end) + while (sp != 0) { + while (nbytes < sp->value.i) { /* align properly */ + nbytes++; + genbyte(0); + } + nbytes += inittype(sp->tp,NULL); + if (lastst == comma) + getsym(); + if (lastst == end || lastst == semicolon) + break; + sp = sp->next; + } + while (nbytes < tp->size) { + genbyte(0); + nbytes++; + } + if (tp->size != nbytes && tpp) + tp = copy_type_global(tp), + *tpp = tp, + tp->size = nbytes; // we need this for the 'sizeof' operator... + + return tp->size; +} + +static int initchar() { + genbyte((int) intexpr()); + return 1; +} + +static int initshort() { + genword((int) intexpr()); + return 2; +} + +static int initlong() { +/* + * We allow longs to be initialized with pointers now. + * Thus, we call constexpr() instead of intexpr. + */ +#if 0 +/* + * This is more strict + */ + genlong(intexpr()); + return 4; +#endif + genptr(constexpr()); + return 4; +} + +#ifndef NOFLOAT +static int initfloat() { +#ifndef NOFLOAT + double floatexpr(); +#ifdef PC + genfloat(floatexpr()); +#else +#ifndef BCDFLT + genptr(floatexpr()); +#else + genfloat(floatexpr()); +#endif +#endif +#endif +#ifdef NOFLOAT + genptr(0l); +#endif + return 4; +} + +#ifdef DOUBLE +static int initdouble() { +#ifdef NOFLOAT + int i; + for (i=0; i< tp_double.size; i++) + genbyte(0); +#endif +#ifndef NOFLOAT + double floatexpr(); + gendouble(floatexpr()); +#endif + return tp_double.size; +} +#endif +#endif + +static int initpointer() { + genptr(constexpr()); + return 4; +} + +static struct enode *constexpr() { + struct enode *ep; + struct typ *tp; +/* if (lineid==0x1e0) + bkpt();*/ + tp=exprnc(&ep); + if (tp == 0) { + error(ERR_EXPREXPECT); + return 0; + } + opt0(&ep); + if (!tst_const(ep)) { + error(ERR_CONSTEXPECT); + return 0; + } + return ep; +} +// vim:ts=4:sw=4 diff --git a/gtc/src/intexpr.c b/gtc/src/intexpr.c new file mode 100644 index 0000000..a29da9a --- /dev/null +++ b/gtc/src/intexpr.c @@ -0,0 +1,96 @@ +/* + * GTools C compiler + * ================= + * source file : + * integer expression routines + * + * Copyright 2001-2004 Paul Froissart. + * Credits to Christoph van Wuellen and Matthew Brandt. + * All commercial rights reserved. + * + * This compiler may be redistributed as long there is no + * commercial interest. The compiler must not be redistributed + * without its full sources. This notice must stay intact. + */ + +#include "define.h" +_FILE(__FILE__) +#include "c.h" +#include "expr.h" +#include "gen.h" +#include "cglbdec.h" +#ifndef NOFLOAT +#include "ffplib.h" +#endif + +#ifndef NOFLOAT +double floatexpr() { +/* floating point expression */ + struct enode *ep; + struct typ *tp; + + tp = exprnc(&ep); + if (tp == 0) { + error(ERR_FPCON); + return (double) 0; + } + + opt0(&ep); + + if (ep->nodetype == en_icon) +#ifdef PC + return (double) ep->v.i; +#else + return ffpltof(ep->v.i); +#endif + + if (ep->nodetype == en_fcon) + return ep->v.f; + + error (ERR_SYNTAX); + return (double) 0; +} +#endif /* !NOFLOAT */ + +long intexpr() { + struct enode *ep; + struct typ *tp; + long val; + + tmp_use(); + tp = exprnc(&ep); + if (tp == 0) { + error(ERR_INTEXPR); + return 0; + } + opt0(&ep); + + if (ep->nodetype != en_icon) { + error(ERR_SYNTAX); + return 0; + } + val=ep->v.i; + tmp_free(); + return val; +} + +#if 0 +long intexpr_notemp() { + struct enode *ep; + struct typ *tp; + + tp = exprnc(&ep); + if (tp == 0) { + error(ERR_INTEXPR); + return 0; + } + opt0(&ep); + + if (ep->nodetype != en_icon) { + error(ERR_SYNTAX); + return 0; + } + return ep->v.i; +} +#endif +// vim:ts=4:sw=4 diff --git a/gtc/src/memmgt.c b/gtc/src/memmgt.c new file mode 100644 index 0000000..856e335 --- /dev/null +++ b/gtc/src/memmgt.c @@ -0,0 +1,532 @@ +/* + * GTools C compiler + * ================= + * source file : + * memory management + * + * Copyright 2001-2004 Paul Froissart. + * Credits to Christoph van Wuellen and Matthew Brandt. + * All commercial rights reserved. + * + * This compiler may be redistributed as long there is no + * commercial interest. The compiler must not be redistributed + * without its full sources. This notice must stay intact. + */ + +#include "define.h" +_FILE(__FILE__) +#include "c.h" +#include "expr.h" +#include "gen.h" +#define USE_MEMMGT +#include "cglbdec.h" + +int glbsize CGLOB, /* size left in current global block */ + locsize CGLOB, /* size left in current local block */ + tmpsize CGLOB, /* size left in current temp block */ + glbindx CGLOB, /* global index */ + locindx CGLOB, /* local index */ + tmpindx CGLOB; /* temp index */ + +int temp_mem CGLOB,temp_local CGLOB; +#ifdef MIN_TEMP_MEM +int min_temp_mem CGLOB; +#endif + +#ifdef PC +int glbmem CGLOB,locmem CGLOB; +#endif + +int max_mem CGLOB, /* statistics... */ + glo_mem CGLOB; + +struct blk *locblk CGLOB, /* pointer to local block list */ + *glbblk CGLOB, /* pointer to global block list */ + *tmpblk CGLOB; /* pointer to temporary block list */ + +#ifdef PC +//void *calloc(); +#endif +static void _err_attr error_memory() { + uerrc2("not enough memory to compile function '%s'",func_sp->name); +} +int *_xalloc(int siz) { + struct blk *bp; + char *rv; + if (temp_local) /* this is NOT perfect, but it's close to being so :) */ + goto glb_xalloc; +/* if (locmem>=50000) + bkpt();*/ +/* if (siz>=1000) + bkpt();*/ +#ifdef MIN_TEMP_MEM + if (temp_mem<=min_temp_mem) { +#else + if (!temp_mem) { +#endif + glb_xalloc: + if (global_flag) { + #ifdef PC + glbmem += siz; + #endif + if (glbsize >= siz) { + rv = &(glbblk->m[glbindx]); + glbsize -= siz; + glbindx += siz; +/* if ((long)rv==0x789388) + bkpt();*/ + return (int *) rv; + } else { + // bp = (struct blk *) calloc(1, (int) sizeof(struct blk)); + bp = (struct blk *) malloc(sizeof(struct blk)); + if (!bp) { +#ifdef PC + msg("not enough memory.\n"); + _exit(1); +#else + error_memory(); + fatal("Not enough global memory"); +#endif + } + memset(bp, 0, sizeof(struct blk)); + glo_mem++; + bp->next = glbblk; + glbblk = bp; + glbsize = BLKLEN - siz; + glbindx = siz; + return (int *) glbblk->m; + } + } else { /* not global */ + #ifdef PC + locmem += siz; + #endif + if (locsize >= siz) { + rv = &(locblk->m[locindx]); + locsize -= siz; + /*if ((long)rv==0x7f86bc) + bkpt();*/ + locindx += siz; + #ifdef PC + if (0x80000000&(long)rv) + fatal("A DIRTY HACK FAILED ON YOUR CONFIG. " + "LOOK AT OUT68K_AS.C TO SOLVE THE PROBLEM"); + #endif +/* if (func_sp) infunc("chk_curword") + if ((long)rv==0x7b4bf8) + bkpt();*/ +/* if ((long)rv==0x7e5cd0) + bkpt();*/ + return (int *) rv; + } else { + // bp = (struct blk *) calloc(1, (int) sizeof(struct blk)); + bp = (struct blk *) malloc(sizeof(struct blk)); + if (!bp) { +#ifdef PC + msg("not enough local memory.\n"); + _exit(1); +#else + error_memory(); + fatal("Not enough local memory"); +#endif + } + memset(bp, 0, sizeof(struct blk)); + bp->next = locblk; + locblk = bp; + locsize = BLKLEN - siz; + locindx = siz; + return (int *) locblk->m; + } + } + } else { + if (tmpsize >= siz) { + rv = &(tmpblk->m[tmpindx]); + tmpsize -= siz; + tmpindx += siz; + return (int *) rv; + } else { +// bp = (struct blk *) calloc(1, (int) sizeof(struct blk)); + bp = (struct blk *) malloc(sizeof(struct blk)); + if (!bp) { +#ifdef PC + msg("not enough temporary memory.\n"); + _exit(1); +#else + error_memory(); + fatal("Not enough temporary memory"); +#endif + } +/* if (bp==0x789364) + bkpt();*/ + memset(bp, 0, sizeof(struct blk)); + bp->next = tmpblk; + tmpblk = bp; + tmpsize = BLKLEN - siz; + tmpindx = siz; + return (int *) tmpblk->m; + } + } +} + +int blk_free(struct blk *bp1) { + int blkcnt = 0; + struct blk *bp2; + while (bp1) { + bp2 = bp1->next; + (void) free((char *) bp1); + blkcnt++; + bp1 = bp2; + } + return blkcnt; +} + +#ifdef DUAL_STACK +typedef struct _ds_block { + void *lo,*hi; + struct _ds_block *pop; + void *popstackptr; +} DS_BLOCK; +static DS_BLOCK *ds_current CGLOB; +void *dualstack CGLOB; +void *ds_currentlo CGLOB,*ds_currenthi CGLOB; + +#ifdef PC +int n_ds_allocations CGLOB; +#endif +void ds_allocatleast(unsigned int size) { + size+=DS_BSIZE; + DS_BLOCK *ds_new = malloc(sizeof(DS_BLOCK)+size); + ds_new->lo = (void *)(ds_new+1); + ds_new->hi = (void *)((char *)ds_new->lo+size); + ds_new->pop = ds_current; + ds_new->popstackptr = dualstack; + ds_current = ds_new; + ds_currentlo = ds_current->lo; + ds_currenthi = ds_current->hi; + dualstack = ds_currentlo; +#ifdef PC + n_ds_allocations++; +#endif +} +void ds_free(void) { + DS_BLOCK *ds_old = ds_current; + ds_current = ds_old->pop; + ds_currentlo = ds_current ? ds_current->lo : 0; + ds_currenthi = ds_current ? ds_current->hi : 0; + dualstack = ds_old->popstackptr; + free(ds_old); +} +void rel_dualstack(void) { + while (ds_current) + ds_free(); +#ifdef PC + //msg2(" performed %d dual-stack-related allocations\n",n_ds_allocations); +#endif +} +#endif + +#define VERBOSE +#ifdef GARBAGE_COLLECT +void d_enode(struct enode **node) { + struct enode *dest,*ep=*node; + if (!ep) return; + if (ep->nodetype==en_icon) { *node=mk_icon(ep->v.i); return; } + dest=xalloc((int)sizeof(struct enode), ENODE); + memcpy(dest,ep,sizeof(struct enode)); + *node=dest; + switch (ep->nodetype) { + case en_land: case en_lor: + case en_asand: case en_asor: case en_asxor: + case en_aslsh: case en_asrsh: + case en_asmul: case en_asmod: case en_asdiv: + case en_asadd: case en_assub: + case en_gt: case en_ge: + case en_lt: case en_le: + case en_eq: case en_ne: + case en_cond: case en_assign: + case en_and: case en_or: case en_xor: + case en_lsh: case en_rsh: + case en_mul: case en_mod: case en_div: + case en_add: case en_sub: + case en_fcall: case en_void: + d_enode(&ep->v.p[1]); + case en_deref: + case en_ainc: case en_adec: + case en_uminus: case en_not: case en_compl: + case en_ref: + case en_cast: /* hum hum */ + case en_fieldref: + d_enode(&ep->v.p[0]); + case en_tempref: + case en_autocon: + case en_labcon: + case en_nacon: + case en_fcon: + return; + case en_compound: + d_snode(&ep->v.st); + return; + default: + ierr(D_ENODE,1); + } +} + +void d_snode(struct snode **node) { + struct snode *dest,*block=*node; + if (!block) return; + dest=xalloc((int)sizeof(struct snode), SNODE); + memcpy(dest,block,sizeof(struct snode)); + *node=dest; + while (block != 0) { + switch (block->stype) { + case st_return: + case st_expr: + d_enode(&block->exp); + break; + case st_loop: + d_enode(&block->exp); + d_snode(&block->s1); + d_enode(&block->v2.e); + break; + case st_while: + case st_do: + d_enode(&block->exp); + d_snode(&block->s1); + break; + case st_for: + d_enode(&block->exp); + d_enode(&block->v1.e); + d_snode(&block->s1); + d_enode(&block->v2.e); + break; + case st_if: + d_enode(&block->exp); + d_snode(&block->s1); + d_snode(&block->v1.s); + break; + case st_switch: + d_enode(&block->exp); + d_snode(&block->v1.s); + break; + case st_case: + case st_default: + d_snode(&block->v1.s); + break; + case st_compound: + case st_label: + d_snode(&block->s1); + case st_goto: + case st_break: + case st_continue: + break; + case st_asm: + d_amode(&(struct amode *)block->v1.i); + break; + default: + ierr(D_SNODE,1); + } + block = block->next; + } +} + +void d_amode(struct amode **node) { + struct amode *dest,*mode=*node; + if (!mode) return; + dest=xalloc((int)sizeof(struct amode), AMODE); + memcpy(dest,mode,sizeof(struct amode)); + *node=dest; + d_enode(&dest->offset); +} +extern struct ocode *_peep_head; +void d_ocodes(void) { + struct ocode *dest=NULL,**node=&_peep_head,*instr; + while ((instr=*node)) { + instr->back=dest; + dest=xalloc((int)sizeof(struct ocode), OCODE); + memcpy(dest,instr,sizeof(struct ocode)); + *node=dest; + d_amode(&dest->oper1); + d_amode(&dest->oper2); + node=&dest->fwd; + } + *node=NULL; +} + +extern struct snode *dump_stmt; +void collect(int g) { + struct blk *blk=glbblk; + glbsize=glbindx=0; + glbblk=NIL_BLK; + alloc_dump(g); + // dump snodes & most enodes +// d_snode(&dump_stmt); + // dump ocodes & amodes & the rest of enodes +// d_ocodes(); + // dump most syms & most strs & typs & tables & the rest of syms & a few strs + d_table(&gsyms); d_table(>ags); d_table(&defsyms); + // dump slits & the rest of strs +// + // no dump is needed for cse's since it is a cooperative garbage-collection +} +#endif + +int _k_=0; +void tmp_use() { + temp_mem++; + _k_++; +} +void tmp_free() { + if (!--temp_mem && tmpblk) { +#ifdef PC + int n=0; +#endif +#ifndef LIFO_TMP_FREE + /* Maybe I'm wrong, but I think that this solution + * is quite bad for the TIOS heap manager... */ + struct blk *nxt; + while ((nxt=tmpblk->next)) + #ifdef PC + n++, + #endif + free(tmpblk),tmpblk=nxt; +#else + struct blk *nxt=tmpblk->next,*tofree; + while (nxt) + #ifdef PC + n++, + #endif + tofree=nxt, nxt=nxt->next, free(tofree); +#endif +#ifdef _DBG_SHOW_TEMPMEM + printf("*"); +#ifdef PC + printf("(%dk)",n*BLKLEN/1024); +// getchar(); +#endif +#endif + tmpsize = BLKLEN; + tmpindx = 0; + memset(tmpblk,0,BLKLEN); + /*blk_free(tmpblk); + tmpblk = 0; + tmpsize = 0;*/ + } +} + +void rel_local() { + unsigned int mem; +#ifndef AS +#define pos 0 +#else + extern unsigned int pos; +#endif +#ifdef PC +#ifdef GARBAGE_COLLECT + collect(0); +#endif +#ifdef LISTING + alloc_dump(0); +#endif +#endif + if ((mem=blk_free(locblk))+glo_mem+(2*pos)/BLKLEN > (unsigned int)max_mem) { + max_mem = mem+glo_mem+(2*pos)/BLKLEN; + /*if (max_mem>330/4) + bkpt();*/ + } +#ifndef AS +#undef pos +#endif +#ifdef PC + locmem = 0; +#endif + locblk = 0; + locsize = 0; +//#ifndef PC +#ifndef GTDEV +#ifdef PC + if (verbose) +#endif + msg2("%d kb\n", (int)(mem * BLKLEN/1024)); +#endif +//#endif +#ifdef VERBOSE +#ifdef LISTING +#if 0 + if (list_option) + msg2(" releasing %2d kb local tables.\n", + mem * BLKLEN/1024); +#endif +#endif +#endif +} + +void rel_global() { + int mem; + if ((mem=blk_free(glbblk)) > max_mem) + max_mem = mem; +#ifdef PC + glbmem = 0; +#endif + glo_mem = 0; + glbblk = 0; + glbsize = 0; + blk_free(tmpblk); + tmpblk = 0; + tmpsize = 0; +#ifdef PC +#ifdef LISTING + alloc_dump(1); +#endif +#endif +#ifdef VERBOSE +#ifdef LISTING + if (list_option) + msg2(" releasing %2d kb global tables.\n", + mem * BLKLEN/1024); +#endif +#ifdef DUAL_STACK + //if (ds_current) + // msg("oops, a dual stack remains\n"); + rel_dualstack(); +#endif +#ifndef GTDEV +#ifdef PC + if (verbose) { + msg2("Max memory request : %d kb\n", + (int)(max_mem * BLKLEN/1024)); + msg("\n"); + if (max_mem * BLKLEN/1024<150) + msg("On-calc portability : very good\n"); + else if (max_mem * BLKLEN/1024<230) + msg("On-calc portability : good\n"); + else if (max_mem * BLKLEN/1024<290) + msg("On-calc portability : questionable\n"); + else if (max_mem * BLKLEN/1024<360) + msg("On-calc portability : difficult without splitting\n"); + else + msg("On-calc portabilty : impossible without splitting\n"); + msg("\n"); + } +#endif +#endif +#endif + max_mem = 0; +} + +void clean_up() { + blk_free(tmpblk); + blk_free(locblk); + blk_free(glbblk); +#ifdef DUAL_STACK + //if (ds_current) + // msg("oops, a dual stack remains\n"); + rel_dualstack(); +#endif + temp_mem = 0; + glbblk = locblk = tmpblk = 0; +/*#ifdef OPTIMIZE_BSS + free(bssdata); +#endif*/ +} + +#undef VERBOSE +// vim:ts=4:sw=4 diff --git a/gtc/src/optimize.c b/gtc/src/optimize.c new file mode 100644 index 0000000..7de0d7a --- /dev/null +++ b/gtc/src/optimize.c @@ -0,0 +1,887 @@ +/* + * GTools C compiler + * ================= + * source file : + * optimization + * + * Copyright 2001-2004 Paul Froissart. + * Credits to Christoph van Wuellen and Matthew Brandt. + * All commercial rights reserved. + * + * This compiler may be redistributed as long there is no + * commercial interest. The compiler must not be redistributed + * without its full sources. This notice must stay intact. + */ + +#include "define.h" +_FILE(__FILE__) +#include "c.h" +#include "expr.h" +#include "gen.h" +#include "cglbdec.h" + +static void fold_const(); + +void dooper(struct enode **node) { +/* + * dooper will execute a constant operation in a node and modify the node to + * be the result of the operation. + */ + struct enode *ep = *node; + enum(e_node) type = ep->nodetype; + +#define ep0 ep->v.p[0] +#define ep1 ep->v.p[1] +#define epi ep->v.i +#define epf ep->v.f +#define ulong unsigned long + + ep->nodetype = ep0->nodetype; + if (ep0->nodetype == en_fcon) { +#ifndef NOFLOAT + switch (type) { + case en_uminus: +#ifdef PC + epf = - ep0->v.f; +#else + epf = ep0->v.f; + if (epf) epf^=0x80; +#endif + break; + case en_not: + ep->nodetype = en_icon; + epi = (ep0->v.f) ? 0 : 1; + break; + case en_add: +#ifdef PC + epf = ep0->v.f + ep1->v.f; +#else + epf = ffpadd(ep0->v.f, ep1->v.f); +#endif + break; + case en_sub: +#ifdef PC + epf = ep0->v.f - ep1->v.f; +#else + epf = ffpsub(ep0->v.f, ep1->v.f); +#endif + break; + case en_mul: +#ifdef PC + epf = ep0->v.f * ep1->v.f; +#else + epf = ffpmul(ep0->v.f, ep1->v.f); +#endif + break; + case en_div: + if (ep1->v.f == 0) { + uwarn("division by zero"); + ep->nodetype = en_div; + } else { +#ifdef PC + epf = ep0->v.f / ep1->v.f; +#else + epf = ffpdiv(ep0->v.f, ep1->v.f); +#endif + } + break; + case en_eq: + ep->nodetype = en_icon; + epi = (ep0->v.f == ep1->v.f) ? 1 : 0; + break; + case en_ne: + ep->nodetype = en_icon; + epi = (ep0->v.f != ep1->v.f) ? 1 : 0; + break; + case en_land: + ep->nodetype = en_icon; + epi = (ep0->v.f && ep1->v.f) ? 1 : 0; + break; + case en_lor: + ep->nodetype = en_icon; + epi = (ep0->v.f || ep1->v.f) ? 1 : 0; + break; + case en_lt: + ep->nodetype = en_icon; +#ifdef PC + epi = (ep0->v.f < ep1->v.f) ? 1 : 0; +#else + epi = (ffpcmp_c(ep0->v.f, ep1->v.f) < 0) ? 1 : 0; +#endif + break; + case en_le: + ep->nodetype = en_icon; +#ifdef PC + epi = (ep0->v.f <= ep1->v.f) ? 1 : 0; +#else + epi = (ffpcmp_c(ep0->v.f, ep1->v.f) <= 0) ? 1 : 0; +#endif + break; + case en_gt: + ep->nodetype = en_icon; +#ifdef PC + epi = (ep0->v.f > ep1->v.f) ? 1 : 0; +#else + epi = (ffpcmp_c(ep0->v.f, ep1->v.f) > 0) ? 1 : 0; +#endif + break; + case en_ge: + ep->nodetype = en_icon; +#ifdef PC + epi = (ep0->v.f >= ep1->v.f) ? 1 : 0; +#else + epi = (ffpcmp_c(ep0->v.f, ep1->v.f) >= 0) ? 1 : 0; +#endif + break; + default: + ep->nodetype = type; + iwarn(DOOPER,1); + break; + } +#endif /* NOFLOAT */ + return; + } + /* + * Thus, ep0->nodetype is en_icon + * We have to distinguish unsigned long from the other cases + * + * Since we always store in ep->v.i, it is + * ASSUMED THAT (long) (ulong) ep->v.i == ep->v.i always + */ + if (ep0->etype == bt_ulong || ep0->etype == bt_pointer) { + switch (type) { + case en_uminus: + epi = - ep0->v.i; + break; + case en_not: + epi = ((ulong) ep0->v.i) ? 0 : 1; + break; + case en_compl: + epi = ~ (ulong) ep0->v.i; + epi = strip_icon(epi, ep->etype); + break; + case en_add: + epi = (ulong) ep0->v.i + (ulong) ep1->v.i; + break; + case en_sub: + epi = (ulong) ep0->v.i - (ulong) ep1->v.i; + break; + case en_mul: + epi = (ulong) ep0->v.i * (ulong) ep1->v.i; + break; + case en_div: + if ((ulong) ep1->v.i == 0) { + uwarn("division by zero"); + ep->nodetype = en_div; + } else { + epi = (ulong) ep0->v.i / (ulong) ep1->v.i; + } + break; + case en_mod: + if ((ulong) ep1->v.i == 0) { + uwarn("division by zero"); + ep->nodetype = en_mod; + } else { + epi = (ulong) ep0->v.i % (ulong) ep1->v.i; + } + break; + case en_and: + epi = (ulong) ep0->v.i & (ulong) ep1->v.i; + break; + case en_or: + epi = (ulong) ep0->v.i | (ulong) ep1->v.i; + break; + case en_xor: + epi = (ulong) ep0->v.i ^ (ulong) ep1->v.i; + break; + case en_eq: + epi = ((ulong) ep0->v.i == (ulong) ep1->v.i) ? 1 : 0; + break; + case en_ne: + epi = ((ulong) ep0->v.i != (ulong) ep1->v.i) ? 1 : 0; + break; + case en_land: + epi = ((ulong) ep0->v.i && (ulong) ep1->v.i) ? 1 : 0; + break; + case en_lor: + epi = ((ulong) ep0->v.i || (ulong) ep1->v.i) ? 1 : 0; + break; + case en_lt: + epi = ((ulong) ep0->v.i < (ulong) ep1->v.i) ? 1 : 0; + break; + case en_le: + epi = ((ulong) ep0->v.i <= (ulong) ep1->v.i) ? 1 : 0; + break; + case en_gt: + epi = ((ulong) ep0->v.i > (ulong) ep1->v.i) ? 1 : 0; + break; + case en_ge: + epi = ((ulong) ep0->v.i >= (ulong) ep1->v.i) ? 1 : 0; + break; + case en_lsh: +#ifdef MINIMAL_SIZES + epi = (ulong) ep0->v.i << (char) ep1->v.i; +#else + epi = (ulong) ep0->v.i << (ulong) ep1->v.i; +#endif + break; + case en_rsh: +#ifdef MINIMAL_SIZES + epi = (ulong) ep0->v.i >> (char) ep1->v.i; +#else + epi = (ulong) ep0->v.i >> (ulong) ep1->v.i; +#endif + break; + default: + ep->nodetype = type; + iwarn(DOOPER,2); + break; + } + } else { + switch (type) { + case en_uminus: + epi = - ep0->v.i; + break; + case en_not: + epi = (ep0->v.i) ? 0 : 1; + break; + case en_compl: + epi = ~ ep0->v.i; + epi = strip_icon(epi, type); + break; + case en_add: + epi = ep0->v.i + ep1->v.i; + break; + case en_sub: + epi = ep0->v.i - ep1->v.i; + break; + case en_mul: + epi = ep0->v.i * ep1->v.i; + break; + case en_div: + if (ep1->v.i == 0) { + uwarn("division by zero"); + ep->nodetype = en_div; + } else { + epi = ep0->v.i / ep1->v.i; + } + break; + case en_mod: + if (ep1->v.i == 0) { + uwarn("division by zero"); + ep->nodetype = en_mod; + } else { + epi = ep0->v.i % ep1->v.i; + } + break; + case en_and: + epi = ep0->v.i & ep1->v.i; + break; + case en_or: + epi = ep0->v.i | ep1->v.i; + break; + case en_xor: + epi = ep0->v.i ^ ep1->v.i; + break; + case en_eq: + epi = (ep0->v.i == ep1->v.i) ? 1 : 0; + break; + case en_ne: + epi = (ep0->v.i != ep1->v.i) ? 1 : 0; + break; + case en_land: + epi = (ep0->v.i && ep1->v.i) ? 1 : 0; + break; + case en_lor: + epi = (ep0->v.i || ep1->v.i) ? 1 : 0; + break; + case en_lt: + epi = (ep0->v.i < ep1->v.i) ? 1 : 0; + break; + case en_le: + epi = (ep0->v.i <= ep1->v.i) ? 1 : 0; + break; + case en_gt: + epi = (ep0->v.i > ep1->v.i) ? 1 : 0; + break; + case en_ge: + epi = (ep0->v.i >= ep1->v.i) ? 1 : 0; + break; + case en_lsh: +#ifdef MINIMAL_SIZES + epi = ep0->v.i << (char)ep1->v.i; +#else + epi = ep0->v.i << ep1->v.i; +#endif + break; + case en_rsh: +#ifdef MINIMAL_SIZES + epi = ep0->v.i >> (char)ep1->v.i; +#else + epi = ep0->v.i >> ep1->v.i; +#endif + break; + default: + ep->nodetype = type; + iwarn(DOOPER,3); + break; + } + } +#undef ep0 +#undef ep1 +#undef epi +#undef epf +#undef ulong +} + +int pwrof2(long i) { +/* + * return which power of two i is or -1. + */ + int p; + long q; + q = 2; + p = 1; + while (q > 0) { + if (q == i) + return p; + q <<= 1; + ++p; + } + return -1; +} + +long mod_mask(long i) { +/* + * make a mod mask for a power of two. + */ + long m; + m = 0; + while (i--) + m = (m << 1) | 1; + return m; +} + +void opt0(struct enode **node) { +/* + * opt0 - delete useless expressions and combine constants. + * + * opt0 will delete expressions such as x + 0, + * x - 0, + * x * 0, + * x * 1, + * 0 / x, + * x / 1, + * x % (1<<3), + * etc from the tree pointed to by node and combine obvious + * constant operations. It cannot combine name and label constants but will + * combine icon type nodes. + */ + struct enode *ep; + +#define ep0 ep->v.p[0] +#define ep1 ep->v.p[1] + + long val, sc; + enum(e_node) typ; + ep = *node; + if (ep == 0) + return; + typ = ep->nodetype; + switch (typ) { + case en_ref: + case en_fieldref: + case en_ainc: + case en_adec: + case en_deref: + opt0(&ep0); + break; + case en_uminus: + case en_compl: + opt0(&ep0); + /* + * This operation applied twice is a no-op + */ + if (ep0->nodetype == typ) { + *node = ep0->v.p[0]; + break; + } + if (ep0->nodetype == en_icon || ep0->nodetype == en_fcon) + dooper(node); + break; + case en_not: + opt0(&ep0); + if (ep0->nodetype == en_icon || ep0->nodetype == en_fcon) + dooper(node); + break; + case en_add: + case en_sub: + opt0(&ep0); + opt0(&ep1); + /* + * a + (-b) = a - b + * a - (-b) = a + b + * (-a) + b = b - a + */ + if (ep1->nodetype == en_uminus) { + ep1 = ep1->v.p[0]; + ep->nodetype = typ = (typ == en_add) ? en_sub : en_add; + } + if (ep0->nodetype == en_uminus && typ == en_add) { + ep0 = ep0->v.p[0]; + swap_nodes(ep); + ep->nodetype = typ = en_sub; + } + /* + * constant expressions + */ + if ((ep0->nodetype == en_icon && ep1->nodetype == en_icon) || + (ep0->nodetype == en_fcon && ep1->nodetype == en_fcon)) { + dooper(node); + break; + } + /*infunc("DrawNumberOfClock") + bkpt();*/ + /* the following would bug, as : + short my_array[2]={12,570}; + int i=2; + while (i--) printf("%d",my_array[i]); + wouldn't print 570 correctly... */ +#ifdef BUGGY_AND_ANYWAY_NOT_COMPAT_WITH_NO_OFFSET_AUTOCON + if (typ == en_add) { + if (ep1->nodetype == en_autocon) + swap_nodes(ep); + } +#endif + if (ep0->nodetype == en_icon) { + if (ep0->v.i == 0) { + if (typ == en_sub) { + ep0 = ep1; + ep->nodetype = typ = en_uminus; + } else + *node = ep1; + break; +#ifdef PREFER_POS_VALUES + } else if (ep0->nodetype==en_add && ep0->v.i<0) { + ep0->v.i=-ep0->v.i; + swap_nodes(ep); + ep->nodetype=en_sub; +#endif + } + } else if (ep1->nodetype == en_icon) { +#ifdef BUGGY_AND_ANYWAY_NOT_COMPAT_WITH_NO_OFFSET_AUTOCON + if (ep0->nodetype == en_autocon && typ == en_add) { + ep0->v.i += ep1->v.i; + *node = ep0; + break; + } +#endif + if (ep1->v.i == 0) { + *node = ep0; + break; +#ifdef PREFER_POS_VALUES + } else if (ep1->v.i<0) { + ep->nodetype^=1; + ep1->v.i=-ep1->v.i; +#endif + } + } + break; + case en_mul: + opt0(&ep0); + opt0(&ep1); + /* + * constant expressions + */ + if ((ep0->nodetype == en_icon && ep1->nodetype == en_icon) || + (ep0->nodetype == en_fcon && ep1->nodetype == en_fcon)) { + dooper(node); + break; + } + if (ep0->nodetype == en_icon) { + val = ep0->v.i; + if (val == 0) { + *node = ep0; + break; + } + if (val == 1) { + *node = ep1; + break; + } + sc = pwrof2(val); + if (sc IS_VALID) { + swap_nodes(ep); + ep1->v.i = sc; + ep->nodetype = en_lsh; + } + } else if (ep1->nodetype == en_icon) { + val = ep1->v.i; + if (val == 0) { + *node = ep1; + break; + } + if (val == 1) { + *node = ep0; + break; + } + sc = pwrof2(val); + if (sc IS_VALID) { + ep1->v.i = sc; + ep->nodetype = en_lsh; + } + } + break; + case en_div: + opt0(&ep0); + opt0(&ep1); + /* + * constant expressions + */ + if ((ep0->nodetype == en_icon && ep1->nodetype == en_icon) || + (ep0->nodetype == en_fcon && ep1->nodetype == en_fcon)) { + dooper(node); + break; + } + if (ep0->nodetype == en_icon) { + if (ep0->v.i == 0) { /* 0/x */ + *node = ep0; + break; + } + } else if (ep1->nodetype == en_icon) { + val = ep1->v.i; + if (val == 1) { /* x/1 */ + *node = ep0; + break; + } + sc = pwrof2(val); + if (sc IS_VALID) { + ep1->v.i = sc; + ep->nodetype = en_rsh; + } + } + break; + case en_mod: + opt0(&ep0); + opt0(&ep1); + /* + * constant expressions + */ + if ((ep0->nodetype == en_icon && ep1->nodetype == en_icon) || + (ep0->nodetype == en_fcon && ep1->nodetype == en_fcon)) { + dooper(node); + break; + } + if (ep1->nodetype == en_icon) { + sc = pwrof2(ep1->v.i); + if (sc IS_VALID) { + ep1->v.i = mod_mask(sc); + ep->nodetype = en_and; + } + } + break; + case en_land: + case en_lor: +#if 0 /* perhaps this isn't *that* useful... and ep0/ep1 are long to access */ + opt0(&ep0); + opt0(&ep1); + if ((ep0->nodetype == en_icon && ep1->nodetype == en_icon) || + (ep0->nodetype == en_fcon && ep1->nodetype == en_fcon)) + dooper(node); + else { + typ = (typ==en_lor); + if (ep0->nodetype == en_icon) { + if ((!ep0->v.i)!=typ) /* absorbing element */ + ep = ep0; + else /* "neutral" element */ + //ep = ep1; -> not quite, should be !!x + (void)0; + } else if (ep1->nodetype == en_icon) { + if ((!ep1->v.i)!=typ) /* absorbing element */ + ep->nodetype = en_void, ep1->v.i=typ; + else /* "neutral" element */ + //ep = ep0; -> not quite, should be !!x + (void)0; + } + } + break; +#else + /* FALL THROUGH */ +#endif + case en_and: + case en_or: + case en_xor: + case en_eq: + case en_ne: + case en_lt: + case en_le: + case en_gt: + case en_ge: + opt0(&ep0); + opt0(&ep1); + /* + * constant expressions + */ + if ((ep0->nodetype == en_icon && ep1->nodetype == en_icon) || + (ep0->nodetype == en_fcon && ep1->nodetype == en_fcon)) + dooper(node); + break; + case en_lsh: + case en_rsh: + opt0(&ep0); + opt0(&ep1); + if (ep0->nodetype == en_icon && ep1->nodetype == en_icon) { + dooper(node); + break; + } + /* + * optimize a << 0 and a >> 0 + */ + if (ep1->nodetype == en_icon && ep1->v.i == 0) + *node = ep0; + break; + case en_cond: + opt0(&ep0); + opt0(&ep1); + if (ep0->nodetype == en_icon) { + if (ep0->v.i) { + if (ep1->v.p[0]) *node=ep1->v.p[0]; + else *node=ep0; + } else + *node=ep1->v.p[1]; + } + break; + case en_asand: + case en_asor: + case en_asxor: + case en_asadd: + case en_assub: + case en_asmul: + case en_asdiv: + case en_asmod: + case en_asrsh: + case en_aslsh: + case en_fcall: + case en_void: + case en_assign: + opt0(&ep0); + opt0(&ep1); + break; + /* now handled in expr.c */ + case en_cast: + opt0(&ep0); + if (ep0->nodetype == en_icon) { +#ifndef NOFLOAT + if (ep->etype != bt_float +#ifdef DOUBLE + && ep->etype != bt_double +#endif + ) { +#endif + ierr(OPT0,1); +/* ep->nodetype = en_icon; + ep->v.i = ep0->v.i;*/ +#ifndef NOFLOAT + } else { +#ifdef XCON_DOESNT_SUPPORT_FLOATS +#error Fix me now :) +#endif + ep->nodetype = en_fcon; +#ifdef PC + ep->v.f = (double)ep0->v.i; +#else +#ifndef BCDFLT + ep->v.f = ffpltof(ep0->v.i); +#else + ep->v.f = (double)ep0->v.i; +#endif +#endif + } +#endif + } + /* perhaps BUGGY */ + else if ((ep0->nodetype == en_labcon || ep0->nodetype == en_nacon) + && ep->esize<=ep0->esize) { + ep0->etype = ep->etype; + ep0->esize = ep->esize; + ep=ep0; + *node=ep; + } +#ifndef NOFLOAT + else if (ep0->nodetype == en_fcon && bt_integral(ep->etype)) { + ep->nodetype = en_icon; +#ifdef PC + ep->v.i = (long)ep0->v.f; +#else + ep->v.i = ffpftol(ep0->v.f); +#endif + } +#endif + break; + /*case en_icon: + case en_fcon: + case en_labcon: + case en_nacon: + case en_autocon: + case en_tempref: + break; + default: + uwarn("Didn't optimize nodetype %d. Please send me your source code.",typ);*/ + } + +#undef ep0 +#undef ep1 +} + +static long xfold(struct enode *node) { +/* + * xfold will remove constant nodes and return the values to the calling + * routines. + */ + long i; + if (node == 0) + return 0; + switch (node->nodetype) { + case en_icon: + i = node->v.i; + node->v.i = 0; + return i; + case en_add: + return xfold(node->v.p[0]) + xfold(node->v.p[1]); + case en_sub: + return xfold(node->v.p[0]) - xfold(node->v.p[1]); + case en_mul: + if (node->v.p[0]->nodetype == en_icon) + return xfold(node->v.p[1]) * node->v.p[0]->v.i; + else if (node->v.p[1]->nodetype == en_icon) + return xfold(node->v.p[0]) * node->v.p[1]->v.i; + else { + fold_const(&node->v.p[0]); + fold_const(&node->v.p[1]); + return 0; + } + /* + * CVW: This seems wrong to me... case en_lsh: if( + * node->v.p[0]->nodetype == en_icon ) return xfold(node->v.p[1]) << + * node->v.p[0]->v.i; else if( node->v.p[1]->nodetype == en_icon ) + * return xfold(node->v.p[0]) << node->v.p[1]->v.i; else return 0; + */ + case en_uminus: + return -xfold(node->v.p[0]); + case en_lsh: + case en_rsh: + case en_div: + case en_mod: + case en_asadd: + case en_assub: + case en_asmul: + case en_asdiv: + case en_asmod: + case en_and: + case en_land: + case en_or: + case en_lor: + case en_xor: + case en_asand: + case en_asor: + case en_asxor: + case en_void: + case en_fcall: + case en_assign: + case en_eq: + case en_ne: + case en_lt: + case en_le: + case en_gt: + case en_ge: + fold_const(&node->v.p[0]); + fold_const(&node->v.p[1]); + return 0; + case en_ref: + case en_fieldref: + case en_compl: + case en_not: + case en_deref: + fold_const(&node->v.p[0]); + return 0; + /* + * This is not stricly legal: (long)(x+10) * 4l might not be the same + * as (long)(x) * 4l + 40l but it is the same as long as no overflows + * occur + */ + case en_cast: +#ifdef DONTDEF + return xfold(node->v.p[0]); +#endif + /* + * Well, sometimes I prefer purity to efficiency + * It is a matter of taste how you decide here.... + */ + fold_const(&node->v.p[0]); + return 0; + } + return 0; +} + +static void fold_const(struct enode **node) { +/* + * reorganize an expression for optimal constant grouping. + */ + struct enode *ep; + long i; + ep = *node; + if (ep == 0) + return; + if (ep->nodetype == en_add) { + if (ep->v.p[0]->nodetype == en_icon) { + ep->v.p[0]->v.i += xfold(ep->v.p[1]); + return; + } else if (ep->v.p[1]->nodetype == en_icon) { + ep->v.p[1]->v.i += xfold(ep->v.p[0]); + return; + } + } else if (ep->nodetype == en_sub) { + if (ep->v.p[0]->nodetype == en_icon) { + ep->v.p[0]->v.i -= xfold(ep->v.p[1]); + return; + } else if (ep->v.p[1]->nodetype == en_icon) { + ep->v.p[1]->v.i -= xfold(ep->v.p[0]); + return; + } + } + i = xfold(ep); + if (i != 0) { +/* + * strip_icon is in fact harmless here since this value is + * just added to *node + * consider in 16-bit mode: + * + * int day, year; + * day = 365 * (year - 1970); + * + * and look at the code, which is transformed to + * + * day = 365*year + 1846; + * + * which works if the multiplication returns the lower 16 bits of + * the result correctly. + */ + i = strip_icon(i, (*node)->etype); + ep = mk_icon(i); + ep->etype = (*node)->etype; + ep->esize = (*node)->esize; + ep = mk_node(en_add, *node, ep); + ep->etype = (*node)->etype; + ep->esize = (*node)->esize; + *node = ep; + } +} + +void opt4(struct enode **node) { +/* + * apply all constant optimizations. + */ + /* opt0(node); */ + fold_const(node); + opt0(node); +} +// vim:ts=4:sw=4 diff --git a/gtc/src/out68k_as.c b/gtc/src/out68k_as.c new file mode 100644 index 0000000..43f840c --- /dev/null +++ b/gtc/src/out68k_as.c @@ -0,0 +1,3017 @@ +/* + * GTools C compiler + * ================= + * source file : + * assembled binary output + * + * Copyright 2001-2004 Paul Froissart. + * Credits to Christoph van Wuellen and Matthew Brandt. + * All commercial rights reserved. + * + * This compiler may be redistributed as long there is no + * commercial interest. The compiler must not be redistributed + * without its full sources. This notice must stay intact. + */ + +#include "define.h" +_FILE(__FILE__) +#include "c.h" +#include "expr.h" +#include "gen.h" +#include "cglbdec.h" + +#ifdef PC +void nl(void) { +} +#define nl() while (0) +#endif + +#ifdef SECURIZED_ALIGN +#define put_align(__a) while (0) +#else +#define put_align(__a) put_align2() +#endif + +#ifdef PC +#define tabs "\t" +#else +#define tabs " " +#endif + +#define N_TAB 64 +#define N_TAB_LOG 6 +typedef struct _ltab { + struct _ltab *nxt; + unsigned int t[N_TAB]; +} LTAB; +#define N_REF 8 +#define N_REF_LOG 3 +typedef struct _ref { + unsigned int r[N_REF]; + struct _ref *nxt; // very important to be afterwards : if nxt==NULL, then r[N_REF]==0 +} REF; +typedef struct _gtab { + struct _gtab *nxt; + unsigned int t[N_TAB]; + REF *r[N_TAB]; +} GTAB; + +typedef struct _rtype { + REF *r0,*r; +} RTYPE; +typedef struct _func { + RTYPE rt; + unsigned int f; + struct _func *nxt; +} FUNC; +typedef struct _xtab { + struct _xtab *nxt; + RTYPE *t[N_TAB]; +} XTAB; + +FILE *output CGLOB; +unsigned char *bin CGLOB; +struct slit *strtab CGLOB; +long lc_bss CGLOB; +xstatic int lc_stk CGLOB,uses_lc_stk CGLOB; +xstatic char odd CGLOB; // for put_align +xstatic int extlabel CGLOB; +int glblabel CGLOB; +struct ocode *scope_head CGLOB; +unsigned int pos CGLOB,bin_size CGLOB; +int nostub_mode CGLOB; +#ifdef EXE_OUT +int exestub_mode CGLOB; +#else +#define exestub_mode 0 +#endif +LTAB *loc_tab CGLOB; +GTAB *glb_tab CGLOB; +XTAB *ext_tab CGLOB; +LTAB *exp_tab CGLOB; // warning : the content is the exported label (but not the offset) +FUNC *rom_funcs CGLOB; +#ifdef RAM_CALLS +FUNC *ram_funcs CGLOB; +#endif +RTYPE reloc_tab CGLOBL,bss_tab CGLOBL; +HTABLE alsyms CGLOBL; +TABLE libsyms CGLOBL; // (FUNC *)sym->value.i + +#ifdef SIZE_STATS +xstatic unsigned int c_compiler_sz CGLOB; +#endif + +#ifdef MC680X0 +/* variable initialization */ +enum e_gt { + nogen, bytegen, wordgen, longgen, floatgen +}; +enum e_sg { + noseg, codeseg, dataseg +}; + + +char *outlate(); +#ifndef NOFLOAT +#ifdef PC +unsigned long double2ffp(); +#else +#define double2ffp(__x) (__x) +#endif +#endif +void wrt2(short x); +void set_label(int lab,unsigned int pos); +unsigned int lab_src(int n); +void put_label(int lab); +void put_align2(void); + +enum(e_gt) gentype; +enum(e_sg) curseg; +int outcol; + +#define BIN_STEP 128 + +void out_init() { +// fputs("gtc_compiled:\n", output); + curseg = noseg; + gentype = nogen; + outcol = 0; + lc_stk = 0; + odd = 0; + extlabel = -1; + glblabel = -32768; + scope_head = 0; + pos = 4; + hashinit(&alsyms); + reloc_tab.r = 0; + bss_tab.r = 0; + libsyms.tail = libsyms.head = 0; + rom_funcs = 0; +#ifdef RAM_CALLS + ram_funcs = 0; +#endif + loc_tab = 0; + glb_tab = 0; + ext_tab = 0; + nostub_mode = 0; +#ifdef EXE_OUT + exestub_mode = 0; +#endif + bin = malloc(bin_size = BIN_STEP); + pos = 4; + put_label(label("gtc_compiled")); +#ifdef SIZE_STATS + c_compiler_sz=0; +#endif +} + +char *unres_name(int lab) { + SYM *ttail; int crc=N_HASH;; + while (crc--) { + ttail=alsyms.h[crc].tail; + while (ttail) { + if ((short)ttail->value.splab==(short)lab) + return ttail->name; + ttail = ttail->prev; + } + } + return 0; +} +void scan_unresolved() { + GTAB *t=glb_tab; int l=0x8000; + while (t) { + REF **r=t->r; int n; + n=N_TAB; + while (n--) { + if (*r++) + uerrc2("unresolved symbol '%s'",unres_name(l)); + l++; + } + t=t->nxt; + } +} + +int eval_rt(RTYPE *r) { + int n=1; + REF *p=r->r0,*q=r->r; + while (p!=q) + n+=N_REF,p=p->nxt; + if (p) { + unsigned int *a=p->r; + while (*a++) n++; + } + return n; +} +unsigned int eval_functab(FUNC *f) { + int n=1; + while (f) + n+=1+eval_rt(&f->rt),f=f->nxt; + return n+n; +} +unsigned int eval_libs() { + int n=2; + SYM *sp=libsyms.head; + while (sp) + n+=10+eval_functab((FUNC *)sp->value.i),sp=sp->next; +// return 2; + return n; +} +unsigned int eval_export() { + int i=N_TAB,n=i; + int *a; + if (!exp_tab) + return 0; + a=exp_tab->t; + while (i--) + if (*a++) n=i; + return (1+N_TAB-n)<<1; +} + +#ifdef PC +xstatic unsigned char *hdr CGLOB,*hdrp CGLOB; +#else +xstatic unsigned short *hdr CGLOB,*hdrp CGLOB; +#endif +xstatic short hshift CGLOB; +#ifdef PC +void _wri(unsigned short x) { + unsigned char hi=(char)(x>>8),lo=(char)x; + *hdrp++=hi; + *hdrp++=lo; +} +void _ovwri(unsigned int i,unsigned short x) { + unsigned char hi=(char)(x>>8),lo=(char)x; + if (i&1) fatal("ODD OVWRI"); + hdr[i+0]=hi; + hdr[i+1]=lo; +} +void _orwri(unsigned int i,unsigned short x) { + unsigned char hi=(char)(x>>8),lo=(char)x; + if (i&1) fatal("ODD ORWRI"); + hdr[i+0]|=hi; + hdr[i+1]|=lo; +} +#define wri(x) (_wri((unsigned short)(x))) +#define ovwri(i,x) (_ovwri(i,(unsigned short)(x))) +#define orwri(i,x) (_orwri(i,(unsigned short)(x))) +#else +#define wri(x) (*hdrp++=x) +#define ovwri(i,x) (*(unsigned short *)((char *)hdr+i)=x) +#define orwri(i,x) (*(unsigned short *)((char *)hdr+i)|=x) +#endif +void write_rt(RTYPE *r) { + REF *p=r->r0; + while (p) { + unsigned int x,*a=p->r; int n; + if ((p=p->nxt)) { + n=N_REF; while (n--) wri((*a++)+hshift); + } else + while ((x=*a++)) wri(x+hshift); + } + wri(0); +} +void write_reloc( +#ifdef OBJ_OUT + int directly_to_bin +#else + #define directly_to_bin 0 +#endif + ) { + RTYPE *r=&reloc_tab; + REF *p=r->r0; + while (p) { + unsigned int x,*a=p->r; int n; + if ((p=p->nxt)) { + n=N_REF; while (n--) { + x=*a++; + directly_to_bin?wrt2(x+hshift+2):wri(x+hshift); + #ifdef PC + { short a=bin[x+2]<<8; + a+=bin[x+3]+hshift; /* logically, shouldn't overflow... */ + bin[x+2]=(unsigned char)(a>>8); + bin[x+3]=(unsigned char)(a); + } + #else + *(long *)(bin+x)+=hshift; + #endif + } + } else + while ((x=*a++)) { + #ifdef PC + { short a=bin[x+2]<<8; + a+=bin[x+3]+hshift; /* logically, shouldn't overflow... */ + bin[x+2]=(unsigned char)(a>>8); + bin[x+3]=(unsigned char)(a); + } + #else + *(long *)(bin+x)+=hshift; + #endif + directly_to_bin?wrt2(x+hshift+2):wri(x+hshift); + } + } + directly_to_bin?wrt2(0):wri(0); +} +#undef directly_to_bin +void write_functab(FUNC *f0) { + int n=0; FUNC *f=f0; + while (f) + n++,f=f->nxt; + wri(n-1); + f=f0; + while (f) + wri(f->f),write_rt(&f->rt),f=f->nxt; +} +void write_libs() { + int n=0; + SYM *sp=libsyms.head; +// wri(0); return; + while (sp) + n++,sp=sp->next; + wri(n); + sp=libsyms.head; + while (sp) { + memset(hdrp,0,8); + strcpy((char *)hdrp,sp->name); + hdrp+=8/sizeof(*hdrp); + wri(0); + sp=sp->next; + } + sp=libsyms.head; + while (sp) + write_functab((FUNC *)sp->value.i),sp=sp->next; +} +unsigned int qlab_src(int n); +void write_export(unsigned int l) { + int *a=exp_tab->t,x; + l=(l>>1)-1; + wri((short)l); + while (l--) { + if ((x=*a++)) + x=qlab_src(x)+hshift; + wri(x); + } +} + +#ifdef EXE_OUT +typedef struct { + short t; // type + unsigned short loc; // location, offset based on relocated output +} EXE_ITEM; +int +#ifdef PC +#ifdef _MSC_VER +__cdecl +#endif +#else +CALLBACK +#endif +exe_compare(const void *a,const void *b) { + return ((EXE_ITEM *)a)->loc-((EXE_ITEM *)b)->loc; +} +void *GTPackDo(void *buf,unsigned int *buflen); +#include "out68k_exe.h" +#endif + +readonly char pgm_init[0x1A]={0x61,0,0,0,'6','8','k','P'}; +readonly char lib_init[0x1A]={0x4E,0x75,0x4E,0x75,'6','8','k','L'}; +readonly char pgm_stub[0xA]={0x2F,0x38,0x00,0x34,0x66,0x02,0x50,(char)0x8F,0x4E,0x75}; +void wrt2(short x); +void wrt1(char x); +void out_close() { +#ifdef PC + int calctype_used[]={0,0,0}; + char *calc_symbols[]={"USE_TI89","USE_TI92PLUS","USE_V200"}; + int calc,specific=1,something; + for (something=0;!something;specific=0) + for (calc=0;calc<3;calc++) + if (!specific || search(calc_symbols[calc],-1,&defsyms)) + calctype_used[calc]++,something++; +#endif + if (bin) { + /* + * 0x1A+(2+10*nLibs+2*(nLibs+nLibCalls+nLibFuncs))+(2+2+2*(nRomFuncs+nRomCalls)) + * +2+2+(4+nBSS*2)+(2+nExport*2) + * +0xA+(nReloc+1)*2 + * = + * 0x1A+(2+10*nLibs+nLibs(eval(Lib)))+(2+eval(rom)) + * +2+2+(4+nBSS*2)+(2+nExport*2) + * +0xA+eval_rt(reloc_tab)*2 + * = + * 0x1A+(2+eval_libs())+(2+eval(rom)) + * +2+2+(4+nBSS*2)+(2+nExport*2) + * +0xA+eval_rt(reloc_tab)*2 + */ + SYM *mainsym; + unsigned int rom=eval_functab(rom_funcs)-2,lib=eval_export(); +#ifdef RAM_CALLS + unsigned int ram=eval_functab(ram_funcs)-2; +#else +#define ram 0 +#endif +#ifdef OBJ_OUT + int object=!!search("_GENERIC_ARCHIVE",-1,&defsyms); + if (!object) { +#endif + int nostub=search("_nostub",-1,&alsyms) || search("_nostub",-1,&gsyms) + || search("_nostub",-1,&defsyms) || nostub_mode; +#ifdef EXE_OUT + int exestub=!!search("EXE_OUT",-1,&defsyms); + if (exestub) nostub=0; +#else +#define exestub 0 +#endif + debug('+'); + if (nostub) { + if (ram || rom) fatal("RAM/ROM_CALL in _nostub"); + if (libsyms.head) fatal("Libraries in _nostub"); + if (bss_tab.r) fatal("BSS in _nostub"); + hshift=0; +#ifdef EXE_OUT + } else if (exestub) { + if (ram) fatal("RAM_CALL in EXE format"); + if (libsyms.head) fatal("Libraries in exe format"); +#endif + } else { + hdrp=hdr=malloc((hshift=0x1A-4+(eval_libs())+(rom?rom+4:2) + +(ram?ram+4:2)+(eval_rt(&reloc_tab)<<1)+(bss_tab.r?4+(eval_rt(&bss_tab)<<1):0) + +(lib)+(lib?0:0xA))+4); + if (!hdr) + fatal("memory"); + memcpy(hdr,lib?lib_init:pgm_init,0x1A); + hdrp+=0x1A/sizeof(*hdrp); + write_libs(); // import table + wri(rom); // ROM table + if (rom) write_functab(rom_funcs); + #ifdef RAM_CALLS + wri(ram); // RAM table + if (ram) write_functab(ram_funcs); + #else + wri(0); // no RAM table + #endif + #ifdef OBJ_OUT + write_reloc(0); // reloc table + #else + write_reloc(); // reloc table + #endif + if (bss_tab.r) { + ovwri(0x14,(char *)hdrp-(char *)hdr); // BSS table + wri(lc_bss>>16),wri(lc_bss); + write_rt(&bss_tab); + } + if (lib) { + ovwri(0x16,(char *)hdrp-(char *)hdr); // export table + write_export(lib); + } + if (!lib) { + ovwri(0x02,(char *)hdrp-(char *)hdr-2); // stub + memcpy(hdrp,pgm_stub,0xA); + hdrp+=0xA/sizeof(*hdrp); + } + #ifdef PC + if (hdrp!=hdr+(hshift+4)/sizeof(*hdrp)) + ierr(LINK_MISPL,1); + #endif + /* link with file */ + if ((mainsym=search("VERSION",-1,&defsyms))) { + + ovwri(0x10,1<<8); + } + } + mainsym=NULL; + if (!lib && ((!nostub && !exestub) || !search("NO_MAIN",-1,&defsyms))) { + if (!(mainsym=search("_main",-1,&alsyms)) && !(mainsym=search("__main",-1,&alsyms))) + fatal("_main not found"); + if (!nostub && !exestub) { + ovwri(0x0C,qlab_src(mainsym->value.splab)+hshift); + if (!!search("NO_SCREEN",-1,&defsyms)) + orwri(0x10,(1<<2)); + } + } + scan_unresolved(); + + /* finally, write the output to the file */ + if (nostub) { + if (!mainsym) + memmove(bin,bin+4,pos-4),pos-=4,hshift=-4; + else { + #ifdef PC + bin[0]=0x60,bin[1]=0x00; + bin[2]=(unsigned char)((qlab_src(mainsym->value.splab)-2)>>8); + bin[3]=(unsigned char)((qlab_src(mainsym->value.splab)-2)); + #else + *(short *)bin=0x6000; + *(short *)(bin+2)=qlab_src(mainsym->value.splab)-2; + #endif + hshift=0; + } + put_align2(); + wrt2(0); + { + RTYPE *r=&reloc_tab; + REF *p=r->r0; + while (p) { + unsigned int x,*a=p->r; int n; + if ((p=p->nxt)) { + n=N_REF; while (n--) { + #ifdef PC + { short z=bin[(x=*a++)+2+hshift]<<8; + z+=bin[x+3+hshift]+hshift; + wrt2(z); + } + #else + wrt2(*(unsigned short *)(bin+(x=*a++)+2+hshift)+hshift); + #endif + if (*(unsigned short *)(bin+x+hshift)!=0) + uerrc("invalid _nostub relocation"); + *(unsigned short *)(bin+x+2+hshift)=0; + wrt2((unsigned short)(x+hshift)); + } + } else + while ((x=*a++)) { + #ifdef PC + { short z=bin[x+2+hshift]<<8; + z+=bin[x+3+hshift]+hshift; + wrt2(z); + } + #else + wrt2(*(unsigned short *)(bin+x+2+hshift)+hshift); + #endif + if (*(unsigned short *)(bin+x+hshift)!=0) + uerrc("invalid _nostub relocation"); + *(unsigned short *)(bin+x+2+hshift)=0; + wrt2((unsigned short)(x+hshift)); + } + } + } + wrt1((char)0xF3); + rel_global(); + #ifndef PC + fwrite(bin,1,pos,output); + #endif +#ifdef EXE_OUT + } else if (exestub) { +#ifdef TWIN_COMPILE + if (twinc_necessary) { + rel_global(); + goto close_it; // don't lose time compressing... + } else { +#endif + #define EXE_END -1 + #define EXE_PROGRELOC 0 + #define EXE_BSSRELOC 1 + #define EXE_ROMRELOC 2 + #define EXE_ROMRELOC_NOJSR (0x100|EXE_ROMRELOC) + EXE_ITEM *exe_data=calloc(6000,sizeof(EXE_ITEM)); /* 12 kb */ + EXE_ITEM *exe_ptr=exe_data; + int exe_num; + if (!exe_data) + fatal("Memory"); + memmove(bin,bin+4,pos-4),pos-=4; + { + RTYPE *r=&reloc_tab; + REF *p=r->r0; + while (p) { + unsigned int x,*a=p->r; int n; + if ((p=p->nxt)) { + n=N_REF; while (n--) { + exe_ptr->t=EXE_PROGRELOC; + exe_ptr->loc=(*a++)-4; + exe_ptr++; + } + } else + while ((x=*a++)) { + exe_ptr->t=EXE_PROGRELOC; + exe_ptr->loc=x-4; + exe_ptr++; + } + } + } + { + FUNC *f=rom_funcs; + while (f) { + RTYPE *r=&f->rt; + REF *p=r->r0; + while (p) { + unsigned int x,*a=p->r; int n; + if ((p=p->nxt)) { + n=N_REF; while (n--) { + exe_ptr->t=EXE_ROMRELOC; + exe_ptr->loc=(*a++)-4; + if (*(long *)(bin+exe_ptr->loc)) + fatal("Invalid ROM_CALL"); + bin[exe_ptr->loc+2]=f->f>>8; + bin[exe_ptr->loc+3]=f->f&255; + if (bin[exe_ptr->loc-2]==0x4e + && bin[exe_ptr->loc-1]==0xb9) + exe_ptr->loc-=2; + else bin[exe_ptr->loc+2]|=0x80,exe_ptr->t=EXE_ROMRELOC_NOJSR; + exe_ptr++; + } + } else + while ((x=*a++)) { + exe_ptr->t=EXE_ROMRELOC; + exe_ptr->loc=x-4; + if (*(long *)(bin+exe_ptr->loc)) + fatal("Invalid ROM_CALL"); + bin[exe_ptr->loc+2]=f->f>>8; + bin[exe_ptr->loc+3]=f->f&255; + if (bin[exe_ptr->loc-2]==0x4e + && bin[exe_ptr->loc-1]==0xb9) + exe_ptr->loc-=2; + else bin[exe_ptr->loc+2]|=0x80,exe_ptr->t=EXE_ROMRELOC_NOJSR; + exe_ptr++; + } + } + f=f->nxt; + } + } + exe_ptr->t=-1; exe_ptr->loc=pos; exe_ptr++; + exe_num=exe_ptr-exe_data; + qsort(exe_data,exe_num,sizeof(EXE_ITEM),exe_compare); + { + long relocated_size; + unsigned short last_pos=0; unsigned char *ptr=bin,*out=bin; + char *reloc_ptr=(char *)exe_data,*last_esc=NULL; + int last_esc_num=0; + int i=exe_num; exe_ptr=exe_data; + while (i--) { + unsigned char *dest_ptr=bin+exe_ptr->loc; + unsigned short delta; short type; +#ifdef PC +#define g16(p) (p+=2,(p[-2]<<8)+p[-1]) +#define rd16(p) ((p[0]<<8)+p[1]) +#define w16(p,v) (*p++=(v)>>8,*p++=(v)&255,(void)0) +#else +#define g16(p) (*((int *)p)++) +#define rd16(p) (*((int *)p)) +#define w16(p,v) (g16(p)=(v)) +#endif + while (ptr =dest_ptr) break; + w16(out,rd16(ptr)+((char *)ptr-(char *)bin)); + ptr+=2; + } + } + delta=(exe_ptr->loc-last_pos)+2; + last_pos=exe_ptr->loc; + if ((delta&1)) + uerrc("invalid relocation offset"); + delta>>=1; + switch ((type=exe_ptr->t)) { // we *NEED* to save exe_ptr->t as it will be lost + case EXE_PROGRELOC: + if (g16(ptr)) + uerrc("invalid _nostub relocation"); + w16(out,rd16(ptr)-4); // parameters to w16 can't have side-fx... + ptr+=2; + last_pos+=4; + break; + case EXE_ROMRELOC: + ptr+=4; + w16(out,rd16(ptr)); // parameters to w16 can't have side-fx... + ptr+=2; + last_pos+=6; + break; + case EXE_ROMRELOC_NOJSR: + ptr+=2; + w16(out,rd16(ptr)); // parameters to w16 can't have side-fx... + ptr+=2; + last_pos+=4; + break; + } + if (delta<128) + *reloc_ptr++=delta&255; + else *reloc_ptr++=128|(delta>>8),*reloc_ptr++=delta&255; + if (!last_esc_num--) + last_esc=reloc_ptr,*reloc_ptr++=0,last_esc_num=3; + if (type IS_INVALID) { + *reloc_ptr++=0; + break; + } + (*last_esc)|=type<<(last_esc_num<<1); + exe_ptr++; + } + rel_global(); + exe_num=reloc_ptr-(char*)exe_data; + *reloc_ptr=0; /* (same remark as below...) */ + reloc_ptr=realloc(exe_data,exe_num+1); /* we don't know if we will need padding... */ + relocated_size=pos; + pos=out-bin; + bin=realloc(bin,pos); +#if 0 + { + unsigned int i; + for (i=0; i >8,header[3]=loader_offset&255; + *(long *)(header+4)=0; + } else { + #ifdef PC + const unsigned char header32[8]= + #else + memcpy(header,(char[]) + #endif + {0x41,0xFA,0x7F,0xF2,0x4E,0xE8,0x80,0x0C} + #ifdef PC + ; memcpy(header,header32, 8); + #else + , 8); + #endif + loader_offset+=(0x800C-2); + header[6]=loader_offset>>8,header[7]=loader_offset&255; + loader_offset-=(0x800C-2); // restore it for future use + } + bin=realloc(bin,8+12+pos+exe_num+(bss_tab.r?exeloadersize_bss:exeloadersize_nobss)); + if (!bin) + fatal("Memory"); + memmove(bin+8+12,bin,pos); + memcpy(bin,header,8); + exe_hdr[2]=pos>>8,exe_hdr[3]=pos&255; + exe_hdr[5]=(char)((relocated_size>>16)&255), + exe_hdr[6]=(char)((relocated_size>>8)&255), + exe_hdr[7]=(char)(relocated_size&255); + if (bss_tab.r) + fatal("BSS in exes are not implemented"); + memcpy(bin+8,exe_hdr,12); + memcpy(bin+8+12+pos,reloc_ptr,exe_num); + free(reloc_ptr); + memcpy(bin+8+12+pos+exe_num,bss_tab.r?exeloader_bss:exeloader_nobss, + bss_tab.r?exeloadersize_bss:exeloadersize_nobss); +#ifdef PC + if (verbose) { + msg2("RAM required during execution : %5u bytes\n",(unsigned int)relocated_size); + msg2("Memory required for EXE program : %5u bytes\n",8+12+pos+exe_num); + msg2("Memory required for EXE loader : %5u bytes\n",bss_tab.r?exeloadersize_bss:exeloadersize_nobss); + } +#endif + pos=8+12+pos+exe_num+(bss_tab.r?exeloadersize_bss:exeloadersize_nobss); + bin[pos-3]=(loader_offset+22+2)>>8,bin[pos-2]=(loader_offset+22+2)&255; +#ifdef PC + if (verbose) + msg2("Total program size : %5u bytes\n",pos); +#endif + } + } + #ifndef PC + fwrite(bin,1,pos,output); + #endif +#ifdef TWIN_COMPILE + } +#endif +#endif + } else { + rel_global(); + put_align2(); + wrt2(0); + wrt1((char)0xF3); + #ifdef PC + if (!(bin=realloc(bin,bin_size+=hshift))) + fatal("Memory"); + memmove(bin+hshift+4,bin+4,pos-4); + memcpy(bin,hdr,hshift+4); + pos+=hshift; + #else + fwrite(hdr,1,hshift+4,output); + fwrite(bin+4,1,pos-4,output); + #endif + free(hdr); + } +#ifdef OBJ_OUT + } else { + unsigned int len; + int j; + if (pos&1) + wrt1(0); + len=pos-4; + + /* reloc table */ + hshift=-4; + write_reloc(1); + + /* export table */ + j=N_HASH; + while (j--) { + SYM *sp = gsyms.h[j].head; + while (sp) { + if ((sp->storage_class == sc_external && sp->used) || + (sp->storage_class == sc_global && sp->value.splab)) { +#ifdef PC + if (!lab_src(sp->value.splab)) + fatal("UNDEF LABEL"); // should this happen ? +#endif + wrt2(lab_src(sp->value.splab)-2/*fix offset for object format*/); + } + sp = sp->next; + } + } + wrt2(0); + j=N_HASH; + while (j--) { + SYM *sp = gsyms.h[j].head; + while (sp) { + if ((sp->storage_class == sc_external && sp->used) || + (sp->storage_class == sc_global && sp->value.i != -1)) { + char *s=sp->name; + do + wrt1(*s); + while (*s++); + } + sp = sp->next; + } + } + if (pos&1) + wrt1(0); + + /* import table */ + { + GTAB *t=glb_tab; + while (t) { + REF **r=t->r; int m=N_TAB; + while (m--) { + REF *q; + if ((q=*r++)) { + while (q) { + unsigned int p,*a=q->r; + int n=N_REF; + while (n--) { + if (!(p=*a++)) + goto ref_done; + if (p&1) + fatal("Negative reloc in object output"); + // warning, this is a 16-bit reloc, but we have to store it as a 32-bit one + #define offs_convert(p) (p-2/*since 16->32 bit*/-4/*convert bin[] offsets to final object offsets*/) + if (!offs_convert(p)) + fatal("Word reloc at beginning"); + wrt2(offs_convert(p)); + #undef offs_convert + } + q=q->nxt; + } + ref_done: + wrt2(0); + } + } + t=t->nxt; + } + } + wrt2(0); + { + GTAB *t=glb_tab; int l=0x8000; + while (t) { + REF **r=t->r; int m=N_TAB; + while (m--) { + if (*r++) { + char *s=unres_name(l); + do + wrt1(*s); + while (*s++); + } + l++; + } + t=t->nxt; + } + } + if (pos&1) + wrt1(0); + wrt2(0); // leave space for future BSS extension + hdr=bin; // hack pawa =) + ovwri(0x0,pos-4); + ovwri(0x2,len+2); + #ifndef PC + wrt1(0); + wrt1('E'); + wrt1('X'); + wrt1('T'); + wrt1(0); + wrt1(0xF8); + fwrite(bin,1,pos,output); + #endif + } +#endif + #ifdef PC + { +#ifdef OBJ_OUT + if (!object) { +#endif + char *extensions[]={".89z",".9xz",".v2z"}; + for (calc=0;calc<3;calc++) { + if (calctype_used[calc]) { + unsigned int tifilelen; + extern char *calcfolder; + char *tifile=create_ti_file(calc,0x21,calcname,calcfolder,bin,pos,&tifilelen); + char *buffer; FILE *fp; + buffer=alloca(strlen(outputname)+strlen(extensions[calc])+1); + strcpy(buffer,outputname); + strcat(buffer,extensions[calc]); + if (!(fp=fopen(buffer,"wb"))) + fatal("Could not open output file."); + fwrite(tifile,1,tifilelen,fp); + free(tifile); + fclose(fp); + } + } +#ifdef OBJ_OUT + } else { + char buffer[100]; FILE *fp; + strcpy(buffer,calcname); + strcat(buffer,".ext"); + if (!(fp=fopen(buffer,"wb"))) + fatal("Could not open output file."); + fwrite(bin,1,pos,fp); + fclose(fp); + } +#endif + } + #endif + #ifdef TWIN_COMPILE + close_it: + #endif + free(bin); + bin=0; + } +} + +void bin_chk(unsigned int pos) { + while (bin_size >N_TAB_LOG; + LTAB *p=local(n)?loc_tab:(LTAB *)glb_tab,*o; + debugf("lab_set(%x,%x)\n",n,v); + global_flag+=n&0x8000; + if (!p) { + if (local(n)) + loc_tab=p=(LTAB *)xalloc(sizeof(LTAB),_TAB); + else glb_tab=(GTAB *)(p=(LTAB *)xalloc(sizeof(GTAB),_TAB)); + } + while (i--) + if (!(p=(o=p)->nxt)) + o->nxt=p=(LTAB *)xalloc(local(n)?sizeof(LTAB):sizeof(GTAB),_TAB); + global_flag&=0x7FFF; +#ifndef PC + n&=N_TAB-1; + p->t[n]=v; +#else + i=n&(N_TAB-1); + p->t[i]=v; +#endif +} + +#ifdef PC +/* that's what we use if we want the storage to be persistent, even if we call it from a + * temp_mem location + */ +void *xallocnt(int s,int m) { + void *p; + temp_local++; + p=xalloc(s,m); + temp_local--; + return p; +} +/* xallocnt in global mode */ +void *xallocntg(int s,int m) { + void *p; + global_flag++; + p=xallocnt(s,m); + global_flag--; + return p; +} +#else +#define xallocnt(s,m) _xallocnt(s) +void *_xallocnt(int s) { + void *p; + temp_local++; + p=xalloc(s,0); + temp_local--; + return p; +} +#define xallocntg(s,m) _xallocnt(s) +void *_xallocntg(int s) { + void *p; + global_flag++; + p=xallocnt(s,0); + global_flag--; + return p; +} +#endif +unsigned int lab_src(int n) { + int i=(n&0x7FFF)>>N_TAB_LOG; + LTAB *p=local(n)?loc_tab:(LTAB *)glb_tab,*o; + debugfq("lab_src(%x)",n); + global_flag+=n&0x8000; + if (!p) { + if (local(n)) + loc_tab=p=(LTAB *)xallocnt(sizeof(LTAB),_TAB); + else glb_tab=(GTAB *)(p=(LTAB *)xallocntg(sizeof(GTAB),_TAB)); + } + while (i--) + if (!(p=(o=p)->nxt)) + o->nxt=p=(LTAB *)(local(n)?xallocnt(sizeof(LTAB),_TAB):xallocntg(sizeof(GTAB),_TAB)); + global_flag&=0x7FFF; + n&=N_TAB-1; + debugf("=%x\n",p->t[n]); + return p->t[n]; +} + +RTYPE **xt_find(int n) { + int i=(n=(int)((short)~n))>>N_TAB_LOG; + XTAB *p=ext_tab,*o; + global_flag++; + if (!p) + ext_tab=p=(XTAB *)xalloc(sizeof(XTAB),_TAB); + while (i--) + if (!(p=(o=p)->nxt)) + o->nxt=p=(XTAB *)xalloc(sizeof(XTAB),_TAB); + global_flag--; + n&=N_TAB-1; + return &p->t[n]; +} + +int *exp_find(int n) { + int i=n>>N_TAB_LOG; + LTAB *p=exp_tab,*o; + global_flag++; + if (!p) + exp_tab=p=(LTAB *)xalloc(sizeof(LTAB),_TAB); + while (i--) + if (!(p=(o=p)->nxt)) + o->nxt=p=(LTAB *)xalloc(sizeof(LTAB),_TAB); + global_flag--; + n&=N_TAB-1; + return (int *)&p->t[n]; +} + +/*void loc_clear() { + LTAB *p=loc_tab,*o; + while (p) { + memset(p->t,0,sizeof(p->t)); + p=p->nxt; + } +}*/ + +unsigned int qlab_src(int n) { + int i=(n&0x7FFF)>>N_TAB_LOG; + LTAB *p=local(n)?loc_tab:(LTAB *)glb_tab; + n&=N_TAB-1; + while (i--) p=p->nxt; + return p->t[n]; +} + +REF *ref_add(REF *r,unsigned int v) { + unsigned int *a; + debugf("ref_add(%lx,%x)\n",r,v); + a=r->r; + while (*a++); + if (a>(unsigned int *)&r->nxt) { + global_flag++; + (r=r->nxt=(REF *)xalloc(sizeof(REF),_REF+REF_ADD))->r[0]=v; + global_flag--; + } else a[-1]=v; + return r; +} + +REF **glb_ref(int n) { + int i=(n&0x7FFF)>>N_TAB_LOG; + GTAB *p=glb_tab; + n&=N_TAB-1; + while (i--) + p=p->nxt; + return &p->r[n]; +} + +void lab_add_ref(int n,unsigned int r) { + int i=(n&0x7FFF)>>N_TAB_LOG; + GTAB *p=glb_tab; REF **ro; + debugf("lab_add_r(%x,%x)\n",n,r); +#ifndef PC +// asm("0: jbra 0b"); +#endif + if (local(n)) + uerrc2("local label not found: '%s'",unres_name(n)); + global_flag++; + n&=N_TAB-1; + while (i--) + p=p->nxt; + ro=&p->r[n]; + if (!*ro) + *ro=(REF *)xalloc(sizeof(REF),_REF+LAB_ADD_REF); + while ((*ro)->nxt) + ro=&(*ro)->nxt; + global_flag--; + ref_add(*ro,r); +} +void rt_add_ref(RTYPE *rt,unsigned int r) { // effectively appends reloc to reloc table + debugf("rt_add_r(%lx,%x)\n",rt,r); + if (!rt->r) { + global_flag++; + rt->r0=rt->r=(REF *)xalloc(sizeof(REF),_REF+RT_ADD_REF); + global_flag--; + } + rt->r=ref_add(rt->r,r); +} +FUNC *func_search(FUNC **f0,unsigned int f) { + while (*f0) + if ((*f0)->f==f) break; + else f0=&(*f0)->nxt; + if (*f0) return *f0; + global_flag++; + *f0=(FUNC *)xalloc(sizeof(FUNC),_RT); + global_flag--; + (*f0)->f=f; + return *f0; +} + +typedef struct gv_ret { + long i; + int ir,xr,tr; // Internal/eXternal/Total Relocation count +} GV; +int get_value(struct enode *ep,GV *r,unsigned int rp,int m) { + int lab; unsigned int p; + r->ir=0; r->xr=0; + gv_restart: + switch (ep->nodetype) { + case en_autocon: + case en_icon: +#ifndef NOFLOAT +#ifndef PC + case en_fcon: +#endif +#endif + r->i=ep->v.i; + r->tr=0; + break; +#ifndef NOFLOAT +#ifdef PC +#ifndef BCDFLT + case en_fcon: + r->i=double2ffp(ep->v.f); + r->tr=0; + break; +#endif +#endif +#endif + case en_labcon: + case en_nacon: + lab=ep->v.enlab; + r->tr=1; + if (global(lab)) { + r->ir=1; + if (!(p=lab_src(lab))) { + if (rp) + lab_add_ref(lab,(rp+2)+m); + r->i=0; + return 1; + } else + r->i=p; + } else { + if (m) uerrc("negative external reference"); + r->i=0,r->xr=1; + if (rp) { + RTYPE *rt=*xt_find(lab); + if (((long)rt)&0x80000000) { // DIRTY, but no hidden bug possible (cf xalloc) + r->i=((long)rt)&0x7FFFFFFF; // BSS ref + rt_add_ref(&bss_tab,rp); + } else rt_add_ref(rt,rp); // lib/ROM ref + } + return 1; + } + break; + case en_add: + case en_sub: + { + GV a,b; + int res=get_value(ep->v.p[0],&a,rp,m); + res|=get_value(ep->v.p[1],&b,rp,ep->nodetype==en_sub?1-m:m); + r->xr=a.xr+b.xr; + r->tr=a.tr+b.tr; + if (ep->nodetype==en_sub) { + if (b.xr) + uerrc("negative external reference"); + r->i=a.i-b.i,r->ir=a.ir-b.ir; + } else + r->i=a.i+b.i,r->ir=a.ir+b.ir; + return res; + } + break; + case en_uminus: + m=1-m; + ep=ep->v.p[0]; + goto gv_restart; + default: + uerrc("invalid expression"); + } + return 0; +} +int involved_lab(struct enode *ep) { + gv_restart: + switch (ep->nodetype) { + case en_autocon: + case en_icon: +#ifndef NOFLOAT +#ifdef PC + case en_fcon: +#endif +#endif + return -1; + case en_labcon: + case en_nacon: + return ep->v.enlab; + case en_add: + case en_sub: + return max(involved_lab(ep->v.p[0]),involved_lab(ep->v.p[1])); + case en_uminus: + ep=ep->v.p[0]; + goto gv_restart; + default: + uerrc("invalid expression"); + } + return -1; +} + +xstatic int rel CGLOB, is_long CGLOB; +long get_long(struct enode *ep,unsigned int rp) { + GV v; + get_value(ep,&v,rp,0); + if (v.ir) { + rt_add_ref(&reloc_tab,rp); + if (v.ir!=1) + uerr(ERRA_INVALIDREL); + } + rel=v.ir+v.xr; + return v.i; +} +short get_pcword(struct enode *ep,unsigned int rp) { + GV v; + int no_check=get_value(ep,&v,rp-2,0); + if (v.ir!=1 || v.xr) + uerr(ERRA_INVALIDREL); + if (!no_check) { + v.i -= rp; + if (v.i>32767L || v.i<-32768L) +#ifdef TWIN_COMPILE + { + if (!twinc_necessary) uwarn("twin compilation required"); + twinc_necessary=1; + *twinc_info++=involved_lab(ep); + *twinc_info++=rp; + } +#else + uerrc("PC-relative mode not allowed here"); +#endif +// v.i += rp; + return (short)v.i; + } else + return (short)v.i-(short)rp; +} +short get_word(struct enode *ep,unsigned int rp,int sign) { + GV v; + int no_check=get_value(ep,&v,rp-2,0); + if (v.ir || v.xr) + uerr(ERRA_INVALIDREL); + /* otherwise this would bug with myval&0xFFFF7FFF which is converted to and.w */ + if (!no_check && (v.i>(sign?32767L:65535L) || v.i<(sign?-32768L:-65535L))) +// if (!no_check && (v.i>(sign?32767L:65535L) || v.i<-32768L)) + uerrc("value can't fit in a word"); + return (short)v.i; +} +long get_offs(struct enode *ep,unsigned int rp) { + GV v; int l=0; + get_value(ep,&v,0,0); + if (v.ir || v.xr) + l=1; + if (v.i>32767L || v.i<-32768L) + l=1; + if ((is_long=l)) + return get_long(ep,rp); + else return get_word(ep,rp,1); +} +unsigned char get_byte(struct enode *ep) { + GV v; + get_value(ep,&v,0,0); + if (v.tr) + uerr(ERRA_INVALIDREL); + if ((unsigned long)(((unsigned long)v.i)+128)>255) + uerrc("value can't fit in a byte"); + return (unsigned char)v.i; +} +unsigned short get_quick(struct enode *ep) { + GV v; + get_value(ep,&v,0,0); + if (v.tr) + uerr(ERRA_INVALIDREL); + if ((unsigned long)(((unsigned long)v.i)-1)>=8) + uerrc("value can't fit in a quick constant"); + if (v.i==8) + v.i=0; + return (unsigned short)v.i; +} + +enum { + oi_move=1, + oi_moveq=oi_move+8, + oi_clr=oi_moveq+1, + oi_lea=oi_clr+1, + oi_add=oi_lea+1, + oi_addi=oi_add+4, + oi_addq=oi_addi+1, + oi_sub=oi_addq+1, + oi_subi=oi_sub+4, + oi_subq=oi_subi+1, + oi_muls=oi_subq+1, + oi_mulu=oi_muls+1, + oi_divs=oi_mulu+1, + oi_divu=oi_divs+1, + oi_and=oi_divu+1, + oi_andi=oi_and+3, + oi_or=oi_andi+1, + oi_ori=oi_or+3, + oi_eor=oi_ori+1, + oi_eori=oi_eor+2, + oi_lsl=oi_eori+1, + oi_lsr=oi_lsl+3, + oi_jmp=oi_lsr+3, + oi_jsr=oi_jmp+1, + oi_movem=oi_jsr+1, + oi_rts=oi_movem+3, + oi_bra=oi_rts+1, + oi_bsr=oi_bra+1, + oi_beq=oi_bsr+1, + oi_bne=oi_beq+1, + oi_bhs=oi_bne+1, + oi_bge=oi_bhs+1, + oi_bhi=oi_bge+1, + oi_bgt=oi_bhi+1, + oi_bls=oi_bgt+1, + oi_ble=oi_bls+1, + oi_blo=oi_ble+1, + oi_blt=oi_blo+1, + oi_tst=oi_blt+1, + oi_ext=oi_tst+1, + oi_swap=oi_ext+1, + oi_neg=oi_swap+1, + oi_not=oi_neg+1, + oi_cmp=oi_not+1, + oi_link=oi_cmp+5, + oi_unlk=oi_link+1, + oi_label=oi_unlk+1, + oi_pea=oi_label+0, + oi_cmpi=oi_pea+1, + oi_dbra=oi_cmpi+1, + oi_asr=oi_dbra+1, + oi_bset=oi_asr+3, + oi_bclr=oi_bset+4, + oi_bchg=oi_bclr+4, + _oi_asm=oi_bchg+4, + _oi_adj=_oi_asm+0, +#ifndef ASM + __oi_end=_oi_adj+0 +#endif +#ifdef ASM + /* ASM-only */ + oi_asl=_oi_adj+0, + oi_rol=oi_asl+3, + oi_ror=oi_rol+3, + oi_roxl=oi_ror+3, + oi_roxr=oi_roxl+3, + oi_btst=oi_roxr+3, + oi_exg=oi_btst+4, + oi_dc=oi_exg+4, + oi_ds=oi_dc+1, + oi_dcb=oi_ds+1, + oi_bvs=oi_dcb+1, + oi_bvc=oi_bvs+1, + oi_bpl=oi_bvc+1, + oi_bmi=oi_bpl+1, + oi_trap=oi_bmi+1, + oi_negx=oi_trap+1, + oi_addx=oi_negx+1, + oi_subx=oi_addx+2, + oi_chk=oi_subx+2, + oi_even=oi_chk+1, + oi_dbeq=oi_even+1, + oi_dbne=oi_dbeq+1, +#ifndef LIGHT_DBXX_AND_SXX + oi_dbhs=oi_dbne+1, + oi_dbge=oi_dbhs+1, + oi_dbhi=oi_dbge+1, + oi_dbgt=oi_dbhi+1, + oi_dbls=oi_dbgt+1, + oi_dble=oi_dbls+1, + oi_dblo=oi_dble+1, + oi_dblt=oi_dblo+1, + oi_dbvs=oi_dblt+1, + oi_dbvc=oi_dbvs+1, + oi_dbpl=oi_dbvc+1, + oi_dbmi=oi_dbpl+1, + oi_st=oi_dbmi+1, + oi_sf=oi_st+1, + oi_seq=oi_sf+1, + oi_sne=oi_seq+1, + oi_shs=oi_sne+1, + oi_sge=oi_shs+1, + oi_shi=oi_sge+1, + oi_sgt=oi_shi+1, + oi_sls=oi_sgt+1, + oi_sle=oi_sls+1, + oi_slo=oi_sle+1, + oi_slt=oi_slo+1, + oi_svs=oi_slt+1, + oi_svc=oi_svs+1, + oi_spl=oi_svc+1, + oi_smi=oi_spl+1, + oi_tas=oi_smi+1, + __oi_end=oi_tas+1 +#else + __oi_end=oi_dbne+1 +#endif +#endif +}; + +readonly unsigned char opi[_op_max+2]={ + oi_move, oi_moveq, oi_clr, oi_lea, oi_add, oi_addi, oi_addq, oi_sub, oi_subi, oi_subq, + oi_muls, oi_mulu, oi_divs, oi_divu, oi_and, oi_andi, oi_or, oi_ori, oi_eor, oi_eori, + oi_lsl, oi_lsr, oi_jmp, oi_jsr, oi_movem, + oi_rts, oi_bra, oi_bsr, oi_beq, oi_bne, oi_bhs, oi_bge, oi_bhi, + oi_bgt, oi_bls, oi_ble, oi_blo, oi_blt, oi_tst, oi_ext, oi_swap, oi_neg, oi_not, oi_cmp, + oi_link, oi_unlk, oi_label, oi_pea, oi_cmpi, oi_dbra, oi_asr, + oi_bset, oi_bclr, oi_bchg, _oi_asm, _oi_adj, +#ifdef ASM + /* ASM-only */ + oi_asl, oi_rol, oi_ror, oi_roxl, oi_roxr, oi_btst, oi_exg, oi_dc, oi_ds, oi_dcb, + oi_bvs, oi_bvc, oi_bpl, oi_bmi, oi_trap, oi_negx, oi_addx, oi_subx, oi_chk, oi_even, + oi_dbeq, oi_dbne, +#ifndef LIGHT_DBXX_AND_SXX + oi_dbhs, oi_dbge, oi_dbhi, oi_dbgt, oi_dbls, oi_dble, oi_dblo, oi_dblt,/* unsigned, signed */ + oi_dbvs, oi_dbvc, oi_dbpl, oi_dbmi, + oi_st, oi_sf, oi_seq, oi_sne, + oi_shs, oi_sge, oi_shi, oi_sgt, oi_sls, oi_sle, oi_slo, oi_slt, /* unsigned, signed */ + oi_svs, oi_svc, oi_spl, oi_smi, oi_tas, +#endif +#endif + __oi_end +}; + +typedef struct _opcode { + char impl,nargs,model,lenf; + unsigned short bo; + int a1,a2; +} OPCODE; +enum { + M_BASIC, M_BASICSWAPPED, M_BRANCH, M_DC, M_ALIGN +}; +enum { L_0=1<<0, L_1=1<<1, L_2=1<<2, L_4=1<<4 }; +enum { + A_DREG=0x1, + A_AREG=0x2, + A_MEM0=0x4, + A_MEM=0x84, + A_PCR=0x8, + A_IMM=0x10, + A_MASK1=0x20, + A_MASK2=0x40, + A_ADEC=0x80, + D_RAW2=0x0100, // |= %00000000 00000000 +WORD + D_RAW=0x0200, // |= %00000000 00000000 (+DAT) + D_LOW=0x0400, // |= %00000000 dddddddd + D_EA2=0x0800, // |= %0000nnnm mm000000 (+DAT) + D_SZ3=0x3000, // |= %00000000 0S000000 (argument-independent) + D_SZ2=0x1000, // |= %0000000S 00000000 (argument-independent) + D_SZ=0x2000, // |= %00000000 ss000000 (argument-independent) + D_Q=0x4000, // |= %0000qqq0 00000000 + D_EA=0x8000, // |= %00000000 00mmmnnn (+DAT) +}; +#define A_CCR A_MASK1 +#define A_SR A_MASK2 +#define A_USP A_MASK1 +/* we have to implement A_CCR and A_SR like that to avoid the use + * of a longword for flags... */ +#define A_SRC A_DREG|A_AREG|A_MEM|A_PCR|A_IMM +#define A_SRC2 A_DREG|A_MEM|A_PCR|A_IMM +#define A_DST A_DREG|A_AREG|A_MEM +#define A_DST2 A_DREG|A_MEM + +// for each enum(e_op) value : +readonly OPCODE ops[]={ + // op_label + {0}, + // op_move + {1,2,M_BASIC,L_2,0x3000,A_SRC|D_EA,A_DST|D_EA2}, // movea is in fact the same instruction + {1,2,M_BASIC,L_4,0x2000,A_SRC|D_EA,A_DST|D_EA2}, + {1,2,M_BASIC,L_1,0x1000,A_SRC2|D_EA,A_DST2|D_EA2}, // move.b does not accept aregs + {1,2,M_BASIC,L_2,0x44C0,A_SRC2|D_EA,A_CCR}, + {1,2,M_BASIC,L_2,0x46C0,A_SRC2|D_EA,A_SR}, + {1,2,M_BASIC,L_2,0x40C0,A_SR,A_DST2|D_EA}, + {1,2,M_BASIC,L_4,0x4E60,A_AREG|D_LOW,A_USP}, + {1,2,M_BASIC,L_4,0x4E68,A_USP,A_AREG|D_LOW}, + // op_moveq + {1,2,M_BASIC,L_0+L_4,0x7000,A_IMM|D_LOW,A_DREG|D_Q}, + // op_clr + {1,1,M_BASIC,L_1+L_2+L_4,0x4200,A_DST2|D_EA|D_SZ}, + // op_lea + {1,2,M_BASIC,L_0,0x41C0,A_MEM|A_PCR|D_EA,A_AREG|D_Q}, + // op_add + {1,2,M_BASIC,L_1+L_2+L_4,0xD000,A_SRC|D_EA|D_SZ,A_DREG|D_Q}, + {1,2,M_BASIC,L_1+L_2+L_4,0xD100,A_DREG|D_Q|D_SZ,A_MEM|D_EA}, + {1,2,M_BASIC, L_2+L_4,0xD0C0,A_SRC|D_EA|D_SZ2,A_AREG|D_Q}, + {1,2,M_BASIC,L_1+L_2+L_4,0x0600,A_IMM|D_RAW|D_SZ,A_DST2|D_EA}, + // op_addi + {1,2,M_BASIC,L_1+L_2+L_4,0x0600,A_IMM|D_RAW|D_SZ,A_DST2|D_EA}, + // op_addq + {1,2,M_BASIC,L_1+L_2+L_4,0x5000,A_IMM|D_Q|D_SZ,A_DST|D_EA}, + // op_sub + {1,2,M_BASIC,L_1+L_2+L_4,0x9000,A_SRC|D_EA|D_SZ,A_DREG|D_Q}, + {1,2,M_BASIC,L_1+L_2+L_4,0x9100,A_DREG|D_Q|D_SZ,A_MEM|D_EA}, + {1,2,M_BASIC, L_2+L_4,0x90C0,A_SRC|D_EA|D_SZ2,A_AREG|D_Q}, + {1,2,M_BASIC,L_1+L_2+L_4,0x0400,A_IMM|D_RAW|D_SZ,A_DST2|D_EA}, + // op_subi + {1,2,M_BASIC,L_1+L_2+L_4,0x0400,A_IMM|D_RAW|D_SZ,A_DST2|D_EA}, + // op_subq + {1,2,M_BASIC,L_1+L_2+L_4,0x5100,A_IMM|D_Q|D_SZ,A_DST|D_EA}, + // op_muls + {1,2,M_BASIC,L_2,0xC1C0,A_SRC2|D_EA,A_DREG|D_Q}, + // op_mulu + {1,2,M_BASIC,L_2,0xC0C0,A_SRC2|D_EA,A_DREG|D_Q}, + // op_divs + {1,2,M_BASIC,L_2,0x81C0,A_SRC2|D_EA,A_DREG|D_Q}, + // op_divu + {1,2,M_BASIC,L_2,0x80C0,A_SRC2|D_EA,A_DREG|D_Q}, + // op_and + {1,2,M_BASIC,L_1+L_2+L_4,0xC000,A_SRC2|D_EA|D_SZ,A_DREG|D_Q}, + {1,2,M_BASIC,L_1+L_2+L_4,0xC100,A_DREG|D_Q|D_SZ,A_MEM|D_EA}, + {1,2,M_BASIC,L_1+L_2+L_4,0x0200,A_IMM|D_RAW|D_SZ,A_DST2|D_EA}, + // op_andi + {1,2,M_BASIC,L_1+L_2+L_4,0x0200,A_IMM|D_RAW|D_SZ,A_DST2|D_EA}, + // op_or + {1,2,M_BASIC,L_1+L_2+L_4,0x8000,A_SRC2|D_EA|D_SZ,A_DREG|D_Q}, + {1,2,M_BASIC,L_1+L_2+L_4,0x8100,A_DREG|D_Q|D_SZ,A_MEM|D_EA}, + {1,2,M_BASIC,L_1+L_2+L_4,0x0000,A_IMM|D_RAW|D_SZ,A_DST2|D_EA}, + // op_ori + {1,2,M_BASIC,L_1+L_2+L_4,0x0000,A_IMM|D_RAW|D_SZ,A_DST2|D_EA}, + // op_eor + {1,2,M_BASIC,L_1+L_2+L_4,0xB100,A_DREG|D_Q|D_SZ,A_DST2|D_EA}, + {1,2,M_BASIC,L_1+L_2+L_4,0x0A00,A_IMM|D_RAW|D_SZ,A_DST2|D_EA}, + // op_eori + {1,2,M_BASIC,L_1+L_2+L_4,0x0A00,A_IMM|D_RAW|D_SZ,A_DST2|D_EA}, + // op_lsl + {1,2,M_BASIC,L_1+L_2+L_4,0xE108,A_IMM|D_Q|D_SZ,A_DREG|D_EA}, + {1,2,M_BASIC,L_1+L_2+L_4,0xE128,A_DREG|D_Q|D_SZ,A_DREG|D_EA}, + {1,1,M_BASIC,L_2,0xE3C0,A_MEM|D_EA}, + // op_lsr + {1,2,M_BASIC,L_1+L_2+L_4,0xE008,A_IMM|D_Q|D_SZ,A_DREG|D_EA}, + {1,2,M_BASIC,L_1+L_2+L_4,0xE028,A_DREG|D_Q|D_SZ,A_DREG|D_EA}, + {1,1,M_BASIC,L_2,0xE2C0,A_MEM|D_EA}, + // op_jmp + {1,1,M_BASIC,L_0,0x4EC0,A_MEM|A_PCR|D_EA}, + // op_jsr + {1,1,M_BASIC,L_0,0x4E80,A_MEM|A_PCR|D_EA}, + // op_movem - contains a little hack : default size is .l, so we separe L_4 from L_2. + // Uses M_BASICSWAPPED because when 'uses_link' is set, the link reg needs to be after + // the reg mask. + {1,2,M_BASIC,L_4,0x4880,A_MASK1|D_RAW|D_SZ3,A_MEM|D_EA}, /* LBUG : A_MEM&~POST_I */ + {1,2,M_BASIC,L_2,0x4880,A_MASK1|D_RAW|D_SZ3,A_MEM|D_EA}, /* LBUG : A_MEM&~POST_I */ + {1,2,M_BASICSWAPPED,L_2+L_4,0x4C80,A_MASK2|D_RAW,A_MEM0|D_EA|D_SZ3}, + // op_rts + {1,0,M_BASIC,L_0,0x4E75}, + // op_bra + {1,1,M_BRANCH,L_0+L_1+L_2,0x6000}, + // op_bsr + {1,1,M_BRANCH,L_0+L_1+L_2,0x6100}, + // op_beq + {1,1,M_BRANCH,L_0+L_1+L_2,0x6700}, + // op_bne + {1,1,M_BRANCH,L_0+L_1+L_2,0x6600}, + // op_bhs + {1,1,M_BRANCH,L_0+L_1+L_2,0x6400}, + // op_bge + {1,1,M_BRANCH,L_0+L_1+L_2,0x6C00}, + // op_bhi + {1,1,M_BRANCH,L_0+L_1+L_2,0x6200}, + // op_bgt + {1,1,M_BRANCH,L_0+L_1+L_2,0x6E00}, + // op_bls + {1,1,M_BRANCH,L_0+L_1+L_2,0x6300}, + // op_ble + {1,1,M_BRANCH,L_0+L_1+L_2,0x6F00}, + // op_blo + {1,1,M_BRANCH,L_0+L_1+L_2,0x6500}, + // op_blt + {1,1,M_BRANCH,L_0+L_1+L_2,0x6D00}, + // op_tst + {1,1,M_BASIC,L_1+L_2+L_4,0x4A00,A_DST2|D_EA|D_SZ}, + // op_ext + {1,1,M_BASIC,L_2+L_4,0x4880,A_DREG|D_EA|D_SZ3}, + // op_swap + {1,1,M_BASIC,L_4,0x4840,A_DREG|D_EA}, + // op_neg + {1,1,M_BASIC,L_1+L_2+L_4,0x4400,A_DST2|D_EA|D_SZ}, + // op_not + {1,1,M_BASIC,L_1+L_2+L_4,0x4600,A_DST2|D_EA|D_SZ}, + // op_cmp + {1,2,M_BASIC,L_1+L_2+L_4,0xB000,A_SRC2|D_EA|D_SZ,A_DREG|D_Q}, + {1,2,M_BASIC, L_2+L_4,0xB000,A_AREG|D_EA|D_SZ,A_DREG|D_Q}, + {1,2,M_BASIC, L_2+L_4,0xB0C0,A_SRC|D_EA|D_SZ2,A_AREG|D_Q}, +/* {1,2,M_BASIC, L_2 ,0xB100,A_SRC2|D_EA|D_SZ,A_AREG|D_Q}, + {1,2,M_BASIC, L_4,0xB1C0,A_SRC2|D_EA|D_SZ,A_AREG|D_Q},*/ + {1,2,M_BASIC,L_1+L_2+L_4,0x0C00,A_IMM|D_RAW|D_SZ,A_DST2|D_EA}, + {1,2,M_BASIC,L_1+L_2+L_4,0xB108,A_MEM0|D_LOW|D_SZ,A_MEM0|D_Q}, // hum; other modes than A_AINC will generate an internal error (#8451/8452) + // op_link + {1,2,M_BASIC,L_2,0x4E50,A_AREG|D_LOW,A_IMM|D_RAW}, + // op_unlk + {1,1,M_BASIC,L_2,0x4E58,A_AREG|D_LOW}, + // op_pea + {1,1,M_BASIC,L_0,0x4840,A_MEM|A_PCR|D_EA}, + // op_cmpi + {1,2,M_BASIC,L_1+L_2+L_4,0x0C00,A_IMM|D_RAW|D_SZ,A_DST2|D_EA}, + // op_dbra + {1,2,M_BRANCH,L_2,0x51C8,A_DREG|D_LOW}, + // op_asr + {1,2,M_BASIC,L_1+L_2+L_4,0xE000,A_IMM|D_Q|D_SZ,A_DREG|D_EA}, + {1,2,M_BASIC,L_1+L_2+L_4,0xE020,A_DREG|D_Q|D_SZ,A_DREG|D_EA}, + {1,1,M_BASIC,L_2,0xE0C0,A_MEM|D_EA}, + // op_bset + {1,2,M_BASIC,L_0+L_1,0x08C0,A_IMM|D_RAW2,A_MEM|D_EA}, + {1,2,M_BASIC,L_0+L_4,0x08C0,A_IMM|D_RAW2,A_DREG|D_EA}, + {1,2,M_BASIC,L_0+L_1,0x01C0,A_DREG|D_Q,A_MEM|D_EA}, + {1,2,M_BASIC,L_0+L_4,0x01C0,A_DREG|D_Q,A_DREG|D_EA}, + // op_bclr + {1,2,M_BASIC,L_0+L_1,0x0880,A_IMM|D_RAW2,A_MEM|D_EA}, + {1,2,M_BASIC,L_0+L_4,0x0880,A_IMM|D_RAW2,A_DREG|D_EA}, + {1,2,M_BASIC,L_0+L_1,0x0180,A_DREG|D_Q,A_MEM|D_EA}, + {1,2,M_BASIC,L_0+L_4,0x0180,A_DREG|D_Q,A_DREG|D_EA}, + // op_bchg + {1,2,M_BASIC,L_0+L_1,0x0840,A_IMM|D_RAW2,A_MEM|D_EA}, + {1,2,M_BASIC,L_0+L_4,0x0840,A_IMM|D_RAW2,A_DREG|D_EA}, + {1,2,M_BASIC,L_0+L_1,0x0140,A_DREG|D_Q,A_MEM|D_EA}, + {1,2,M_BASIC,L_0+L_4,0x0140,A_DREG|D_Q,A_DREG|D_EA}, +#ifdef ASM + /* ASM-only */ + // op_asl + {1,2,M_BASIC,L_1+L_2+L_4,0xE100,A_IMM|D_Q|D_SZ,A_DREG|D_EA}, + {1,2,M_BASIC,L_1+L_2+L_4,0xE120,A_DREG|D_Q|D_SZ,A_DREG|D_EA}, + {1,1,M_BASIC,L_2,0xE1C0,A_MEM|D_EA}, + // op_rol + {1,2,M_BASIC,L_1+L_2+L_4,0xE118,A_IMM|D_Q|D_SZ,A_DREG|D_EA}, + {1,2,M_BASIC,L_1+L_2+L_4,0xE138,A_DREG|D_Q|D_SZ,A_DREG|D_EA}, + {1,1,M_BASIC,L_2,0xE7C0,A_MEM|D_EA}, + // op_ror + {1,2,M_BASIC,L_1+L_2+L_4,0xE018,A_IMM|D_Q|D_SZ,A_DREG|D_EA}, + {1,2,M_BASIC,L_1+L_2+L_4,0xE038,A_DREG|D_Q|D_SZ,A_DREG|D_EA}, + {1,1,M_BASIC,L_2,0xE6C0,A_MEM|D_EA}, + // op_roxl + {1,2,M_BASIC,L_1+L_2+L_4,0xE110,A_IMM|D_Q|D_SZ,A_DREG|D_EA}, + {1,2,M_BASIC,L_1+L_2+L_4,0xE130,A_DREG|D_Q|D_SZ,A_DREG|D_EA}, + {1,1,M_BASIC,L_2,0xE5C0,A_MEM|D_EA}, + // op_roxr + {1,2,M_BASIC,L_1+L_2+L_4,0xE010,A_IMM|D_Q|D_SZ,A_DREG|D_EA}, + {1,2,M_BASIC,L_1+L_2+L_4,0xE030,A_DREG|D_Q|D_SZ,A_DREG|D_EA}, + {1,1,M_BASIC,L_2,0xE4C0,A_MEM|D_EA}, + // op_btst + {1,2,M_BASIC,L_0+L_1,0x0800,A_IMM|D_RAW2,A_MEM|D_EA}, + {1,2,M_BASIC,L_0+L_4,0x0800,A_IMM|D_RAW2,A_DREG|D_EA}, + {1,2,M_BASIC,L_0+L_1,0x0100,A_DREG|D_Q,A_MEM|D_EA}, + {1,2,M_BASIC,L_0+L_4,0x0100,A_DREG|D_Q,A_DREG|D_EA}, + // op_exg + {1,2,M_BASIC,L_0+L_4,0xC140,A_DREG|D_LOW,A_DREG|D_Q}, + {1,2,M_BASIC,L_0+L_4,0xC148,A_AREG|D_LOW,A_AREG|D_Q}, + {1,2,M_BASIC,L_0+L_4,0xC188,A_AREG|D_LOW,A_DREG|D_Q}, + {1,2,M_BASIC,L_0+L_4,0xC188,A_DREG|D_Q,A_AREG|D_LOW}, + // op_dc + {1,1,M_DC,0,-1}, + // op_ds + {1,1,M_DC,0,0}, + // op_dcb + {1,2,M_DC,0,1}, + // op_bvs + {1,1,M_BRANCH,L_0+L_1+L_2,0x6900}, + // op_bvc + {1,1,M_BRANCH,L_0+L_1+L_2,0x6800}, + // op_bpl + {1,1,M_BRANCH,L_0+L_1+L_2,0x6A00}, + // op_bmi + {1,1,M_BRANCH,L_0+L_1+L_2,0x6B00}, + // op_trap + {1,1,M_BASIC,L_0,0x4E40,A_IMM|D_LOW}, + // op_negx + {1,1,M_BASIC,L_1+L_2+L_4,0x4000,A_DST2|D_EA|D_SZ}, + // op_addx + {1,2,M_BASIC,L_1+L_2+L_4,0xD100,A_DREG|D_LOW|D_SZ,A_DREG|D_Q}, + {1,2,M_BASIC,L_1+L_2+L_4,0xD108,A_ADEC|D_LOW|D_SZ,A_ADEC|D_Q}, + // op_subx + {1,2,M_BASIC,L_1+L_2+L_4,0x9100,A_DREG|D_LOW|D_SZ,A_DREG|D_Q}, + {1,2,M_BASIC,L_1+L_2+L_4,0x9108,A_ADEC|D_LOW|D_SZ,A_ADEC|D_Q}, + // op_chk + {1,2,M_BASIC,L_2,0x4180,A_SRC2|D_EA,A_DREG|D_Q}, + // op_even + {1,0,M_ALIGN,L_0,2}, + // op_dbeq + {1,2,M_BRANCH,L_2,0x57C8,A_DREG|D_LOW}, + // op_dbne + {1,2,M_BRANCH,L_2,0x56C8,A_DREG|D_LOW}, +#ifndef LIGHT_DBXX_AND_SXX + // op_dbhs + {1,2,M_BRANCH,L_2,0x54C8,A_DREG|D_LOW}, + // op_dbge + {1,2,M_BRANCH,L_2,0x5CC8,A_DREG|D_LOW}, + // op_dbhi + {1,2,M_BRANCH,L_2,0x52C8,A_DREG|D_LOW}, + // op_dbgt + {1,2,M_BRANCH,L_2,0x5EC8,A_DREG|D_LOW}, + // op_dbls + {1,2,M_BRANCH,L_2,0x53C8,A_DREG|D_LOW}, + // op_dble + {1,2,M_BRANCH,L_2,0x5FC8,A_DREG|D_LOW}, + // op_dblo + {1,2,M_BRANCH,L_2,0x55C8,A_DREG|D_LOW}, + // op_dblt + {1,2,M_BRANCH,L_2,0x5DC8,A_DREG|D_LOW}, + // op_dbvs + {1,2,M_BRANCH,L_2,0x59C8,A_DREG|D_LOW}, + // op_dbvc + {1,2,M_BRANCH,L_2,0x58C8,A_DREG|D_LOW}, + // op_dbpl + {1,2,M_BRANCH,L_2,0x5AC8,A_DREG|D_LOW}, + // op_dbmi + {1,2,M_BRANCH,L_2,0x5BC8,A_DREG|D_LOW}, + // op_st + {1,1,M_BASIC,L_1,0x50C0,A_DST2|D_EA}, + // op_sf + {1,1,M_BASIC,L_1,0x51C0,A_DST2|D_EA}, + // op_seq + {1,1,M_BASIC,L_1,0x57C0,A_DST2|D_EA}, + // op_sne + {1,1,M_BASIC,L_1,0x56C0,A_DST2|D_EA}, + // op_shs + {1,1,M_BASIC,L_1,0x54C0,A_DST2|D_EA}, + // op_sge + {1,1,M_BASIC,L_1,0x5CC0,A_DST2|D_EA}, + // op_shi + {1,1,M_BASIC,L_1,0x52C0,A_DST2|D_EA}, + // op_sgt + {1,1,M_BASIC,L_1,0x5EC0,A_DST2|D_EA}, + // op_sls + {1,1,M_BASIC,L_1,0x53C0,A_DST2|D_EA}, + // op_sle + {1,1,M_BASIC,L_1,0x5FC0,A_DST2|D_EA}, + // op_slo + {1,1,M_BASIC,L_1,0x55C0,A_DST2|D_EA}, + // op_slt + {1,1,M_BASIC,L_1,0x5DC0,A_DST2|D_EA}, + // op_svs + {1,1,M_BASIC,L_1,0x59C0,A_DST2|D_EA}, + // op_svc + {1,1,M_BASIC,L_1,0x58C0,A_DST2|D_EA}, + // op_spl + {1,1,M_BASIC,L_1,0x5AC0,A_DST2|D_EA}, + // op_smi + {1,1,M_BASIC,L_1,0x5BC0,A_DST2|D_EA}, + // op_tas + {1,1,M_BASIC,L_1,0x4AC0,A_DST2|D_EA}, +#endif +#endif +}; + +void wrt4(long x) { + if (odd) fatal("ALIGN"); + bin_chk(pos+=4); +#ifdef PC + bin[pos-4]=(unsigned char)(x>>24); + bin[pos-3]=(unsigned char)(x>>16); + bin[pos-2]=(unsigned char)(x>>8); + bin[pos-1]=(unsigned char)(x); +#else + *(long *)(bin+pos-4)=x; +#endif +#ifdef PC + if ((pos^odd)&1) + fatal("INT/ODD"); +#endif +} +void wrt2(short x) { + if (odd) fatal("ALIGN"); + bin_chk(pos+=2); +#ifdef PC + bin[pos-2]=(unsigned char)(x>>8); + bin[pos-1]=(unsigned char)(x); +#else + *(short *)(bin+pos-2)=x; +#endif +#ifdef PC + if ((pos^odd)&1) + fatal("INT/ODD"); +#endif +} +void wrt1(char x) { + bin_chk(pos+=1); +#ifdef PC + bin[pos-1]=(unsigned char)(x); +#else + *(char *)(bin+pos-1)=x; +#endif + odd=~odd; +#ifdef PC + if ((pos^odd)&1) + fatal("INT/ODD"); +#endif +} +void fill(int n) { + if (odd) wrt1(0); + bin_chk(pos+=n); + memset(bin+pos-n,0,n); + odd = -(n&1); +} +void move_pos(long diff) { /* caution : only works in overwrite mode */ + odd^=-(diff&1); + pos+=diff; +} +void rewrite(long size) { + bin_chk(pos+=size); + memcpy(bin+(pos-size),bin+(pos-2*size),size); + odd^=-(size&1); +#ifdef PC + if ((pos^odd)&1) + fatal("INT/ODD"); +#endif +} + +readonly int sz_table[]={0,0,0,0,0,2,2,2,0,0,2,2,2,2,4,0,0,0}; + +readonly struct enode zero={en_icon,0,0,{0},0,0}; +readonly struct amode am_null={am_direct,(struct enode *)&zero,0,0,0,0}; +#define ip_lab (((struct lbls *)ip)->lab) +void pass1() { + struct ocode *ip=scope_head; + OPCODE *op; + unsigned int vpos=pos; + while (ip) { + int opt,sz,n,f; + struct amode *ap; + int c=opi[ip->opcode],nm=opi[ip->opcode+1]-c; + int orig_len=ip->length; + int argnum_ok=0; +/* if (ip->opcode==_op_adj) { + sz=0; opt=0; c=-1; + goto ok; + }*/ + err_cur_line=ip->line; + if (!nm) { + if (ip->opcode!=op_label) + fatal("P1: UNIMPL"); + { + if (!local(ip_lab) && lab_src(ip_lab)) { + char *name=unres_name(ip_lab); + while (ip && ip->opcode==op_label) ip=ip->fwd; + if (ip) err_cur_line=ip->line-1; + else err_assembly=0; + uerrc2("label '%s' redefined",name); + } + lab_set(ip_lab,vpos); + ip->opcode=0; + sz=0; + goto ok_lab; + } + } + nm--; do { + opt=0; + op=(OPCODE *)&ops[c]; + if ((!(n=op->nargs) && ip->oper1) || (n==1 && (!ip->oper1 || ip->oper2)) + || (n==2 && !ip->oper2)) + goto nxt; + argnum_ok++; + ip->length=orig_len; + switch (op->model) { + case M_BASICSWAPPED: /* caution : assumes that it is the sole M_BASICSWAPPED */ + ap=ip->oper1; /* and that it is placed at the very end... */ + ip->oper1=ip->oper2; + ip->oper2=ap; + /* FALLTHROUGH */ + case M_BASIC: + if (!((f=op->lenf) & (1< length))) { + if (!ip->length) { + if (!(f & (1<<2))) { + if (!(f & (1<<4))) + ip->length=1; + else ip->length=4; + } else ip->length=2; + } else goto nxt; + } + sz=2; + ap=ip->oper1; + f=op->a1; + while (n--) { + int m=ap->mode; + if (!(f& + (m length?(m==am_ainc?A_MEM0:A_ADEC):0) + ) + ) + : + (m offset->nodetype==en_labcon + || ap->offset->nodetype==en_nacon) && +#ifndef LARGE_MODEL + global(ap->offset->v.enlab) +#else + local(ap->offset->v.enlab) +#endif +#ifdef TWIN_COMPILE + && (!twinc_prev || + ((tclab=twinc_prev[0],tcoff=twinc_prev[1], + twinc_prev+=2, + tclab!=ap->offset->v.enlab||abs(tcoff-vpos)>=5000) + && (twinc_prev-=2,1))) +#endif + )) { + /*if (ap->offset->v.enlab==0xFFFF8032) + bkpt();*/ + m=am_pcrel; + } else { + get_offs(ap->offset,0); + if (is_long) + m=am_dirl; + else m=am_dirw; + } + ap = *(ap==ip->oper1 ? &ip->oper1 : &ip->oper2) = copy_addr(ap); + /* this is because the same operand might be either pcrel or + dirl, depending on the instruction/place of the operand */ + ap->mode=m; + } +#ifdef TWIN_COMPILE + } +#endif + if (f&D_RAW2) + sz+=2; + else if ((f&D_RAW) && m==am_immed) + sz+=(ip->length+1)&-2; + else if (!(f&(D_Q|D_LOW))) + sz+=(m==am_immed?(ip->length+1)&-2:sz_table[m]); + ap=ip->oper2; + f=op->a2; + } + break; + case M_BRANCH: + if (n==1) { // Bcc + if (ip->oper1->offset->nodetype!=en_labcon + && ip->oper1->offset->nodetype!=en_nacon) +// fatal("BRANCH"); + uerrc("invalid branch"); + n=ip->oper1->offset->v.enlab; + if (!global(n)) +// fatal("XT BRANCH"); + uerrc("invalid branch"); + if (ip->length==2) opt=0,sz=4; + else { + if ((f=lab_src(n))) { + f-=vpos; + opt=(f>129 || f<-126); // all branches are backwards so we needn't + // handle branches to next stmt in this pass + } else opt=1; + sz=2+(opt<<1); + } + } else { // DBcc + if ((ip->oper2->offset->nodetype!=en_labcon + && ip->oper2->offset->nodetype!=en_nacon) + || (ip->oper1->mode!=am_dreg)) +// fatal("DBRANCH"); + uerrc("invalid branch"); + n=ip->oper2->offset->v.enlab; + if (!global(n)) +// fatal("XT BRANCH"); + uerrc("invalid branch"); + sz=4; + } + break; +#ifdef ASM + case M_DC: + f=ip->length-2; + if (f<=0) f++; // f=log_2(ip->length) + if (ip->oper1->mode!=am_direct) +// fatal("DC"); + uerrc("invalid declaration"); + sz=1; + if (((short)op->bo)>=0) { + if (ip->oper1->offset->nodetype!=en_icon) + uerrc("invalid declaration"); + sz=ip->oper1->offset->v.i; + if (op->bo && ip->oper2->mode!=am_direct) + uerrc("invalid declaration"); + } + sz<<=f; + if (sz>=128) + uerrsys("too many elements in 'dc' instruction; use C arrays"); + break; + case M_ALIGN: + sz=0; + if (vpos&1) { + sz=1; + c=oi_dc; + ip->length=1; + ip->oper1=(struct amode *)&am_null; + } + break; + default: + fatal("P1"); + sz=0; + break; +#endif + } + goto ok; + nxt: + c++; + } while (nm--); + if (!argnum_ok) + uerrc2("instruction requires %d arguments",n); + uerrc("invalid address modes"); + return; +// fatal("P1: INVALID"); + ok: +#ifdef SIZE_STATS + if (!ip->opt) /* not from an asm() statement */ + c_compiler_sz+=sz; /* note this is approximative, but close to reality */ +#endif + ip->opt=opt; + ip->sz=sz; + ip->opcode=c; + ok_lab: + ip=ip->fwd; + vpos+=sz; + } +} + +void pass2() { + struct ocode *ip=scope_head; + unsigned int vpos=pos,opos=vpos,s; + OPCODE *op; + while (ip) { + if (ip->opcode>0) { + s=ip->sz; + if (ip->opt) { + op=(OPCODE *)&ops[ip->opcode]; + switch (op->model) { + case M_BASIC: case M_BASICSWAPPED: + break; + case M_BRANCH: { // this is necessarily a Bcc since ip->opt==1 + int n=ip->oper1->offset->v.enlab; + long f=qlab_src(n); + if (!f) break; // global label not found + if ((unsigned int)f>opos) // we HAVE TO compare with opos (since opos>=vpos) + f-=opos+2; // <- here, f is afterwards, so relative to old pos + else f-=vpos+2; + /* the case of the next stmt branch : + * PASS 1 : the label is unknown, so opt=1 and ip->sz=4 + * PASS 2 : qlab_src(n)-opos==4, so here, f==2 (rather than f==0) */ + if (f!=2 && f>=-128 && f<=127) + ip->sz=2; + else if (f>=-32768 && f<=32767) + ip->sz=4; + else err_cur_line=ip->line, uerrc("branch size can't fit in a word"); + } break; + } + } + opos+=s, vpos+=ip->sz; + } else if (!ip->opcode) {// op_label +/* if (vpos==0x2642) + printf("rjo");*/ + lab_set(ip_lab,vpos); + } +/* else { // _op_adj + + }*/ + ip=ip->fwd; + } +} + +int movem(short x) { + int n=0; + while (x) { + if (x<0) n++; + x+=x; + } + return n; +} + +void pass3() { + struct ocode *ip=scope_head; +#ifdef PC + unsigned int opos=pos; +#endif + OPCODE *op; + while (ip) { + int n,f; + struct amode *ap; + short code; + if (ip->opcode>0) { + err_cur_line=ip->line; + op=(OPCODE *)&ops[ip->opcode]; + n=op->nargs; + switch (op->model) { + case M_BASIC: case M_BASICSWAPPED: { + int ds=0,ds2=0; int len=ip->length; +#ifdef PC + long dc=0xdddddddd,dc2=0xdddddddd; +#else + long dc=dc,dc2=dc2; +#endif + unsigned int vpos=pos+2; + code=op->bo; + ap=ip->oper1; + f=op->a1; +#ifndef USE_LINK + if (n) + if (ap->preg==STACKPTR-8) { + if (ap->mode==am_ainc) { // for (a7)+,... + lc_stk-=len+(len&1); + } else if (ap->mode==am_adec) + lc_stk+=len+(len&1); // for clr -(a7) + } +#endif + while (n--) { + if ((f&D_SZ3)==D_SZ3) { + if (len==4) code|=0x40; + } else if (f&D_SZ) + code|=(len==2?0x40:(len==4?0x80:0x00)); + else if ((f&D_SZ2) && len==4) + code|=0x100; + if (f&D_EA) + switch (ap->mode) { + case am_areg: + case am_ind: + case am_ainc: + case am_adec: + code+=ap->mode<<3; + case am_dreg: + code+=ap->preg; + break; + case am_indx: +#ifndef USE_LINK + if (ap->preg==FRAMEPTR-8) { + if (uses_link) + ap->preg+=TRUE_FRAMEPTR-FRAMEPTR; + else { + ap->preg+=STACKPTR-FRAMEPTR; + ap->offset->v.i += lc_stk - (ap->offset->v.i>0 ? 4 : 0); + uses_lc_stk = 1; + } + } +#endif + code+=0x28+ap->preg; + ds=1; dc=get_word(ap->offset,vpos,1); + break; + case am_pcrel: + code+=0x3A; + ds=1; dc=get_pcword(ap->offset,vpos); // rel to vpos, not pos! + break; + case am_dirw: + code+=0x38; + ds=1; dc=get_word(ap->offset,vpos,1); + break; + case am_dirl: + code+=0x39; + ds=2; dc=get_long(ap->offset,vpos); + break; + case am_immed: + code+=0x3C; + ds=(1+len)>>1; + if (ds==1) dc=get_word(ap->offset,vpos,0); + else dc=get_long(ap->offset,vpos); + break; + case am_indx2: + code+=0x30+ap->preg; + ds=1; + dc=get_byte(ap->offset)+((short)ap->sreg<<12)+ + (ap->slen==4?0x0800:0x0000); + break; + case am_indx3: + code+=0x30+ap->preg; + ds=1; + dc=get_byte(ap->offset)+((short)ap->sreg<<12)+ + (ap->slen==4?0x8800:0x8000); + break; +#ifdef PC + default: + ierr(PASS3,1); +#endif + } + else if (f&D_EA2) + switch (ap->mode) { + case am_areg: + case am_ind: + case am_ainc: + case am_adec: + code+=ap->mode<<6; + case am_dreg: + code+=((short)ap->preg)<<9; + break; + case am_indx: +#ifndef USE_LINK + if (ap->preg==FRAMEPTR-8) { + if (uses_link) + ap->preg+=TRUE_FRAMEPTR-FRAMEPTR; + else { + ap->preg+=STACKPTR-FRAMEPTR; + ap->offset->v.i += lc_stk - (ap->offset->v.i>0 ? 4 : 0); + uses_lc_stk = 1; + } + } +#endif + code+=(0x28<<3)+((short)ap->preg<<9); + ds=1; dc=get_word(ap->offset,vpos,1); + break; +/* case am_pcrel: + code+=(0x38<<3)+(0x02<<9); + ds=1; dc=get_pcword(ap->offset,vpos); // rel to vpos, not pos! + break;*/ + case am_dirw: + code+=0x38<<3; + ds=1; dc=get_word(ap->offset,vpos,1); + break; + case am_dirl: + code+=(0x38<<3)+(0x01<<9); + ds=2; dc=get_long(ap->offset,vpos); + break; + case am_indx2: + code+=(0x30<<3)+(ap->preg<<9); + ds=1; + dc=get_byte(ap->offset)+((short)ap->sreg<<12)+ + (ap->slen==4?0x0800:0x0000); + break; + case am_indx3: + code+=(0x30<<3)+(ap->preg<<9); + ds=1; + dc=get_byte(ap->offset)+((short)ap->sreg<<12)+ + (ap->slen==4?0x8800:0x8000); + break; +#ifdef PC + default: + ierr(PASS3,2); +#endif + } + else if (f&D_Q) + switch (ap->mode) { + case am_areg: + case am_dreg: + case am_ainc: + case am_adec: + code+=((unsigned short)ap->preg)<<9; + break; + case am_immed: + code+=get_quick(ap->offset)<<9; + break; +#ifdef PC + default: + ierr(PASS3,3); +#endif + } + else if (f&D_LOW) + switch (ap->mode) { + case am_areg: + case am_dreg: + case am_adec: + case am_ainc: + code+=ap->preg; + break; + case am_immed: + code+=get_byte(ap->offset); + break; +#ifdef PC + default: + ierr(PASS3,4); +#endif + } + else if (f&D_RAW) + switch (ap->mode) { + case am_immed: + if (len==4) + ds=2,dc=get_long(ap->offset,vpos); + else + ds=1,dc=get_word(ap->offset,vpos,0); + break; + case am_mask1: + case am_mask2: + ds=1; dc=ap->offset->v.i; + break; +#ifdef PC + default: + ierr(PASS3,5); +#endif + } + else if (f&D_RAW2) + ds=1,dc=get_word(ap->offset,vpos,0); + ap=ip->oper2; + f=op->a2; + vpos+=ds<<1; + if (n) { + ds2=ds,dc2=dc,ds=0; +#ifndef USE_LINK + if (ap->preg==STACKPTR-8) { + if (ap->mode==am_adec) { // for ...,-(a7) + if (ip->oper1->mode==am_mask1) + lc_stk+=movem((short)ip->oper1->offset->v.i)<<(len>>1); + else lc_stk+=len+(len&1); + } + else if (ap->mode==am_ainc && ip->oper1->mode==am_mask2) + lc_stk-=movem((short)ip->oper1->offset->v.i)<<(len>>1); + } +#endif + } + } +#ifndef USE_LINK + if (code==0x4FEF // lea x(a7),a7 + || (code&0xF13F)==0x500F // addq.* #x,a7 + || (code&0xFEFF)==0xDEFC) // add.* #x,a7 + lc_stk-=ip->oper1->offset->v.i; + else if ((code&0xF13F)==0x510F // subq.* #x,a7 + || (code&0xFEFF)==0x9EFC) // sub.* #x,a7 + lc_stk+=ip->oper1->offset->v.i; + else if (((code&0xFFC0)==0x4840 && (code&0x0038/*!swap*/))) // pea + lc_stk+=4; +#endif + wrt2(code); + if (--ds2>=0) { + if (!ds2) wrt2((short)dc2); + else wrt4(dc2); + } + if (--ds>=0) { + if (!ds) wrt2((short)dc); + else wrt4(dc); + } + } break; + case M_BRANCH: { + unsigned int vpos=pos+2; + code=op->bo; + if (ip->oper2) // DBcc + n=ip->oper2->offset->v.enlab, code+=ip->oper1->preg; + else n=ip->oper1->offset->v.enlab; // Bcc + if ((f=qlab_src(n))) { + if (ip->sz==2) + wrt2(code|=(f-vpos)&0xFF); + else + wrt2(code),wrt2((short)(f-vpos)); + } else + wrt2(code),wrt2((short)-(short)vpos),lab_add_ref(n,vpos); + } break; + case M_DC: { + struct enode *ep=ip->oper1->offset; + n=1; + if (((short)op->bo)>=0) { + n=ip->oper1->offset->v.i; + if (op->bo) + ep=ip->oper2->offset; + else ep=(struct enode *)&zero; + } + f=ip->length-2; + while (n--) { + if (f<0) { + GV v; + get_value(ep,&v,0,0); + if (v.tr) + uerr(ERRA_INVALIDREL); + if (v.i>255 || v.i<-128) + uerrc("result can't fit in a byte"); + wrt1((char)v.i); + } else if (!f) wrt2(get_word(ep,pos,0)); + else wrt4(get_long(ep,pos)); + } + } break; + } +#ifdef PC + opos+=ip->sz; + if (pos!=opos) { +// printf("%d",oi_ds); + ierr(PASS3,6); + } +#endif + } +/* else if (ip->opcode) { // _op_adj + + }*/ + else if (!ip->opcode) { // op_label +//#ifdef PC +// if (pos!=qlab_src(ip_lab)) +// ierr(PASS3,7); +//#endif + if (pos!=qlab_src(ip_lab)) + uerrc2("label '%s' defined twice",unres_name(ip_lab)); + if (!local(ip_lab)) { + lab_set(ip_lab,0); // 'unset' it so there will be no error... + set_label(ip_lab,pos); + } + } + ip=ip->fwd; + } +} + +void scope_flush(void) { + err_assembly=1; + pass1(); + pass2(); + pass3(); + err_assembly=0; + if (uses_lc_stk && lc_stk) { + uwarn("stack displacement of %d: compiler bug?",(int)lc_stk); + iwarn(WARN_LC_STK,1); + } + scope_head = 0; + loc_tab = 0; +} + +void scope_init(void) { + if (scope_head) scope_flush(); + lc_stk = 0; + uses_lc_stk = 0; + nextlabel = 1; + loc_tab = 0; +} + +void local_clean(void) { /* remove local symbols from alsyms -- to be called just before rel_local */ + HTABLE *tab=&alsyms; + SYM *ttail,**prv; + struct htab *root; + int i; + if (!tab->hash) + ierr(TABLE_HASH,2); +#ifdef PC + if (tab->hash!=0x2489) + ierr(TABLE_HASH,1); +#endif + i=N_HASH; + while (i--) { + prv=&((root=&tab->h[i])->tail); + while ((ttail=*prv)) { + if (local(ttail->value.splab)) { +// *prv = ttail->prev; + if (ttail->next) ttail->next->prev = ttail->prev; + if (ttail->prev) ttail->prev->next = ttail->next; +// ttail->next = prv; + if (root->tail==ttail) root->tail=ttail->prev; + if (root->head==ttail) root->head=ttail->next; +/* if (!root->tail) + root->head=0;*/ + } + prv = &(ttail->prev); + } + } +} + +int label(char *s) { + int lab; SYM *sp; +/* if (!strcmp(s,"__L_plane") || !strcmp(s,"__D_plane")) + bkpt();*/ + if (!(sp=search(s,-1,&alsyms))) { + if (s[0]!='\\') + global_flag++; + sp=(SYM *)xalloc((int)sizeof(SYM),_SYM); + sp->name=strsave(s); + if (s[0]=='\\') + lab_src(sp->value.splab=lab=nxtlabel()); + else if (internal(s)) + lab_src(sp->value.splab=lab=nxtglabel()); + else + sp->value.splab=lab=extlabel--; + insert(sp,&alsyms); + if (s[0]!='\\') + global_flag--; + } else + lab=sp->value.splab; + debugf("label(%s)=%x\n",s,lab); +#ifdef PC +/* if (lab==0x806d) + bkpt();*/ + if (!*s) + return lab; +#endif + return lab; +} + +void set_label(int lab,unsigned int pos) { + /*if ((unsigned short)lab==0x8014) + bkpt();*/ + debugf("set_lab(%x,%x)\n",lab,pos); + if (lab_src(lab)) uerrc("label redefinition"); + if (global(lab)) { + lab_set(lab,pos); + if (!local(lab)) { + REF **rp,*r; + unsigned int p,*a; int n; + r=*(rp=glb_ref(lab)); + while (r) { + a=r->r; + n=N_REF; + while (n--) { + if (!(p=*a++)) + goto ref_done; +#ifdef PC + { int m=p&1; short a,olda; + p-=m; + a=(bin[p]<<8)+bin[p+1],olda=a; + if (m) { + if ((a-=pos)>0 && olda) fatal("PC RANGE 3"); + } else if ((a+=pos)<0 && olda) fatal("PC RANGE 2"); + bin[p]=(unsigned char)(a>>8); + bin[p+1]=(unsigned char)(a); + } +#else + if (p&1) { + short *z=(short *)(bin+(p&-2)); + if (*z && ((*z)-=pos)>0) + fatal("PC RANGE 3"); + else (*z)-=pos; + } else if ((*(short *)(bin+p)+=pos)<0 && *(short *)(bin+p)!=pos) + fatal("PC RANGE 2"); +#endif + } + r=r->nxt; + } + ref_done: + *rp=0; + } + } + else debugf(" --local\n"); +} + +void put_label(int lab) { +/* + * output a compiler generated label. + */ +#ifdef NO_OUT + return; +#endif + set_label(lab,pos); +} + +void g_strlab(char *s) { +/* + * generate a named label. + */ +#ifdef NO_OUT + return; +#endif + put_label(label(s)); +} + +void genbyte(int val) { +#ifdef NO_OUT + return; +#endif + wrt1((char)val); +} + +void genword(int val) { +#ifdef NO_OUT + return; +#endif + put_align2(); + wrt2((short)val); +} + +typedef struct _pc_bcd_s { + short exponent; + unsigned char mantissa[8]; +} _pc_bcd; +#ifndef NOFLOAT +void genfloat(double val) { +#ifndef BCDFLT + put_align2(); + wrt4(double2ffp(val)); +#else + BCD bcd; + double2bcd(val,&bcd); + wrt2(bcd.exponent); +#ifdef PC + { + int i; + for (i=0;i tp->size; +#ifdef NO_OUT + return; +#endif +#ifdef PC +#define no_bss (nostub_mode || forbid_bss) +#else +#define no_bss nostub_mode +#endif + if (align!=1) put_align2(); + size=(size+1)&-2; // round size + if (sp->value.splab) { + if (no_bss) { /* that's OK in _nostub mode :) */ + if (lab_src(sp->value.splab)) + return; + } else + uerrc2("BSS redeclaration of '%s' : use 'extern' for prototyping",sp->name); + } else if (no_bss) { + if (sp->storage_class==sc_static) + sp->value.splab=nxtglabel(); + else + sp->value.splab=label(sp->name); + } + if (no_bss) { + put_label(sp->value.splab); + fill(size); + } else { + *(long *)xt_find(sp->value.splab=extlabel--)=lc_bss|0x80000000; // DIRTY, but no hidden + lc_bss+=size; // bug possible + } // (cf xalloc) +#if 0 + remain = size % AL_DEFAULT; + if (remain != 0) + size = size + AL_DEFAULT - remain; + if (sp->storage_class == sc_static) { + fprintf(output, "L%ld:" tabs "ds.b %ld\n", sp->value.i, size); + lc_bss += sp->tp->size; + } else + fprintf(output, "L%d:" tabs "ds.b %ld\n", label(sp->name),size); +#endif +#undef no_bss +} + +void dumplits() { +/* + * dump the string literal pool. + */ + char *cp; + int len; +/* + * The ACK assembler may produce a .text section of an uneven length. + * This will eventually bomb the linker when it tries to relocate + * something in a following (.data) section, which then is misaligned + * as a whole in memory (perhaps this is just a bug in the linker). + * + * To avoid this (it can only happen if the string pool is the last + * thing dumped to the assembler file) we count the total number of + * bytes in the string pool and emit a zero filler byte if that + * number was uneven. + * This is perhaps an ugly hack, but in virtually all of the cases + * this filler byte is inserted anyway by the assembler when + * doing the alignment necessary for the next function body. + */ +// long count=0; + + while (strtab != 0) { + cseg(); + nl(); + put_label((unsigned int) strtab->label); + cp = strtab->str; + len = strtab->len; + //count += (len+1); + while (len--) + wrt1(*cp++); + wrt1(0); + strtab = strtab->next; + } + put_align2(); +} + + +void put_align2(void) { +/* align the following data to 2 */ + if (odd) wrt1(0); +} +/*put_align(align) + int align; +// align the following data +{ + switch (align) { + case 1: + break; + case 2: + if (odd) wrt1(0); + } +}*/ + +#ifdef LISTING +void put_external(char *s) { +/* put the definition of an external name in the ouput file */ + +} +void put_global(char *s) { +/* put the definition of a global name in the output file */ + +} +#endif + +/*cseg() +{ + if (curseg != codeseg) { + nl(); +#ifdef PC + fputs(tabs ".text\n", output); +#endif + curseg = codeseg; + } +}*/ +/*dseg() +{ + if (curseg != dataseg) { + nl(); +#ifdef PC + fputs(tabs ".data\n", output); +#endif + curseg = dataseg; + } +}*/ + +int radix16(char c) { + if (isdigit(c)) + return c - '0'; +/* if (c >= 'a' && c <= 'z') + return c - 'a' + 10;*/ + if (c >= 'A' && c <= 'Z') + return c - 'A' + 10; + return -1; +} +int hexatoi(char *s) { + int x=0; + if (strlen(s)>3) return -1; + while (*s) { + int y=radix16(*s++); + if (y<0) return -1; + x<<=4; x+=y; + } + return x; +} + +int internal(char *s) { + int n=0; + char c,old=0,*p; + if (*s == '.') + return 1; + p=s; + while ((c=*p++)) { + if (n==10) { + if ((( +#ifdef FLINE_RC + !fline_rc && +#endif + !strncmp(s,"_ROM_CALL_",10))) +#ifdef RAM_CALLS + || !strncmp(s,"_RAM_CALL_",10) +#endif + ) { + int f=hexatoi(p-1); + if (f<0) + goto cont; + *xt_find(extlabel)=&(func_search( +#ifdef RAM_CALLS + s[2]=='O' ? &rom_funcs : &ram_funcs +#else + &rom_funcs +#endif + ,f))->rt; + return 0; + } + } + if (n==export_pfx_len) { + if (!strncmp(s,export_pfx,n)) { + int f=hexatoi(p); + if (f<0) + goto cont3; + *exp_find(f)=glblabel; + return 1; + } + } + if (c=='_' && n && old=='_' && *p=='0') { + SYM *sp; + int f=hexatoi(p+1); + if (f<0) + goto cont2; + p[-2]=0; + if (!(sp=search(s,-1,(HTABLE *)&libsyms))) { + global_flag++; + sp=(SYM *)xalloc((int)sizeof(SYM),_SYM); + sp->name=strsave(s); + insert(sp,(HTABLE *)&libsyms); + global_flag--; + } + *xt_find(extlabel)=&(func_search((FUNC **)&sp->value.i,f))->rt; + p[-2]='_'; + return 0; + } + cont: + cont2: + cont3: + old=c; n++; + } + return 1; +} + +#ifdef PCH +unsigned char *_end_of(short *p) { /* works endian-independently */ + while (*p++); + return (unsigned char *)p; +} +unsigned char *_end_of2(short *p) { /* works endian-independently */ + while (*p++ || *p); + return (unsigned char *)(p+1); +} +#define end_of(p) _end_of((short *)(p)) +#define end_of2(p) _end_of2((short *)(p)) + + +#ifndef isidch +#ifdef PC +static int isidch(char c) { + return (c>='0'&&c<='9') || (c>='A'&&c<='Z') || (c>='a'&&c<='z') + || c == '_' || c == '$'; +} +#else +#define isidch(___c) ({register short __c=(___c); \ +(__c>='0'&&__c<='9') || (__c>='A'&&__c<='Z') || (__c>='a'&&__c<='z') || __c=='_' || __c=='$';}) +#endif +#endif + +int pchsearch(char *id,int mode); +#define lscan(x) pchsearch(x,PCHS_ADD) +#define lexpand(x) (x) +/*#define lscan (void)lexpand +void macro_expansion(char *in,char *inbound); +char lexp_buf[100]; +char *lexpand(char *s) { + char c,*p=lexp_buf; + strcpy(p,s); + macro_expansion(p,&lexp_buf[100]); + if (*p>='0' && *p<='9') + return s; + while ((c=*p++)) + if (!isidch(c)) return s; + return lexp_buf; +}*/ + +#ifdef PC +#define g16(p) (p+=2,(p[-2]<<8)+p[-1]) +#define r16(o) ((ext[o]<<8)+ext[o+1]) +#define align(strp) if ((strp-ext)&1) strp++ +#else +#define g16(p) (*((int *)p)++) +#define r16(o) (*(int *)(ext+o)) +#define align(strp) if (((short)((long)strp))&1) strp++ +#endif +void extscan(unsigned char *ext) { + int codeOff=r16(0); + unsigned char *offp=ext+codeOff,*strp; + /* reloc table */ + offp=end_of(offp); + /* export table */ + strp=end_of(offp); + while (g16(offp)) + while (*strp++); + align(strp); + /* import table */ + offp=strp; strp=end_of2(offp); + while (*(short *)offp) { + lscan(strp); + offp=end_of(offp); + while (*strp++); + } +} + +#undef off // for TI-GCC :D +#ifdef PC +#define add_offs(val,offs) do { \ + short a=bin[offs+0]<<8; \ + a+=bin[offs+1]; \ + a+=val; \ + bin[offs+0]=(unsigned char)(a>>8); \ + bin[offs+1]=(unsigned char)(a); \ + } while (0) +#else +#define add_offs(val,offs) (*(short *)(bin+offs)+=val) +#endif + +void extload(unsigned char *ext) { + int codeOff=r16(0); unsigned int wriOff; + SYM *sp; + if (odd) wrt1(0); +/*#ifdef PC + if (codeOff>=0x2000) + printf("gfio"); +#endif*/ + /* In the following case, either the .ext has already been loaded, either + * there is a conflict, in which case the error will arise at the end + * (what's more, it allows for overriding of the default functions) */ + sp=search(end_of(end_of(ext+codeOff)),-1,&alsyms); + if (sp && lab_src(sp->value.splab)) + return; + wriOff=pos-2; /* since offsets are based on ext::$00, not on ext::$02=code */ + bin_chk(pos+=codeOff-2); + memcpy(bin+pos-codeOff+2,ext+2,codeOff-2); + { + /* reloc table */ + unsigned short off; unsigned char *offp=ext+codeOff; + while ((off=g16(offp))) { + rt_add_ref(&reloc_tab,off+wriOff); + add_offs(wriOff+2,off+wriOff+2); + } + { + /* export table */ + unsigned char *strp=end_of(offp); + while ((off=g16(offp))) { + set_label(label(strp),off+wriOff); + while (*strp++); + } + align(strp); + /* import table */ + offp=strp; strp=end_of2(offp); + while (*(short *)offp) { + int n=label(lexpand(strp)); unsigned int p=lab_src(n); + while ((off=g16(offp))) { + off+=wriOff; + if (p) { +#ifdef PC + unsigned short a=bin[off+2]<<8; + a+=bin[off+3]; + a+=p; + bin[off+2]=(unsigned char)(a>>8); + bin[off+3]=(unsigned char)(a); +#else + *(short *)(bin+off+2)+=p; +#endif + /* if (ip->sz==2) + wrt2(code|=(f-vpos)&0xFF); + else wrt2(code),wrt2((short)(f-vpos));*/ + } else + lab_add_ref(n,off+2); + rt_add_ref(&reloc_tab,off); + } + while (*strp++); + } + } + } +} +#endif + +#endif /* MC680X0 */ +// vim:ts=4:sw=4 diff --git a/gtc/src/out68k_exe.h b/gtc/src/out68k_exe.h new file mode 100644 index 0000000..87e2a1c --- /dev/null +++ b/gtc/src/out68k_exe.h @@ -0,0 +1,71 @@ +/* + * GTools C compiler + * ================= + * source file : + * EXE loader + * + * Copyright 2001-2004 Paul Froissart. + * Credits to Christoph van Wuellen and Matthew Brandt. + * All commercial rights reserved. + * + * This compiler may be redistributed as long there is no + * commercial interest. The compiler must not be redistributed + * without its full sources. This notice must stay intact. + */ + +#define exeloadersize_bss (-1) +readonly unsigned char exeloader_bss[1]; +#define exeloadersize_nobss sizeof(exeloader_nobss) +readonly unsigned char exeloader_nobss[]={ + 0x4f,0xef,0x00,0x30,0x4e,0x75,0x20,0x78,0x00,0xc8,0x0c,0xa0,0x54,0x8f,0x4e,0x75, + 0x66,0xf8,0x42,0x67,0x2f,0x08,0x48,0xe7,0x1f,0x3e,0x47,0xf9,0x00,0x00,0x00,0x00, + 0x7a,0xf2,0xda,0x8b,0x24,0x78,0x00,0xc8,0x76,0x00,0x36,0x2b,0x00,0x0c,0x2f,0x13, + 0x20,0x6a,0x02,0x48,0x4e,0x90,0x58,0x8f,0x3f,0x00,0x67,0xc4,0x20,0x6a,0x02,0x58, + 0x4e,0x90,0x3e,0x1f,0x28,0x48,0x22,0x4c,0xd3,0xd3,0x93,0xc3,0x2c,0x09,0x41,0xeb, + 0x00,0x08,0x4e,0xba,0x01,0x2c,0x20,0x46,0x22,0x4c,0x70,0x00,0x30,0x23,0x47,0xf3, + 0x08,0x0a,0x61,0x00,0x00,0x9e,0x3f,0x47,0x00,0x2c,0x48,0x54,0x3f,0x3c,0x00,0x0a, + 0x42,0xa7,0x20,0x6a,0x01,0xb0,0x4e,0x90,0x5c,0x8f,0x26,0x08,0x78,0x00,0x08,0x28, + 0x00,0x02,0x00,0x0a,0x67,0x10,0x3f,0x28,0x00,0x0c,0x20,0x6a,0x02,0x58,0x4e,0x90, + 0x54,0x8f,0xba,0x88,0x67,0x0a,0x20,0x6a,0x01,0xb4,0x4e,0x90,0x26,0x08,0x66,0xde, + 0x48,0xe7,0x1f,0x3e,0x48,0x7a,0x00,0x52,0x20,0x78,0x00,0xc8,0x0c,0xa0,0x00,0x00, + 0x03,0xe8,0x65,0x48,0x26,0x6f,0x00,0x2c,0x20,0x08,0xe1,0x98,0x6b,0x12,0x0c,0x57, + 0x00,0x04,0x64,0x38,0x26,0x7c,0x00,0x03,0xe0,0x00,0x58,0x57,0x58,0x6f,0x00,0x2c, + 0xef,0x98,0x72,0x70,0xc2,0x80,0x52,0x81,0x48,0x41,0xe3,0x99,0x24,0x17,0x2f,0x01, + 0x2f,0x01,0x4f,0xef,0xff,0xf4,0x4e,0x4c,0x46,0xfc,0x27,0x00,0x2f,0x02,0x42,0x67, + 0x76,0x0f,0x20,0x78,0x00,0xac,0x4e,0xd0,0x4f,0xef,0x00,0x14,0x4c,0xdf,0x7c,0xf9, + 0x4e,0x75,0x48,0xe7,0x18,0x1c,0x72,0x00,0x70,0x00,0x10,0x1b,0x67,0x00,0x00,0x6c, + 0x6a,0x06,0xd0,0x00,0xef,0x48,0x10,0x1b,0x55,0x40,0x65,0x2e,0x60,0x02,0x32,0xd8, + 0x38,0x10,0x76,0xc0,0x86,0x44,0x5c,0x43,0x67,0x0e,0xc8,0x7c,0xf0,0xff,0xb8,0x7c, + 0x60,0x00,0x57,0xc8,0xff,0xea,0x66,0x10,0x53,0x40,0x65,0x0c,0x32,0xd8,0x36,0x09, + 0x96,0x4c,0x97,0x50,0x51,0xc8,0xff,0xd8,0x32,0xd8,0x51,0xc9,0x00,0x06,0x58,0x41, + 0x14,0x1b,0x4a,0x13,0x67,0x24,0xd4,0x02,0x65,0x0e,0x42,0x59,0x32,0xd8,0x20,0x0c, + 0xd4,0x02,0xd1,0xa9,0xff,0xfc,0x60,0xa0,0xd4,0x02,0x30,0x18,0x6b,0x04,0x32,0xfc, + 0x4e,0xb9,0xe5,0x48,0x22,0xf2,0x00,0x00,0x60,0x8e,0x4c,0xdf,0x38,0x18,0x4e,0x75, + 0x48,0xe7,0x1f,0x3e,0x7a,0xff,0x42,0x05,0x47,0xfa,0x01,0x70,0x50,0x88,0x70,0x00, + 0x10,0x18,0x38,0x00,0x72,0x00,0x12,0x18,0x3c,0x41,0xd0,0x40,0x36,0x33,0x00,0x02, + 0x70,0x08,0x90,0x44,0x38,0x40,0x24,0x48,0x12,0x18,0xd2,0x41,0x4b,0xf3,0x10,0x02, + 0x70,0x00,0x10,0x18,0xd0,0xc0,0x7e,0x00,0x9e,0x44,0x6a,0x08,0x50,0x47,0x16,0x86, + 0x3c,0x13,0x1c,0x18,0x32,0x06,0xee,0x69,0xc2,0x43,0xb2,0x4e,0x67,0x14,0x9e,0x4c, + 0x6a,0x08,0x50,0x47,0x16,0x86,0x3c,0x13,0x1c,0x18,0x32,0x06,0xee,0x69,0x12,0xc1, + 0x60,0xd6,0x61,0x4e,0x4a,0x41,0x67,0x00,0x00,0x8e,0x30,0x02,0x61,0x44,0x0c,0x42, + 0x00,0xff,0x66,0x06,0x4c,0xdf,0x7c,0xf8,0x4e,0x75,0x53,0x42,0x12,0x12,0x67,0x08, + 0xe3,0x6a,0x61,0x60,0xc2,0x55,0x84,0x41,0x16,0x82,0x32,0x13,0x74,0xff,0xb3,0x42, + 0x61,0x58,0x14,0x01,0x47,0xf1,0x28,0x00,0x12,0xdb,0x51,0xc8,0xff,0xfc,0x47,0xfa, + 0x00,0xda,0x60,0x94,0x61,0x44,0x82,0x45,0x12,0xf1,0x10,0x00,0x12,0xf1,0x10,0x00, + 0x60,0x86,0x72,0xff,0x51,0xcf,0x00,0x0a,0x50,0x47,0x16,0x86,0x3c,0x13,0x1c,0x18, + 0x52,0x41,0x0f,0x06,0x57,0xcf,0xff,0xfa,0x66,0xee,0x9e,0x41,0x6a,0x08,0x50,0x47, + 0x16,0x86,0x3c,0x13,0x1c,0x18,0x34,0x06,0xee,0x6a,0x03,0xc2,0xd2,0x41,0xc4,0x73, + 0x10,0x04,0x4e,0x75,0x9e,0x41,0x6a,0x08,0x50,0x47,0x16,0x86,0x3c,0x13,0x1c,0x18, + 0x32,0x06,0xee,0x69,0x4e,0x75,0x51,0xcf,0x00,0x0a,0x50,0x47,0x16,0x86,0x3c,0x13, + 0x1c,0x18,0x0f,0x06,0x67,0x9e,0x51,0xcf,0x00,0x0a,0x50,0x47,0x16,0x86,0x3c,0x13, + 0x1c,0x18,0x0f,0x06,0x66,0x20,0x32,0x04,0x61,0xca,0xc2,0x43,0x30,0x0e,0x3c,0x41, + 0x32,0x0c,0xe3,0x68,0x61,0xbe,0x34,0x0c,0xd4,0x42,0xc2,0x73,0x20,0x02,0x80,0x41, + 0x12,0xc0,0x60,0x00,0xff,0x04,0x61,0x00,0xff,0x7a,0x30,0x02,0x0c,0x40,0x00,0x80, + 0x6d,0x10,0x72,0x01,0x61,0x9e,0x10,0x01,0x61,0x00,0xff,0x68,0x53,0x02,0xe1,0x4a, + 0x80,0x42,0x61,0x00,0xff,0x5e,0x04,0x42,0x00,0x20,0x6a,0x06,0x14,0x32,0x20,0x21, + 0x60,0x0e,0xe7,0x4a,0x72,0x03,0x61,0x00,0xff,0x7c,0x02,0x41,0x00,0x07,0x84,0x41, + 0x12,0xc2,0x51,0xc8,0xff,0xfc,0x60,0x00,0xfe,0xc0,0x00,0x00,0x00,0x00,0x00,0x01, + 0x00,0x03,0x00,0x07,0x00,0x0f,0x00,0x1f,0x00,0x3f,0x00,0x7f,0x00,0xff,0x01,0xff, + 0x03,0xff,0x07,0xff,0x0f,0xff,0x1f,0xff,0x3f,0xff,0x7f,0xff,0x00,0x00,0x00,0x0c, + 0x00,0x1c,0xf3, +}; diff --git a/gtc/src/pch.h b/gtc/src/pch.h new file mode 100644 index 0000000..977beb3 --- /dev/null +++ b/gtc/src/pch.h @@ -0,0 +1,53 @@ +/* + * GTools C compiler + * ================= + * source file : + * PCH management definitions + * + * Copyright 2001-2004 Paul Froissart. + * Credits to Christoph van Wuellen and Matthew Brandt. + * All commercial rights reserved. + * + * This compiler may be redistributed as long there is no + * commercial interest. The compiler must not be redistributed + * without its full sources. This notice must stay intact. + */ + +#ifndef PCH_H +#define PCH_H + +typedef struct { + TI_LONG magic; + TI_SHORT h_off; // offset to .H section + TI_SHORT ext_off; // offset to .EXT table (int ext_table[nExt]) + TI_SHORT dic_off; // offset to dictionnary ((char[]) sPk_table[]) + TI_SHORT nID; +} PCH_HEAD; + +#define PCH_HEAD_SIZE 12 + +#define PCHID_MASK 0xFFF +#define PCHID_MACRO 0x8000 +#define PCHID_VAMAC 0x4000 +#define PCHID_PACKED 0x2000 + +#ifndef PC +char *__attribute__((stkparm)) sUnpack(char *in,char *out,char *dic); +#else +char *sUnpack(char *in,char *out,char *dic); +#endif + +/* GTC-only */ +extern FILE *pchfile[]; +extern char *pchdata[]; +extern char *pchtab[]; +extern char pchname[][15]; +extern char pchrequired[]; +extern int pchnum; +#define pchhead ((PCH_HEAD **)pchdata) + +/* PchMaker-only */ +extern int def_is_packed; + +#endif +// vim:ts=4:sw=4 diff --git a/gtc/src/peep68k.c b/gtc/src/peep68k.c new file mode 100644 index 0000000..4566ae1 --- /dev/null +++ b/gtc/src/peep68k.c @@ -0,0 +1,1291 @@ +/* + * GTools C compiler + * ================= + * source file : + * peephole optimizations + * + * Copyright 2001-2004 Paul Froissart. + * Credits to Christoph van Wuellen and Matthew Brandt. + * All commercial rights reserved. + * + * This compiler may be redistributed as long there is no + * commercial interest. The compiler must not be redistributed + * without its full sources. This notice must stay intact. + */ + +#define NEWLAB +//#define NO_PEEP + +#include "define.h" +_FILE(__FILE__) +#include "c.h" +#include "expr.h" +#include "gen.h" +#include "cglbdec.h" +#ifndef NOFLOAT +#include "ffplib.h" +#endif + +#ifdef MC680X0 + +extern struct enode *regexp[REGEXP_SIZE]; +struct ocode *_peep_head CGLOB; +extern struct ocode *scope_head; +#ifdef SPEED_OPT +int speed_opt_value CGLOB; +#endif +#ifndef VCG +struct ocode *peep_head CGLOB; +#else +struct ocode *vcg_peep_head[VCG_MAX+1] CGLOBL; +struct ocode *vcg_peep_tail[VCG_MAX+1] CGLOBL; +int vcg_lvl CGLOB; +#define peep_head vcg_peep_head[vcg_lvl] +#define peep_tail vcg_peep_tail[vcg_lvl] +#endif +xstatic struct ocode *next_ip CGLOB; +xstatic struct ocode *last_param_pop CGLOB; + +#define getop1(__ip) (__ip->oper1->offset->v.i) +#define getoplab(__ip) (__ip->oper1->offset->v.enlab) +#define getop2(__ip) (__ip->oper2->offset->v.i) +#ifdef NEWLAB +#define getlab(__ip) (((struct lbls *)__ip)->lab) +#else +#define getlab(__ip) (__ip->oper1->offset->v.i) +#endif +/*static enum(e_op) revcond[] = { op_bne, op_beq, op_bge, op_bgt, op_ble, op_blt, + op_bls, op_blo, op_bhs, op_bhi };*/ +xstatic readonly enum(e_op) revcond[] = + { + op_bne, op_beq, op_blo, op_blt, op_bls, op_ble, op_bhi, op_bgt, op_bhs, op_bge + }; + +void add_peep(struct ocode *new_ocode); +void opt3(void); + +void g_code(enum(e_op) op, int len, struct amode *ap1, struct amode *ap2) { +/* + * generate a code sequence into the peep list. + */ + struct ocode *new_ocode; + new_ocode = (struct ocode *) xalloc((int) sizeof(struct ocode), OCODE+G_CODE); + new_ocode->opcode = op; + new_ocode->length = len; + if ((unsigned int)len>4 || len==3) + ierr(G_CODE,1); + new_ocode->oper1 = ap1; + new_ocode->oper2 = ap2; +#ifdef PC +/* if (op>=op_add && op<=op_subq && ap1->mode>am_areg && ap2->mode>am_areg + && ap1->mode!=am_immed) + fatal("INVALID INSTRUCTION"); + if ((long)new_ocode==0x7a6314) + bkpt();*/ +/* if (lineid==1157) + bkpt();*/ +#endif +#ifdef DB_POSSIBLE + new_ocode->line=lineid; +#endif + add_peep(new_ocode); +} + +void g_coder(enum(e_op) op, int len, struct amode *ap1, struct amode *ap2) { +/* + * generate a code sequence and put it in front of the list + */ + struct ocode *new_ocode; + new_ocode = (struct ocode *) xalloc((int) sizeof(struct ocode), OCODE+G_CODE); + new_ocode->opcode = op; + new_ocode->length = len; + new_ocode->oper1 = ap1; + new_ocode->oper2 = ap2; +#ifdef DB_POSSIBLE + new_ocode->line=lineid; +#endif + if (peep_head == 0) { + /* must use add_peep to take care of peep_tail */ + add_peep(new_ocode); + } else { + new_ocode->back = 0; + new_ocode->fwd = peep_head; + peep_head->back = new_ocode; + peep_head = new_ocode; + /* peep_tail does not change */ + } +} + +/* should be in add_peep(), but SConvert would put it in the text */ +/* segment, preventing it from being modified */ +#ifndef VCG +xstatic struct ocode *peep_tail CGLOB; +#endif + +void add_peep(struct ocode *new_ocode) { +/* + * add the ocode pointed to by new to the peep list. + */ + if (peep_head == 0) { + peep_head = peep_tail = new_ocode; + } else { + new_ocode->back = peep_tail; + peep_tail->fwd = new_ocode; + peep_tail = new_ocode; + } +#ifndef NOFLOAT + if (new_ocode->opcode==op_jsr && new_ocode->oper1->mode==en_nacon) { + struct enode *ep=new_ocode->oper1->offset; + char *s=ep->v.ensp; + if (!strcmp("iround",s) || !strcmp("uround",s) || !strcmp("ifloor",s)) { + int lab=nxtlabel(); +#ifdef AS + ep->v.enlab=label( +#endif + ep->v.ensp=strsave(s[0]=='i'?str(ffpftol):str(ffpftou)) +#ifdef AS + ) +#endif + ; + g_code(s[1]=='r'?op_bhs:op_bge, 1, mk_label(lab), NIL_AMODE); + g_code(s[1]=='r'?op_addq:op_subq, 4, mk_immed(1), + (struct amode *) xalloc((int) sizeof(struct amode), AMODE)); + #ifdef NO_CALLOC + #error Above line bugs. + #endif + g_label(lab); + } + } +#endif +} + +extern unsigned int pos; +void g_label(unsigned int labno) { +/* + * add a compiler-generated label to the peep list. + */ +#ifdef NEWLAB + struct lbls *new_ocode; +/* if (pos==0x25D2 && labno==1) + printf("ghio");*/ + new_ocode = (struct lbls *) xalloc((int) sizeof(struct lbls), OCODE+G_LABEL); + new_ocode->opcode = op_label; + new_ocode->lab = labno; + add_peep((struct ocode *)new_ocode); +#else + struct ocode *new_ocode; + new_ocode = (struct ocode *) xalloc((int) sizeof(struct ocode), OCODE+G_LABEL); + new_ocode->opcode = op_label; + new_ocode->oper1 = mk_immed((long) labno); + add_peep(new_ocode); +#endif +} + +void flush_peep() { +/* + * output all code and labels in the peep list. + */ +#ifndef AS + register struct ocode *ip; + register int line; +#endif +#ifdef SHOWSTEP + printf("\npeep"); +#endif + opt3(); /* do the peephole optimizations */ +#ifdef SHOWSTEP + printf(" ok "); + printf("\nflush"); +#endif + _peep_head=peep_head; +#ifndef AS + ip = peep_head; + line = -1; + if (DEBUG && func_sp) + fprintf(output,"; function '%s'\n",func_sp->name); + while (ip != 0) { + if (ip->opcode == op_label) + put_label((unsigned int) getlab(ip)); + else { + #ifdef DB_POSSIBLE + if (DEBUG && line!=ip->line) + fprintf(output,"; line %d\n",line=ip->line); + #endif + put_code(ip->opcode, ip->length, ip->oper1, ip->oper2); + } + ip = ip->fwd; + } + if (DEBUG) + fprintf(output,"; end of function\n"); +#else + scope_head = peep_head; +#endif + peep_head = 0; +#ifdef SHOWSTEP + printf(" ok "); +#endif +} + +static void peep_delete(struct ocode *ip) { +/* + * delete an instruction referenced by ip + */ + if (ip == 0) + ierr(PEEP_DELETE,1); + + if (ip->back) { + if ((ip->back->fwd = ip->fwd) != 0) + ip->fwd->back = ip->back; + next_ip = ip->back; + } else { + if ((peep_head = ip->fwd) != 0) + peep_head->back = 0; + next_ip = peep_head; + } +} + +static void peep_pea(struct ocode *ip) { +/* + * changes lea ,An + pea (An) to pea + * The value of An is not needed (An is scratch register) + * CAVEAT code generator modifier! + */ + struct ocode *prev; + if (ip->oper1->mode != am_ind) + return; + if ((prev = ip->back) == 0) + return; + if (prev->opcode == op_lea && prev->oper2->preg == ip->oper1->preg + && ip->oper1->preg <= MAX_ADDR) { + prev->opcode = op_pea; + prev->oper2 = 0; + peep_delete(ip); + } +} + +static void peep_lea(struct ocode *ip) { +/* + * changes lea ,An + move.l An,Am to lea ,Am + * -- the value of An is not needed (An scratch, Am typically tempref) + * and lea ,An + move.* (An),An to move.* ,An + * CAVEAT code generator modifier! + */ + struct ocode *next; + reg_t reg; + restart: + if ((next = ip->fwd) == 0 +#if defined(AS) && defined(ASM) + || next->opt +#endif + ) + return; + if (next->opcode == op_move && ip->oper2->preg <= MAX_ADDR && + next->oper1->mode == am_areg && next->oper1->preg == ip->oper2->preg + && next->oper2->mode == am_areg && next->oper2->preg > MAX_ADDR) { + ip->oper2 = next->oper2; + peep_delete(next); + goto restart; + } + /* lea ,An + move.* (An),An => move.* ,An */ + if (next->opcode == op_move && next->oper1->mode == am_ind) + if (((reg=next->oper1->preg) == ip->oper2->preg) && next->oper2->mode == am_areg && + (reg==next->oper2->preg)) { + ip->opcode = op_move; + ip->length = next->length; + peep_delete(next); + } +} + +static void peep_move(struct ocode *ip) { +/* + * peephole optimization for move instructions. + * makes quick immediates when possible (redundant for most assemblers). + * changes move #0 to clr except on address registers + * changes move #0 to address registers to sub An,An + * changes long moves to address registers to short when possible. + * changes move immediate/areg to stack to pea. + * changes move immediate to An to lea. + * deletes move , (The code generator does not know that this sets + * the flags, and it is necessary for peep_and + * to work correctly if ea is am_dreg) + */ + struct enode *ep; +#ifdef ADVANCED_MEMORY_MOVE + struct ocode *next; +#endif + + if (equal_address(ip->oper1, ip->oper2) && +/* + * move.w An,An changes the contents of An through sign extension + */ + (ip->oper1->mode != am_areg || ip->length != 2)) { + peep_delete(ip); + return; + } + if ((ip->oper1->mode == am_areg || ip->oper1->mode == am_immed) + && ip->oper2->mode == am_adec && ip->oper2->preg == 7 + && ip->length == 4) { + ip->opcode = op_pea; + ip->length = 0; + ip->oper1 = copy_addr(ip->oper1); + am_doderef(ip->oper1->mode); + ip->oper2 = 0; + return; + } +//#if 0 +#ifdef ADVANCED_TEMP_REGS +#ifndef INFINITE_REGISTERS + if (ip->oper1->mode==am_dreg && ip->oper1->preg<=MAX_DATA + && ip->oper2->mode==am_dreg) { + struct ocode *ip_save=ip; + reg_t a=ip->oper1->preg,b=ip->oper2->preg,s=ip->length; + struct amode *ap,*destap=ip->oper2; + /* BUGGY: we should check if da isn't used afterwards... + * Currently, g_assign does in such way that it returns Db + * rather than Da, so it should work fine in most cases, + * but it might fail eg with custom asm statements */ + ip=ip->back; + while (ip) { + switch (ip->opcode) { + case op_label: + case op_jsr: + case op_bxx: + case op_dbxx: + case op_dc: // this might mean op_jsr... + return; + case op_ext: + if (ip->oper1->mode==am_dreg && ip->oper1->preg==a) { + s=ip->length>>1; + break; + } + if ((ap=ip->oper1) && ap->mode==am_dreg && ap->preg==b) { +#ifdef PC + if (ip->length && ip->length<=s) + fatal("OP DISCARDED BY ASSIGNMENT"); + else +#endif + return; + } + break; + case op_clr: + ap=ip->oper1; + goto check_ok; + case op_move: + case op_moveq: + case op_lea: + ap=ip->oper2; + check_ok: + if (ap->mode==am_dreg && ap->preg==a) { + if (ip->length && ip->length oper1) && ((ap->mode==am_dreg && ap->preg==b) || + (ap->mode==am_indx2 && ap->sreg==b))) + return; + if ((ap=ip->oper2) && ap->mode==am_indx2 && ap->sreg==b) + return; + if ((ap=ip->oper2) && ap->mode==am_dreg && ap->preg==b) { +#ifdef PC + if (ip->length && ip->length<=s) + fatal("OP DISCARDED BY ASSIGNMENT"); + else +#endif + return; + } + } + ip=ip->back; + } + ierr(UNINIT_TEMP,1); + ok_atr: + next_ip=ip; + ip=ip_save; + while (ip!=next_ip) { + if (ip->oper1 && ip->oper1->mode==am_dreg && ip->oper1->preg==a) + ip->oper1=destap; + if (ip->oper2 && ip->oper2->mode==am_dreg && ip->oper2->preg==a) + ip->oper2=destap; + ip=ip->back; + } + if (ip->opcode==op_clr) + ip->oper1=destap; + else ip->oper2=destap; + return; + } +#endif +#endif +#ifdef ADVANCED_MEMORY_MOVE + /* try to use post-increment where possible */ + /* (might be improved to allow for interstitial instructions, but + beware of modifications of _any_ of _both_ indexing registers...) */ + if (ip->oper2->mode == am_indx && (next=ip->fwd) && next->opcode==op_move + && next->oper2->mode == am_indx && next->oper2->preg == ip->oper2->preg + && next->oper2->offset->v.i-ip->oper2->offset->v.i==ip->length) { + int reg=-1; +#ifndef INFINITE_REGISTERS + if (arsearch(0,ip)) + reg=8; + else if (arsearch(1,ip)) + reg=9; +#endif + if (reg IS_VALID) { + struct ocode *load = xalloc(sizeof(struct ocode),OCODE); + long offs; struct amode *ap; + load->opcode=op_lea; + load->oper1=ip->oper2; + load->oper2=mk_reg(reg); + load->line=ip->line; + load->back=ip->back; + load->fwd=ip; + load->back->fwd=load; + ip->back=load; + next=ip; + reg=ip->oper2->preg; + offs=ip->oper2->offset->v.i; + ap=mk_reg(reg); ap->mode=am_ainc; + do { + next->oper2=ap; + offs+=next->length; + next=next->fwd; + } while (next->opcode==op_move && next->oper2->preg==reg + && next->oper2->mode==am_indx + && next->oper2->offset->v.i==offs); + } + } +#endif + if (ip->oper1->mode != am_immed) + return; +#ifdef ADVANCED_MEMORY_MOVE + /* optimize contiguous -(an)/(an)+ assignments */ + restart_advmove: + if (am_is_increment(ip->oper2->mode) && ip->length<=2 && (next=ip->fwd) + && next->opcode==op_move && ip->oper1->offset->nodetype==en_icon + && next->oper1->mode == am_immed && next->oper2->mode==ip->oper2->mode + && next->length==ip->length + && next->oper1->offset->nodetype==en_icon) { + unsigned short a,b; /* very important *not* to be long's !!! */ + a=(unsigned short)ip->oper1->offset->v.i,b=(unsigned short)next->oper1->offset->v.i; + if (ip->oper2->mode==am_adec) + b=a,a=(unsigned short)next->oper1->offset->v.i; + ip->oper1=copy_addr(ip->oper1); + ip->oper1->offset = + mk_icon((ip->length==2?((long)a<<16)|b:(long)(unsigned short)((a<<8)|(unsigned char)b))); + ip->length<<=1; + peep_delete(next); + if (ip->back->opcode==op_move) { + next_ip=ip->back; + return; + } else goto restart_advmove; + /* + move.b #0,(a0)+ <- + move.b #0,(a0)+ + move.b #0,(a0)+ + move.b #0,(a0)+ + -> + move.w #0,(a0)+ <- + move.b #0,(a0)+ + move.b #0,(a0)+ + -> + clr.w (a0)+ + move.b #0,(a0)+ <- + move.b #0,(a0)+ + -> + clr.w (a0)+ <- + move.w #0,(a0)+ + -> + clr.w (a0)+ <- + move.w #0,(a0)+ + -> + move.l #0,(a0)+ <- + -> + clr.l (a0)+ <- + */ + } +#endif + + ep = ip->oper1->offset; + if (ip->oper2->mode == am_areg && ep->nodetype == en_icon) { + if (ep->v.i == 0) { + ip->length = 4; + ip->opcode = op_sub; + ip->oper1 = ip->oper2; + } else if (-32768 <= ep->v.i && ep->v.i <= 32767) + ip->length = 2; + return; + } + if (ip->oper2->mode == am_dreg && ep->nodetype == en_icon + && -128 <= ep->v.i && ep->v.i <= 127) { + ip->opcode = op_moveq; + ip->length = 0; + return; + } + if (ep->nodetype == en_icon && ep->v.i == 0) { + ip->opcode = op_clr; + ip->oper1 = ip->oper2; + ip->oper2 = 0; + return; + } + if (ip->oper2->mode == am_areg && ip->length == 4) { + next_ip = ip; + ip->opcode = op_lea; + ip->length = 0; + ip->oper1 = copy_addr(ip->oper1); + ip->oper1->mode = am_direct; + return; + } +} + +int equal_address(struct amode *ap1, struct amode *ap2) { +/* + * compare two address nodes and return true if they are equivalent. + */ + if (ap1 == 0 || ap2 == 0) + return 0; + if (ap1->mode != ap2->mode) + return 0; + switch (ap1->mode) { + case am_areg: + case am_dreg: + case am_ind: + return ap1->preg == ap2->preg; + case am_indx: + return ap1->preg == ap2->preg && + ap1->offset->nodetype == en_icon && + ap2->offset->nodetype == en_icon && + ap1->offset->v.i == ap2->offset->v.i; + case am_indx2: + case am_indx3: + return + ap1->preg == ap2->preg && + ap1->sreg == ap2->sreg && + ap1->slen == ap2->slen && + ap1->offset->nodetype == en_icon && + ap2->offset->nodetype == en_icon && + ap1->offset->v.i == ap2->offset->v.i; + } + return 0; +} + +static void peep_movem(struct ocode *ip) { +/* + * peephole optimization for movem instructions. movem instructions are used + * to save registers on the stack. if 1 or 2 registers are being saved we + * can convert the movem to move instructions. + */ + int i,mask,n,t,a,b=0; + struct ocode *root; + +#ifdef PC + a=1234; /* prevent a warning from being output - we can afford this on PC :) */ +#endif + + if (ip->oper1->mode == am_mask1) + mask = getop1(ip); + else mask = getop2(ip); + + t=1,n=2,i=16; + while (i--) { + if (mask & t) { + b=a,a=i; + if (--n<0) return; + } + t<<=1; + } + root=ip; + ip->opcode = op_move; + if ((i=1-n)) { + struct ocode *new_ocode = (struct ocode *) + xalloc((int) sizeof(struct ocode), OCODE); + new_ocode->opcode = op_move; + new_ocode->length = ip->length; + new_ocode->oper1 = copy_addr(ip->oper1); + new_ocode->oper2 = copy_addr(ip->oper2); +#ifdef DB_POSSIBLE + new_ocode->line=ip->line; +#endif + new_ocode->back = ip; + if ((new_ocode->fwd=ip->fwd)) + ip->fwd->back=new_ocode; + ip->fwd=new_ocode; + } + do { + if (ip->oper1->mode == am_mask1) { + if ((ip->oper1->preg = a) >= 8) { + ip->oper1->mode = am_areg; + ip->oper1->preg -= 8; +#ifdef INFINITE_REGISTERS + ip->oper1->preg += TAREGBASE-AREGBASE; +#endif + } else { + ip->oper1->mode = am_dreg; +#ifdef INFINITE_REGISTERS + ip->oper1->preg += TDREGBASE; +#endif + } + } else { + if ((ip->oper2->preg = 15 - a) >= 8) { + ip->oper2->mode = am_areg; + ip->oper2->preg -= 8; +#ifdef INFINITE_REGISTERS + ip->oper2->preg += TAREGBASE-AREGBASE; +#endif + } else { + ip->oper2->mode = am_dreg; +#ifdef INFINITE_REGISTERS + ip->oper2->preg += TDREGBASE; +#endif + } + } + ip=ip->fwd; + a=b; + } while (i--); + next_ip=root; /* optimize move.l An,-(a7) => pea (An) */ +} + +int drsearch(int r,struct ocode *ip) { + while ((ip=ip->fwd)) { + struct amode *ap=ip->oper1; + int n=0; + do { + switch (ap->mode) { + case am_dreg: + if (ap->preg==r) + return n && op_destroy(ip->opcode); + case am_areg: + case am_ind: case am_adec: case am_ainc: case am_indx: + case am_indx3: + break; + case am_indx2: + if (ap->sreg==r) + return 0; + break; + } + n++; + } while ((ap=ip->oper2)); + } + return 1; +} + +int arsearch(int r,struct ocode *ip) { + struct amode *ap; int n,z; +// printf("$%d",r); + z=0; + while ((ip=ip->fwd) && ip->opcode!=op_rts) { + if (ip->opcode==op_label) continue; +#ifdef INFINITE_REGISTERS + if (ip->opcode==_op_cleanup_for_external_call) continue; +#endif + z++; + ap=ip->oper1; + n=0; + do { + switch (ap->mode) { + case am_areg: + if (ap->preg==r) { +// printf("*%d ",z); + return n && op_destroy(ip->opcode); + } + case am_dreg: + break; + case am_indx3: + if (ap->sreg==r) { +// printf("-%d ",z); + return 0; + } + /* FALL THROUGH */ + case am_ind: case am_adec: case am_ainc: case am_indx: + case am_indx2: + if (ap->preg==r) { +// printf("-%d ",z); + return 0; + } + break; + } + n++; + } while ((ap=ip->oper2) && n==1); + } +// printf("/%d ",z); + return 1; +} + +static void peep_addsub(struct ocode *ip, enum (e_op) op) { +/* + * peephole optimization for add/sub instructions. +A* changes add/sub.* Rn,An; move (An),X to move 0(An,+/- Rn.*),X +A* changes add/sub.* Rn,An; move x(An),X to move x(An,+/- Rn.*),X +A* changes add/sub #x,An; move 0(An,Rn.*),X to move x(An,+/- Rn.*),X + * makes quick immediates out of small constants (redundant for most as's). + * change add/sub immediate to address registers to lea where possible +A* and try to avoid operand volatilizing when doing so + */ + struct enode *ep; + struct ocode *next=ip->fwd; +#ifdef ADV_OPT + int reg; + if (next +#ifdef AS + && !next->opt +#endif + && next->opcode==op_move + && ip->oper2->mode==am_areg && (reg=ip->oper2->preg)==next->oper1->preg + && arsearch(reg,next)) { + int sub=op-op_add,ok=0,sz=ip->length,sreg=ip->oper1->preg; + long offs=next->oper1->offset?getop1(next):0; +/* infunc("InitLevel") + bkpt();*/ + ok=next->oper1->mode; + if (ip->oper1->mode==am_dreg || ip->oper1->mode==am_areg) { + if (ok==am_ind) + offs=0; + else if (ok!=am_indx) + ok=0; + /* if we do the conversion, select am_indx2/3 appropriately */ + if (ok) + ok=ip->oper1->mode-am_dreg+am_indx2; + } else if (ip->oper1->mode==am_immed) { + sz=next->oper1->slen; + sreg=next->oper1->sreg; + offs=getop1(ip); + if (sub) offs=-offs; + sub=0; + if (ok==am_indx3) + sreg+=AREGBASE; + else if (ok!=am_indx3) + ok=0; + } else ok=0; + if (ok && offs>=-128 && offs<128) { + if (sub) ip->opcode=op_neg,ip->oper2=NULL; + else peep_delete(ip); + next->oper1=copy_addr(next->oper1); + next->oper1->mode=ok; + next->oper1->slen=sz; + next->oper1->sreg=sreg; + next->oper1->offset=mk_icon(offs); + return; + } + } +#endif + if (ip->oper2->preg == STACKPTR-AREGBASE && ip->length == 2) { /* alloca... */ + last_param_pop = NULL; + } + if (ip->oper1->mode == am_immed) { + ep = ip->oper1->offset; + if (ip->oper2->mode != am_areg) + ip->opcode = op+op_addi-op_add; + if (ep->nodetype != en_icon) + return; +#ifdef POP_OPT + if (ip->oper2->preg == STACKPTR-AREGBASE && + ip->oper2->mode == am_areg && ip->length == 4) { /* parameter popping */ + if (last_param_pop) + ep->v.i+=getop1(last_param_pop), peep_delete(last_param_pop); + last_param_pop = ip; + } +#endif +/* if (!ep->v.i) { // unnecessary + peep_delete(ip); + return; + }*/ + if (1 <= ep->v.i && ep->v.i <= 8) { + ip->opcode = op+op_addq-op_add; + return; + } + if (-8 <= ep->v.i && ep->v.i <= -1) { + ip->opcode = op==op_add?op_subq:op_addq; + ep->v.i = -ep->v.i; + return; + } + if (ip->oper2->mode == am_areg && isshort(ep)) { + ip->oper1 = copy_addr(ip->oper1); + ip->oper1->mode = am_indx; + ip->oper1->preg = ip->oper2->preg; + if (op==op_sub) ip->oper1->offset=mk_icon(-getop1(ip)); + ip->length = 0; + ip->opcode = op_lea; + next_ip = ip; +#ifdef ADV_OPT + if (ip->back && ip->back->opcode==op_move && ip->back->oper2->mode==am_areg + && ip->back->oper2->preg==ip->oper1->preg + && ip->back->oper1->mode==am_areg + && arsearch(ip->oper1->preg,ip)) + ip->oper1->preg=ip->back->oper1->preg, peep_delete(ip->back); +#endif + return; + } + } +} + +static void peep_and(struct ocode *ip) { +/* + * conversion of unsigned data types often yields statements like + * move.b source,d0 + andi.l #255,d0 + * which should be converted to + * clr.l d0 + move.b source,d0 + * deletes and #-1 + */ + struct ocode *prev; + int size; + long arg; + if (ip->oper1->mode != am_immed || + ip->oper1->offset->nodetype != en_icon) + return; + arg = getop1(ip); + /* + * and #-1 does only set flags, which the code generator does not know + */ + if (arg == -1) { + peep_delete(ip); + return; + } + if (ip->oper1->mode != am_immed || + (arg != 255 && arg != 65535)) + return; + + size = (arg == 255) ? 1 : 2; + + /* move.b,dn; and.* #$FF,dn condition que != x(An,Dn) */ + /* move.w ,dn; and.* #$FFFF,dn condition que != x(An,Dn) */ + if ((prev = ip->back) == 0 || prev->length != size + || prev->opcode != op_move + || ip->oper2->mode != am_dreg || prev->oper2->mode != am_dreg + || ip->oper2->preg != prev->oper2->preg + || (prev->oper1->mode == am_indx2 && + prev->oper1->sreg == prev->oper2->preg)) + return; + + prev->length = ip->length; + ip->length = size; + prev->opcode = op_clr; + ip->opcode = op_move; + ip->oper1 = prev->oper1; + prev->oper1 = prev->oper2; + prev->oper2 = 0; + + next_ip = prev; +} + +static void peep_clr(struct ocode *ip) { +/* + * removes consecutive clr-statements + * + */ + struct ocode *prev; + + if ((prev = ip->back) == 0 || prev->opcode != op_clr || + !equal_address(ip->oper1, prev->oper1)) + return; + + if (prev->length < ip->length) + prev->length = ip->length; + + peep_delete(ip); +} + +static void peep_cmp(struct ocode *ip) { +/* + * peephole optimization for compare instructions. + * changes compare #0 to tst + * + */ + struct enode *ep; + if (ip->oper1->mode != am_immed) + return; + ep = ip->oper1->offset; + if (ip->oper2->mode == am_areg) + /* cmpa.w extents the first argument automatically */ + { + if (isshort(ep)) + ip->length = 2; + return; + } + ip->opcode = op_cmpi; + if (ep->nodetype != en_icon || ep->v.i != 0) + return; + ip->oper1 = ip->oper2; + ip->oper2 = 0; + ip->opcode = op_tst; + next_ip = ip; +} + +static void peep_tst(struct ocode *ip) { +/* + * deletes a tst instruction if the flags are already set. + */ + struct ocode *prev,*next; + enum(e_op) op; + prev = ip->back; + if (prev == 0) + return; +/* + * All the following cases used to be checked with an obscure + * if-statement. There was an error in it that caused prev->oper2->mode + * to be referenced even if prev->opcode is op_clr. (This yields a NIL- + * pointer reference. + * I threw all this stuff away and replaced it by this case-statement. + * This is much more readable. + */ + switch (prev->opcode) { + case op_label: + case op_dc: + case _op_asm: + case _op_adj: +/* + * List all pseudo-instructions here. Of course, they do not do + * anything. + */ + return; + + case op_move: +/* + * A move TO an address register does not set the flags + */ + if (prev->oper2->mode == am_areg) + return; + case op_moveq: + case op_clr: + case op_ext: +/* + * All other move and clr instructions set the flags according to + * the moved operand, which is prev->oper1 + */ + if (equal_address(prev->oper1, ip->oper1)) + break; + if (equal_address(prev->oper2, ip->oper1)) + break; + return; + case op_btst: case op_bset: case op_bclr: case op_bchg: + case op_cmp: + /* these instructions affect the flags in a non-standard way */ + case op_swap:/*[longword test]*/ + /* FALL THROUGH */ + case op_exg: + /* these instructions don't affect the flags */ + return; + default: +/* + * All instructions that have a target set the flags according to the + * target (prev->oper2) + * Note that equal_address may be called with a NIL pointer -> OK for clr + */ + next = ip->fwd; + if (next && ((op=next->opcode)==op_beq || op==op_bne) + && !(next->fwd && (op=next->fwd->opcode)>=_op_bcond_min && op<=_op_bxx_max)) + if (equal_address(prev->oper2, ip->oper1)) + break; + return; + } +/* + * We come here if the flags are already set, thus the tst + * instruction can be deleted. + */ + if (ip->length==prev->length) + peep_delete(ip); +} + +static void peep_uctran(struct ocode *ip) { +/* + * peephole optimization for unconditional transfers. deletes instructions + * which have no path. applies to bra, jmp, and rts instructions. + */ + while (ip->fwd != 0 && ip->fwd->opcode != op_label) + peep_delete(ip->fwd); + next_ip=ip->fwd; +} + +static void peep_bxx(struct ocode *ip) { +/* + * optimizes conditional branch over a bra. + */ + struct ocode *next = ip->fwd; + if (next && next->opcode == op_bra) { + /* peep_uctran increases the 'hit' probability */ + peep_uctran(next); + while ((next = next->fwd) && next->opcode == op_label) + if (getoplab(ip) == getlab(next)) { + /* bxx \lab | bra \out | ... | \lab: + * => (peep_uctran) + * bxx \lab | bra \out | \lab: + * => + * byy \out | \lab: + */ + ip->fwd->opcode = revcond[(int)ip->opcode - (int)_op_bcond_min]; + ip=ip->fwd; + peep_delete(ip->back); + break; + } + } + if (ip->opcode==op_bhs && ip->back && ip->back->opcode==op_subq + && ip->back->oper1->offset->v.i==1 /* since oper1->mode is am_immed->en_icon */ + && ip->back->oper2->mode==am_dreg) + ip->opcode=op_dbra, + ip->oper2=ip->oper1, + ip->oper1=ip->back->oper2, + peep_delete(ip->back); +} + +static void peep_label(struct ocode *ip) { +/* + * if a label is followed by a branch to another label, the + * branch statement can be deleted when the label is moved + */ + struct ocode *prev, *next, *target; + long label; + last_param_pop = NULL; // reset function parameter popping optimization + prev = ip->back; + + if ((next = ip->fwd) == 0 || next->opcode != op_bra || next->oper1->offset->nodetype!=en_labcon) + return; + /* + * To make this fast, assume that the label number is really + * getoplab(next) + */ + label = getoplab(next); + if (label == getlab(ip)) + return; + target = peep_head; + /* + * look for the label + */ + while (target != 0) { + if (target->opcode == op_label + && getlab(target) == label) + break; + target = target->fwd; + } + /* we should have found it */ + if (target == 0) { +#ifdef VCG + if (vcg_lvl==VCG_MAX) +#endif + iwarn(PEEP_LABEL,1); + return; + } + /* move label */ + peep_delete(ip); + ip->fwd = target->fwd; + ip->back = target; + target->fwd = ip; + if (ip->fwd != 0) + ip->fwd->back = ip; + /* possibly remove branches */ + /* in fact, prev is always != 0 if peep_delete has succeeded */ + if (prev != 0) { + if (prev->opcode == op_bra || prev->opcode == op_jmp + || prev->opcode == op_rts) + peep_uctran(prev); + else if (prev->opcode == op_label) + next_ip=prev; /* so that peep_label will be called once again (this label + * might be aliased by other ones) */ + } +} + +void opt3(void) { +/* + * peephole optimizer. This routine calls the instruction specific + * optimization routines above for each instruction in the peep list. + */ +//#define NO_PEEP +#ifndef NO_PEEP + struct ocode *ip; + enum(e_op) instr; + next_ip = peep_head; + if (!opt_option) + return; + instr=-1; + last_param_pop = NULL; + while (next_ip != 0) { +/* if (ip->opcode==instr) + if (!(ip = ip->fwd)) break; + instr=ip->opcode;*/ + ip = next_ip; + next_ip = ip->fwd; +#ifdef AS + if (ip->opcode!=op_label && ip->opt) + continue; +#endif + switch (ip->opcode) { + case op_move: + peep_move(ip); + break; + case op_movem: + peep_movem(ip); + break; + case op_pea: + peep_pea(ip); + break; + case op_lea: + peep_lea(ip); + break; + case op_ext: { /* ext.l Dn ; add/sub Dn,Am (where Dn is a word) */ + struct ocode *nxt=ip->fwd; reg_t reg; + if (!nxt || (nxt->opcode!=op_add && nxt->opcode!=op_sub) +#if defined(AS) && defined(ASM) + || nxt->opt +#endif + || ip->length!=4 || nxt->oper1->mode!=am_dreg + || (reg=nxt->oper1->preg)!=ip->oper1->preg + || nxt->oper2->mode!=am_areg + || (reg>MAX_DATA && regexp[reg_t_to_regexp(reg)]->esize==4)) + break; + peep_delete(ip); + nxt->length=2; + } break; + case op_add: + case op_sub: + peep_addsub(ip,ip->opcode); + //peep_add/peep_sub(ip); + break; + case op_and: + peep_and(ip); + break; + case op_clr: + peep_clr(ip); + break; + case op_cmp: + peep_cmp(ip); + break; + case op_tst: + peep_tst(ip); + break; + case op_beq: + case op_bne: + case op_bgt: + case op_bge: + case op_blt: + case op_ble: + case op_blo: + case op_bls: + case op_bhi: + case op_bhs: + peep_bxx(ip); + /* FALL THROUGH */ + last_param_pop = NULL; // reset function parameter popping optimization + break; + case op_dbxx: + last_param_pop = NULL; // reset function parameter popping optimization + break; + case op_bra: + last_param_pop = NULL; // reset function parameter popping optimization + peep_uctran(ip); + /* delete branches to the following statement */ + { + struct ocode *p = ip->fwd; + long label = getoplab(ip); + while (p != 0 && p->opcode == op_label) { + if (getlab(p) == label) { + peep_delete(ip); + ip = 0; + break; + } + p = p->fwd; + } + } + if (!ip) + break; +#ifdef SPEED_OPT + if (next_ip && speed_opt_value>0) { /* then it's necessarily a label, due to peep_uctran */ + int i,lab=getoplab(ip); + struct ocode *p=peep_head,*s,*e; + do { + if (p->opcode==op_label && getlab(p)==lab) break; + } while ((p=p->fwd)); + if (!p) break; + s=p; + lab=getlab(next_ip); + i=speed_opt_value; + /* NOTE : we ought never stop copying on a 'bra', but rather go on */ + do { + if (!(p=p->fwd)) goto bad; + if (p->opcode==op_label) i++; /* don't count it as an instruction */ + else if (p->opcode>=_op_bcond_min && p->opcode<=_op_bxx_max + && getoplab(p)==lab) { + break; + } else if (p->opcode==op_bra || p->opcode==op_jmp || p->opcode==op_rts) + break; +#ifndef ALLOW_TWIN_STACK_OPS + else { + struct amode *ap=p->oper1; + if (ap && ap->mode==am_ainc && ap->preg==7) + goto bad; + ap=p->oper2; + if (ap && (ap->mode==am_areg || ap->mode==am_adec) && ap->preg==7) + goto bad; + } +#endif + } while (i--); + if (i>=0) { + struct ocode *prv,*nxt; + e=p; + p=s; + prv=ip->back; + next_ip=prv; + nxt=ip->fwd; + peep_delete(ip); + do { + p=p->fwd; + if (p->opcode!=op_label) { + struct ocode *n=(struct ocode *) + xalloc(sizeof(struct ocode), OCODE); + *n=*p; + if (p==e && p->opcode>op_bra) { /* we assume that op_jmp fwd,*nl; + int dlab; + if (pn->opcode==op_label) dlab=getlab(pn); + else { + dlab=nxtlabel(); + #ifdef NEWLAB + nl = (struct ocode *) xalloc((int) sizeof(struct lbls), OCODE); + nl->opcode = op_label; + ((struct lbls *)nl)->lab = dlab; + #else + nl = (struct ocode *) xalloc((int) sizeof(struct ocode), OCODE); + nl->opcode = op_label; + nl->oper1 = mk_immed((long)dlab); + #endif + p->fwd=nl; + nl->back=p; + nl->fwd=pn; + pn->back=nl; + } + n->opcode=revcond[p->opcode-_op_bcond_min]; + n->oper1=mk_label(dlab); + } + n->back=prv; + prv->fwd=n; + prv=n; + } + } while (p!=e); + prv->fwd=nxt; + nxt->back=prv; + next_ip=next_ip->fwd; + } + } +bad: +#endif + break; + case op_jmp: + case op_rts: + last_param_pop = NULL; // reset function parameter popping optimization + peep_uctran(ip); + break; + case op_label: + peep_label(ip); + break; + case _op_adj: + peep_delete(ip); + /* FALL THROUGH */ + case _op_asm: + last_param_pop = NULL; // reset function parameter popping optimization + break; + } + } +#endif +} +#ifdef VCG +#include "vcg.c" +#endif + +#endif /* MC680X0 */ +// vim:ts=4:sw=4 diff --git a/gtc/src/preproc.c b/gtc/src/preproc.c new file mode 100644 index 0000000..85e5871 --- /dev/null +++ b/gtc/src/preproc.c @@ -0,0 +1,572 @@ +/* + * GTools C compiler + * ================= + * source file : + * preprocessor + * + * Copyright 2001-2004 Paul Froissart. + * Credits to Christoph van Wuellen and Matthew Brandt. + * All commercial rights reserved. + * + * This compiler may be redistributed as long there is no + * commercial interest. The compiler must not be redistributed + * without its full sources. This notice must stay intact. + */ + +#include "define.h" +_FILE(__FILE__) +#include "c.h" +#include "expr.h" +#include "gen.h" +#define USE_MEMMGT +#include "cglbdec.h" +#ifdef PCH +#include "pch.h" +#endif + +extern char *curname; +extern char *lptr; +char *inclname[10]; +FILE *inclfile[10]; +int inclifreldepth[10]; +int incldepth CGLOB; +#ifdef PCH +FILE *pchfile[20]; +char *pchdata[20] CGLOBL; +char *pchtab[20]; +#ifdef REQ_MGT +char pchname[20][15]; +char pchrequired[20]; +#endif +int pchnum CGLOB; +#endif +int inclline[10]; +int lineno CGLOB; +int lineid CGLOB; +int prevlineid CGLOB; +int flags CGLOB; +#ifdef PC +int verbose CGLOB; +#endif +#ifdef PC +int verbosity CGLOB; +#endif +int ifdepth CGLOB; +int ifreldepth CGLOB; +int ifcount[MAX_IF_DEPTH]; +int ifval[MAX_IF_DEPTH]; +int ifhas[MAX_IF_DEPTH]; +int ifskip CGLOB, ifsd CGLOB; + +HTABLE defsyms CGLOBL; + +extern int getline(int f); + +extern TYP *expression(); +extern unsigned char id_are_zero; + +int doinclude( +#ifdef PCH + int pch +#endif + ); + +extern enum(e_sym) forbid; +xstatic int pp_old_forbid CGLOB; +xstatic int pp_old_crc CGLOB; +xstatic char pp_old_id[MAX_ID_LEN+1]; + +/*static int mem_if=0,mem_def=0; +#define MEM_USE(x,s) mem_##x-=glbmem; s mem_##x+=glbmem;*/ + +int ppquit() { + if (pp_old_forbid IS_VALID) { + forbid=pp_old_forbid; + if (pp_old_forbid==id) memcpy(lastid,pp_old_id,MAX_ID_LEN+1), lastcrc=pp_old_crc; + } +#ifdef MACRO_PPDIR + if (*lptr) lptr=strchr(lptr,'\n')+1; + if (!*lptr) return getline(incldepth == 0); + else return 0; +#else + return getline(incldepth == 0); +#endif +} + +#if 0 +char *strend(char *s) { + while (*s++); + return s-1; +} +#endif + +int preprocess() { + if ((pp_old_forbid=forbid)==id) memcpy(pp_old_id,lastid,MAX_ID_LEN+1), pp_old_crc=lastcrc, + forbid=-1; + ++lptr; // skip '#' + lastch = ' '; + getch(); + getsym(); /* get first word on line */ + if(lastst != id && lastst != kw_if && lastst != kw_else) { + uerrc("preprocessor command expected"); + return ppquit(); + } +/* if (!strcmp(curname,"compat.h") && lineno>=23) + bkpt();*/ +/* if (!strcmp(curname,"messages.c") && lineno>=0) + bkpt();*/ + if (lastst == kw_if /*!strcmp(lastid,"if")*/ || !strcmp(lastid,"elif")) { + struct enode *ep; TYP *tp; enum(e_bt) typ; + int v=lastst==kw_if; + if (!v) ifskip=ifhas[ifdepth]; + if (ifskip) return doif(-1,v); +#ifndef MACRO_PPDIR + strcpy(lptr," ] "); // so that getsym() in the new expression will + getsym(); // not read any new line +#else + { + char *q=strchr(lptr,'\n'); + memmove(q+3,q,strlen(q)+1); + memcpy(q," ] ",3); + getsym(); + } +#endif + tmp_use(); + id_are_zero++; + tp=expression(&ep); + id_are_zero--; + if (!tp || lastst!=closebr) error(ERR_EXPREXPECT); + else if ((typ=tp->type)==bt_void || typ==bt_pointer) error(ERR_INTEGER); + else { + opt0(&ep); + if (ep->nodetype!=en_icon) error(ERR_CONSTEXPECT); + else { int w=doif(ep->v.i!=0,v); tmp_free(); return w; } + } + tmp_free(); + return ppquit(); + } else if (!strcmp(lastid,"ifdef") || !strcmp(lastid,"ifndef")) { + int v=lastid[2]!='d'; + if (ifskip) return doif(-1,1); + skipspace(); + if ((lastch>='A'&&lastch<='Z') || (lastch>='a'&&lastch<='z') + || lastch=='_' || lastch=='$') { + getidstr(); + return doif(v ^ !!search(lastid,lastcrc,&defsyms),1); + } else error(ERR_IDEXPECT); + return ppquit(); + } else if (lastst == kw_else/*!strcmp(lastid,"else")*/) { + if (!ifreldepth) uerrc("'#else' unexpected"); + else if (!ifskip || ifdepth<=ifsd) { + if (--ifcount[ifdepth]!=0) uerrc("'#else' unexpected"); + else ifskip = ifval[ifdepth]; + } + return ppquit(); + } else if (!strcmp(lastid,"endif")) { + if (!ifreldepth) uerrc("'#endif' unexpected"); + else { + ifdepth--, ifreldepth--; + if (ifdepth base); +#endif + progr_readtonow=0; +} +#endif +int doinclude( +#ifdef PCH + int pch +#endif + ) { + int rv; char c; + strcat(lptr," "); + skipspace(); + if ((c=lastch-'"') && c!='<'-'"') + goto incl_err; + getch(); + if (!((lastch>='A'&&lastch<='Z') || (lastch>='a'&&lastch<='z') + || lastch=='_' || lastch=='$' || lastch=='\\')) + goto incl_err; + getidstr(); /* get file to include, without extension */ +#ifdef PCH + if (!pch) { +#endif + inclline[incldepth] = lineno; + inclifreldepth[incldepth] = ifreldepth; +#ifdef GTDEV + inclread[incldepth] = progr_readtonow; + inclcoeff[incldepth] = progr_coeff; +#endif + inclname[incldepth] = curname; + inclfile[incldepth++] = input; /* push current input file */ + restart_h: + input = xfopen(lastid,"r",c); + if (!input) { + char *tigcclib_aliases = "all\0alloc\0args\0asmtypes\0assert\0bascmd\0basfunc\0basop\0cert\0compat\0ctype\0default\0dialogs\0dll\0error\0estack\0events\0files\0flash\0float\0gdraw\0graph\0graphing\0gray\0homescr\0intr\0kbd\0limits\0link\0math\0mem\0menus\0nostub\0peekpoke\0printf\0romsymb\0rsa\0setjmp\0sprites\0statline\0stdarg\0stddef\0stdio\0stdlib\0string\0system\0textedit\0timath\0unknown\0values\0vat\0version\0wingraph\0"; + while (*tigcclib_aliases) + if ( + #ifdef PC + !strncmp(lastid,tigcclib_aliases,strlen(tigcclib_aliases)) && !strcmp(lastid+strlen(tigcclib_aliases),".h") + #else + !strcmp(lastid,tigcclib_aliases) + #endif + ) { + #ifdef PC + strcpy(lastid,"tigcclib.h"); + #else + strcpy(lastid,"tigcclib"); + #endif + goto restart_h; + } else { + while (*tigcclib_aliases++); + } +// input = inclfile[--incldepth]; + uerr(ERR_CANTOPEN,lastid); +// _exit(18); + } + ifreldepth = 0; +#ifdef GTDEV + progr_initforcurfile(); +#endif + global_flag++; + curname = strsave(lastid); + global_flag--; +#ifdef PCH + } else { + char b[30]; +#ifdef REQ_MGT + int i=pchnum; + while (i--) + if (!strcmp(lastid,pchname[i])) + goto done; +#endif +#ifdef PC + sprintf(b,"%s.pch",lastid); +#else + sprintf(b,"zheader\\%s",lastid); +#endif + if (!(pchfile[pchnum] = xfopen(b, "rb", c))) { + if (pch<0) + goto done; + uerr(ERR_CANTOPEN,b); +// _exit(18); + } +#ifdef REQ_MGT + strcpy(pchname[pchnum],lastid); + pchrequired[pchnum]=0; +#endif +#ifdef PC + pchdata[pchnum] = malloc(150000); + fread(pchdata[pchnum],1,150000,pchfile[pchnum]); + if (w2ul(pchhead[pchnum]->magic)!= + ((long)'P'<<24)+((long)'C'<<16)+((long)'H'<<8) + || !(pchtab[pchnum] = malloc(w2us(pchhead[pchnum]->nID)))) { + fclose(pchfile[pchnum]); + goto incl_err; + } +#define w2s(x) ((short)w2us(x)) +#else + if (w2ul(((PCH_HEAD *)(pchdata[pchnum] = *(char **)(pchfile[pchnum])))->magic)!= + ((long)'P'<<24)+((long)'C'<<16)+((long)'H'<<8) + || !(pchtab[pchnum] = malloc((short)pchhead[pchnum]->nID))) { + fclose(pchfile[pchnum]); + goto incl_err; + } +#define w2s(x) ((short)(x)) +#endif + memset(pchtab[pchnum],0,w2s(pchhead[pchnum]->nID)); + pchnum++; + } +#endif +done: + if (lastch=='.') getch(),getidstr(); + c=c?'>':'"'; + if (lastch!=c) + uerr(ERR_PUNCT,c); + rv = getline(incldepth == 1); +#ifdef PCH + if (!pch) +#endif + lineno = 1; /* dont list include files */ + return rv; +incl_err: + error(ERR_INCLFILE); + return ppquit(); +} + +char *litlate(char *s); +extern int getch_noppdir; +int dodefine(int mode) { // 1: #define, -1 : #macro, 0 : #undef + SYM *sp,*ds; + int n=0,flags=0; +/* getsym();*/ + skipspace(); + if ((lastch>='A'&&lastch<='Z') || (lastch>='a'&&lastch<='z') + || lastch=='_' || lastch=='$') { + getidstr(); /* get past #define */ + } else { + error(ERR_DEFINE); + return ppquit(); + } + if (!mode) { + if (!symremove(lastid,&defsyms)) /* if we didn't unload anything, let's */ + pchsearch(lastid,PCHS_UNLOAD); /* try and unload the symbol */ + return ppquit(); + } +#ifdef AS + if (!strcmp(lastid,"NOSTUB")) + nostub_mode=1; +#endif +#ifdef ASM + if (asm_isreserved()) + flags|=PPSYM_ASM_KEYWORD; + if (asm_flag) + flags|=PPSYM_DEFINED_IN_ASM; +#endif + ++global_flag; /* always do #define as globals */ + sp = (SYM *)xalloc((int)sizeof(SYM), _SYM+DODEFINE); + sp->name = strsave(lastid); + sp->storage_class = sc_define; + if (lastch=='(') { + TABLE *tp; +/* if (lineid==0x1A) + bkpt();*/ + sp->tp=(TYP *)(tp=(TABLE *)xalloc((int)sizeof(TABLE), _TABLE+DODEFINE)); +#ifdef NO_CALLOC + tp->hash=0; + tp->head=tp->tail=NULL; +#endif + getsym(); + getsym(); + if (lastst!=closepa) { + while (1) { + SYM *arg; + n++; + if (lastst!=id) error(ERR_IDEXPECT); + else { + arg=(SYM *)xalloc((int)sizeof(SYM), _SYM+DODEFINE); + arg->name=strsave(lastid); +#ifdef NO_CALLOC + arg->tp=NULL; +#endif + insert(arg,(HTABLE *)tp); + } + getsym(); + if (lastst!=comma) break; + getsym(); + } + if (lastst==dots) { sp->storage_class = sc_vamac; getsym(); } + if (lastst!=closepa) needpunc(closepa); + } + if (!isspace(lastch)) // undo last getch()... + lptr--; +#ifdef NO_CALLOC + } else { + sp->tp=NULL; +#endif + } +#ifdef MACRO_PPDIR + if (mode<0) { + char *s=(char *)alloca(500),*p=s; + int n=499; + getch_noppdir++; + do { + if (getch()<0) error(ERR_DEFINE); + *p++=(/*lastch=='\n'?'\r':*/lastch); + } while (n-- && (lastch!='#' || *lptr!='e' || strncmp(lptr+1,"ndm",3))); + getch_noppdir--; + if (n<=0) error(ERR_DEFINE); + p-=2; // remove '\n' '#' + *p++=0; + n = p-s; + p = (char *)xalloc(n, STR); + memcpy(p,s,n); + sp->value.s=p; + } else +#endif + if (strlen(lptr)>1500) + uerrsys("definition too long (1500 characters max)"); + if (!(sp->value.s = litlate(lptr))) + uerrc("unbalanced quotes in #define"); +#ifdef FLINE_RC + if (!strcmp(sp->name,"USE_FLINE_ROM_CALLS")) + fline_rc=1; +#endif + if ((ds=search(sp->name,-1,&defsyms))) { + if (strcmp(sp->value.s,ds->value.s)) + uwarn("redefinition of macro '%s'",sp->name); + symremove(sp->name,&defsyms); + } + insert(sp,&defsyms); + sp->used=n+flags; + --global_flag; + return ppquit(); +} + +// x = result of the test (1 : true, 0 : false, -1 : ignore all branches) +// c = is it a #if ? (rather than a #elif) +int doif(int x,int c) { + if ((ifreldepth+=c,ifdepth+=c)>MAX_IF_DEPTH) uerrc("too many imbricated '#if's"); + else if (!ifreldepth) uerrc("'#elif' unexpected"); + else if (!ifskip || ifdepth<=ifsd) { + ifsd=ifdepth; + if (c) + ifhas[ifdepth] = x; + else + ifhas[ifdepth] |= x; + ifskip = (ifval[ifdepth] = x) - (ifcount[ifdepth] = 1); + } + if (x<0) { + ifhas[ifdepth] = x; + ifskip = x; + } + return ppquit(); +} +// vim:ts=4:sw=4 diff --git a/gtc/src/protos.h b/gtc/src/protos.h new file mode 100644 index 0000000..96601cc --- /dev/null +++ b/gtc/src/protos.h @@ -0,0 +1,329 @@ +// Auto-generated file, do not edit! + +#ifndef PROTOS_H_ +#define PROTOS_H_ + +enum OptionModes; +enum e_am; +enum e_bt; +enum e_node; +enum e_op; +enum e_sc; +enum e_sym; +struct _regsimg; +struct _stackimg; +struct amode; +struct bcd; +struct blk; +struct cse; +struct enode; +struct hstab; +struct ocode; +struct snode; +struct stab; +struct sym; +struct typ; + +struct typ *shiftop(struct enode **node); +void local_clean(void); /* remove local symbols from alsyms -- to be called just before rel_local */ +void g_label(unsigned int labno); +struct snode *casestmt(void); +void compile(void); +void dump_endnode(); +int blk_free(struct blk *bp1); +int complexity(struct enode *ep); +void check_table(struct hstab *table); +struct typ *nameref(struct enode **node); +int en_dir_cost(struct enode *ep); +void extscan(unsigned char *ext); +void genstorage(struct sym *sp, int align); +void freeregs(struct _regsimg *img); /* used by g_fcall */ +struct amode *mk_immed(long i); +char *litlate(char *s); +struct snode *forstmt(void); +struct amode *g_xmul(struct enode *node, int flags, enum(e_op) op); +struct enode *mk_icon(long i); +void getsym(); +struct typ *equalops(struct enode **node); +void genfunc(struct snode *stmt); +struct typ *copy_type(struct typ *s); +void repcse(struct snode *block); +int internal(char *s); +void genbyte(int val); +struct typ *bitor(struct enode **node); +void fill(int n); +void scan(struct snode *block); +struct snode *retstmt(void); +void out_init(); +void _scr_main(); +void add_code(enum(e_op) op, int len, struct amode *ap1, struct amode *ap2, int line); +char *create_ti_file(int calc,int tigl_type,char *name,char *folder,char *content,unsigned long content_size,unsigned long *ti_file_size); +long intexpr(); +int bitwise_reduction(unsigned long x,int *size); +void double2bcd(double d,struct bcd *bcd); +struct amode *g_aslogic(struct enode *node, int flags, enum(e_op) op); +long auto_init(long offs,struct typ *typ,struct typ **tpp,int brace_level,int offmod,int stroff); +void initstack(); +void falsejp(struct enode *node, unsigned int lab); +int getch(); +int doif(int x,int c); +void temp_inv(void); +long inittype(struct typ *tp,struct typ **tpp); +void do_warning(char *s, ...); +struct typ *forcefit(struct enode **node1, struct typ *tp1, struct enode **node2, struct typ *tp2); +void collect(int g); +int movem(short x); +void g_code(enum(e_op) op, int len, struct amode *ap1, struct amode *ap2); +struct enode *parmlist(struct sym *f); +int isbyte(struct enode *node); +void clean_up(); +void getrawid(); +struct typ *deref(struct enode **node, struct typ *tp); +long strip_icon(long i, enum(e_bt) type); +void genword(int val); +int getid(int c); +void d_snode(struct snode **node); +struct snode *exprstmt(void); +struct typ *relation(struct enode **node); +int integral(struct typ *tp); +void g_bitmancode(enum(e_op) op,int size,struct amode *ap1,struct amode *ap2); +struct amode *g_offset(struct amode *ap, int off); +struct amode *as_fcall(struct enode *node, int flags, char *libname); +struct snode *contstmt(void); +int vcg_init(); +long push_param(struct enode *ep); +int label(char *s); +struct amode *get_asmparam(); +struct amode *g_fderef(struct enode *node, struct amode *ap0, int flags); +int req_all_aregs(struct enode *plist,int rp_dn,int rp_an); +void genstmt(struct snode *stmt); +int vcg_cost(); +void useregs(struct _regsimg *img); /* used by g_fcall */ +char *strend(char *s); +TI_SHORT process_attr(); +void dump_genfunc(struct snode *stmt); +void getidstr(); +int stringlit(char *s, int len); +void ds_free(void); +void scope_init(void); +void verbose_print_include(char *filename); +void tmp_use(); +struct sym *symremove(char *na, struct hstab *tab); +struct sym *search(char *na, int crc, struct hstab *tab); +void add_label(int lab); +void dump_startline(); +struct typ *cond_deref(struct enode **node, struct typ *tp); +struct amode *temp_addr(void); +struct amode *g_cast2(struct enode *ep, enum(e_bt) typ2, int flags); +void get_offset(struct amode *ap); +void scanexpr(struct enode *node, int duse); +void progr_initforcurfile(); +void move_pos(long diff); /* caution : only works in overwrite mode */ +void dump_newnode(char *name); +void fatal(char *message); +int arsearch(int r,struct ocode *ip); +void usestack(struct _stackimg *img); /* used by g_expr::en_compound */ +struct typ *bitand(struct enode **node); +FILE *xfopen(char *f,char *m,int sys); +int tst_const(struct enode *node); +long mod_mask(long i); +struct amode *mk_strlab(char *s); +void concat(struct stab *dest,struct stab *src); +struct amode *temp_data(void); +void rel_dualstack(void); +int pwrof2(long i); +void hashinit(struct hstab *t); +int eq_type(struct typ *tp1, struct typ *tp2); +void dodecl(enum(e_sc) defclass); +struct snode *gotostmt(void); +void g_coder(enum(e_op) op, int len, struct amode *ap1, struct amode *ap2); +struct typ *expression(struct enode **node); +struct snode *breakstmt(void); +int has_autocon(struct enode *ep); +struct snode *dostmt(void); +char *strsave(char *s); +void opt_compare(struct enode *node); +struct amode *g_asmod(struct enode *node, int flags); +int hexatoi(char *s); +struct ocode *new_code(int s); +void d_amode(struct amode **node); +int getline(int listflag); +void call_library(char *lib_name); +unsigned long _w2ul(TI_LONG *x); +int asm_isreserved(); +void dooper(struct enode **node); +short count_dn_an(struct enode *plist,int rp_dn,int rp_an); +struct amode *g_compound(struct snode *st, int flags); +void repexpr(struct enode *node); +void initpch(); +void genfloat(double val); +void asm_searchkw(); +struct amode *g_deref(struct enode *node, enum(e_bt) type, int flags, long size); +int free_data(void); +int indir_num(struct typ *tp); +int _getline(int listflag,char *base); +struct typ *asnop(struct enode **node); +struct amode *g_fcall(struct enode *node, int flags); +void warn_usr(char *s,...); +int tst_ushort(struct enode *node); +void scope_flush(void); +void rewrite(long size); +struct amode *g_aincdec(struct enode *node, int flags, enum(e_op) op); +void funcbottom(void); +struct typ *bitxor(struct enode **node); +struct amode *g_addsub(struct enode *node, int flags, enum(e_op) op); +struct snode *statement(void); +void searchkw(void); +void opt0(struct enode **node); +void decl(struct hstab *table); /* table is used only for enum members */ +struct amode *g_index(struct enode *node); +void g_strlab(char *s); +struct enode *copynode(struct enode *node); +void expand_do(char *q,int len,char *in,char *inbound,int need_ds_update); +unsigned int getconst(enum(e_sym) s,enum(e_sym) e); +void opt1(struct snode *block); +long intexpr_notemp(); +int getasm_main(); +unsigned short _w2us(TI_SHORT *x); +struct amode *g_div(struct enode *node, int flags); +struct amode *mk_offset(struct enode *node); +unsigned long desire(struct cse *csp); +int equalnode(struct enode *node1, struct enode *node2); +void funcbody(struct sym *sp, char *names[], int nparms); +struct amode *g_commute(void *func,struct enode *node,int flags,enum(e_op) op,int dummy/*void *reversal*/); +void add_peep(struct ocode *new_ocode); +struct snode *ifstmt(void); +void locate(void); +void allocate(void); +size_t option_parse(size_t listc,char **listv,enum(OptionModes) ex_mode); +void opt3(void); +long auto_pad(long offs,int len,int offmod); +struct amode *g_asxor(struct enode *node, int flags); +void truejp(struct enode *node, unsigned int lab); +void opt4(struct enode **node); +void macro_expansion(char *in,char *inbound,int need_ds_update); +void insert(struct sym *sp,struct hstab *table); +void dumplits(); +struct amode *g_asdiv(struct enode *node, int flags); +struct amode *g_mod(struct enode *node, int flags); +struct amode *copy_addr(struct amode *ap); +int equal_address(struct amode *ap1, struct amode *ap2); +void gendouble(double val); +struct typ *commaop(struct enode **node); +void swap_nodes(struct enode *node); +int preprocess(); +void dump_addstr(char *name,char *v); +struct amode *g_alloca(struct enode *node); +struct snode *whilestmt(void); +struct amode *mk_rmask(unsigned int mask); +struct amode *mk_reg(int r); +void do_compile(); +void bitwise_optimize(struct enode *ep,long mode); +void out_close(); +unsigned int getconst2(enum(e_sym) e); +struct amode *func_result(int flags, long bytes); +struct amode *g_cast(struct amode *ap, enum(e_bt) typ1, enum(e_bt) typ2, int flags); +struct amode *g_asmul(struct enode *node, int flags); +int start_block(int m); // used in block() (func.c) +void error(int n); +void ds_allocatleast(unsigned int size); +struct typ *forceft2(struct enode **node1, struct typ *tp1, struct enode **node2, struct typ *tp2); +char *type_str(struct typ *tp); +struct amode *mk_label(unsigned int lab); +struct snode *loopstmt(void); +void asm_getsym(); +void d_ocodes(void); +void extload(unsigned char *ext); +void initsym(); +struct amode *g_shift(struct enode *node, int flags, enum(e_op) op); +void block(struct sym *sp); /* CAUTION : always requires a compound_done() after call */ +struct amode *g_ybin(struct enode *node, int flags, enum(e_op) op); +struct sym *gsearch(char *na,int crc); +int cast_ok(struct typ *tp1, struct typ *tp2, int need_physically_compatible); +void needpunc(enum(e_sym) p); +struct amode *mk_scratch(long size); +void dump_genstmt(struct snode *stmt); +void d_enode(struct enode **node); +int ap_hasbeenpushed(struct amode *ap); +struct amode *g_unary(struct enode *node, int flags, enum(e_op) op); +void append(struct sym **ptr_sp, struct hstab *table); +void checkstack(void); +void rel_global(); +void option_parse_all(enum(OptionModes) ex_mode); +int pchload(char *name,char *data,unsigned int flags,unsigned char *tabp, unsigned char *p0,TI_SHORT *extTab); +void my_fclose(FILE *f); +struct typ *andop(struct enode **node); +struct amode *g_expr(struct enode *node, int flags); +struct amode *g_assign(struct enode *node, int flags); +void rel_local(); +struct sym *mk_int(char *name); +struct snode *asmstmt(void); +unsigned long double2ffp(double d); +void decl1(void); +struct typ *orop(struct enode **node); +int alignment(struct typ *tp); +struct amode *g_asshift(struct enode *node, int flags, enum(e_op) op); +void closepch(); +void castback(long offset, struct typ *tp1, struct typ *tp2); +void dump_addreg(char *name,int v); +double floatexpr(); +void freeop(struct amode *ap); +void err_usr(int m,...); +struct typ *cast_op(struct enode **ep, struct typ *tp1, struct typ *tp2); +struct amode *g_asadd(struct enode *node, int flags, enum(e_op) op); +int tst_short(struct enode *node); +struct typ *mk_type(enum(e_bt) bt, int siz); +struct enode *mk_node(enum(e_node) nt, struct enode *v1, struct enode *v2); +void _repexpr(struct enode **ep); +struct typ *binlog(struct enode **node, struct typ *(*xfunc)(), enum(e_node) nt, enum(e_sym) sy); +struct amode *func_result2(int flags, long bytes, int reg); +struct typ *force_cast_op(struct enode **ep, struct typ *tp1, struct typ *tp2); +void _exit(int code); +struct amode *g_mul(struct enode *node, int flags); +void tmp_free(); +struct snode *switchstmt(void); +void g_pop(int reg, enum(e_am) rmode, int number); +struct snode *compound(int no_init); +int isshort(struct enode *node); +void flush_peep(); +void put_label(int lab); +int not_lvalue(struct enode *node); +struct amode *mk_smask(unsigned int mask); +int datalit(char *s, int len); +void verbose_print_searchdirs(); +void structassign(struct amode *ap1, struct amode *ap2, long size, int mode); +int pchsearch(char *id,int mode); /* returns 0 if not PCH, 1 if PCH/def, -1 if PCH/init */ +struct snode *labelstmt(void); +int getsch(int flag); +struct amode *g_xbin(struct enode *node, int flags, enum(e_op) op); +void genfuncbegin(void); +int crcN(char *na); +struct typ *binop(struct enode **node, struct typ *(*xfunc)(), enum(e_node) nt, enum (e_sym) sy); +void bsort(struct cse **list); +int macro_expand(char *id,int crc/* may equal -1 */,char *in,char *oldin,char *inbound,int need_ds_update); +void g_push(int reg, enum(e_am) rmode, int number); +int checkcases(struct snode *head); +struct amode *g_hook(struct enode *node, int flags); +void insert_macros(char *p); +struct typ *exprnc(struct enode **node); +void genptr(struct enode *node); +int *_xalloc(int siz); +int castbegin(enum(e_sym) st); +void skipspace(); +int ppquit(); +void dump_addint(char *name,int v); +void validate(struct amode *ap); +int radix36(char c); +struct amode *mk_legal(struct amode *ap, int flags, long size); +struct typ *copy_type_global(struct typ *tp); +void freestack(struct _stackimg *img); /* used by g_expr::en_compound */ +char *fill_calcvar(char *buffer, char *input); +int getcache(enum(e_sym) f); +int vcg_done(); +void put_align2(void); +int dodefine(int mode); // 1: #define, -1 : #macro, 0 : #undef +int drsearch(int r,struct ocode *ip); +struct typ *conditional(struct enode **node); +void doinit(struct sym *sp, int align); + +#endif diff --git a/gtc/src/reg68k.c b/gtc/src/reg68k.c new file mode 100644 index 0000000..7a1434b --- /dev/null +++ b/gtc/src/reg68k.c @@ -0,0 +1,446 @@ +/* + * GTools C compiler + * ================= + * source file : + * register allocation + * + * Copyright 2001-2004 Paul Froissart. + * Credits to Christoph van Wuellen and Matthew Brandt. + * All commercial rights reserved. + * + * This compiler may be redistributed as long there is no + * commercial interest. The compiler must not be redistributed + * without its full sources. This notice must stay intact. + */ + +#include "define.h" +_FILE(__FILE__) +#include "c.h" +#include "expr.h" +#include "gen.h" +#include "cglbdec.h" + +/* + * Register allocation (for the expression evaluation) + * This modules handles the management of scratch registers. + * It keeps track of the allocated registers and of the stack + */ + +#ifdef MC680X0 + +xstatic int next_data CGLOB, next_addr CGLOB; + +#ifndef INFINITE_REGISTERS +xstatic char dreg_in_use[MAX_DATA + 1] CGLOBL; +xstatic char areg_in_use[MAX_ADDR + 1] CGLOBL; + +xstatic struct reg_struct reg_stack[MAX_REG_STACK + 1] CGLOBL, + reg_alloc[MAX_REG_STACK + 1] CGLOBL; + +xstatic int reg_stack_ptr CGLOB; +xstatic int reg_alloc_ptr CGLOB; +#endif + +void g_push(int reg, enum(e_am) rmode, int number) { +#ifndef INFINITE_REGISTERS +/* + * this routine generates code to push a register onto the stack + */ + struct amode *ap; + ap = (struct amode *) xalloc((int) sizeof(struct amode), AMODE+G_PUSH); + ap->preg = reg; + ap->mode = rmode; + g_code(op_move, 4, ap, push_am); + reg_stack[reg_stack_ptr].mode = rmode; + reg_stack[reg_stack_ptr].reg = reg; + reg_stack[reg_stack_ptr].flag = number; + if (reg_alloc[number].flag) + ierr(G_PUSH,1); + reg_alloc[number].flag = 1; + /* check on stack overflow */ + if (++reg_stack_ptr > MAX_REG_STACK) + ierr(G_PUSH,2); +#else + fatal("GPUSH/infinite"); +#endif +} + +void g_pop(int reg, enum(e_am) rmode, int number) { +#ifndef INFINITE_REGISTERS +/* + * generate code to pop a register from the stack. + */ + struct amode *ap; + + /* check on stack underflow */ + if (reg_stack_ptr-- == 0) + ierr(G_POP,1); + /* check if the desired register really is on stack */ + if (reg_stack[reg_stack_ptr].flag != number) + ierr(G_POP,2); + /* check if the register which is restored is really void */ + if (rmode == am_dreg) { + if (dreg_in_use[reg] >= 0) + ierr(G_POP,3); + dreg_in_use[reg] = number; + } else { + if (areg_in_use[reg] >= 0) + ierr(G_POP,4); + areg_in_use[reg] = number; + } + ap = (struct amode *) xalloc((int) sizeof(struct amode), AMODE+G_PUSH); + ap->mode = rmode; + ap->preg = reg; + g_code(op_move, 4, pop_am, ap); + /* clear the push_flag */ + reg_alloc[number].flag = 0; +#endif +} + +void initstack() { +/* + * this routine should be called before each expression is evaluated to make + * sure the stack is balanced and all of the registers are marked free. + * This is also a good place to free all 'pseudo' registers in the + * stack frame by setting act_scratch to zero + */ +#ifndef INFINITE_REGISTERS + int i; + next_data = 0; + next_addr = 0; + for (i = 0; i <= MAX_DATA; i++) + dreg_in_use[i] = -1; + for (i = 0; i <= MAX_ADDR; i++) + areg_in_use[i] = -1; + reg_stack_ptr = 0; + reg_alloc_ptr = 0; +#else + next_data = FIRSTREG; + next_addr = FIRSTREG; +#endif + act_scratch = 0; +} + +//#if 0 +#ifndef __HAVE_STACK_IMAGE +#define __HAVE_STACK_IMAGE +typedef struct _stackimg { + int next_data,next_addr; +#ifndef INFINITE_REGISTERS + int reg_alloc_ptr,reg_stack_ptr; + char dreg_in_use[MAX_DATA+1]; + char areg_in_use[MAX_ADDR+1]; + struct reg_struct reg_stack[MAX_REG_STACK+1],reg_alloc[MAX_REG_STACK+1]; + int act_scratch; +#endif +} STACK_IMAGE; +#endif +void usestack(STACK_IMAGE *img) { /* used by g_expr::en_compound */ + img->next_data = next_data; + img->next_addr = next_addr; +#ifndef INFINITE_REGISTERS + img->act_scratch = act_scratch; + img->reg_alloc_ptr = reg_alloc_ptr; + img->reg_stack_ptr = reg_stack_ptr; + memcpy(img->dreg_in_use, dreg_in_use, MAX_DATA+1); + memcpy(img->areg_in_use, areg_in_use, MAX_ADDR+1); + memcpy(img->reg_stack, reg_stack, sizeof(struct reg_struct)*(MAX_REG_STACK+1)); + memcpy(img->reg_alloc, reg_alloc, sizeof(struct reg_struct)*(MAX_REG_STACK+1)); +#endif +} +void freestack(STACK_IMAGE *img) { /* used by g_expr::en_compound */ + next_data = img->next_data; + next_addr = img->next_addr; +#ifndef INFINITE_REGISTERS + act_scratch = img->act_scratch; + reg_alloc_ptr = img->reg_alloc_ptr; + reg_stack_ptr = img->reg_stack_ptr; + memcpy(dreg_in_use, img->dreg_in_use, MAX_DATA+1); + memcpy(areg_in_use, img->areg_in_use, MAX_ADDR+1); + memcpy(reg_stack, img->reg_stack, sizeof(struct reg_struct)*(MAX_REG_STACK+1)); + memcpy(reg_alloc, img->reg_alloc, sizeof(struct reg_struct)*(MAX_REG_STACK+1)); +#endif +} +//#endif + +#ifdef REGPARM +#ifndef __HAVE_REGS_IMAGE +#define __HAVE_REGS_IMAGE +typedef struct _regsimg { +#ifndef INFINITE_REGISTERS + int reg_alloc_ptr,reg_stack_ptr; + int next_data,next_addr; +#endif +} REGS_IMAGE; +#endif +void useregs(REGS_IMAGE *img) { /* used by g_fcall */ +#ifndef INFINITE_REGISTERS + img->reg_alloc_ptr = reg_alloc_ptr; + img->reg_stack_ptr = reg_stack_ptr; + img->next_data = next_data; + img->next_addr = next_addr; + next_data = 0; + next_addr = 0; +#endif +} +void freeregs(REGS_IMAGE *img) { /* used by g_fcall */ +#ifndef INFINITE_REGISTERS + int i; + for (i = 0; i <= MAX_DATA; i++) + dreg_in_use[i] = -1; + for (i = 0; i <= MAX_ADDR; i++) + areg_in_use[i] = -1; + reg_alloc_ptr = img->reg_alloc_ptr; + reg_stack_ptr = img->reg_stack_ptr; + next_data = img->next_data; + next_addr = img->next_addr; +#endif +} +#endif + +#ifdef PC +void checkstack(void) { +#ifndef INFINITE_REGISTERS +/* + * this routines checks if all allocated registers were freed + */ + int i; + for (i=0; i<= MAX_DATA; i++) + if (dreg_in_use[i] != -1) + ierr(CHECKSTACK,1); + for (i=0; i<= MAX_ADDR; i++) + if (areg_in_use[i] != -1) + ierr(CHECKSTACK,2); + if (reg_stack_ptr != 0) + ierr(CHECKSTACK,5); + if (reg_alloc_ptr != 0) + ierr(CHECKSTACK,6); +#endif + if (next_data != FIRSTREG) + ierr(CHECKSTACK,3); + if (next_addr != FIRSTREG) + ierr(CHECKSTACK,4); +} +#endif + +int ap_hasbeenpushed(struct amode *ap) { +#ifndef INFINITE_REGISTERS + return reg_alloc[(int)(ap)->deep].flag; +#else + return 0; +#endif +} + +void validate(struct amode *ap) { +#ifndef INFINITE_REGISTERS +/* + * validate will make sure that if a register within an address mode has been + * pushed onto the stack that it is popped back at this time. + */ + switch (ap->mode) { + case am_dreg: + if (ap->preg <= MAX_DATA && reg_alloc[(int)ap->deep].flag) { + g_pop(ap->preg, am_dreg, (int) ap->deep); + } + break; + case am_indx2: + if (ap->sreg <= MAX_DATA && reg_alloc[(int)ap->deep].flag) { + g_pop(ap->sreg, am_dreg, (int) ap->deep); + } + goto common; + case am_indx3: + if (ap->sreg <= MAX_ADDR && reg_alloc[(int)ap->deep].flag) { + g_pop(ap->sreg, am_areg, (int) ap->deep); + } + goto common; + case am_areg: + case am_ind: + case am_indx: + case am_ainc: + case am_adec: +common: + if (ap->preg <= MAX_ADDR && reg_alloc[(int)ap->deep].flag) { + g_pop(ap->preg, am_areg, (int) ap->deep); + } + break; + } +#endif +} + +struct amode *temp_data(void) { +/* + * allocate a temporary data register and return it's addressing mode. + */ + struct amode *ap; + ap = (struct amode *) xalloc((int) sizeof(struct amode), AMODE+TEMP_DATA); +#ifndef INFINITE_REGISTERS + if (dreg_in_use[next_data] >= 0) + /* + * The next available register is already in use. it must be pushed + */ + g_push(next_data, am_dreg, dreg_in_use[next_data]); + dreg_in_use[next_data] = reg_alloc_ptr; +#endif + ap->mode = am_dreg; + ap->preg = next_data; +#ifndef INFINITE_REGISTERS + ap->deep = reg_alloc_ptr; + reg_alloc[reg_alloc_ptr].reg = next_data; + reg_alloc[reg_alloc_ptr].mode = am_dreg; + reg_alloc[reg_alloc_ptr].flag = 0; + if (next_data++ == MAX_DATA) + next_data = 0; /* wrap around */ + if (reg_alloc_ptr++ == MAX_REG_STACK) + ierr(TEMP_DATA,1); +#else + next_data++; +#endif + return ap; +} + +struct amode *temp_addr(void) { +/* + * allocate a temporary addr register and return it's addressing mode. + */ + struct amode *ap; + ap = (struct amode *) xalloc((int) sizeof(struct amode), AMODE+TEMP_ADDR); +#ifndef INFINITE_REGISTERS + if (areg_in_use[next_addr] >= 0) + /* + * The next available register is already in use. it must be pushed + */ + g_push(next_addr, am_areg, areg_in_use[next_addr]); + areg_in_use[next_addr] = reg_alloc_ptr; +#endif + ap->mode = am_areg; + ap->preg = next_addr; +#ifndef INFINITE_REGISTERS + ap->deep = reg_alloc_ptr; + reg_alloc[reg_alloc_ptr].reg = next_addr; + reg_alloc[reg_alloc_ptr].mode = am_areg; + reg_alloc[reg_alloc_ptr].flag = 0; + if (next_addr++ == MAX_ADDR) + next_addr = 0; /* wrap around */ + if (reg_alloc_ptr++ == MAX_REG_STACK) + ierr(TEMP_ADDR,1); +#else + next_addr++; +#endif + return ap; +} + +int free_data(void) { +/* + * returns TRUE if a data register is available at ,,no cost'' (no push). + * Used to determine e.g. wether cmp.w #0,An or move.l An,Dm is better + */ +#ifndef INFINITE_REGISTERS + return (dreg_in_use[next_data] < 0); +#else + return 1; +#endif +} + +void freeop(struct amode *ap) { +/* + * release any temporary registers used in an addressing mode. + */ + int number; + if (ap == 0) + /* This can happen freeing a NOVALUE result */ + return; + switch (ap->mode) { + case am_dreg: + if (ap->preg <= MAX_DATA) { + if (next_data-- == 0) + next_data = MAX_DATA; +#ifndef INFINITE_REGISTERS + number = dreg_in_use[(int)ap->preg]; + dreg_in_use[(int)ap->preg] = -1; +#endif + break; + } + return; + case am_indx2: + if (ap->sreg <= MAX_DATA) { + if (next_data-- == 0) + next_data = MAX_DATA; +#ifndef INFINITE_REGISTERS + number = dreg_in_use[(int)ap->sreg]; + dreg_in_use[(int)ap->sreg] = -1; +#endif + break; + } + goto common; + case am_indx3: + if (ap->sreg <= MAX_ADDR) { + if (next_addr-- == 0) + next_addr = MAX_ADDR; +#ifndef INFINITE_REGISTERS + number = areg_in_use[(int)ap->sreg]; + areg_in_use[(int)ap->sreg] = -1; +#endif + break; + } + goto common; + case am_areg: + case am_ind: + case am_indx: + case am_ainc: + case am_adec: +common: + if (ap->preg <= MAX_ADDR) { + if (next_addr-- == 0) + next_addr = MAX_ADDR; +#ifndef INFINITE_REGISTERS + number = areg_in_use[(int)ap->preg]; + areg_in_use[(int)ap->preg] = -1; +#endif + break; + } + return; + default: + return; + } +#ifndef INFINITE_REGISTERS + /* some consistency checks */ + if (number != ap->deep) + ierr(FREEOP,1); + /* we should only free the most recently allocated register */ + if (reg_alloc_ptr-- == 0) + ierr(FREEOP,2); + if (reg_alloc_ptr != number) + ierr(FREEOP,3); + /* the just freed register should not be on stack */ + if (reg_alloc[number].flag) + ierr(FREEOP,4); +#endif +} + +void temp_inv(void) { +#ifndef INFINITE_REGISTERS +/* + * push any used temporary registers. + * This is necessary across function calls + * The reason for this hacking is actually that temp_inv should dump + * the registers in the correct order, + * the least recently allocated register first. + * the most recently allocated register last. + */ + int i; + + for (i = 0; i < reg_alloc_ptr; i++) + if (reg_alloc[i].flag == 0) { + g_push(reg_alloc[i].reg, reg_alloc[i].mode, i); + /* mark the register void */ + if (reg_alloc[i].mode == am_dreg) + dreg_in_use[reg_alloc[i].reg] = -1; + else + areg_in_use[reg_alloc[i].reg] = -1; + } +#else + g_code(_op_cleanup_for_external_call, 0, NIL_AMODE, NIL_AMODE); +#endif +} +#endif /* MC680X0 */ +// vim:ts=4:sw=4 diff --git a/gtc/src/searchkw.c b/gtc/src/searchkw.c new file mode 100644 index 0000000..c5c3222 --- /dev/null +++ b/gtc/src/searchkw.c @@ -0,0 +1,182 @@ +/* + * GTools C compiler + * ================= + * source file : + * keyword searching + * + * Copyright 2001-2004 Paul Froissart. + * Credits to Christoph van Wuellen and Matthew Brandt. + * All commercial rights reserved. + * + * This compiler may be redistributed as long there is no + * commercial interest. The compiler must not be redistributed + * without its full sources. This notice must stay intact. + */ + +#include "define.h" +_FILE(__FILE__) +#include "c.h" +#include "expr.h" +#include "gen.h" +#include "cglbdec.h" + +xstatic readonly struct kwblk { + char *word; + enum(e_sym) stype; +#ifndef PC + int pad; +#endif +} keywords[] = { + { + "__asm__", kw_asm + }, { + "__attribute__", kw_attr + }, { + "__builtin_constant_p", kwb_constant_p + }, { + "__c__", kw_c + }, { + "__count__", kw_count + }, { + "__eval__", kw_eval + }, { + "__loop__", kw_loop + }, { + "__softcast__", kw_softcast + }, { + "__until__", kw_until + }, { + "alloca", kw_alloca + }, { + "asm", kw_asm + }, { + "auto", kw_auto + }, { + "break", kw_break + }, { + "case", kw_case + }, { + "char", kw_char + }, { + "const", kw_const + }, { + "continue", kw_continue + }, { + "default", kw_default + }, { + "defined", kw_defined + }, { + "do", kw_do + }, { + "double", kw_double + }, { + "else", kw_else + }, { + "enum", kw_enum + }, { + "extern", kw_extern + }, { + "float", kw_float + }, { + "for", kw_for + }, { + "goto", kw_goto + }, { + "if", kw_if + }, { + "incbin", kw_incbin + }, { + "int", kw_int + }, { + "long", kw_long + }, { + "loop", kw_loop + }, { + "register", kw_register + }, { + "return", kw_return + }, { + "short", kw_short + }, { + "signed", kw_signed + }, { + "sizeof", kw_sizeof + }, { + "static", kw_static + }, { + "struct", kw_struct + }, { + "switch", kw_switch + }, { + "typedef", kw_typedef + }, { + "typeof", kw_typeof + }, { + "union", kw_union + }, { + "unsigned", kw_unsigned + }, { + "until", kw_until + }, { + "void", kw_void + }, { + "volatile", kw_volatile + }, { + "while", kw_while +/* }, { + 0, 0*/ + } +}; + +#define kw_N 48 + +/* + * Dichotomic search allows a max of 6 comparisons instead of 50... + */ +void searchkw(void) { + char *s1,*s2,c; + const struct kwblk *kwbp; + int a=0,b=kw_N-1,m; +#ifdef PC + if (sizeof(keywords)/sizeof(struct kwblk)!=kw_N) + fatal("BUILD ERROR: INVALID KEYWORDS #"); +#endif + while (a<=b) { + m=(a+b)>>1; + kwbp=&keywords[m]; + s1=lastid; + s2=kwbp->word; + do { + if (!(c=*s2++)) { + if (!*s1) + lastst = kwbp->stype; + if (is_lang_ext(lastst) && lastid[0]!='_' && !(flags&X_LANG_EXT)) + lastst = id; + if (*s1!='u') // the only case when a kw is the beginning of another one + return; // is 'do' vs 'double' + } + } while (*s1++==c); + if (s1[-1] word != 0) { + s1 = lastid; + s2 = kwbp->word; + kwbp++; + do { + if (!(c=*s2++)) { + if (!*s1++) + lastst = (--kwbp)->stype; + return; + } + } while (*s1++==c); + } +}*/ +// vim:ts=4:sw=4 diff --git a/gtc/src/securecommdef.h b/gtc/src/securecommdef.h new file mode 100644 index 0000000..795d204 --- /dev/null +++ b/gtc/src/securecommdef.h @@ -0,0 +1,23 @@ +/* + * GTools C compiler + * ================= + * source file : + * (on-calc) GT-Dev header file + * + * Copyright 2001-2004 Paul Froissart. + * Credits to Christoph van Wuellen and Matthew Brandt. + * All commercial rights reserved. + * + * This compiler may be redistributed as long there is no + * commercial interest. The compiler must not be redistributed + * without its full sources. This notice must stay intact. + */ + +#ifndef __SECURECOMMDEF_H +#define __SECURECOMMDEF_H +typedef struct { + long dummy; + void *sft[]; +} SecureTab; +#endif +// vim:ts=4:sw=4 diff --git a/gtc/src/stmt.c b/gtc/src/stmt.c new file mode 100644 index 0000000..4292c1e --- /dev/null +++ b/gtc/src/stmt.c @@ -0,0 +1,952 @@ +/* + * GTools C compiler + * ================= + * source file : + * statement handling + * + * Copyright 2001-2004 Paul Froissart. + * Credits to Christoph van Wuellen and Matthew Brandt. + * All commercial rights reserved. + * + * This compiler may be redistributed as long there is no + * commercial interest. The compiler must not be redistributed + * without its full sources. This notice must stay intact. + */ + +#include "define.h" +_FILE(__FILE__) +#include "c.h" +#include "expr.h" +#include "gen.h" +#include "cglbdec.h" +#ifdef PC +#ifdef SHORT_INT +#undef int +#endif +#include +#ifdef SHORT_INT +#define int short +#endif +#endif + +struct enode *init_node CGLOB; + +TYP *lastexpr_tp CGLOB; +int lastexpr_size CGLOB, lastexpr_type CGLOB; + +/* + * the statement module handles all of the possible c statements and builds a + * parse tree of the statements. + * + * each routine returns a pointer to a statement parse node which reflects the + * statement just parsed. + */ + + +int start_block(int m) { // used in block() (func.c) + if (m) { + needpunc(begin); + return 1; // we don't care about the result in this case + } else + return lastst==begin; +} + +unsigned int getconst(enum(e_sym) s,enum(e_sym) e) { + struct enode *en; + getsym(); + if (lastst != s) + error(ERR_EXPREXPECT); + else { + getsym(); + if (exprnc(&en) == 0) + error(ERR_EXPREXPECT); + needpunc(e); + opt0(&en); + if (en->nodetype != en_icon) + error(ERR_CONSTEXPECT); + else if ((unsigned long)en->v.i>=65536) + error(ERR_OUTRANGE); + else return en->v.i; + } + return 0; // make the compiler happy +} +unsigned int getconst2(enum(e_sym) e) { + struct enode *en; + if (exprnc(&en) == 0) + error(ERR_EXPREXPECT); + needpunc(e); + opt0(&en); + if (en->nodetype != en_icon) + error(ERR_CONSTEXPECT); + else if ((unsigned long)en->v.i>=65536) + error(ERR_OUTRANGE); + else return en->v.i; + return 0; // make the compiler happy +} + +struct snode *whilestmt(void) { +/* + * whilestmt parses the c while statement. + */ + struct snode *snp; + snp = (struct snode *) xalloc((int) sizeof(struct snode), SNODE); + snp->stype = st_while; + snp->count = 3; + getsym(); + if (lastst != openpa) + error(ERR_EXPREXPECT); + else { + getsym(); + if (expression(&(snp->exp)) == 0) + error(ERR_EXPREXPECT); +#ifdef DB_POSSIBLE + snp->line=lineid; +#endif + needpunc(closepa); + if (lastst == kw_count) snp->count=getconst(openpa,closepa); + snp->s1 = statement(); + } + return snp; +} + +struct snode *asmstmt(); +#if !defined(AS) && !defined(ASM) +struct snode *asmstmt(void) { +/* + * asmstmt parses the gtc c asm statement. + */ + struct snode *snp; + snp = (struct snode *) xalloc((int) sizeof(struct snode), SNODE); + snp->stype = st_asm; + snp->count = 1; + getsym(); + if (lastst != openpa) + error(ERR_EXPREXPECT); + else { + getsym(); + if (lastst != sconst) + error(ERR_SYNTAX); + snp->v1.i = (long)strsave(laststr); + getsym(); + if (lastst == colon) { + getsym(); + uwarn("only asm(\"...\") is supported yet"); + error(ERR_SYNTAX); + } + needpunc(closepa); + needpunc(semicolon); + } +#ifdef DB_POSSIBLE + snp->line=lineid; +#endif + return snp; +} +#endif + +//struct enode lp_one = { en_icon, bt_ushort, 2, {1L}, 0, 0}; +xstatic struct enode *lp_one CGLOB; +struct snode *loopstmt(void) { +/* + * loopstmt parses the gtc c loop statement. + */ + struct snode *snp; TYP *tp; + struct enode *exp; + int has_count; + snp = (struct snode *) xalloc((int) sizeof(struct snode), SNODE); + snp->stype = st_loop; + snp->count = 3; + has_count = 0; + getsym(); + if (lastst != openpa) + error(ERR_EXPREXPECT); + else { + getsym(); + if (lastst != id) + error(ERR_IDEXPECT); + if (!nameref(&(snp->v1.e))) error(ERR_EXPREXPECT); + if (lastst != assign) + error(ERR_SYNTAX); + getsym(); + if (!(tp=expression(&(snp->exp)))) + error(ERR_EXPREXPECT); + cast_op(&(snp->exp),tp,(TYP *)&tp_ushort); +#ifdef DB_POSSIBLE + snp->line=lineid; +#endif + needpunc(closepa); + if (lastst == kw_count) { snp->count=getconst(openpa,closepa); has_count=1; } + opt0(&(snp->exp)); + if (snp->exp->nodetype==en_icon) { + unsigned int c=snp->exp->v.i; + if (has_count) { + if (c!=snp->count) + uwarn("loop has an effective count of %u whereas %u precised", + c,snp->count); + } else snp->count=c; + } + lp_one = mk_icon(1L); + lp_one->etype = bt_ushort; lp_one->esize = 2; + snp->exp = exp = mk_node(en_sub,snp->exp,lp_one); + exp->etype = bt_ushort; exp->esize = 2; + opt4(&(snp->exp)); + snp->exp = exp = mk_node(en_assign,snp->v1.e,snp->exp); + exp->etype = bt_ushort; exp->esize = 2; + snp->s1 = statement(); + if (lastst == kw_until) { + getsym(); + if (!expression(&(snp->v2.e))) error(ERR_EXPREXPECT); + } else snp->v2.e=NULL; + } + return snp; +} + +struct snode *dostmt(void) { +/* + * dostmt parses the c do-while construct. + */ + struct snode *snp; + snp = (struct snode *) xalloc((int) sizeof(struct snode), SNODE); + snp->stype = st_do; + snp->count = 3; + getsym(); + snp->s1 = statement(); +#ifdef DB_POSSIBLE + snp->line=lineid; +#endif + if (lastst != kw_while) + error(ERR_WHILEXPECT); + else { + getsym(); + if (lastst != openpa) + error(ERR_EXPREXPECT); + else { + getsym(); + if (expression(&(snp->exp)) == 0) + error(ERR_EXPREXPECT); + needpunc(closepa); + if (lastst == kw_count) snp->count=getconst(openpa,closepa); + } + if (lastst != end) + needpunc(semicolon); + } + return snp; +} + +struct snode *forstmt(void) { + struct snode *snp; + snp = (struct snode *) xalloc((int) sizeof(struct snode), SNODE); + snp->stype = st_for; + snp->count = 3; + getsym(); + needpunc(openpa); + /*if (*/expression(&(snp->exp))/* == 0) + snp->exp = 0*/; + needpunc(semicolon); + /*if (*/expression(&(snp->v1.e))/* == 0) + snp->v1.e = 0*/; + needpunc(semicolon); + /*if (*/expression(&(snp->v2.e))/* == 0) + snp->v2.e = 0*/; +#ifdef DB_POSSIBLE + snp->line=lineid; +#endif + needpunc(closepa); + if (lastst == kw_count) snp->count=getconst(openpa,closepa); + snp->s1 = statement(); + return snp; +} + +struct snode *ifstmt(void) { +/* + * ifstmt parses the c if statement and an else clause if one is present. + */ + struct snode *snp; + snp = (struct snode *) xalloc((int) sizeof(struct snode), SNODE); + snp->stype = st_if; + snp->count=32768; + getsym(); + if (lastst != openpa) + error(ERR_EXPREXPECT); + else { + getsym(); + if (expression(&(snp->exp)) == 0) + error(ERR_EXPREXPECT); +#ifdef DB_POSSIBLE + snp->line=lineid; +#endif + needpunc(closepa); + if (lastst == kw_count) { + unsigned int i=getconst(openpa,comma),j=getconst2(closepa); + snp->count=((unsigned long)i<<16)/(i+j); + } + snp->s1 = statement(); + if (lastst == kw_else) { + getsym(); + snp->v1.s = statement(); + } else { +#ifdef NO_CALLOC + snp->v1.s = 0; +#endif + } + } + return snp; +} + +/* + * consider the following piece of code: + * + * switch (i) { + * case 1: + * if (j) { + * ..... + * } else + * case 2: + * .... + * } + * + * case statements may be deep inside, so we need a global variable + * last_case to link them + */ +xstatic struct snode *last_case CGLOB; /* last case statement within this switch */ + +struct snode *casestmt(void) { +/* + * cases are returned as seperate statements. for normal cases label is the + * case value and v1.i is zero. for the default case v1.i is nonzero. + */ + struct snode *snp,*snp0; + snp0 = snp = (struct snode *) xalloc((int) sizeof(struct snode), SNODE); +#ifdef NO_CALLOC + snp->s1 = NIL_SNODE; +#endif + if (lastst == kw_case) { + long v; + getsym(); + snp->stype = st_case; + snp->v2.i = v = intexpr(); + if (lastst == dots) { // TODO : make only one 'case' label + long max; + getsym(); + if ((max = intexpr()) < v) error(ERR_CASERANGE); + else while (v != max) { + last_case = last_case->s1 = snp; + snp = (struct snode *) xalloc((int) sizeof(struct snode), SNODE); + last_case->v1.s = snp; +#ifdef NO_CALLOC + snp->s1 = NIL_SNODE; +#endif + snp->stype = st_case; + snp->v2.i = ++v; + } + } + } else { + /* lastst is kw_default */ + getsym(); + /* CVW: statement type needed for analyze etc. */ + snp->stype = st_default; + } + last_case = last_case->s1 = snp; + needpunc(colon); + if (lastst != end) + snp->v1.s = statement(); + return snp0; +} + +int checkcases(struct snode *head) { +/* + * checkcases will check to see if any duplicate cases exist in the case list + * pointed to by head. + */ + struct snode *top, *cur; + cur = top = head; + while (top != 0) { + cur = top->s1; + while (cur != 0) { + if (cur->stype != st_default && top->stype != st_default + && cur->v2.i == top->v2.i) { + uwarn("duplicate case label for value %ld", cur->v2.i); + return 1; + } + if (cur->stype == st_default && top->stype == st_default) { + uwarn("duplicate default label"); + return 1; + } + cur = cur->s1; + } + top = top->s1; + } + return 0; +} + +struct snode *switchstmt(void) { + struct snode *snp; + struct snode *local_last_case; + local_last_case = last_case; + snp = (struct snode *) xalloc((int) sizeof(struct snode), SNODE); + last_case = snp; +#ifdef NO_CALLOC + snp->s1 = 0; +#endif + snp->stype = st_switch; + getsym(); + needpunc(openpa); + if ((expression(&(snp->exp))) == 0) + error(ERR_EXPREXPECT); +#ifdef DB_POSSIBLE + snp->line=lineid; +#endif + needpunc(closepa); + needpunc(begin); + snp->v1.s = compound(1); + if (checkcases(snp->s1)) + error(ERR_DUPCASE); + last_case = local_last_case; + return snp; +} + +struct snode *retstmt(void) { + struct snode *snp; + TYP *tp; + snp = (struct snode *) xalloc((int) sizeof(struct snode), SNODE); + snp->stype = st_return; + getsym(); + tp = expression(&(snp->exp)); + if (snp->exp != 0) + (void) cast_op(&(snp->exp), tp, ret_type); + if (lastst != end) + needpunc(semicolon); +#ifdef DB_POSSIBLE + snp->line=prevlineid; +#endif + return snp; +} + +struct snode *breakstmt(void) { + struct snode *snp; + snp = (struct snode *) xalloc((int) sizeof(struct snode), SNODE); + snp->stype = st_break; + getsym(); + if (lastst != end) + needpunc(semicolon); +#ifdef DB_POSSIBLE + snp->line=prevlineid; +#endif + return snp; +} + +struct snode *contstmt(void) { + struct snode *snp; + snp = (struct snode *) xalloc((int) sizeof(struct snode), SNODE); + snp->stype = st_continue; + getsym(); + if (lastst != end) + needpunc(semicolon); +#ifdef DB_POSSIBLE + snp->line=prevlineid; +#endif + return snp; +} + +struct snode *exprstmt(void) { +/* + * exprstmt is called whenever a statement does not begin with a keyword. the + * statement should be an expression. + */ + struct snode *snp; + debug('u'); + snp = (struct snode *) xalloc((int) sizeof(struct snode), SNODE); + snp->stype = st_expr; +/* + * I have a problem here. + * If expression() fails on the first character and does not do a getsym(), + * there may be an infinite loop since we will continue coming up here. + * Since the compiler will stop after MAX_ERROR_COUNT calls to error(), + * this might not be THAT much of a problem. + */ + if (!(lastexpr_tp=expression(&(snp->exp)))) + error(ERR_EXPREXPECT); + else { + lastexpr_type=snp->exp->etype; + lastexpr_size=snp->exp->esize; + } + debug('v'); + if (lastst != end) + needpunc(semicolon); +#ifdef DB_POSSIBLE + snp->line=prevlineid; +#endif + debug('w'); + return snp; +} + +#ifdef AUTOINIT_PAD +//long auto_init(long offs,TYP *typ,int brace_level,int offmod); +long auto_pad(long offs,int len,int offmod) { + long nbytes=0; + while (len>0) { + int size; + if ((offs+offmod)&1) + size=1; + else if (len<=2) + size=len; + else if (len==3) + size=2; + else size=4; + + { + struct enode *ep1,*ep2=mk_icon(0L),*ep3; + ep2->esize = size; /* don't care about the etype, it's set to char */ + + ep1 = mk_node(en_autocon, NIL_ENODE, NIL_ENODE); + ep1->v.i = offs; + ep1->etype = bt_pointer; + ep1->esize = 4; + + ep3 = mk_icon((long)offmod); + ep3->etype = bt_long; + ep3->esize = 4; + + ep1 = mk_node(en_add, ep1, ep3); + ep1->etype = bt_pointer; + ep1->esize = 4; + + ep1 = mk_node(en_ref, ep1, NIL_ENODE); + ep1->esize = size; /* don't care about the etype, it's set to char */ + + ep1 = mk_node(en_assign, ep1, ep2); + ep1->esize = size; /* don't care about the etype, it's set to char */ + + if (init_node == 0) { + init_node = ep1; + } else { + init_node = mk_node(en_void, init_node, ep1); + } + } + + len-=size; + nbytes+=size; + offmod+=size; + } + return nbytes; +} +#endif + +long auto_init(long offs,TYP *typ,TYP **tpp,int brace_level,int offmod,int stroff) { +/* + * generated assignment statements for initialization of auto and register + * variables. The initialization is generated like comma operators so a + * single statement does all the initializations + */ + struct enode *ep1, *ep2; + struct typ *tp; + int brace_seen = 0; + long nbytes = 0; + +auto_init_restart: + if (lastst == begin) { + brace_level++; + brace_seen++; + getsym(); + } + if (typ->type==bt_struct && brace_level) { + struct sym *sp; + sp = typ->lst.head; /* start at top of symbol table */ + while (sp != 0) { +/* infunc("DrawPacmanLogoAndHandleMenu") + bkpt();*/ + nbytes+=auto_init(offs,sp->tp,NULL,brace_level,(int)(offmod+sp->value.i),-1); + if (lastst == comma) + getsym(); + if (lastst == end || lastst == semicolon) + break; + sp = sp->next; + } +#ifdef AUTOINIT_PAD + nbytes+=auto_pad(offs,(int)(typ->size-nbytes),offmod+nbytes); /* negative args are OK for auto_pad */ +#endif + } else if (typ->type==bt_union) { + typ = (typ->lst.head)->tp; + goto auto_init_restart; + } else if (typ->val_flag) { +// if (!brace_level) error(ERR_SYNTAX); + if (lastst != end) { + int stroff=-1; + if (lastst == sconst && !brace_seen) + stroff=0; + while (1) { + nbytes+=auto_init(offs,typ->btp,NULL,brace_level,(int)(offmod+nbytes),stroff); + if (stroff>=0) { + stroff++; + if (stroff>lstrlen || (stroff==lstrlen && typ->size)) { + getsym(); + break; + } + } else { + if (lastst == comma) + getsym(); + if (lastst == end || lastst == semicolon) break; + } + } + } + if (typ->size && nbytes > typ->size) + error(ERR_INITSIZE); + if (nbytes != typ->size && tpp) { + /* fix the symbol's size, unless tpp=0 (item of a struct/union or array) */ + typ = copy_type(typ); + *tpp = typ; + typ->size = nbytes; + } +#ifdef AUTOINIT_PAD + nbytes+=auto_pad(offs,(int)(typ->size-nbytes),offmod+nbytes); /* negative args are OK for auto_pad */ +#endif + } else { + if (stroff<0) { + if (!(tp = exprnc(&ep2))) + error(ERR_ILLINIT); + } else + ep2=mk_icon(stroff type); + +/* if (offs==0xfffffe4e) + bkpt();*/ + + ep1 = mk_node(en_autocon, NIL_ENODE, NIL_ENODE); + ep1->v.i = offs; +/* ep1->etype = typ->type; // this is a ridiculous bug that I spent hours finding... + ep1->esize = typ->size; */ + ep1->etype = bt_pointer; + ep1->esize = 4; + + if (offmod) { + struct enode *ep3 = mk_icon((long)offmod); + ep3->etype = bt_long; + ep3->esize = 4; + + ep1 = mk_node(en_add, ep1, ep3); + ep1->etype = bt_pointer; + ep1->esize = 4; + } + + ep1 = mk_node(en_ref, ep1, NIL_ENODE); + ep1->etype = typ->type; + ep1->esize = typ->size; + + ep1 = mk_node(en_assign, ep1, ep2); + ep1->etype = typ->type; + ep1->esize = typ->size; + +#ifdef MID_DECL_IN_EXPR + if (middle_decl) + md_expr = ep1, md_type = typ; + #error fix needed around here... + else { +#endif + if (init_node == 0) { + init_node = ep1; + } else { + init_node = mk_node(en_void, init_node, ep1); + } +#ifdef MID_DECL_IN_EXPR + } +#endif + } + while (brace_seen--) + needpunc(end); + return nbytes; +} + +struct snode *compound(int no_init) { +/* + * compound processes a block of statements and forms a linked list of the + * statements within the block. + * + * compound expects the input pointer to already be past the begin symbol of the + * block. + * + * If no_init is true, auto initializations are not desirable + */ + struct snode *head, *tail, *snp; +// struct sym *local_tail, *local_tagtail; + HTABLE old_lsyms,old_ltags; +// hashinit(&symtab); +/* local_tail = lsyms.tail; + local_tagtail = ltags.tail;*/ + memcpy(&old_lsyms,&lsyms,sizeof(HTABLE)); + memcpy(&old_ltags,<ags,sizeof(HTABLE)); + dodecl(sc_auto); + if (init_node == 0) { + head = tail = 0; + } else { + if (no_init>0) { + uwarn("auto initialization not reached"); + } + head = tail = (struct snode *) xalloc((int) sizeof(struct snode), SNODE); + head->stype = st_expr; + head->exp = init_node; +#ifdef NO_CALLOC + head->next = 0; +#endif +#ifdef DB_POSSIBLE + head->line = prevlineid; +#endif + } + init_node = 0; + while (lastst != end) { + if (head == 0) + head = tail = statement(); + else { + tail->next = statement(); + if (tail->next != 0) + tail = tail->next; + } + } + if (no_init>=0) + getsym(); +#ifdef LISTING + if (list_option) { +/* if (local_tail != lsyms.tail) { + if (local_tail != 0) + symtab.head = local_tail->next; + else + symtab.head = lsyms.head; + symtab.tail = lsyms.tail; + fprintf(list, "\n*** local symbol table ***\n\n"); + list_table(&symtab, 0); + fprintf(list, "\n"); + }*/ + fprintf(list, "\n*** local symbol table ***\n\n"); + list_table(&lsyms, 0); + fprintf(list, "\n"); +/* if (local_tagtail != ltags.tail) { + if (local_tagtail != 0) + symtab.head = local_tagtail->next; + else + symtab.head = ltags.head; + symtab.tail = ltags.tail; + fprintf(list, "\n*** local structures and unions ***\n\n"); + list_table(&symtab, 0); + fprintf(list, "\n"); + }*/ + fprintf(list, "\n*** local structures and unions ***\n\n"); + list_table(<ags, 0); + fprintf(list, "\n"); + } +#endif +/* if (local_tagtail != 0) { + ltags.tail = local_tagtail; + ltags.tail->next = 0; + } else { + ltags.head = 0; + ltags.tail = 0; + } + + + if (local_tail != 0) { + lsyms.tail = local_tail; + lsyms.tail->next = 0; + } else { + lsyms.head = 0; + lsyms.tail = 0; + }*/ + memcpy(&lsyms,&old_lsyms,sizeof(HTABLE)); + memcpy(<ags,&old_ltags,sizeof(HTABLE)); + + snp = (struct snode *) xalloc((int) sizeof(struct snode), SNODE); + snp->stype = st_compound; + snp->s1 = head; +#ifdef DB_POSSIBLE + snp->line=lineid; +#endif + return snp; +} + +extern unsigned int pos; +struct snode *labelstmt(void) { +/* + * labelstmt processes a label that appears before a statement as a seperate + * statement. + */ + struct snode *snp; + struct sym *sp; + snp = (struct snode *) xalloc((int) sizeof(struct snode), SNODE); + /*if (pos>=0x25C2) + printf("jiotrh");*/ + snp->stype = st_label; + if ((sp = search(lastid, lastcrc, &labsyms)) == 0) { + sp = (struct sym *) xalloc((int) sizeof(struct sym), _SYM); + sp->name = strsave(lastid); + sp->storage_class = sc_label; +#ifdef NO_CALLOC + sp->tp = 0; +#endif + sp->value.i = nxtlabel(); + append(&sp, &labsyms); + } else { + if (sp->storage_class != sc_ulabel) + error(ERR_LABEL); + else + sp->storage_class = sc_label; + } + getsym(); /* get past id */ + needpunc(colon); + if (sp->storage_class == sc_label) { + snp->v2.i = sp->value.i; + if (lastst != end) + snp->s1 = statement(); + return snp; + } + return 0; +} + +struct snode *gotostmt(void) { +/* + * gotostmt processes the goto statement and puts undefined labels into the + * symbol table. + */ + struct snode *snp; + struct sym *sp; + getsym(); + if (lastst != id) { + error(ERR_IDEXPECT); + return 0; + } + snp = (struct snode *) xalloc((int) sizeof(struct snode), SNODE); + if ((sp = search(lastid, lastcrc, &labsyms)) == 0) { + sp = (struct sym *) xalloc((int) sizeof(struct sym), _SYM); + sp->name = strsave(lastid); + sp->value.i = nxtlabel(); + sp->storage_class = sc_ulabel; +#ifdef NO_CALLOC + sp->tp = 0; +#endif + append(&sp, &labsyms); + } +#ifdef DB_POSSIBLE + snp->line=lineid; +#endif + getsym(); /* get past label name */ + if (lastst != end) + needpunc(semicolon); + if (sp->storage_class != sc_label && sp->storage_class != sc_ulabel) + error(ERR_LABEL); + else { + snp->stype = st_goto; + snp->v2.i = sp->value.i; + snp->next = 0; + return snp; + } + return 0; +} + +struct snode *statement(void) { +/* + * statement figures out which of the statement processors should be called + * and transfers control to the proper routine. + */ + struct snode *snp; +/* if (lineid==0x20A) + bkpt();*/ + switch (lastst) { + case semicolon: + getsym(); + snp = 0; + break; + case kw_char: case kw_short: case kw_unsigned: case kw_long: + case kw_struct: case kw_union: case kw_enum: case kw_void: + case kw_float: case kw_double: case kw_int: case kw_typeof: + case kw_signed: case kw_const: case kw_volatile: + case kw_register: case kw_auto: + case kw_static: case kw_typedef: case kw_extern: +middle_decl: + if (!(flags & X_MID_DECL)) goto default_decl; +#ifdef OLD_MID_DECL + snp = compound(0); + if ((int)cached_sym IS_VALID) fatal("CACHE"); // will never happen since no caching is + // performed when lastst==begin +/* cached_sym2 = cached_sym;*/ + cached_sym = lastst; cached_lineid = lineid; + lastst = end; + break; +#else +#ifdef MID_DECL + /* the following is much cleaner than the old mid_decl handler */ + dodecl(sc_auto); + if (init_node) { + snp = (struct snode *) xalloc((int) sizeof(struct snode), SNODE); + snp->stype = st_expr; + snp->exp = init_node; +#ifdef DB_POSSIBLE + snp->line = prevlineid; +#endif + init_node = 0; // compound resets after calling rather than before... + } // I find it pretty weird :) (maybe it should be changed?) + else snp = 0; + break; +#endif +#endif + case begin: + getsym(); + snp = compound(0); + break; + case kw_if: + snp = ifstmt(); + break; + case kw_while: + snp = whilestmt(); + break; + case kw_for: + snp = forstmt(); + break; + case kw_return: + snp = retstmt(); + break; + case kw_break: + snp = breakstmt(); + break; + case kw_goto: + snp = gotostmt(); + break; + case kw_continue: + snp = contstmt(); + break; + case kw_do: + snp = dostmt(); + break; + case kw_switch: + snp = switchstmt(); + break; + case kw_case: + case kw_default: + snp = casestmt(); + break; + case kw_loop: + snp = loopstmt(); + break; + case kw_count: + snp = NULL; + error(ERR_EXPREXPECT); + break; + case kw_asm: + snp = asmstmt(); + break; + case id: + if (!getcache(id) && cached_sym==colon) { + snp = labelstmt(); + break; + } +#if defined(OLD_MID_DECL) || defined(MID_DECL) + if (lastsp && lastsp->storage_class == sc_typedef) + goto middle_decl; +#endif +default_decl: + /* else fall through to process expression */ + default: + snp = exprstmt(); + break; + } + if (snp != 0) + snp->next = 0; + return snp; +} +// vim:ts=4:sw=4 diff --git a/gtc/src/sunpack.c b/gtc/src/sunpack.c new file mode 100644 index 0000000..2ca460e --- /dev/null +++ b/gtc/src/sunpack.c @@ -0,0 +1,91 @@ +/* + * GTools C compiler + * ================= + * source file : + * precompiled header string unpacking + * + * Copyright 2001-2004 Paul Froissart. + * Credits to Christoph van Wuellen and Matthew Brandt. + * All commercial rights reserved. + * + * This compiler may be redistributed as long there is no + * commercial interest. The compiler must not be redistributed + * without its full sources. This notice must stay intact. + */ + +#ifdef PC +#include + +char *sUnpack(char *in,char *out,char *dic) { + char c; char *out0=out; + while ((c=*in++)) { + if ((char)c>=0) *out++=c; + else { + if (c==(char)0x80) *out++=*in++; + else if (c==(char)0xFF) { + + } else { + char *dp=dic; + c-=(char)0x81; + while (c--) { + while (*dp++); + } + strcpy(out,dp); + while (*out++); out--; + } + } + } + *out++=0; + return out0; +} +#else +char *__attribute__((stkparm)) sUnpack(char *in,char *out,char *dic); +asm( +" xdef sUnpack\n" +"sUnpack:\n" +"/* bra.s sUnpack*/\n" +" move.l 4(%sp),%a0\n" +" move.l 8(%sp),%a1\n" +" moveq #126,%d1\n" +" moveq #0,%d0\n" +" move.b (%a0)+,%d0\n" +" beq su_quit\n" +" bmi su_special\n" +"su_copy_lp:\n" +" move.b %d0,(%a1)+\n" +"su_next:\n" +" move.b (%a0)+,%d0\n" +" bgt su_copy_lp\n" +" beq su_quit\n" +"su_special:\n" +" subq.b #1,%d0\n" +" bmi su_not_escape\n" +" move.b (%a0)+,(%a1)+\n" +" bra su_next\n" +"su_not_escape:\n" +" addq.b #2,%d0\n" +" bmi su_not_romcall\n" +" \n" +"su_not_romcall:\n" +" add.b %d1,%d0\n" +" move.l %a0,%d2\n" +" move.l 12(%sp),%a0\n" +" dbf %d0,su_search_loop\n" +" bra su_search_done\n" +"su_search_loop:\n" +" tst.b (%a0)+\n" +" bne su_search_loop\n" +" dbf %d0,su_search_loop\n" +"su_search_done:\n" +" move.b (%a0)+,(%a1)+\n" +" bne su_search_done\n" +" subq.w #1,%a1\n" +" move.l %d2,%a0\n" +" moveq #0,%d0\n" +" bra su_next\n" +"su_quit:\n" +" move.b %d0,(%a1)+\n" +" move.l 8(%sp),%a0\n" +" rts"); +#endif +// vim:ts=4:sw=4 diff --git a/gtc/src/symbol.c b/gtc/src/symbol.c new file mode 100644 index 0000000..97b8400 --- /dev/null +++ b/gtc/src/symbol.c @@ -0,0 +1,343 @@ +/* + * GTools C compiler + * ================= + * source file : + * symbol handling (insertion & search) + * + * Copyright 2001-2004 Paul Froissart. + * Credits to Christoph van Wuellen and Matthew Brandt. + * All commercial rights reserved. + * + * This compiler may be redistributed as long there is no + * commercial interest. The compiler must not be redistributed + * without its full sources. This notice must stay intact. + */ + +#include "define.h" +_FILE(__FILE__) +#include "c.h" +#include "expr.h" +#include "gen.h" +#include "cglbdec.h" +#ifdef PCH +#include "pch.h" +#endif + +#ifdef EXE_OUT +#ifndef AS +int exestub_mode CGLOB; +#endif +#endif + +HTABLE gsyms CGLOBL, gtags CGLOBL, lsyms CGLOBL, labsyms CGLOBL, ltags CGLOBL; + +void concat(TABLE *dest,TABLE *src) { + SYM *sp=src->tail,*sp2; + while (sp) { + sp2=(SYM *)xalloc((int)sizeof(SYM), _SYM+SYMBOL); + *sp2=*sp; + insert(sp2,(HTABLE *)dest); + sp=sp->prev; + } +} + +void hashinit(HTABLE *t) { + t->hash=0x2489; + memset(t->h,0,sizeof(t->h)); +} + +void insert(SYM *sp,HTABLE *table) { +/* if (!strcmp(sp->name,"wrong_calc")) + uwarn("def!");*/ + if (!table->hash) { + if (!search(sp->name,0,table)) { + TABLE *tab=(TABLE *)table; + if (!tab->head) { + tab->head = tab->tail = sp; + sp->prev = 0; + sp->used = 0; + } else { + tab->tail->next = sp; + sp->prev = tab->tail; + tab->tail = sp; + sp->used = 0; + tab->tail = sp; + } + sp->next = 0; + } + else uerr(ERR_DUPSYM,sp->name); + } else { + int crc=crcN(sp->name); +#ifdef EXE_OUT + if (table==&defsyms && sp->name[0]=='E' && !strcmp(sp->name,"EXE_OUT")) + exestub_mode=1; +#endif + if (!search(sp->name,crc,table)) { + struct htab *tab=&table->h[crc]; + if (!tab->head) { + tab->head = tab->tail = sp; + sp->prev = 0; + sp->used = 0; + } else { + tab->tail->next = sp; + sp->prev = tab->tail; + tab->tail = sp; + sp->used = 0; + tab->tail = sp; + } + sp->next = 0; + } + else uerr(ERR_DUPSYM,sp->name); + } +} + +struct sym *symremove(char *na, HTABLE *tab) { + SYM *ttail,**prv; + struct htab *root; + char *s1,*s2,c; + if (!tab->hash) + ierr(TABLE_HASH,2); +#ifdef PC + if (tab->hash!=0x2489) + ierr(TABLE_HASH,1); +#endif + prv=&((root=&tab->h[crcN(na)])->tail); + while ((ttail=*prv)) { + s1 = ttail->name; + s2 = na; + while (*s1++==(c=*s2++)) { + if (!c) { +// *prv = ttail->prev; + if (ttail->next) ttail->next->prev = ttail->prev; + if (ttail->prev) ttail->prev->next = ttail->next; +// ttail->next = prv; + if (root->tail==ttail) root->tail=ttail->prev; + if (root->head==ttail) root->head=ttail->next; +/* if (!root->tail) + root->head=0;*/ + return ttail; + } + } + prv = &(ttail->prev); + } + return 0; +} + +#ifdef PC +int crcN(char *na) { + unsigned long crc=-1; int n; + unsigned char c; + c=*na++; + do { + crc^=c; + n=crc&7; + crc=(crc>>n)+(crc<<(32-n)); + } while ((c=*na++)); + crc^=crc>>16; + crc^=crc>>8; + return crc & (N_HASH-1); +} +#else +int crcN(char *na); +asm("crcN:\n" +" move.l 4(%sp),%a0\n" +" moveq #-1,%d0\n" +" move.b (%a0)+,%d1\n" +"crcN_loop:\n" +" eor.b %d1,%d0\n" +" moveq #7,%d1\n" +" and.w %d0,%d1\n" +" ror.l %d1,%d0\n" +" move.b (%a0)+,%d1\n" +" bne crcN_loop\n" +" move.w %d0,%d1\n" +" swap %d0\n" +" eor.w %d1,%d0\n" +" move.w %d0,-(%sp)\n" +" move.b (%sp)+,%d1\n" +" eor.b %d1,%d0\n" +" and.w #" N_HASH_AND ",%d0\n" +" rts"); +#endif + +/*#ifdef PC*/ +struct sym *search(char *na, int crc, HTABLE *tab) { + char *s1,*s2,c; + if (!tab->hash) { + SYM *ttail=((TABLE *)tab)->tail; + while (ttail) { + s1 = ttail->name; + s2 = na; + while (*s1++==(c=*s2++)) { + if (!c) return ttail; + } + ttail = ttail->prev; + } + return 0; + } else { + SYM *ttail; +#ifdef PC + if (tab->hash!=0x2489) + ierr(TABLE_HASH,1); +#endif + if (crc<0) crc=crcN(na); + ttail=tab->h[crc].tail; + while (ttail) { + s1 = ttail->name; + s2 = na; + while (*s1++==(c=*s2++)) { + if (!c) return ttail; + } + ttail = ttail->prev; + } + return 0; + } +} +/*#else +asm("search: + move.l %a2,-(%sp) + move.l 8(%sp),%d1 + move.l %d1,%a1 + tst.b (%a1) +0: beq 0b + move.l 12(%sp),%a0 + move.l %a0,%d0 + beq search_end +search_lp: + move.l (%a0)+,%a2 + move.l %d1,%a1 + cmpm.b (%a1)+,(%a2)+ + bne search_nxt +search_lp2: + move.b (%a1)+,%d0 + beq search_fnd + cmp.b (%a2)+,%d0 + beq search_lp2 +search_nxt: + move.l (%a0)+,%a0 + move.l %a0,%d0 + bne search_lp +search_end: + move.l (%sp)+,%a2 + rts +search_fnd: + tst.b (%a2)+ + bne search_nxt + subq.l #4,%a0 + move.l (%sp)+,%a2 + rts"); +#endif*/ + +struct sym *gsearch(char *na,int crc) { + struct sym *sp; + if (!(sp = search(na, crc, &lsyms))) + sp = search(na, crc, &gsyms); + return sp; +} + +void append(struct sym **ptr_sp, HTABLE *table) { + struct sym *sp1, *sp = *ptr_sp; + if (table == &gsyms && (sp1 = search(sp->name, -1, table)) != 0) { + /* + * The global symbol table has only one level, this means that we + * only check if the new declaration is compatible with the old one + */ + + if (!eq_type(sp->tp, sp1->tp)) + uerr(ERR_REDECL,sp->name); + /* + * The new storage class depends on the old and on the new one. + */ + if (sp->storage_class == sp1->storage_class) { + if (sp->storage_class == sc_global) { + /* + * This hack sets sp->used to -1 so that decl.c knows to + * suppress storage allocation + */ + uwarn("global redeclaration of '%s'", sp->name); + sp1->used = -1; + } + *ptr_sp = sp1; /* caller uses old entry */ + return; + } + /* + * since we use compiler generated label for static data, we must + * retain sc_static + */ + if (sp1->storage_class == sc_static) { + *ptr_sp = sp1; /* caller uses old entry */ + return; + } + /* + * if the new storage class is global, we must update sp1 to generate + * the .globl directive at the very end and perhaps the size (e.g. + * for arrays) + */ + if (sp->storage_class == sc_global) { + sp1->storage_class = sc_global; + sp1->tp = sp->tp; + *ptr_sp = sp1; /* caller uses old entry */ + return; + } + /* + * if the new storage class is static, set it to global (since we may + * have used the ,real' name and cannot use compiler generated names + * for this symbol from now on) and set sp->value.i to -1 to prevent + * it from being exported via .globl directives + */ + if (sp->storage_class == sc_static) { + sp1->storage_class = sc_global; + sp1->value.i = -1; + *ptr_sp = sp1; /* caller uses old entry */ + return; + } + /* + * last case: global declaration followed by external decl.: just do + * nothing + */ + *ptr_sp = sp1; /* caller uses old entry */ + return; + } +/* if (table->head == 0) { + // The table is empty so far... + table->head = table->tail = sp; + sp->next = sp->prev = 0; + sp->used = 0; + } else { + table->tail->next = sp; + sp->prev = table->tail; + table->tail = sp; + sp->next = 0; + sp->used = 0; + }*/ + if (!table->hash) { + TABLE *tab=(TABLE *)table; + if (!tab->head) { + tab->head = tab->tail = sp; + sp->prev = 0; + sp->used = 0; + } else { + tab->tail->next = sp; + sp->prev = tab->tail; + tab->tail = sp; + sp->used = 0; + tab->tail = sp; + } + sp->next = 0; + } else { + struct htab *tab=&table->h[crcN(sp->name)]; + if (!tab->head) { + tab->head = tab->tail = sp; + sp->prev = 0; + sp->used = 0; + } else { + tab->tail->next = sp; + sp->prev = tab->tail; + tab->tail = sp; + sp->used = 0; + tab->tail = sp; + } + sp->next = 0; + } +} +// vim:ts=4:sw=4 diff --git a/gtc/src/trees.c b/gtc/src/trees.c new file mode 100644 index 0000000..c2f0ce8 --- /dev/null +++ b/gtc/src/trees.c @@ -0,0 +1,247 @@ +/* + * GTools C compiler + * ================= + * source file : + * tree dumping + * + * Copyright 2001-2004 Paul Froissart. + * Credits to Christoph van Wuellen and Matthew Brandt. + * All commercial rights reserved. + * + * This compiler may be redistributed as long there is no + * commercial interest. The compiler must not be redistributed + * without its full sources. This notice must stay intact. + */ + +#include "define.h" +_FILE(__FILE__) +#include "c.h" +#include "expr.h" +#include "gen.h" +#include "cglbdec.h" + +typedef struct dump { +} DUMP; +char *dump_node_stack[MAX_DUMP_NODE_STACK]; +int dump_node_stack_depth; +int dump_attribute_phase; + +#define dump_put printf +void dump_startline() { + int i; + for (i=0;i \n"); + dump_startline(); + dump_put("<%s",name); + dump_node_stack[dump_node_stack_depth++] = name; + dump_attribute_phase = 1; +} +void dump_addstr(char *name,char *v) { + assert(dump_attribute_phase); + dump_put(" %s='%s'",name,v); +} +void dump_addint(char *name,int v) { + char b[100]; + sprintf(b,"%d",v); + dump_addstr(name,b); +} +void dump_addreg(char *name,int v) { + assert(dump_attribute_phase); + if (v>=RESULT && v =PRESULT && v \n"); + else + dump_startline(), dump_put("%s>",dump_node_stack[dump_node_stack_depth]); + dump_attribute_phase = 0; +} + +void dump_genstmt(struct snode *stmt) { + while (stmt != 0) { + switch (stmt->type) { + case st_compound: + dump_genstmt(stmt->s1); + break; + case st_label: + dump_newnode("st_label"); + dump_addint("id",stmt->v2.i); + dump_endnode(); + dump_genstmt(stmt->s1); + break; + case st_goto: + dump_newnode("st_goto"); + dump_addint("id",stmt->v2.i); + dump_endnode(); + break; + case st_break: + dump_newnode("st_break"); + dump_endnode(); + break; + case st_continue: + dump_newnode("st_continue"); + dump_endnode(); + break; + case st_expr: + dump_newnode("st_expr"); + dump_expr(stmt->exp); + dump_endnode(); + break; + case st_return: + if (!stmt->exp || ret_type->type==bt_void) { + dump_newnode("st_return"); + dump_endnode(); + break; + } + switch (ret_type->type) { + case bt_struct: + case bt_union: +#ifdef BCDFLT + case bt_float: +#ifdef DOUBLE + case bt_double: +#endif +#endif +#ifdef SHORT_STRUCT_PASSING + if (ret_type->size<=4) { + if (stmt->exp->nodetype!=en_ref) + ierr(DUMP,1); + dump_newnode("st_return"); + dump_newnode("expr"); + dump_addreg("target",mk_reg(RESULT)); + dump_newnode("e_deref"); + dump_addint("esize",ret_type->size); + dump_expr(stmt->exp->v.p[0]); + dump_endnode(); + dump_endnode(); + dump_endnode(); + break; + } +#endif + assert(0); + dump_newnode("st_return"); + dump_newnode("expr"); + dump_addstr("target","__tmp_structreturn"); + dump_expr(stmt->exp); + dump_newnode(""); + dump_newnode(""); + break; +#ifndef BCDFLT + case bt_float: +#ifdef DOUBLE + case bt_double: +#endif +#endif + case bt_char: case bt_uchar: + case bt_short: case bt_ushort: + case bt_long: case bt_ulong: + case bt_pointer: + dump_newnode("st_return"); + dump_newnode("expr"); + dump_addreg("target",ret_type->type==bt_pointer?mk_reg(PRESULT):mk_reg(RESULT)); + dump_expr(stmt->exp); + dump_endnode(); + dump_endnode(); + break; + default: + ierr(DUMP,1); + } + break; + case st_if: + dump_newnode("st_if"); + dump_newnode("condition"); + dump_expr(stmt->exp); + dump_endnode(); + dump_newnode("true"); + dump_genstmt(stmt->s1); + dump_endnode(); + dump_newnode("false"); + dump_genstmt(stmt->v1.s); + dump_endnode(); + dump_endnode(); + break; + case st_asm: + dump_newnode("st_asm"); + dump_newnode("TODO"); + //dump_asm((struct ocode *)stmt->v1.i); + dump_endnode(); + dump_endnode(); + break; + case st_while: + dump_newnode("st_while"); + if (stmt->exp) { + dump_newnode("condition"); + dump_expr(stmt->exp); + dump_endnode(); + } + dump_newnode("body"); + dump_genstmt(stmt->s1); + dump_newnode("st_labelcontinue"); + dump_endnode(); + dump_endnode(); + dump_endnode(); + break; + case st_do: + dump_newnode(stmt->exp ? "st_do" : "st_while"); + dump_newnode("body"); + dump_genstmt(stmt->s1); + dump_endnode(); + if (stmt->exp) { + dump_newnode("condition"); + dump_expr(stmt->exp); + dump_endnode(); + } + dump_endnode(); + break; + case st_for: + if (stmt->exp) { + dump_newnode("st_expr"); + dump_expr(stmt->exp); + dump_endnode(); + } + dump_newnode("st_while"); + dump_newnode("condition"); + dump_expr(stmt->v1.e); + dump_endnode(); + dump_newnode("body"); + dump_genstmt(stmt->s1); + if (stmt->v2.e) { + dump_newnode("st_expr"); + dump_expr(stmt->v2.e); + dump_endnode(); + } + dump_endnode(); + dump_endnode(); + break; + case st_switch: + default: + ierr(DUMP,2); + } + stmt = stmt->next; + } +} + +void dump_genfunc(struct snode *stmt) { + opt1(stmt); + dump_newnode("function"); + dump_newnode("returns"); + dump_type(ret_type); + dump_endnode(); + dump_newnode("code"); + dump_genstmt(stmt); + dump_genreturn(NIL_SNODE); + dump_endnode(); + dump_endnode(); +} diff --git a/gtc/src/vcg.c b/gtc/src/vcg.c new file mode 100644 index 0000000..3547009 --- /dev/null +++ b/gtc/src/vcg.c @@ -0,0 +1,98 @@ +#ifdef VCG +#ifdef PC +#define MAXINT 0x7FFFFFFF +#endif +#ifndef __HAVE_STACK_IMAGE +#define __HAVE_STACK_IMAGE +typedef struct _stackimg { + int next_data,next_addr; +#ifndef INFINITE_REGISTERS + int reg_alloc_ptr,reg_stack_ptr; + char dreg_in_use[MAX_DATA+1]; + char areg_in_use[MAX_ADDR+1]; + struct reg_struct reg_stack[MAX_REG_STACK+1],reg_alloc[MAX_REG_STACK+1]; + int act_scratch; +#endif +} STACK_IMAGE; +#endif +STACK_IMAGE vcg_img[VCG_MAX+1]; +int vcg_nxl[VCG_MAX+1]; +int vcg_aborted[VCG_MAX+1]; +int vcg_init() { + if (--vcg_lvl<0) { + vcg_lvl++; + return 0; + } +// tmp_use(); + usestack(&vcg_img[vcg_lvl]); + vcg_peep_head[vcg_lvl]=0; + vcg_aborted[vcg_lvl]=0; + vcg_nxl[vcg_lvl]=nextlabel; + g_code(op_label,0,0,0); + return 1; +// vcg_on++; +// vcg_cost[vcg_lvl]=0; +} +int en_dir_cost(struct enode *ep) { + switch (ep->nodetype) { + case en_icon: + return (ep->v.i>=-32768 && ep->v.i<32767)?1:2; + case en_labcon: + case en_nacon: + return 1; + case en_add: + case en_sub: + return max(en_dir_cost(ep->v.p[0]),en_dir_cost(ep->v.p[1])); + } +} +int cost_tab[] = { + 0,0,0,0,0,1,1,1,-MAXINT-1,2,1,1,1,1,2,0,0 +}; +int vcg_cost() { + int cost=0; + if (!vcg_aborted[vcg_lvl]) { + struct ocode *ip; + opt3(); + ip = peep_head; + while (ip != 0) { + #define am_cost(x) (x?(x->mode==am_direct?en_dir_cost(x->offset):cost_tab[x->mode]):0) + cost++; + switch (ip->opcode) { + case op_label: + case op_even: + cost--; + break; + case op_moveq: + case op_addq: case op_subq: + case op_lsl: case op_lsr: case op_asl: case op_asr: + case op_rol: case op_ror: case op_roxl: case op_roxr: + case op_trap: + cost+=am_cost(ip->oper2); + break; + case op_bxx: + /* what should we do here? */ + break; + case op_dbxx: + cost++; + break; + default: + cost+=am_cost(ip->oper1)+am_cost(ip->oper2); + break; + } + if (cost<0) cost+=(-MAXINT-1)+((ip->length+1)>>1); + ip = ip->fwd; + } + // vcg_on--; + // tmp_free(); + } else cost=12345; + return cost; +} +int vcg_done() { + freestack(&vcg_img[vcg_lvl]); + nextlabel=vcg_nxl[vcg_lvl]; + int cost=vcg_cost(); + vcg_lvl++; + return cost; +} +#endif +// vim:ts=4:sw=4 diff --git a/gtc/src/version.h b/gtc/src/version.h new file mode 100644 index 0000000..40dbaa1 --- /dev/null +++ b/gtc/src/version.h @@ -0,0 +1,8 @@ +#ifndef VERSION_H_ +#define VERSION_H_ + +#define GTC_MAJOR 0 +#define GTC_MINOR 902 +#define GTC_VERSION "0.90.2" + +#endif diff --git a/h/Makefile b/h/Makefile new file mode 100644 index 0000000..03c8f46 --- /dev/null +++ b/h/Makefile @@ -0,0 +1,24 @@ +BIN=../bin +STRIP = perl script/strip.pl +TXT89 = $(BIN)/txt89t + +all: src/*.h + $(RM) *.89t + $(RM) processed/*.89t + $(RM) -r stripped + mkdir stripped + sh -c 'for f in src/*.h; do $(STRIP) "$$f" > "stripped/$${f#src/}"; done' + $(TXT89) --compact -f gtchdr stripped/*.h + mv *.89t processed + $(RM) -r stripped + touch all + +clean: +distclean: clean +scratchclean: distclean + $(RM) processed/*.89t all + +include ../config.mk +install: all + mkdir -p $(prefix)/share/gtc/include + install -m 644 src/*.h $(prefix)/share/gtc/include diff --git a/h/all b/h/all new file mode 100644 index 0000000..e69de29 diff --git a/h/legacy/README b/h/legacy/README new file mode 100644 index 0000000..23ccd55 --- /dev/null +++ b/h/legacy/README @@ -0,0 +1 @@ +These files are deprecated, but I'm leaving them here for reference purposes. diff --git a/h/legacy/ezgen b/h/legacy/ezgen new file mode 100644 index 0000000..93fddff --- /dev/null +++ b/h/legacy/ezgen @@ -0,0 +1,67 @@ + #include "inclgen" + #include "genle" + #ifdef RESOURCE + FILE *resf=0; + #ifdef RES_TYPE + RES_TYPE *data=0; + #else + void *data=0; + #endif + #endif + DSCREEN *scr1=0,*scr2=0,*sc=0; + #ifdef DISP_SCR + DSCREEN *sd=0; + #endif + + int curscr=0; + void gl_main(); + void gl_upd() { + if (!curscr) { + gl_set_dscreen_int( + #ifdef DISP_SCR + sd= + #endif + scr1); + gl_set_dscreen_function(sc=scr2); + } else { + gl_set_dscreen_int( + #ifdef DISP_SCR + sd= + #endif + scr2); + gl_set_dscreen_function(sc=scr1); + } + curscr=~curscr; + } + int gl_load() { + int hd; + gl_init(); + gl_init_dscreen(&scr1, &hd); + if (!hd) goto nohd; + gl_push_hd(hd); + gl_init_dscreen(&scr2, &hd); + if (!hd) goto nohd; + gl_push_hd(hd); + gl_upd(); + #ifdef RESOURCE + resf=fopen(RESOURCE,"rb"); + if (!resf) goto nohd; + (void *)data=*(void **)resf; + #ifdef GFX_RES + gl_set_spr_xy(0,0); + gl_set_spr_tile(data); + #endif + #endif + return 1; + nohd: + return 0; + } + void _main() { + if (gl_load()) gl_main(); + #ifdef RESOURCE + if (resf) fclose(resf); + #endif + gl_wait_no_key(); + gl_free_hd(); + gl_quit(); + } diff --git a/h/legacy/ezgensc b/h/legacy/ezgensc new file mode 100644 index 0000000..fb9ad39 --- /dev/null +++ b/h/legacy/ezgensc @@ -0,0 +1,42 @@ + #include "inclgen" + #include "genle" + #include "sccomm" + #include "scliba" + #ifdef RESOURCE + FILE *resf; + #endif + + void gl_main(); + int gl_load() { + GLB + int hd; + gl_init(); + gl_init_dscreen(&g scr1, &hd); + if (!hd) goto nohd; + gl_push_hd(hd); + gl_init_dscreen(&g scr2, &hd); + if (!hd) goto nohd; + gl_push_hd(hd); + gl_upd(); + #ifdef RESOURCE + resf=fopen(RESOURCE,"rb"); + if (!resf) goto nohd; + (void *)g data=*(void **)resf; + #ifdef GFX_RES + gl_set_spr_xy(0,0); + gl_set_spr_tile(g data); + #endif + #endif + return 1; + nohd: + return 0; + } + void _main() { + if (gl_load()) gl_main(); + #ifdef RESOURCE + if (resf) fclose(resf); + #endif + gl_wait_no_key(); + gl_free_hd(); + gl_quit(); + } diff --git a/h/legacy/genle b/h/legacy/genle new file mode 100644 index 0000000..c59cdc6 --- /dev/null +++ b/h/legacy/genle @@ -0,0 +1 @@ +#include \ No newline at end of file diff --git a/h/legacy/inclgen b/h/legacy/inclgen new file mode 100644 index 0000000..9e42b25 --- /dev/null +++ b/h/legacy/inclgen @@ -0,0 +1,4 @@ +#define USE_KERNEL +#include +#define X 160 +#define Y 100 diff --git a/h/legacy/include b/h/legacy/include new file mode 100644 index 0000000..27bda51 --- /dev/null +++ b/h/legacy/include @@ -0,0 +1 @@ +#include \ No newline at end of file diff --git a/h/processed/COPYING b/h/processed/COPYING new file mode 100644 index 0000000..2ba72d5 --- /dev/null +++ b/h/processed/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/h/processed/assert.89t b/h/processed/assert.89t new file mode 100644 index 0000000000000000000000000000000000000000..e64b549ec32d83efc5eeadd68fdb479357fb0702 GIT binary patch literal 222 zcmdPW3h}hC)Y4*PNH0mwNGW0<8Za^h0o5iJ7pE4LFfb@GFf-f(@|Q+|4QOFtR8Y=L z%S%a3Q}A 2j~ts!>nTdh3SNUq3Z!4%u~ZcyS_%x}rW%!%r0T^E-0z z@i$eY8@r9`ZD`dr=Zks+e(rpa2BV=dvW=l-&S?-j2e5YbdxpDS2mUdlU;X3m$@g4( zy>-GCTW@&2yW7;ECmP$kOze(rHm}Y ;wNP z4^K4x>%<~xp^7$i81`mmX$!(ax@7T9TLD8Gliu4^?7WalrwX=bL<-$1QZ<)Tf|aXS zdsa-MSA`?jg$jq2ygs}&rz(-nO%=YF=(+BxmtbPP7-HD&xrgkuCrfar%@?{krE?6A z7;k^{auWy8h7^WtZr*}N=jhQ4^CQ@~EtX-J{AdC2e0TxT keSsw}m8D8WvfFC>V?FdvtLaizRRtWzY0t5xFC z^DNYD5`@{o47)|9EU*9rw=)o3b;<2TI^+de;i2rLqkuT#-Xd9%Q-lJEFHaH@Bo6il LVR$mBUybb_X#sIV literal 0 HcmV?d00001 diff --git a/h/processed/default.89t b/h/processed/default.89t new file mode 100644 index 0000000000000000000000000000000000000000..4966a1f5b28f3b4d0bf1bea926d74a00c7715f76 GIT binary patch literal 3054 zcmb_e-EP}96n3yX_a#^u2qYmLY_}bpH4UK1bShMq3`q{w76su%RHDX~3|ZO|w7uIS z>}C(J_u3Qe8Fna26eTN5H!L@?4!`rm@BC5Id~ 21X9k}9);mChD2(A45i-RyeQEjq0enU=l_gQgAWIJu-#i{K1Vl)z zrPm+OIEcbN7<|et1PVW&9IJ yzV_fU7oyOb`68qY(W+uHl}O zW8&D>JK+buFfnw?D8 r%x cO}LDoNvk#@PsEhx1FSGAXO#2TPV8Z*%B&63#~ zKI(w;Hrj(e7f`z1Q5GPd7<=~;M^)d8jMjeTFbgyPB2IySJW$R=Nr>R3&Pk)0+ha%+ zPenzYqzl~@Y*eR2_kEXm{*(|HnyV~Jqsu&_geVFjyX $o*X_lvP!wyU%>r6M^g4a5PnsYAnO~)&&KLTk)BCxfz({2?3IH-QMap#6XNLy%` zX9UFibfxr~)1{2mea4uY?#&;$PKBytmkFw+ok5k97STO)r6T$Y$m8jNe%fqFcDY81 zru>{lfu?C{W4)0y*^sN%daYzftD{H-oRTS8nM =sKnWS|{ VNO&zMwPB#+o&TQsk- 1q* g%lR~i1) ^YEO&@LV`IDPm Eg}1|(k-WpKi>9OcPqD8KZCO&N1qV)&J_`z-~FXm lS-n>86{!Dp9?+8@Nz&c-H>VXFl{`*%S$@e6 MI+j%L&tHH48&M6URsaA1 literal 0 HcmV?d00001 diff --git a/h/processed/doors.89t b/h/processed/doors.89t new file mode 100644 index 0000000000000000000000000000000000000000..c79f0db4e5ef392a8780ba3235a1b7f00db79c5f GIT binary patch literal 906 zcma))QHt9z5Qd%REvL}N5F`^qA6qB|uOp~wVg*@VLSF`NByUU|8DyJM*c0>~y;qM? zIZk3{4W)h=N%PP5kH+#m5q|jSc@yWQJ{+ZS{`;Fa+-hZ6n##rpXX^Z#I?nHJEnxcI znIJdMv{V^dGsfeYYnQoJ*Ik~qsffiQd7Qb*n9|J8tkrRTYN{IPvPRDe<@!)GQc1g* z>$0kw=lQ9W>S5+KL%1p`HM52-l hnYvO$Mbx8xV4l}T&WiYv=T z-<8p-KrMS^E49os%j?WPS!&u8_3HTfY73@3!67Y*(E+4Vn%iw}I$ST)Wlpe%ag99y zUkDB&WHA6q30?qaTL}Ek23$8Mgp3JiFt&&{+Fp4|bBzf=7yEOQcD>?!SrhAjM)*U! zv3BS-lwOC-sYrMPPyQyMeRV|X8UnW6ZRj4hei-$m?A}7efbK&9akASnZvWBcRlvV0 zQ74jktRk &*0KkD6IM^Xzp literal 0 HcmV?d00001 diff --git a/h/processed/extgraph.89t b/h/processed/extgraph.89t new file mode 100644 index 0000000000000000000000000000000000000000..1ea97098b6829abcb8158edf5ca2126aff0f6d76 GIT binary patch literal 113 zcmdPW3h}hC)Y4*PNH0mwNGW0<8Za^h0oA5fl%y9W7Gx+gFf$Ya`Aeg~28c5-Dkx{9 SCZ?no*}#<8aWOpTW(NTIj}e;y literal 0 HcmV?d00001 diff --git a/h/processed/gen.89t b/h/processed/gen.89t new file mode 100644 index 0000000000000000000000000000000000000000..7baf2e82abce6a8b76349615188996b303eb0355 GIT binary patch literal 108 zcmdPW3h}hC)Y4*PNH0mwNGW0<8Za^h0oA6b=7Du6GB7jb09i|;z+52)Mg`@J)Wnq3 OA{(F*J1&L?v8(_~I1LW~ literal 0 HcmV?d00001 diff --git a/h/processed/nostub.89t b/h/processed/nostub.89t new file mode 100644 index 0000000000000000000000000000000000000000..2897f15db638ae19579d3a7fa72be1994b3d9b69 GIT binary patch literal 629 zcma)3OKQU~6jaikuh2ym8;WH@)-9BRlc->@EhEVxWb<%hyD|6!{_Jv{?s}*mrFLDb z>84a0N%Lmr&66xkIuDPQHAAoM=^WSS-)n|=&n>H_?T!d7&<*P52)!K!gZV9*VIxb+ zI7zY3gbdf3(Vw$2QP(UTid)9G(2S(6t6Cq;R%gBFniiK;i;oG;%2VFON!%awZB^Bc zUQ}_i(2VYvdy+SaW_**Mdh4jm+tvBG$5K4Dj?GX|cyS${0%sm =oi^IrLbVPu3TOBP7Sa}HPi``ODl zONW@ld;CdIa|nA!L2Njs{#AZXWypQl*=|UCcrnf8GoX7%f(V0vae1YnzP)xSP|g{L vQQk)#br^g~x3FPe;L<&Kw&Sa;6QhW-(j)-m{-Yc}5`W=JG|q`W?%qEEuTZt7 literal 0 HcmV?d00001 diff --git a/h/processed/patch.89t b/h/processed/patch.89t new file mode 100644 index 0000000000000000000000000000000000000000..094e1d461f810a97669cbeb0e4af106e15dca861 GIT binary patch literal 5660 zcmbVQ%W~t^5#>~N*e9zjIK!$ba)y!tkb=lbdBLGE9#$w)#fLnJ>AD3HkVFS0C;%GL zj_p6mGC$%k@j73T)Axl7iZgLV3lX@ukM7gmr@QZ~SF=H<`|8!R%3Z#?57Wx;{(DxL zVD2u!GW}!AIPX>L~oAlogZhQ+LXnf+& z=93Y-=?&)?!^nCYRT<0jw0>yR4#v S?9)I77H zm*~;Sp!arY3Uf1pM3bA>^=$oPl-$;_4auSxK=ekVVMT{LO1IV3eUS3`-+uQOs}^m; z^{xJS LdY$|G{VD`AiGMM!x?Q>yNLlhyDk4)f }EQkBjgFv1Q_QhvQ4nwzR}zAS7=A0kS5NeVx#G7{#H-a z>$gdkKQ6ID8HuvWo8)739#_Lw^Q<0RHmqgzu-GOn-> zX)WR;*;zptKAi7sE{$Z5%ZKxro?FI3e!%w`Y&02Pv3_qjWNxb`ChV)B-P98B4aJEx z_FC_QX_xdO0T7xUZP~F2nUctS~XM+*@`u%u1W7F$i-&d-*Hq^GQ zU>ib5`{3L3M K6K3dL5+?ZM&~_ J&%GKNpujyR6+^dX_yC{Gs-|t(T zzE~PPJg(CytnXG(HVqb=?2bi;b#57wDmqiK8e `#L_i8-aCmF3=Q`~+ zy)Rd*^UM@+nME9yjxrs0XNBDv)PmW77&jZaC!VEaI~rqzj)Tz2b`8V&rS~#?POH-v z_}LcxmL5gq#5GuPr#6v`gboh5*BM_{(qg^M@*s{az-j0uP$b=!2tbF6mgboyr^rQb z_(>abK=&;0z6e`qh%6yEpgnVKT3AQ~Q?|MnZZpsUEl^fL;OQU`UhcFU`w|YP;{f
val>gwaPcjL2Zf8zV2#> |=tk6yrC)4@$ z^>{L4lnjs&`cux`{E?03S0do{H9bI*fXGo&C@9NvG%UeNe43~Lq`2deFLoJ^hJWLX z#Fb3`LHi+_5-}Dde5v56eVT0VxMoiYN~&|bP?43CtyD+|aYo20NZMe#PvrD+aZs99 zDr` ULaFd4gP7|t5w|(L9r;Zt@Zu?SjVc-hN!ahf4M9txU z7$8jwYjUF#w{TYZf`^pk7PYXHZYdfDqZ#4>b}y0G9Hv=EL4>JW>7%4%g(gxQ$V( zvU_-Z9BD_Rn6?j+hY @}@4@w}3*{R} THhzqJxM;A z7>-4Q)^ce3xDnAT*+WJ%P$kU0wnC;1<>!q0du&C!zW%(mBwi}oKH-I8Bf}MsP(O+j zBOXM0Dnf%NY!OA6RVXf;OPqrsQ8<)*{A62j5@YT!+-YSo&V5EYt=;vgPA)u}TbP%O zRN|>h0YakQSp=KRVOY+ aA^tZ;>NgrtIAL#U@f6LF}jyu~g}?$ThxsDh!Ss}dMh^pp$Cer1(L0s0m4=vZ_! zJaBZg;dq{^wc5=9eT!;z 0YXn zP=gpJ@u^bP@^LDxi3i?Jr X|l44rw9=11rBTIw7rHQ$EpLj{d&olw~c4%Wsl zRrH=+kb yAQdyW#`FBZW$5u2g3lw1GG-QSmE6~`9 zN{VW43T+-hjNOdPut6(F!DvPeahs@gsd^TQ%Zz;zo|49f3psYT$tFG7DBJcs14OA* z(MQu{GZz1c^krx5c$~;TA+(hJ)Q^ac&k=n&Rg0$Md@mVU$1-Pn)nfAOqWf7w7wx}F z=dRsG|8HAy7E^;vkEVegGLp%T;54d~&-cPa%Dpu+>pI=2B4rV8RO>1jiz>B&8ebKl zAchl{1r1BLu~O|At+KoeC^)u60%h)_PPjyWC*r4wEAsooA1-hqCzUM!e70|S`BLd* zz=7f(H*6oHt!0+?g2B& wy*+-AKft_3yJCrqcdd~!iSJHP*?bxoJ9Rds9eWK+$WGO~?p X$uD0l>=&mlF$=+jxhlW?=U@K?Bu%Hc literal 0 HcmV?d00001 diff --git a/h/processed/std.89t b/h/processed/std.89t new file mode 100644 index 0000000000000000000000000000000000000000..13d9c73aa41fa2f4b38d5a5f658bc0bf830a7a48 GIT binary patch literal 168 zcmdPW3h}hC)Y4*PNH0mwNGW0<8Za^h0o4|lq=0oOGB7i&0J4@wfw_JRj0(z`X?ZEB zX$r0po+0tUp#cH@K_OhqK#|P6R0Ti(cvSJ!yp+r|F6GR; 6>RMUoBH)r(H{pLFssPW3w1BN~bc`|qd4$&*x T;0Nf9Z0$tbt$5AD=lJvmyBc*5 literal 0 HcmV?d00001 diff --git a/h/processed/ttunpack.89t b/h/processed/ttunpack.89t new file mode 100644 index 0000000000000000000000000000000000000000..742d0969b7a28437bfe3a6c5568ba9a82cdc17d1 GIT binary patch literal 3610 zcma)8+iqJ`5Ou}dk>CS(GD522Xd~_WMQK59o0h61uF?dRB4k<4A+g9!wu7LhpTke^ z#Ha8nthM(!$Hq>9_MtwrXV0uzvu1X8caNXPw7Yw+ceb3KpU!*#`_H}J5qy`++pC+& z^rz2yAN4-{q}TiX4Fi1qXYXEr`Rh%6TL0KzEa$h=<-6+kYB4*zs!#jV^U1t_y_mhN z#~0UociPWqoA%4e*=(xrwCYXk^aHVreLHr&*p7U4y}Vu2r)D#DW4D`j#Mr`dHo3f< zY+=sUE#LZ=<$QASb~9{~ZYxM*-wHFosOzicd{!^^s`tmoCx )4p*&VgL9+Tdk@y&R!v(q(oaeh5t!m!iDE=hL>*>mv4 zmu<&?`){Z7*@FjhFc@s7{&{jSJ8g1*I8_nL!-pM~Qs@2q{{k=H(VKVl3PTrc^kVp3 ze??1YKOF79di->Ba`>dLZS1gj=Qw@z{P-0P)Ar%P@b$Cd!NIVv-5sI#UmqV0zj^Z# zr)vA|;V9RKL%n@CIyruH@^tj={?XCNAzaM13j&W`0e0)MQbX7B(|US+c{8sUi~eTQ zchKTa2Au6(@z2k}U_8Df&|o$BSv>tay}tk9;k!yj?~O1zcrCQF`0brjT0|p_h*B8E z4=Zr$m6oC^1{}a(f)`2~8wL0g+B$s0OQ;}?6hX@ FTt&9rU zCWTeTi;B0M)kv6Bgrn5n!9gV>6pYaan~gRb;jBdk*QA9B)^@H49X;XuWMH&b$`+|j zD9Rd95w(m_Al*6yrG#|~h?x)7Sh_1w;ma9EM(`E#2h*48kuO*8SQL<>aO=GFaPwfH zbyJO-W% $OJ}kY=|Eh z(Ug$DlQZQapj(4B0;a@8Xd*`dWk`g(7BVUKm ))DKil27E4{%~>%NHF^vU zY73XhFl$lTiwa?t)-mO)C>vtyu4c(FRbt;umos0M^SVYq&d{E!F@XkLie5XC5y85n zs$AAho@?a{)`ZqRv~sSzGm0#4LMcUbMO!L3%cdl&+Wu2!)+2fzI>*kyFMwnI;3qrR zG{8iM8D%IPaSw3UyS5&m>xH!X09Kl&X4vaaMX_r_HS7T=rwkk94+=}?kkoodDS$)l zC!ZNenP13^O(NLJVAmD26bUsa6&EXhx}+r(R`immgN? |NQjPEpL6^4w}{S_-ID!JX6-99r5CNo;UutFxX9j)1c9-N1nE3k^*s(1-E@ zd9~c43M0e`Lvfg1AV!-C;x>+HUk0c|Q6*V!g(%G_&0_^D>y0E)P<=ClRa>&mdxz6h z-YR4RQ6Xhc7)s*Jkoa4*x&bc8KZZQ`Wel}KGc}$f9l EFR 6_y zgRKi48ldb9fmgBYfI&OVhvbx$xrSiSEkr>*T451^-w3!Vz_HZQtXKfxB0+X;np_Mv z6SjQ}*i~&oCdV;+LS4*5v{n&;vuOz dSjvzLa8{@Y+b2KO+<$r1@^Nh~;3PlD QIeEtUey{5N^~YC#1Kz1h8~^|S literal 0 HcmV?d00001 diff --git a/h/processed/xupak.89t b/h/processed/xupak.89t new file mode 100644 index 0000000000000000000000000000000000000000..131ce3a9ace1dae66d118c6b810f383e40cb6bc6 GIT binary patch literal 429 zcmdPW3h}hC)Y4*PNH0mwNGW0<8Za^h0o7KN79?f^X+;KRhP8|g3`?Ux1~3LQFe;Q( z7Nn-6rYRJc6qP2IRC8tKl_=yUre`Kc8^v04mF5*^rst)mD1d}Z3$lwdt5S6!lr>j! zMq-gdYH@N>W=XLQkT!q{ DmmF7YPfSlxL1E6uW5dn_g@g6Qg)?CU!OEdFQ z6~H3Cj_#h$h6)-Q>h9_`HWr%N>LKcySd ) { + chomp; + if (!$multicomment) { + s|//.*$| |g; + s|/\*.*?\*/| |g; + if (m|/\*|) { + s|/\*.*$| |g; + $multicomment=1; + } + } elsif (m|\*/|) { + s|^.*?\*/| |g; + $multicomment=0; + } else { + $_=''; + } + s|^\s+||g; + s|\s+$||g; + s|\s+| |g; + s|^(\#define \w+) |\1\t|g; + s|(\W) (.)|\1\2|g; + s|(.) (\W)|\1\2|g; + s:(? + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/h/src/assert.h b/h/src/assert.h new file mode 100644 index 0000000..14bac7e --- /dev/null +++ b/h/src/assert.h @@ -0,0 +1,5 @@ +#ifndef NDEBUG +#define assert(p) ((p)?(void)0:__assertion_failed(#p,__FILE__,__LINE__)) +#else +#define assert(p) ((void)0) +#endif diff --git a/h/src/compat.h b/h/src/compat.h new file mode 100644 index 0000000..c482067 --- /dev/null +++ b/h/src/compat.h @@ -0,0 +1,66 @@ +#ifdef DOORS + #define _CALCULATOR _ram_call(0,const unsigned char*) +#endif + +#if defined(DOORS) && !defined(_ONE_CALC_ONLY) + #define LCD_WIDTH _ram_call(1,unsigned long) + #define LCD_HEIGHT _ram_call(2,unsigned long) + #define LCD_LINE_BYTES _ram_call(4,unsigned long) + #define KEY_LEFT _ram_call(5,unsigned long) + #define KEY_RIGHT _ram_call(6,unsigned long) + #define KEY_UP _ram_call(7,unsigned long) + #define KEY_DOWN _ram_call(8,unsigned long) + #define KEY_UPRIGHT _ram_call(9,unsigned long) + #define KEY_DOWNLEFT _ram_call(A,unsigned long) + #define KEY_DIAMOND _ram_call(B,unsigned long) + #define KEY_SHIFT _ram_call(D,unsigned long) + #define CALCULATOR (_CALCULATOR[0]) + #define HW_VERSION (_CALCULATOR[1]) +#else + #if defined (_TI89_ONLY) + #define ROM_base ((void*)(((unsigned long)__jmp_tbl)&0xE00000)) + #define CALCULATOR 0 + #else +#if defined (_TI92PLUS_ONLY) + #define ROM_base ((void*)0x400000) + #define CALCULATOR 1 + #else +#if defined (_V200_ONLY) + #define ROM_base ((void*)(((unsigned long)__jmp_tbl)&0xE00000)) + #define CALCULATOR 3 + #else + #ifdef DOORS + #define ROM_base _ram_call (3, const void*) + #else + #define ROM_base ((void*)(((unsigned long)__jmp_tbl)&0xE00000)) + #endif + #ifdef NO_CALC_DETECT + #ifdef USE_V200 + #define CALCULATOR (ROM_base==(void*)0x400000?1:(((unsigned char*)(_rom_call_addr(2F)))[2]>=200?3:0)) + #else + #define CALCULATOR (ROM_base==(void*)0x400000) + #endif + #else + extern const short __calculator; + #ifdef USE_TI89 + #define CALCULATOR (__calculator) + #else + #define CALCULATOR (__calculator==3?3:1) + #endif + #endif +#endif +#endif + #endif + #define KEY_DIAMOND (CALCULATOR?8192U:16384U) + #define KEY_DOWN (CALCULATOR?344:340) + #define KEY_DOWNLEFT (CALCULATOR?345:342) + #define KEY_LEFT (CALCULATOR?337:338) + #define KEY_OFF2 (CALCULATOR?8459U:16651U) + #define KEY_RIGHT (CALCULATOR?340:344) + #define KEY_SHIFT (CALCULATOR?16384U:8192U) + #define KEY_UP (CALCULATOR?338:337) + #define KEY_UPRIGHT (CALCULATOR?342:345) + #define LCD_HEIGHT (CALCULATOR?128:100) + #define LCD_LINE_BYTES (CALCULATOR?30:20) + #define LCD_WIDTH (CALCULATOR?240:160) +#endif diff --git a/h/src/default.h b/h/src/default.h new file mode 100644 index 0000000..2ce67b6 --- /dev/null +++ b/h/src/default.h @@ -0,0 +1,132 @@ +#ifndef __DEFAULT +#define __DEFAULT + +#ifdef USE_TI92P +#define USE_TI92PLUS +#endif +#if !defined (USE_TI89) && !defined (USE_TI92PLUS) && !defined (USE_V200) +#define USE_TI89 +#define USE_TI92PLUS +#define USE_V200 +#elif defined(USE_TI89) && !defined (USE_TI92PLUS) && !defined (USE_V200) +#define _TI89_ONLY +#define _ONE_CALC_ONLY +#elif !defined(USE_TI89) && defined (USE_TI92PLUS) && !defined (USE_V200) +#define _TI92PLUS_ONLY +#define _ONE_CALC_ONLY +#elif !defined(USE_TI89) && !defined (USE_TI92PLUS) && defined (USE_V200) +#define _V200_ONLY +#define _ONE_CALC_ONLY +#endif +#if defined (USE_TI89) && defined (USE_TI92PLUS) && defined (USE_V200) +#define _SUPPORT_ALL_CALCS +#endif + +#ifdef DOORS +#define USE_KERNEL +#endif + +#if defined(EXECUTE_IN_GHOST_SPACE) && defined(USE_KERNEL) +#error EXECUTE_IN_GHOST_SPACE does not work in kernel mode yet +#endif + +#if !defined (NO_CALC_DETECT) && (!defined (USE_KERNEL) || !defined (_SUPPORT_ALL_CALCS)) +#define _NEED_CALC_DETECT +#ifdef _ONE_CALC_ONLY +#ifdef USE_TI89 +#define _CALC_NUM 0 +#endif +#ifdef USE_TI92PLUS +#define _CALC_NUM 1 +#endif +#ifdef USE_V200 +#define _CALC_NUM 3 +#endif +#else +#ifndef _SUPPORT_ALL_CALCS +#ifndef USE_TI89 +#define _CALC_NUM 0 +#endif +#ifndef USE_TI92PLUS +#define _CALC_NUM 1 +#endif +#ifndef USE_V200 +#define _CALC_NUM 3 +#endif +#endif +#endif +#endif +#if !defined (_ONE_CALC_ONLY) && !defined (USE_KERNEL) +#define _NEED_CALC_VAR +#endif + +#define __ATTR_STD__ __attribute__((__stkparm__)) +#define __ATTR_STD_NORETURN__ __attribute__((__stkparm__,__noreturn__)) +#define CALLBACK __ATTR_STD__ +#define __ATTR_TIOS__ __ATTR_STD__ +#define __ATTR_TIOS_NORETURN__ __ATTR_STD_NORETURN__ +#define __ATTR_TIOS_CALLBACK__ CALLBACK +#define __ATTR_GCC__ +#define __ATTR_LIB_C__ __attribute__((__regparm__(1))) +#define __ATTR_LIB_ASM__ __ATTR_STD__ +#define __ATTR_LIB_ASM_NORETURN__ __ATTR_STD_NORETURN__ +#define __ATTR_LIB_CALLBACK_C__ CALLBACK +#define __ATTR_LIB_CALLBACK_ASM__ CALLBACK + +#define __jmp_tbl (*(void***)0xC8) +//#define _rom_call(type,args,index) (*((type(*__ATTR_TIOS__)args)(_rom_call_addr_concat(0x##index,_ROM_CALL_##index)))) +//#define _rom_call_addr(index) _rom_call_addr_concat(0x##index,_ROM_CALL_##index) +//#define _rom_call_addr_concat(intindex,romindex) (__jmp_tbl[intindex]) +#define _rom_call(t,a,i) (*((t(*__ATTR_TIOS__)a)(__jmp_tbl[0x##i]))) +#define _rom_call_addr(i) (__jmp_tbl[0x##i]) +#define offsetof(t,m) ((unsigned long)&(((t*)0)->m)) +#define OFFSETOF offsetof +#define import_binary(f,i) asm { i: incbin f }; + +#ifdef _GENERIC_ARCHIVE +#undef OPTIMIZE_ROM_CALLS +#undef USE_FLINE_ROM_CALLS +#undef USE_INTERNAL_FLINE_EMULATOR +#endif + +#ifndef MIN_AMS +#define MIN_AMS 101 +#endif + +#ifdef USE_FLINE_ROM_CALLS +#if !defined (USE_FLINE_EMULATOR) && !defined (USE_INTERNAL_FLINE_EMULATOR) +#if MIN_AMS<204 +#error You need to define USE_[INTERNAL_]FLINE_EMULATOR +#endif +#endif +//#error _INCLUDE_PATCH(fline_rom_calls); +#endif + +#define TIOS_entries (*(unsigned long*)(__jmp_tbl-1)) + +#ifdef DOORS +#define AMS_1xx ((ROM_VERSION&0x0F00)==0x100) +#define AMS_2xx ((ROM_VERSION&0x0F00)==0x200) +#else +#define AMS_1xx (TIOS_entries<1000) +#define AMS_2xx (TIOS_entries>1000) +#endif + +typedef short *__pshort; +typedef unsigned short *__pushort; +typedef long *__plong; +typedef unsigned long *__pulong; + +//extern float __BC()__ATTR_LIB_ASM__; +//#define _tios_float_1(f,x,t) ({typedef float(*__temp__type__)(short,t)__ATTR_LIB_ASM__;((__temp__type__)__BC)(4*0x##f,x);}) +//#define _tios_float_2(f,x,y,t1,t2) ({typedef //float(*__temp__type__)(short,t1,t2)__ATTR_LIB_ASM__;((__temp__type__)__BC)(4*0x##f,x,y);}) + +#if !defined (NOSTUB) && !defined (DOORS) +#ifdef USE_KERNEL +#include +#else +#include +#endif +#endif + +#endif diff --git a/h/src/doors.h b/h/src/doors.h new file mode 100644 index 0000000..b1ff7ab --- /dev/null +++ b/h/src/doors.h @@ -0,0 +1,47 @@ +#ifndef DOORS +#define DOORS + +#ifdef NOSTUB + +#error "doors.h" must not be included in "nostub" mode! +#undef DOORS + +#else + +#ifdef EXE_OUT +#error As of now, you cannot generate EXEs in kernel mode. +#endif + +#include + +//#undef _rom_call_addr_concat +//#define _rom_call_addr_concat(intindex,romindex) (&romindex) +#undef _rom_call +#undef _rom_call_addr +#define _rom_call(t,a,i) (*((t(*__ATTR_TIOS__)a)(&_ROM_CALL_##i))) +#define _rom_call_addr(i) (&_ROM_CALL_##i) + +#define _main() __main() + +/* Begin Auto-Generated Part */ +#define _ram_call(i,t) ((t)(&_RAM_CALL_##i)) +#define _ram_call_addr(i) (&_RAM_CALL_##i) +/* End Auto-Generated Part */ + +#ifdef RETURN_VALUE +#define _NEED_COMPLEX_MAIN +#endif + +#ifndef NO_EXIT_SUPPORT +#define _NEED_COMPLEX_MAIN +#endif + +#if defined (_NEED_COMPLEX_MAIN) || defined (_NEED_AMS_CHECK) || defined (_NEED_CALC_DETECT) +#define NO_VSIMPLE_MAIN +#endif + +#if defined(ENABLE_ERROR_RETURN) && defined(_NEED_COMPLEX_MAIN) +#define SPECIAL_ERROR_RETURN +#endif +#endif +#endif diff --git a/h/src/extgraph.h b/h/src/extgraph.h new file mode 100644 index 0000000..1405f23 --- /dev/null +++ b/h/src/extgraph.h @@ -0,0 +1 @@ +#header \ No newline at end of file diff --git a/h/src/gen.h b/h/src/gen.h new file mode 100644 index 0000000..2c48c3e --- /dev/null +++ b/h/src/gen.h @@ -0,0 +1 @@ +#header diff --git a/h/src/nostub.h b/h/src/nostub.h new file mode 100644 index 0000000..bf5a027 --- /dev/null +++ b/h/src/nostub.h @@ -0,0 +1,36 @@ +#ifndef NOSTUB +#define NOSTUB + +#ifdef DOORS +#error "nostub.h" must not be included in "Doors" mode! +#undef NOSTUB +#else +#include + +#if defined(USE_FLINE_ROM_CALLS) || defined(EXE_OUT) +//#undef _rom_call_addr_concat +//#define _rom_call_addr_concat(intindex,romindex) (&romindex) +//#undef _rom_call_addr +//#define _rom_call_addr(index) (__jmp_tbl[0x##index]) +#undef _rom_call +#define _rom_call(t,a,i) (*((t(*__ATTR_TIOS__)a)(&_ROM_CALL_##i))) +#undef OPTIMIZE_ROM_CALLS +#endif + +#ifdef OPTIMIZE_ROM_CALLS +//#error OPTIMIZE_ROM_CALLS isn't supported yet +#endif + +/* Various conditional compilations are defined below, to make an extra */ +/* support code as small as possible. If no RETURN_VALUE and SAVE_SCREEN */ +/* options are defined, the code overload is only two extra bytes! */ + +#if defined(SAVE_SCREEN) || defined(RETURN_VALUE) || !defined(NO_EXIT_SUPPORT) || defined(ENABLE_ERROR_RETURN) +#define _NEED_COMPLEX_MAIN +#endif + +#define _main() __main() +#define _nostub _main + +#endif +#endif diff --git a/h/src/patch.h b/h/src/patch.h new file mode 100644 index 0000000..5ea85c1 --- /dev/null +++ b/h/src/patch.h @@ -0,0 +1,420 @@ +#ifndef _GENERIC_ARCHIVE +#ifdef RETURN_VALUE +#define __str(x) #x +#define __xstr(x) __str(x) +#define __var(x) x##1 +#define __xvar(x) __var(x) +#if !__xvar(RETURN_VALUE) +#define RETURN_VARIABLE +#define __VN __RV+(sizeof(__xstr(RETURN_VALUE))) +extern char __RV[]; +#endif +#endif +#undef RETURN_VARIABLE ///// bug in GTC!!!!!!! + +#ifdef EXE_OUT +#define _NEED_COMPLEX_MAIN +#endif + +#ifdef ENABLE_ERROR_RETURN +#define SPECIAL_ERROR_RETURN +#endif +asm { +#ifdef NO_VSIMPLE_MAIN +#define NO_MAIN +_main: +#define _main __main +#else +#ifdef NOSTUB +#define NO_MAIN +_nostub: +#endif +#endif +#ifdef EXE_OUT +// [params : d3=optional SYM_ENTRY* to twin ; a2=ROM_CALL table] + move.l d3,-(a7) + beq \no_twin_delete +#if 0 + move.l d3,-(a7) + moveq #0,d7 // we only need the current HSym as DelTwin will make it alright +\loop + addq.w #2,d7 + subq.l #2,d3 + move.l d3,(a7) + jsr _ROM_CALL_23A /* HeapPtrToHandle */ + move.w d0,(a7) + beq \loop + move.l (a7)+,d3 + move.w d7,d3 +#else +//#ifdef FULL_EXE +// // note that in fact the latter won't work, since SymDelTwin won't delete anything... +// move.l d3,a0 +// move.w 12(a0),d3 +// clr.w 12(a0) // hack so that SymDelTwin won't free the handle +//#else + // will work as long as we don't *need* to return a locked handle (TSR...) + // -> maybe should use full version for programs that need ghost space execution? +//#endif +#endif + jsr _ROM_CALL_280 /* SymDelTwin */ +#if 0 + move.l d3,(a7) // save the HSym +#else +//#ifdef FULL_EXE +// clr.l (a7) // for HeapRealloc +// move.w d3,-(a7) // save the HANDLE +// jsr _ROM_CALL_9F /* HeapUnlock */ +// jsr _ROM_CALL_9D /* HeapRealloc */ +//#endif +#endif +\no_twin_delete +#endif +#ifdef EXECUTE_IN_GHOST_SPACE + //-------------------------------------------------------------------------- + // get the HW parm block using the algorithm suggested by Julien Muchembled + //-------------------------------------------------------------------------- + move.l 0xc8,d0 + and.l #0xE00000,d0 // get the ROM base + move.l d0,a0 + move.l 260(a0),a1 // get pointer to the hardware param block + add.l #0x10000,a0 + cmp.l a0,a1 // check if the HW parameter block is near enough + bhs \is_hw1or2 // if it is too far, it is HW1 + cmpi.w #22,(a1) // check if the parameter block contains HW ver + bls \is_hw1or2 // if it is too small, it is HW1 + + //-------------------------------------------------------------------------- + // check for VTI (trick suggested by Julien Muchembled) + //-------------------------------------------------------------------------- + trap #12 // enter supervisor mode. returns old (sr) in d0.w + move.w #0x3000,sr // set a non-existing flag in sr (but keep s-flag) + move.w sr,d1 // get sr content and check for non-existing flag + move.w d0,sr // restore old sr content + btst.l #12,d1 // this non-existing flag can only be set on the VTI + bne \is_hw1or2 // flag set -> VTI -> treat as HW1 + + //-------------------------------------------------------------------------- + // check for HW3 + //-------------------------------------------------------------------------- + cmp.l #3,22(a1) // check the hardware version + bcs \is_hw1or2 // <3 -> proceed + + //-------------------------------------------------------------------------- + // now check for an appropriate ROM patch (HW3Patch?) + //-------------------------------------------------------------------------- + move.l 0xc8,a0 + move.l 0xc0*4(a0),a1 // abuse EX_stoBCD + tst.w 92(a1) // check for HW3Patch (ROM resident) + beq \ghost_done // if it is installed, we're done + cmp.l #0x100,0xac // check for HW3Patch (RAM resident) + beq \ghost_done // if it is installed, we're done + + //-------------------------------------------------------------------------- + // now we have a problem: we are on unpatched HW3 -> can't proceed + //-------------------------------------------------------------------------- + pea __hw3patch_required(pc) + bra \msg_exit + +\is_hw1or2 + #ifndef EXE_OUT + lea gtc_compiled,a0 + move.l a0,d0 + cmp.l #0x40000,d0 + bcc.s \ghost_done + bset.l #18,d0 + moveq #0,d1 + move.w -2(a0),d1 + add.l d0,d1 + subq.l #1,d1 + move.l d1,-(sp) + move.l d0,-(sp) + move.l 0xC8,a0 + move.l 1384(a0),a0 + jsr (a0) + addq.l #8,sp + move.l 0xC8,a0 + cmp.l #1000,-4(a0) + bcc.s \ghost_install + pea \ghost_done(pc) + bset.b #2,1(sp) + rts +\ghost_install: + movem.l a2-a6/d3-d7,-(sp) + lea -20(sp),sp + move.l #0x3E000,a3 + move.l a0,d0 + and.l #0x600000,d0 + add.l #0x20000,d0 + move.l d0,12(sp) + move.l d0,16(sp) + trap #12 + move.w #0x2700,sr + moveq #0xF,d3 + pea \ghost_cont(pc) + bset.b #2,1(sp) + clr.w -(sp) + move.l 0xAC,a0 + jmp (a0) +\ghost_cont + lea 20(sp),sp + movem.l (sp)+,a2-a6/d3-d7 + #endif +\ghost_done +#endif +#if defined(_NEED_CALC_DETECT) || (defined(SAVE_SCREEN) && !defined(USE_KERNEL)) + move.l 0xC8,a0 +#endif +#ifdef _NEED_CALC_DETECT + moveq #1,d0 + move.l a0,d1 + and.l #0x400000,d1 + bne \calc_d0 + clr.w d0 + move.l 0x2F*4(a0),a1 + cmp.b #200,2(a1) + blt \calc_d0 + moveq #3,d0 +\calc_d0 +#ifdef _NEED_CALC_VAR + lea __calculator(pc),a1 + move.w d0,(a1) +#endif +#ifndef _SUPPORT_ALL_CALCS +#if _CALC_NUM + subq.w #_CALC_NUM,d0 +#elif !defined(_NEED_CALC_VAR) + tst.w d0 +#endif +#ifdef _ONE_CALC_ONLY + beq \calc_ok +#else + bne \calc_ok +#endif + pea __wrong_calc(pc) + bra \msg_exit +#endif +\calc_ok +#endif +#ifndef _NEED_COMPLEX_MAIN + #ifdef NOSTUB + bra __main + #else + #ifdef NO_VSIMPLE_MAIN + bra __main + #endif + #endif +#else + #ifdef NOSTUB + #ifdef SAVE_SCREEN + pea (a2) + lea -3840(sp),sp + pea 3840 + pea 0x4C00 + pea 8(sp) + move.l 0x26A*4(a0),a2 + jsr (a2) /* memcpy */ + #endif + #ifndef NO_EXIT_SUPPORT + movem.l d3-d7/a2-a6,-(sp) + #endif + #endif + #ifdef USE_INTERNAL_FLINE_EMULATOR + move.l 0x2C,-(sp) + lea \fline_handler(pc),a1 + lea 0x600000,a0 + and.w #~4,(a0) + move.l a1,0x2C + or.w #4,(a0) + #endif + #ifdef SPECIAL_ERROR_RETURN + lea -60(sp),sp + pea (sp) + move.l 0xC8,a0 + move.l 0x154*4(a0),a0 /* ER_catch */ + jsr (a0) + tst.w d0 + bne \error_returned + #endif + #ifdef NOSTUB + jsr __main + #else + jsr __main + #endif + #if defined(ENABLE_ERROR_RETURN) + move.l 0xC8,a0 + move.l 0x155*4(a0),a0 /* ER_success */ + jsr (a0) + clr.w d0 +\error_returned + lea \error_num(pc),a0 + move.w d0,(a0) + lea 64(sp),sp + #endif + #ifdef USE_INTERNAL_FLINE_EMULATOR + lea 0x600000,a0 + and.w #~4,(a0) + move.l (sp)+,0x2C + or.w #4,(a0) + #endif + #ifdef NOSTUB + #ifndef NO_EXIT_SUPPORT + movem.l (sp)+,d3-d7/a2-a6 + #endif + #ifdef SAVE_SCREEN + pea 3840 + pea 16(sp) + pea 0x4C00 + jsr (a2) + lea 3864(sp),sp + move.l (sp)+,a2 + #endif + #endif + #ifdef SPECIAL_ERROR_RETURN + lea \error_num(pc),a0 + tst.w (a0) + beq \no_error + or.w #0xA000,(a0) + /* for AMS 1, to unlock the prgm hd */ + move.l 0xC8,a2 + cmp.l #1000,-4(a2) + bcc \ams1_err_ok + pea gtc_compiled-2(pc) + move.l 0x23A*4(a2),a0 /* HeapPtrToHandle */ + jsr (a0) + tst.w d0 + beq \ams1_err_ok + move.w d0,-(sp) + move.l 0x9F*4(a2),a0 /* HeapUnlock */ + jsr (a0) +\ams1_err_ok +\error_num: + dc.w 0 +\no_error + #endif +#ifdef EXE_OUT +\program_rts +#if 0 + move.l (a7),d0 + beq \no_twin_create + clr.l -(a7) + jsr _ROM_CALL_166 /* EM_twinSymFromExtMem */ + addq.l #4,a7 +\no_twin_create + addq.l #4,a7 +#else +#ifdef FULL_EXE + tst.w (a7) + beq \no_twin_free + jsr _ROM_CALL_97 /* HeapFree */ + addq.l #2,a7 +\no_twin_free +#endif + addq.l #4,a7 +#endif +#ifdef BSS_SUPPORT + pea __bss_start + jsr _ROM_CALL_A3 /* tios::HeapFreePtr */ + addq.l #4,a7 +#endif + movem.l (a7)+,d3-d7/a2-a6 + move.l 0xC8,a0 + move.l 0x97*4(a0),a0 /* tios::HeapFree */ + jmp (a0) // note : we can't use a _ROM_CALL here, as we need a jmp + #ifdef RETURN_VALUE + #error Not compatible yet. + #endif +#else + #ifndef RETURN_VALUE + rts + #else + #ifdef NOSTUB + #ifndef RETURN_VARIABLE + move.l (sp)+,a0 + cmpi.w #0x21EE,(a0) + bne.s \A2 + addq.l #2,a0 +\A2: + jmp 4(a0) + #else + move.l 0xC8,a0 + move.l 1060(a0),a1 + move.l (a1),-(sp) + move.l #0x40000000,-(sp) + pea __VN(pc) + move.l 0x86*4(a0),a0 + jsr (a0) /* VarStore */ + lea 12(sp),sp + rts + #endif + #else + #ifndef RETURN_VARIABLE + move.l _ROM_CALL_109,_RAM_CALL_00F + rts + #else + move.l _ROM_CALL_109,-(sp) + move.l #0x40000000,-(sp) + pea __VN(pc) + jsr _ROM_CALL_86 + lea 12(sp),sp + rts + #endif + #endif + #endif +/* #ifdef ENABLE_ERROR_RETURN +\error_num: +// move.w #0,#8 + dc.w 0 + #endif*/ +#endif +#endif +#ifdef USE_INTERNAL_FLINE_EMULATOR +\fline_handler: + move.w (sp)+,d0 + move.l (sp)+,a0 + move.w d0,sr + move.w (a0)+,d0 + and.w #0x7FF,d0 + lsl.w #2,d0 + move.l 0xC8,a1 + pea (a0) + move.l 0(a1,d0.w),a0 + jmp (a0) +#endif +#if (defined(_NEED_CALC_DETECT)&&!defined(_SUPPORT_ALL_CALCS)) || defined(EXECUTE_IN_GHOST_SPACE) +\msg_exit: + move.l 0xE6*4(a0),a0 /* ST_helpMsg */ + jsr (a0) + addq.l #4,a7 +#ifdef EXE_OUT + bra \program_rts +#else +#ifdef NOSTUB + rts +#else + jmp _ROM_CALL_51 /* ngetchx */ +#endif +#endif +#endif +#if defined(_NEED_CALC_DETECT) && defined(_NEED_CALC_VAR) + even +__calculator: + dc.w -1 +#endif +#ifndef NO_EXIT_SUPPORT +__save__sp__: + dc.l 0 +#endif + even +}; + +#if (defined(_NEED_CALC_DETECT)&&!defined(_SUPPORT_ALL_CALCS)) +char __wrong_calc[]="Wrong calculator model"; +#endif +#ifdef EXECUTE_IN_GHOST_SPACE +char __hw3patch_required[]="HW3Patch required"; +#endif +#ifdef RETURN_VARIABLE +char __RV[]="\0" __xstr(RETURN_VALUE); +#endif +#endif diff --git a/h/src/std.h b/h/src/std.h new file mode 100644 index 0000000..2fe1388 --- /dev/null +++ b/h/src/std.h @@ -0,0 +1,4 @@ +#ifndef EXIT_SUPPORT +#define NO_EXIT_SUPPORT +#endif +#include diff --git a/h/src/tigcclib.h b/h/src/tigcclib.h new file mode 100644 index 0000000..ed10eb2 --- /dev/null +++ b/h/src/tigcclib.h @@ -0,0 +1,17 @@ +#ifndef __TIGCCLIB +#define __TIGCCLIB +#define inline +#include +#header +#include +#include +#ifndef __SECONDARY_FILE__ +#include +#endif +#headeropt +#headeropt +#headeropt +#headeropt +#headeropt +#headeropt +#endif diff --git a/h/src/ttunpack.h b/h/src/ttunpack.h new file mode 100644 index 0000000..c23edb9 --- /dev/null +++ b/h/src/ttunpack.h @@ -0,0 +1,81 @@ +typedef struct { + unsigned char osize_lo; // original size lowbyte + unsigned char osize_hi; // original size highbyte + unsigned char magic1; // must be equal to TTUNPACK_MAGIC1 + unsigned char magic2; // must be equal to TTUNPACK_MAGIC2 + unsigned char csize_lo; // compressed size lowbyte + unsigned char csize_hi; // compressed size lowbyte + unsigned char esc1; // escape >> (8-escBits) + unsigned char notused3; + unsigned char notused4; + unsigned char esc2; // escBits + unsigned char gamma1; // maxGamma + 1 + unsigned char gamma2; // (1< osize_lo | (((TTUNPACK_HEADER*)(_p_))->osize_hi << 8))) +#define ttunpack_valid(_p_) (((TTUNPACK_HEADER*)(_p_))->magic1 == TTUNPACK_MAGIC1 && ((TTUNPACK_HEADER*)(_p_))->magic2 == TTUNPACK_MAGIC2) + +#define TTUNPACK_OKAY 0 +#define TTUNPACK_NOESCFOUND 248 +#define TTUNPACK_ESCBITS 249 +#define TTUNPACK_MAXGAMMA 250 +#define TTUNPACK_EXTRALZP 251 +#define TTUNPACK_NOMAGIC 252 +#define TTUNPACK_OUTBUFOVERRUN 253 +#define TTUNPACK_LZPOSUNDERRUN 254 + +#define ttunpack_decompress ((unsigned short(*)(unsigned char*,unsigned char*))__ttunpack_decompress) +unsigned short __ttunpack_decompress[] = { +0x48e7,0x7ffa,0x4fef,0xffe8,0x206f,0x0050,0x0c28,0x0054,0x0002,0x6608, +0x0c28,0x0050,0x0003,0x6708,0x303c,0x00fc,0x6000,0x0264,0x4286,0x1c28, +0x0006,0x4247,0x1e28,0x0009,0x4245,0x1a28,0x000a,0x5345,0x4240,0x1028, +0x000c,0x3c40,0x7201,0xeb69,0x3f41,0x000e,0x7002,0xeb68,0x3f40,0x000c, +0x7208,0x9245,0x3f41,0x000a,0x7008,0x9047,0x3840,0x303c,0x00f9,0x0c47, +0x0008,0x6200,0x021e,0x4240,0x1028,0x000b,0xb06f,0x000e,0x660c,0x0c45, +0x0004,0x6306,0x0c45,0x0007,0x6308,0x303c,0x00fa,0x6000,0x01fe,0x7204, +0xb24e,0x6408,0x303c,0x00fb,0x6000,0x01f0,0x43e8,0x000f,0x2f49,0x0010, +0x266f,0x0054,0x43fa,0x01ea,0x2f49,0x0006,0x226f,0x0010,0x4280,0x1011, +0x41f0,0x0810,0x226f,0x0006,0x2288,0x41fa,0x01d4,0x2f48,0x0002,0x30bc, +0x0080,0x3606,0x4a47,0x670c,0x3f07,0x41fa,0x0274,0x4e90,0x3600,0x548f, +0x3043,0xbc88,0x6600,0x018c,0x3f05,0x45fa,0x021a,0x4e92,0x3800,0x426f, +0x0002,0x548f,0x0c44,0x0001,0x6754,0x3f05,0x4e92,0x3600,0x5343,0x302f, +0x000e,0x5540,0x548f,0xb043,0x6618,0x0c44,0x0003,0x6300,0x0170,0x45fa, +0x017e,0x4e92,0x3f40,0x0000,0x4e92,0x6000,0x0120,0x300e,0x6710,0x3f0e, +0x41fa,0x021a,0x4e90,0x320e,0xe36b,0x8640,0x548f,0x41fa,0x015a,0x4e90, +0x0a40,0x00ff,0x3203,0xe149,0x8240,0x6000,0x00fe,0x226f,0x0006,0x2051, +0x4240,0x1010,0x206f,0x0002,0x3210,0xc041,0x6700,0x00ca,0xe219,0x6402, +0x5291,0x3081,0x2051,0x4240,0x1010,0xc041,0x6630,0x3001,0xe218,0x6402, +0x5291,0x226f,0x0002,0x3280,0x3f07,0x45fa,0x01c0,0x4e92,0x3600,0x3f0c, +0x4e92,0x320c,0x48c1,0xe3ae,0x8c00,0x16c6,0x4286,0x3c03,0x588f,0x6000, +0xff26,0x3001,0xe218,0x6402,0x5291,0x206f,0x0002,0x3080,0x3f05,0x4e92, +0x3600,0x548f,0xb66f,0x000e,0x6522,0x3f2f,0x000a,0x41fa,0x0180,0x4e90, +0x966f,0x0010,0x322f,0x000c,0xe36b,0x8640,0x3f05,0x4e92,0x5340,0xe148, +0x8640,0x588f,0x3f05,0x4e92,0x3800,0x548f,0x0c44,0x001f,0x6210,0x4280, +0x3004,0x206f,0x0010,0x1230,0x0800,0x4881,0x6016,0x3f3c,0x0003,0x41fa, +0x0140,0x4e90,0x3204,0x0641,0xffe0,0xe749,0x8240,0x548f,0x4242,0xb642, +0x6500,0xfeac,0x16c1,0x5242,0xb642,0x64f8,0x6000,0xfea0,0x3001,0x226f, +0x0006,0xe218,0x6402,0x5291,0x206f,0x0002,0x3080,0x41fa,0x0056,0x4e90, +0x3200,0x0a41,0x00ff,0x4242,0xb842,0x6500,0xfe7a,0x4280,0x3001,0x204b, +0x91c0,0x102f,0x0001,0xd028,0xffff,0x16c0,0x5242,0xb842,0x64e8,0x6000, +0xfe5e,0x3f0c,0x41fa,0x00d6,0x4e90,0x320c,0xe36b,0x8600,0x16c3,0x548f, +0x6000,0xfe48,0x4240,0x4fef,0x0018,0x4cdf,0x5ffe,0x4e75,0x0000,0x0000, +0x0000,0x41fa,0xfff8,0x2250,0x4240,0x1019,0x2089,0x323a,0xfff0,0x0c01, +0x0080,0x6602,0x4e75,0xe148,0x1011,0x0c01,0x0008,0x6212,0x6630,0x0240, +0x0fff,0xe848,0x4e75,0x0240,0x7fff,0xee48,0x4e75,0x0c01,0x0020,0x62f2, +0x6508,0x0240,0x3fff,0xec48,0x4e75,0x0240,0x1fff,0xea48,0x4e75,0x0240, +0x07ff,0xe648,0x4e75,0x0c01,0x0002,0x62f2,0x6608,0x0240,0x03ff,0xe448, +0x4e75,0x0240,0x01ff,0xe248,0x4e75,0x2f03,0x4281,0x302f,0x0008,0x207a, +0xff84,0x343a,0xff84,0xb041,0x6312,0x3602,0xc610,0xe21a,0x6402,0x5288, +0x4a03,0x6704,0x5241,0x60ea,0x2608,0x41fa,0xff64,0x2083,0x41fa,0xff62, +0x3082,0x2043,0x7601,0xe36b,0x3f01,0x6108,0x544f,0x8043,0x261f,0x4e75, +0x4240,0x322f,0x0004,0x6730,0x207a,0xff3e,0x2243,0x343a,0xff3c,0x5341, +0xe348,0x3602,0xc610,0x6702,0x5200,0xe21a,0x6402,0x5288,0x51c9,0xffee, +0x2609,0x43fa,0xff20,0x3282,0x43fa,0xff16,0x2288,0x2243,0x4e75}; diff --git a/h/src/xupak.h b/h/src/xupak.h new file mode 100644 index 0000000..5471afe --- /dev/null +++ b/h/src/xupak.h @@ -0,0 +1,12 @@ +typedef struct { + int magic[2]; + unsigned int upksize,pksize; + char escbits,esc0; + char lzx,rlenum; + char rlec[0]; +} XPAK_HDR; +#define XPAK_MAGIC1 (('G'<<8)+'T') +#define XPAK_MAGIC2 (('P'<<8)+'k') +#define xpak_ismagic(m) (m[0]==XPAK_MAGIC1 && m[1]==XPAK_MAGIC2) +#define xpak_setmagic(m) (void)(m[0]=XPAK_MAGIC1,m[1]=XPAK_MAGIC2) +#header diff --git a/pch/Makefile b/pch/Makefile new file mode 100644 index 0000000..fc6256b --- /dev/null +++ b/pch/Makefile @@ -0,0 +1,81 @@ +# - no, it's not a true makefile... +# - yes, it's a .bat quick-and-dirtily converted to a makefile +# :-b + +BIN=$(shell pwd)/../bin +MERGE=perl script/merge.pl +PCHMK=$(BIN)/pchmaker +DAT89=$(BIN)/dat89y -e HDR +O2EXT=$(BIN)/obj2ti -x + +PCHFILES = stdhead.pch keywords.pch estack.pch estackle.pch events.pch homescr.pch tiosdlg.pch wingraph.pch xupaki.pch #gen.pch extgraph.pch +TIPCHFILES = $(patsubst %.pch,%.89y,$(PCHFILES)) + +all: src/* srcdata/* subprojects/xupaki.pch + $(RM) lex.txt *.pchsource + cp src/lex.txt src/*.pchsource . + $(MAKE) $(TIPCHFILES) $(PCHFILES) + $(RM) lex.txt pchlog.txt *.pchsource + touch all +stdhead.pchsource: src/* + $(MERGE) src/stdhead-light.pchmerge +tiosdlg.pchsource: src/* + $(MERGE) src/tiosdlg-merge.pchmerge +keywords.pch: keywords.pchsource extfiles + $(PCHMK) $< +stdhead.pch: stdhead.pchsource extfiles + $(PCHMK) $< +estackle.pch: estackle.pchsource stdhead.pch extfiles + $(PCHMK) -istdhead.def $< +estack.pch: estack.pchsource stdhead.pch estackle.pch extfiles + $(PCHMK) -istdhead.def -iestackle.def $< +events.pch: events.pchsource stdhead.pch extfiles + $(PCHMK) -istdhead.def $< +homescr.pch: homescr.pchsource stdhead.pch extfiles + $(PCHMK) -istdhead.def $< +tiosdlg.pch: tiosdlg.pchsource stdhead.pch extfiles + $(PCHMK) -istdhead.def $< +wingraph.pch: wingraph.pchsource stdhead.pch extfiles + $(PCHMK) -istdhead.def $< +#gen.pch: srcdata/gen.pch +# cp $< $@ +#extgraph.pch: srcdata/extgraph.pch +# cp $< $@ +xupaki.pch: subprojects/xupaki.pch + cp $< $@ +%.89y: %.pch + $(DAT89) -f zheader $< + +clean: + $(RM) lex.txt pchlog.txt *.pchsource + $(RM) extfiles + $(RM) -r a2ext + +distclean: clean + +scratchclean: distclean + $(RM) *.pch *.89y *.def subprojects/*.pch all + +include ../config.mk +install: all + mkdir -p $(prefix)/share/gtc/include + install -m 644 *.pch $(prefix)/share/gtc/include + +try-import-tigcc-archive: + mv -f src/tigcc-archive/tigcc.a srcdata/tigcc.a&&rm -f src/tigcc-archive/*.o||true + +srcdata/tigcc.a: try-import-tigcc-archive + +extfiles: srcdata/* + $(RM) -r a2ext + mkdir a2ext + sh -c 'cd a2ext && ar x ../srcdata/tigcc.a' + cp srcdata/export.dat srcdata/*.ext srcdata/*.ref a2ext + $(MAKE) -C a2ext -f ../ext.mk O2EXT="$(O2EXT)" + touch extfiles + +subprojects/xupaki.pch: subprojects/xupaki/xupaki.pchsource subprojects/xupaki/unpack2.o + $(RM) -r subprojects/xupaki/a2ext + mkdir subprojects/xupaki/a2ext + sh -c 'cd subprojects/xupaki/a2ext && cp ../export.dat ../*.o . && for i in *.o; do $(O2EXT) "$$i"; done' + sh -c 'cd subprojects/xupaki && $(PCHMK) xupaki.pchsource && rm -f pchlog.txt xupaki.def && mv xupaki.pch ..' diff --git a/pch/all b/pch/all new file mode 100644 index 0000000..e69de29 diff --git a/pch/deflt.txt b/pch/deflt.txt new file mode 100644 index 0000000..47b5b94 --- /dev/null +++ b/pch/deflt.txt @@ -0,0 +1,345 @@ +#var .text +#var tigcc_compiled. +#var .data +#var qsort +#var .text +#var tigcc_compiled. +#var .data +#var fseek +#var .text +#var tigcc_compiled. +#var .data +#var fputc +#var .text +#var tigcc_compiled. +#var .data +#var fgetc +#var .text +#var tigcc_compiled. +#var .data +#var fwrite +#var .text +#var tigcc_compiled. +#var .data +#var fread +#var .text +#var tigcc_compiled. +#var .data +#var fgets +#var .text +#var tigcc_compiled. +#var .data +#var rename +#var .text +#var tigcc_compiled. +#var .data +#var unlink +#var .text +#var tigcc_compiled. +#var buff.0 +#var .data +#var tmpnam +#var .text +#var tigcc_compiled. +#var .data +#var fsetbufsize +#var .text +#var tigcc_compiled. +#var .data +#var bsearch +#var .text +#var tigcc_compiled. +#var .data +#var Sprite8 +#var .text +#var tigcc_compiled. +#var .data +#var Sprite16 +#var .text +#var tigcc_compiled. +#var .data +#var Sprite32 +#var .text +#var tigcc_compiled. +#var .data +#var __get_HS_pushEmptyFIFONode +#var .text +#var tigcc_compiled. +#var .data +#var HomeStorePair +#var .text +#var tigcc_compiled. +#var .data +#var LoadDLL +#var __DLL_body_ptr +#var __DLL_interface_ptr +#var UnloadDLL +#var .text +#var tigcc_compiled. +#var .data +#var __gray_version +#var .text +#var .data +#var bzero +#var .text +#var .data +#var bcopy +#var .text +#var .data +#var __mulsi3 +#var .text +#var tigcc_compiled. +#var .data +#var atoi +#var .text +#var .data +#var __divsi3 +#var .text +#var .data +#var __udivsi3 +#var .text +#var .data +#var __modsi3 +#var .text +#var .data +#var __umodsi3 +#var .text +#var .data +#var __div_entry +#var .text +#var .data +#var __muldi3 +#var .text +#var .data +#var __ashldi3 +#var .text +#var .data +#var __ashrdi3 +#var .text +#var .data +#var __lshrdi3 +#var .text +#var .data +#var __divdi3 +#var .text +#var tigcc_compiled. +#var .data +#var atol +#var .text +#var .data +#var __udivdi3 +#var .text +#var .data +#var __moddi3 +#var .text +#var .data +#var __umoddi3 +#var .text +#var .data +#var __addbf3 +#var .text +#var .data +#var __subbf3 +#var .text +#var .data +#var __mulbf3 +#var .text +#var .data +#var __negbf2 +#var .text +#var .data +#var __divbf3 +#var .text +#var .data +#var __floatsibf +#var .text +#var .data +#var __fixbfsi +#var __fixunsbfsi +#var .text +#var tigcc_compiled. +#var .data +#var strtol +#var .text +#var .data +#var __cmpbf2 +#var __nebf2 +#var __eqbf2 +#var __gebf2 +#var __ltbf2 +#var __gtbf2 +#var __lebf2 +#var .text +#var .data +#var __fp_entry +#var .text +#var .data +#var __fp_entry_1 +#var __fp_call +#var .text +#var .data +#var __BC +#var .text +#var .data +#var rand +#var __randseed +#var .text +#var __gray_check_hw_version +#var __gray_init_mem +#var __gray_init_handler +#var __gray_patches_for_hw1 +#var __gray_hw2type_detected +#var __gray_size_to_allocate +#var __gray_size_to_add +#var __gray_int1_handler_hw1 +#var __gray_skipcount +#var __gray_proceed_old +#var __gray_store +#var __gray_dummy1 +#var __gray_phase +#var __gray_init_return +#var __gray_used_mem +#var __gray_int1_handler_hw2 +#var __gray_startagain +#var __gray_copy_first_or_sec +#var __gray_to_oldint +#var __gray_copy_next_third +#var __gray_perform_copying +#var __gray_update_index +#var __gray_init_hw1_handler +#var __gray_cpy_d_plane +#var __gray_init_proceed +#var __gray_clr_l_plane +#var __gray_ok +#var __gray_off_out +#var __gray_hw1_cleanup +#var __gray_dark2lcd +#var __gray_continue_cleanup +#var .data +#var GrayOn +#var GrayOff +#var __D_plane +#var __L_plane +#var __gray_handle +#var __gray_hw_type +#var __switch_cnt +#var __gray_old_int1_hw1 +#var __gray_old_int1_hw2 +#var __gray_sync_n_count +#var __gray_plane_index +#var __gray_dbl_offset +#var __L_plane2 +#var __D_plane2 +#var .text +#var .data +#var realloc +#var .text +#var .data +#var calloc +#var .text +#var .data +#var clrscr +#var .text +#var .data +#var printf +#var .text +#var tigcc_compiled. +#var .data +#var strtoul +#var .text +#var .data +#var fprintf +#var .text +#var .data +#var fputchar +#var .text +#var .data +#var puts +#var .text +#var .data +#var strputchar +#var .text +#var .data +#var fputs +#var .text +#var .data +#var atof +#var .text +#var .data +#var push_shortint +#var .text +#var .data +#var push_longint +#var .text +#var .data +#var push_longlongint +#var .text +#var .data +#var NoCallBack +#var .text +#var tigcc_compiled. +#var .data +#var fopen +#var .text +#var .data +#var kbd_queue +#var .text +#var .data +#var OSVRegisterTimer +#var .text +#var .data +#var OSVFreeTimer +#var .text +#var .data +#var EV_getAppID +#var .text +#var .data +#var enter_ghost_space +#var .text +#var .data +#var __exit +#var .text +#var .data +#var atexit +#var .text +#var .data +#var __assertion_failed +#var .text +#var .data +#var _rowread +#var .text +#var .data +#var _extalnum_list +#var .text +#var tigcc_compiled. +#var .data +#var fclose +#var .text +#var .data +#var _extpunct_list +#var .text +#var .data +#var HomeStore +#var .text +#var .data +#var __dummy_handler__ +#var .text +#var .data +#var malloc_throw +#var HeapAllocPtrThrow +#var .text +#var .data +#var calloc_throw +#var .text +#var .data +#var realloc_throw +#var .text +#var .data +#var HeapReallocThrow +#var .text +#var LoadDLLThrow +#var .data +#var .text +#var tigcc_compiled. +#var .data +#var ftell diff --git a/pch/estack.89y b/pch/estack.89y new file mode 100644 index 0000000000000000000000000000000000000000..2003e702beb843294e42ae5e0785b3eece0cb0fd GIT binary patch literal 12268 zcma)Cd3;<|^}lzLX5Y7FZMHUBlal+AX0eJ+X5J*PotZa%Gt(ra5NcaWS=!R3m9hvT zARt9RQPhg8MFkNB6bc9k?t%!VB8v;iUJ%(t)b@Ao_r7iV*RLNwpD^d0cka38p5=Sa zeSLi?V{E*ykF(QH*syl}hHdQs`;Rk=ST}5+U%T!k#!6TYJ9rdhH)iDfM_rK!P07EP zEW15WlL%U=xm0kHvG#?>@ N{=G3;EW=U6#s{vCzg*8F|6B+MqU96j!V8!)Jg>> zqWYWx32SrOSle=<2a`s8N(tD>?`7q~W0Dx3Bu+4Xk+-n?Q7JSS4(m}{?se?XEJq9v zN^;0d+5Ue#7{%TrD_}RIk(jGd7Bah|i-1mXAxecsOB%Y?a>Qg>1q2kR*r09%rr? zvROS^o*2?3pEWUO#Fa{Xn9sA~A!w9H=y4^1ujI$FLJicoZ}|c-hJ7XymT8-h D`?@k!A66M+-iLY!DI zJsHy-tzQrHuxc@iU8jQfNd#D+hE)zjG#!s8xMBqQ5u-<|8WFVCgv}OM5m?P?haqpx zq!se`YQ(tQ@ ~@ZdpG5W-%lkjp$Qm z%oUVV%of3%QOhuW+^x_$9ZRNTP%vjC_fj@E4hd#_rJ}9Od586kK?^e$3o7DV&R({7 z2r|uR+_dcXcjoM79WYYJjD`(GC4DH~gun*PSXhsnz6YIR96K>%iKsp^=fzFVLpjf| zt|9v^_q-u(i3T?f*)Ji?Ahw-OrebDX3CVpT_YI~AxO4~)A`zc>GOu)O z`Gl qZ(3&Oj~sFu|z1oMu|CY!S~ol zk-g|ygbrKDS+Hxt~n#f~19W>92b zj` J(1xX*DWOG8Gokd%Ybz{ZpGIuSkTqyquvy+% z{%*E<80s6zgcn44R^Hpp5JS?J!bT*bTa)m5;1(+S$)ZA;#7rq)&p$4Io|yu9GaU0( zg}4UKl{Sr}<4#?YA`(zTHzwC8E975a5M{HPGN@%H!sfK?>G}5- !O7TNBkS9`jYvC{131Uo9!_!knR$AJKG^wu!FTKdv zCfi&yy6s_wZxxNO%?jq|$&{|Vv?#Brjh(FG2fLh$B~@rb%1IiMqdr5m*pq#V0D>WF zX;CAo9u%2H>)BQ@itWr8Dc{L$Q8t`O5D>G46rI6N6+mGmB;rZlHU>|b)#nmP1LUHc zio@&-F(@5WpCPgFWJ*=3q6do(v(IRnS}|c0_ZJ;xJK%?OmRZ$hUJTlFZ@rz$Wl63y za&dL>0NbS@Mas33vt%b<9X?I1CAFJU+QCStqxwbMs!*IMzJZ;s4a==45JM?UEihla zo1G=pnUk2*lrC!qEscL?F85yXsGk+%GHN4Hpjha+ulV=ubK}w%B1Y7on$8)KZcMC} z?qr7K0Nh#oRydFODZaVz<#00wP0iiRF?FV{e|5Kf1K1)so8|e5hWil zy_kIksc TWX2=P@k{GV2ic`K3P}$}{V94kAPv!vfM{QWGZQ^#hLwFv=St_<6-aVKUZtxz zhJu$%0};{5C?I|rr)-eil#x=*rPr4YvpoWdY|>2Gu(b59(tok5&;XGP6=$WtEB!nB zDu55s(s3i@96!mv619C&sfD$^rXcX7I-jzlvUc_jfl%;4XmEaA49Y||MX=L#({BP> z*vPdkQg$A@1|`Z#sAaQdTiMmiWn3B&a&iADehVF$5wq(**7!EMBqL5x$k}<>p0eB6 zb-+#rWon<-UMtlx;)!%h<^j95mHnDsZwsLZ4wV>hK#LSLVw8}i{$=k~tYCL)*b`NI z%PDx}rR6uX?`vvf@sxuO$`_Y!V&4@b(#NO;)WVcZrI_*+ >=1Gh{;Z5W#I|TB3SHnWv(rqKDnC0fk3HzRdR{0o3ob z>r$UP6jDV2plW9i4Jy(VhuD2X@{p)2wd;MwNfmdpy9H{aq)K(6L&fJS_OPEIUr73t zX=QxM{TS6wK3JoZcu(uQP=4gfnv-KH9<6wZ-J>Dg=#A{mzfaXSs7j^Q^W=Nc;73gg zawWd9wsM+1C^UKCQDxK0?#iRt{mPGyko!|HC{GaYOPuXS$O9T&mjKBGh?OT-p35E* zzzoE_%D0!F2^1A#rR}&=3Rby?JuGmz64khZe?BJ9mO!JVR6ba `@I#QQFHfK^3nGvfrRfjHZ=JRkc+;>{kM%%bCK^g6x+9_=Vo~ zD!!z%Un>*PQYt}IrK>ix-yzq_r98&~_ir)CAZA}Od<2z+HbA_}3#-0f^&ER#sjCzG zSLaZ5Th-6mV+zv8bpLGP_bNw`2>Q=w+CK VPCFgF&$;08u1y z$TRknC^(eRL8>0Cet`X1jK~9^a+OvIwmMRM9(!7K3iSG{dcFFS)mzz9z!8$DR>wkr zMB5iLd`|c$4c!aLR930Js`?i8EKn`ce0ld76oRZ$`J4tc8%sx>UZnbuHO=gKHEfAl z=Cm{As{Th!KKrXcyvNKny00%J#r}ffndJAj|2KiIAWoGL_+PqQ&GH(9{asZgTGV5H zL0}pb4>?g#a}0Y?j7Y#052dX&E*v4kORCLxM 8qy)XkcgUg8mm34 z_Dc3o0oRugyuc?}Z;3$(N+jJfY4+$w|J$m?j5}4N_MzGX>^-4!f-l# d2 zeT}`3PBfn7KL5fb# YKqz?m#Eac?|O*Ijo!`>y~Tij(?MnYtBq7W+`3=OEgY zgA`$hf1@nMZ3}?(AA$LjsT!iX)9QA!LrCF-ugyWu!@f e?QG|lLcT>H&9aN&!V6pC zd=(m>#7q=Uh$CNkZR3T!Pgyx(CS5mQcvnLmZ$Lhl4&}CT3m>cB!7EXx6UH35PB?8h zZ3|zo*LbM_R89obP8(j&>l=CTn6zOcm`r9(NqLdNg9+UV(Wc!%=OxN%v9gQh>sQqu z!^`1^w6x=|ybR5wV)cPQUZFH0k{|QcUsnGZuLV|3#8qytzoGtKUacXd)n1*u3DTKY z0XQV$UV7y<8ioWk51Az=Qu(R=)dt2F3gA(C5K2USM_UKvnlKY--#moZ!(YjS3D@ck zM>Rao+civ-ydJ(G+;9 iRoIE_nW|X;ANo(N z;o63MyjA4_LaLO6CsumNfG@&)l3s` >lVQ7tHJ{pi0sjPgd+K+52#$Xo zK!JF(3Ly`oB_{iXOkE9$n(t_ShevP^WI3c?H9yP4%4%8HW;}%c0err(GS|^2TY4;L z@4BU^rIk+!wQYUUH$~% ~8YW$qnf9Lu&7E-~G(>hTqZZ{XYUHa?UJ3g7FQa%u4N-`koDO=oH{24a zRMIt+pD&tRbP=CcruN%<(cGeWo>rT5&I*2*Qdv<-@DMm(gZ^FG$eXw F^Uc%RDXx5Ux5lw5LRp)cK;UKa* z7iw*29pGwao%B1yr!@2v#Hywwt|rGKLlE5?ytE$Ex`VGpA4PO^C+_kehu$VR6{Jy- zr}n4S^ 2uuW$Q*=fWM|q;wqsy=*`O4$* z(g76NZc5s6+Zy>MiTP}9&%P(fBx^I<)V4u>qHK+c>N|*&&?nHm!7ia~v+a-YvjBaP zv8Z1{+xGSbK98d4eh|?1g|_{CD~cJ>oJ7`kb=zHhv%1Q2;>jPxr(h08FUU^_j!2eU z06UzV*7kDSVZIF|jY!$a_Ec4MT`hgUV7of&)i&U0A80?7pN1Grn)Ho>GIo2oJ;Qej zw9p=8CId0PLtQpXW?xUrKckRnGDV*`s2iyE3)`>er>mQpBjDpMbxBB;b#o})65q+s zz~>jz;7;bil4q(G%JGr*zjb_;pRX=)lIaNtg0z3oG0s1yT6`LzIoQ3Uw4;-sEn#l< z;D~=#4JeYSS^td#KL npCIJvA5$M{slQqOimkwRJ_+OfH%)3(HXkIbs;9PsX?XDiyiOt zFWScSm8^^9M*Ux^u+CC`i5f0YW%4bu8}*7-R NG^*Pez4Ow}C;1iFINdg4z=<7n?(MvfUxs;L zDmWYUcQs$qa4SOWNBGU ){6a_cB5*N*?*K(VS z#RH3X@^8TJ)Dx$-TpU?^48ICSQV)FMzlJ8o=J!qb`PUKdDObkDi?88(0MKdno#kfV zM2buKyH@@!ToI<@L3}}@B60DfOHSc?l|Q8ji6p6GQgw3iD@*$MbqboLWD^0iE