--- /dev/null
+dist
+test
--- /dev/null
+List of known bugs that will not get fixed in the near future:
+
+ * The compiler does not detect if part of an expression evaluated
+ with && or || is constant. Since the expression evaluation is also
+ used for the preprocessor, this defeats the use of
+
+ #if defined(x) && defined(y)
+
+ * Initialization of local variables with compound data types is not
+ possible.
+
--- /dev/null
+
+Many special thanks go to the guy who started it all:
+
+ John R.Dunning.
+
+Without his great work, there would not be a single freeware C crosscompiler
+for the 6502 out there. He built the grounds for this cc65 and some other cc65
+implementations and a lot of his code is still in the current compiler.
+
+
+More special thanks to:
+
+ * Keith W. Gerdes <kwg@freebird.ghofn.org>
+
+ Without his outstanding help, the assembler/compiler wouldn't be, what it
+ is now. He helped with suggestions, bug reports and even kicked me here
+ and then, when I started to get too lazy:-)
+
+ * Tennessee Carmel-Veilleux <veilleux@ameth.org>
+
+ Tennessee worked on the NES port.
+
+ * Kevin Ruland <kevin@rodin.wustl.edu>
+
+ Kevin did the Apple 2 port and found at least one serious error in the
+ C library while doing so.
+
+ * Christian Groessler <cpg@aladdin.de>
+
+ Christian sent me several fixes for 64 bit machines.
+
+ * Sidney Cadot <sidney@ch.twi.tudelft.nl>
+
+ Sidney rewrote the random number generator.
+
+ * Maciej Witkowiak <ytm@friko.onet.pl>
+
+ Maciej is responsible for the GEOS support.
+
+
+
+Thanks to
+
+ Mark Nasgowitz <MNasgowitz@NAZdesign.com>
+ da Blondie <db@tvnet.hu>
+ Jari Tuominen <jer64@kolumbus.fi>
+ MagerValp <magervalp@cling.gu.se>
+ Ingo Korb <unseen@gmx.net>
+ Robert R. Wal <rrw@reptile.eu.org>
+ Jesse Beach <agmorion@erols.com>
+ Chris Ward <chris.ward@freenet.co.uk>
+ Eric Au <eric_au@hotmail.com>
+ Tim Vanderhoek <hoek@FreeBSD.org>
+ Bill Craig <craigw@gusun.georgetown.edu>
+
+for bug reports and suggestions.
+
+
+This list is probably incomplete. So, if you think you should be mentioned
+here, but cannot find yourself, please drop me a mail.
+
+
--- /dev/null
+
+
+ ar65
+
+ An Archiver for Object Files Generated by ca65
+
+ (C) Copyright 1998-1999 Ullrich von Bassewitz
+ (uz@musoftware.de)
+
+
+
+Contents
+--------
+
+ 1. Overview
+
+ 2. Usage
+
+ 3. Bugs/Feedback
+
+ 4. Copyright
+
+
+
+1. Overview
+-----------
+
+ar65 is a replacement for the libr65 archiver that was part of the cc65 C
+compiler suite developed by John R. Dunning. libr65 had some problems and
+the copyright does not permit some things which I wanted to be possible,
+so I decided to write a completely new assembler/linker/archiver suite
+for the cc65 compiler. ar65 is part of this suite.
+
+
+
+2. Usage
+--------
+
+The archiver is called as follows:
+
+ Usage: ar65 <operation> lib file|module ...
+ Operation is one of:
+ a Add modules
+ d Delete modules
+ l List library contents
+ x Extract modules
+ X Print the archiver version
+
+
+You may add modules to a library using the `a' command. If the library
+does not exist, it is created (and a warning message is printed which you
+may ignore if creation of the library was your intention). You may
+specify any number of modules on the command line following the library.
+
+If a module with the same name exists in the library, it is replaced by
+the new one. The archiver prints a warning, if the module in the library
+has a newer timestamp than the one to add.
+
+Here's an example:
+
+ ar65 a mysubs.lib sub1.o sub2.o
+
+This will add two modules to the library `mysubs.lib' creating the
+library if necessary. If the library contains modules named sub1.o or
+sub2.o, they are replaced by the new ones.
+
+Modules names in the library are stored without the path, so, using
+
+ ar65 a mysubs.lib ofiles/sub1.o ofiles/sub2.o
+
+will add two modules named `sub1.o' and `sub2.o' to the library.
+
+
+Deleting modules from a library is done with the `d' command. You may not
+give a path when naming the modules.
+
+Example:
+
+ ar65 d mysubs.lib sub1.o
+
+This will delete the module named `sub1.o' from the library, printing an
+error if the library does not contain that module.
+
+
+The `l' command prints a list of all modules in the library. Any module
+names on the command line are ignored.
+
+Example:
+
+ ar65 l mysubs.lib
+
+
+Using the `x' command, you may extract modules from the library. The
+modules named on the command line are extracted from the library and put
+into the current directory.
+
+Note: Because of the indexing done by the archiver, the modules may have
+a changed binary layout, that is, a binary compare with the old module
+(before importing it into the library) may yield differences. The
+extracted modules are accepted by the linker and archiver, however, so
+this is not a problem.
+
+Example for extracting a module from the library:
+
+ ar65 x mysubs.lib sub1.o
+
+
+The `V' command prints the version number of the assembler. If you send
+any suggestions or bugfixes, please include your version number.
+
+In addition to these operations, the archiver will check for, and warn
+about duplicate external symbols in the library, every time when an
+operation does update the library. This is only a warning, the linker
+will ignore one of the duplicate symbols (which one is unspecified).
+
+
+
+3. Bugs/Feedback
+----------------
+
+If you have problems using the archiver, if you find any bugs, or if
+you're doing something interesting with it, I would be glad to hear from
+you. Feel free to contact me by email (uz@musoftware.de).
+
+
+
+4. Copyright
+------------
+
+ar65 (and all cc65 binutils) are (C) Copyright 1998 Ullrich von Bassewitz.
+For usage of the binaries and/or sources the following conditions do
+apply:
+
+This software is provided 'as-is', without any expressed or implied
+warranty. In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not
+ be misrepresented as being the original software.
+3. This notice may not be removed or altered from any source
+ distribution.
+
+
+
--- /dev/null
+
+
+ ca65
+
+ A Macro Crossassembler for the 6502/65C02/65816 CPUs
+
+ (C) Copyright 1998-1999 Ullrich von Bassewitz
+ (uz@musoftware.de)
+
+
+
+Contents
+--------
+
+ 1. Overview
+
+ 2. Usage
+
+ 3. Input format
+
+ 4. Expressions
+
+ 5. Symbols and labels
+
+ 6. Control commands
+
+ 7. Macros
+
+ 8. Macro packages
+
+ 9. Bugs/Feedback
+
+ 10. Copyright
+
+
+
+1. Overview
+-----------
+
+ca65 is a replacement for the ra65 assembler that was part of the cc65 C
+compiler developed by John R. Dunning. I had some problems with ra65 and
+the copyright does not permit some things which I wanted to be possible,
+so I decided to write a completely new assembler/linker/archiver suite for
+the cc65 compiler. ca65 is part of this suite.
+
+Some parts of the assembler (code generation and some routines for symbol
+table handling) are taken from an older crossassembler named a816 written
+by me a long time ago.
+
+Here's a list of the design criteria, that were important for the
+development:
+
+ * The assembler must support macros. Macros are not essential, but they
+ make some things easier, especially when you use the assembler in the
+ backend of a compiler.
+
+ * The assembler must support the newer 65C02 and 65816 CPUs. I have been
+ thinking about a 65816 backend for the C compiler, and even my old
+ a816 assembler had support for these CPUs, so this wasn't really a
+ problem.
+
+ * The assembler must produce relocatable code. This necessary for the
+ compiler support, and it is more convenient.
+
+ * Conditional assembly must be supported. This is a must for bigger
+ projects written in assembler (like Elite128).
+
+ * The assembler must support segments, and it must support more than
+ three segments (this is the count, most other assemblers support).
+ Having more than one code segments helps developing code for systems
+ with a divided ROM area (like the C64).
+
+ * The linker must be able to resolve arbitrary expressions. Years ago I
+ spent half a day to convince Borlands Turbo Assembler to let me use
+ the size of a structure I had created. So I decided that this is a
+ must. The linker should be able to get things like
+
+ .import S1, S2
+ .export Special
+ Special = 2*S1 + S2/7
+
+ right.
+
+ * True lexical nesting for symbols. This is very convenient for larger
+ assembly projects.
+
+ * "Cheap" local symbols without lexical nesting for those quick, late
+ night hacks.
+
+ * I liked the idea of "options" as Anre Fachats .o65 format has it, so I
+ introduced the concept into the object file format use by the new cc65
+ binutils.
+
+ * The assembler will be a one pass assembler. There was no real need for
+ this decision, but I've written several multipass assemblers, and it
+ started to get boring. A one pass assembler needs much more elaborated
+ data structures, and because of that it's much more fun:-)
+ There is one drawback with this point: It is nearly impossible to
+ generate a listing when reading the source file only once without
+ storing the source file in memory. Consequently, the assembler is not
+ able to produce a listing. This could be added by reading the source
+ file a second time if a listing was requested, but I didn't see an
+ urgent need for a listing, so this was not a disadvantage for me.
+
+ * Non-GPLed code that may be used in any project without restrictions or
+ fear of "GPL infecting" other code.
+
+
+
+2. Usage
+--------
+
+The assembler accepts the following options:
+
+ -g Generate debug info
+ -i Ignore case of symbols
+ -l Create a listing if assembly was ok
+ -o name Name the output file
+ -s Enable smart mode
+ -v Increase verbosity
+ -D name[=value] Define a symbol
+ -U Mark unresolved symbols as import
+ -V Print the assembler version
+ -W n Set warning level n
+ --cpu type Set cpu type
+ --pagelength n Set the page length for the listing
+ --smart Enable smart mode
+
+When the -g option (or the equivalent control command .DEBUGINFO) is used,
+the assembler will add a section to the object file that contains all
+symbols (including local ones) together with the symbol values and source
+file positions. The linker will put these additional symbols into the
+VICE label file, so even local symbols can be seen in the VICE monitor.
+
+The option -i makes the assembler case insensitive on identifiers and
+labels. This option will override the default, but may itself be overriden
+by the .CASE control command (see section 6).
+
+The default output name is the name of the input file with the extension
+replaced by ".o". If you don't like that, you may give another name with
+the -o option. The output file will be placed in the same directory as the
+source file, or, if -o is given, the full path in this name is used.
+
+In smart mode (enabled by -s or the .SMART pseudo instruction) the
+assembler will track usage of the REP and SEP instructions in 65816 mode
+and update the operand sizes accordingly. If the operand of such an
+instruction cannot be evaluated by the assembler (for example, because the
+operand is an imported symbol), a warning is issued. Beware: Since the
+assembler cannot trace the execution flow this may lead to false results
+in some cases. If in doubt, use the .ixx and .axx instructions to tell the
+assembler about the current settings. Smart mode is off by default.
+
+-v does increase the assembler verbosity and is usually only needed for
+debugging purposes. You may use this option more than one time for even
+more verbose output.
+
+-D allows you to predefine symbols on the command line. Without a value,
+the symbol is defined with the value zero. When giving a value, you may
+use the '$' prefix for hexadecimal symbols. Please note that for some
+operating systems, '$' has a special meaning, so you may have to quote
+the expression.
+
+-U marks symbols that are not defined in the sources as imported symbols.
+This should be used with care since it delays error messages about typos
+and such until the linker is run. The compiler uses the equivalent of
+this switch (.AUTOIMPORT, see control command section below) to enable
+auto imported symbols for the runtime library. However, the compiler is
+supposed to generate code that runs through the assembler without
+problems, something which is not always true for assembler programmers.
+
+-V prints the version number of the assembler. If you send any suggestions
+or bugfixes, please include your version number.
+
+-Wn sets the warning level for the assembler. Using -W2 the assembler will
+even warn about such things like unused imported symbols. The default
+warning level is 1, and it would probably be silly to set it to something
+lower.
+
+--cpu sets the default for the CPU type. The option takes a parameter,
+which may be one of
+
+ 6502, 65C02, 65816 and sunplus
+
+(the latter is not available in the freeware version).
+
+--pagelength sets the length of a listing page in lines. See the
+.PAGELENGTH directive for more information.
+
+--smart is identical to -s - see there.
+
+
+
+3. Input format
+---------------
+
+The assembler accepts the standard 6502/65816 assembler syntax. One line
+may contain a label (which is identified by a colon), and, in addition to
+the label, an assembler mnemonic, a macro, or a control command (see
+section 6 for supported control commands). Alternatively, the line may
+contain a symbol definition using the '=' token. Everything after a
+semicolon is handled as a comment (that is, it is ignored).
+
+Here are some examples for valid input lines:
+
+ Label: ; A label and a comment
+ lda #$20 ; A 6502 instruction plus comment
+ L1: ldx #$20 ; Same with label
+ L2: .byte "Hello world" ; Label plus control command
+ mymac $20 ; Macro expansion
+ MySym = 3*L1 ; Symbol definition
+ MaSym = Label ; Another symbol
+
+The assembler accepts all valid 6502 mnemonics when in 6502 mode (the
+default). The assembler accepts all valid 65SC02 mnemonics when in 65SC02
+mode (after a .PC02 command is found). The assembler accepts all valid
+65816 mnemonics with a few exceptions after a .P816 command is found.
+These exceptions are listed below.
+
+In 65816 mode several aliases are accepted in addition to the official
+mnemonics:
+
+ BGE is an alias for BCS
+ BLT is an alias for BCC
+ CPA is an alias for CMP
+ DEA is an alias for DEC A
+ INA is an alias for INC A
+ SWA is an alias for XBA
+ TAD is an alias for TCD
+ TAS is an alias for TCS
+ TDA is an alias for TDC
+ TSA is an alias for TSC
+
+
+Evaluation of banked expressions in 65816 mode differs slightly from the
+official syntax:
+
+Instead of accepting a 24 bit address (something that is difficult for
+the assembler to determine and would have required one more special
+.import command), the bank and the absolute address in that bank are
+separated by a dot:
+
+ jsl 3.$1234 ; Call subroutine at $1234 in bank 3
+
+For literal values, the assembler accepts the widely used number formats:
+A preceeding '$' denotes a hex value, a preceeding '%' denotes a binary
+value, and a bare number is interpeted as a decimal. There are currently
+no octal values and no floats.
+
+
+
+4. Expressions
+--------------
+
+All expressions are evaluated with (at least) 32 bit precision. An
+expression may contain constant values and any combination of internal and
+external symbols. Expressions that cannot be evaluated at assembly time
+are stored inside the object file for evaluation by the linker.
+Expressions referencing imported symbols must always be evaluated by the
+linker.
+
+Sometimes, the assembler must know about the size of the value that is the
+result of an expression. This is usually the case, if a decision has to be
+made, to generate a zero page or an absolute memory references. In this
+case, the assembler has to make some assumptions about the result of an
+expression:
+
+ * If the result of an expression is constant, the actual value is
+ checked to see if it's a byte sized expression or not.
+
+ * If the expression is explicitly casted to a byte sized expression by
+ one of the '>'/'<' operators, it is a byte expression.
+
+ * If this is not the case, and the expression contains a symbol,
+ explicitly declared as zero page symbol (by one of the .importzp or
+ .exportzp instructions), then the whole expression is assumed to be
+ byte sized.
+
+ * If the expression contains symbols that are not defined, and these
+ symbols are local symbols, the enclosing scopes are searched for a
+ symbol with the same name. If one exists and this symbol is defined,
+ it's attributes are used to determine the result size.
+
+ * In all other cases the expression is assumed to be word sized.
+
+Note: If the assembler is not able to evaluate the expression at assembly
+time, the linker will evaluate it and check for range errors as soon as
+the result is known.
+
+
+Boolean expressions:
+
+In the context of a boolean expression, any non zero value is evaluated as
+true, any other value to false. The result of a boolean expression is 1 if
+it's true, and zero if it's false. There are boolean operators with extrem
+low precedence with version 2.x (where x > 0). The .AND and .OR operators
+are shortcut operators. That is, if the result of the expression is
+already known, after evaluating the left hand side, the right hand side is
+not evaluated.
+
+
+Available operators sorted by precedence:
+
+ Op Description Precedence
+ -------------------------------------------------------------------
+ * Builtin pseudo variable (r/o) 1
+ .BLANK Builtin function 1
+ .CONST Builtin function 1
+ .CPU Builtin pseudo variable (r/o) 1
+ .DEFINED Builtin function 1
+ .MATCH Builtin function 1
+ .XMATCH Builtin function 1
+ .PARAMCOUNT Builtin pseudo variable (r/o) 1
+ .REFERENCED Builtin function 1
+ .STRING Builtin function 1
+ :: Global namespace override 1
+ + Unary plus 1
+ - Unary minus 1
+ ~ Unary bitwise not 1
+ .BITNOT Unary bitwise not 1
+ < Low byte operator 1
+ > High byte operator 1
+
+ * Multiplication 2
+ / Division 2
+ .MOD Modulo operation 2
+ & Bitwise and 2
+ .BITAND Bitwise and 2
+ ^ Bitwise xor 2
+ .BITXOR Bitwise xor 2
+ << Shift left operator 2
+ .SHL Shift left operator 2
+ >> Shift right operator 2
+ .SHR Shift right operator 2
+
+ + Binary plus 3
+ - Binary minus 3
+ | Binary or 3
+ .BITOR Binary or 3
+
+ = Compare operation (equal) 4
+ <> Compare operation (not equal) 4
+ < Compare operation (less) 4
+ > Compare operation (greater) 4
+ <= Compare operation (less or equal) 4
+ >= Compare operation (greater or equal) 4
+
+ && Boolean and 5
+ .AND Boolean and 5
+ .XOR Boolean xor 5
+
+ || Boolean or 6
+ .OR Boolean or 6
+
+ ! Boolean not 7
+ .NOT Boolean not 7
+
+
+To force a specific order of evaluation, braces may be used as usual.
+
+Some of the pseudo variables mentioned above need some more explanation:
+
+ * This symbol is replaced by the value of the program
+ counter at start of the current instruction. Note, that
+ '*' yields a rvalue, that means, you cannot assign to it.
+ Use .ORG to set the program counter in sections with
+ absolute code.
+
+
+
+5. Symbols and labels
+---------------------
+
+The assembler allows you to use symbols instead of naked values to make
+the source more readable. There are a lot of different ways to define and
+use symbols and labels, giving a lot of flexibility.
+
+ - Numeric constants
+
+ Numeric constants are defined using the equal sign. After doing
+
+ two = 2
+
+ may use the symbol "two" in every place where a number is expected,
+ and it is evaluated to the value 2 in this context. An example would be
+
+ four = two * two
+
+
+ - Standard labels
+
+ A label is defined by writing the name of the label at the start of
+ the line (before any instruction mnemonic, macro or pseudo
+ directive), followed by a colon. This will declare a symbol with the
+ given name and the value of the current program counter.
+
+
+ - Local labels and symbols
+
+ Using the .PROC directive, it is possible to create regions of code
+ where the names of labels and symbols are local to this region. They
+ are not know outside and cannot be accessed from there. Such regions
+ may be nested like PROCEDUREs in Pascal.
+
+ See the description of the .PROC directive for more information.
+
+ - Cheap local labels
+
+ Cheap local labels are defined like standard labels, but the name of
+ the label must begin with a special symbol (usually '@', but this can
+ be changed by the .LOCALCHAR directive).
+
+ Cheap local labels are visible only between two no cheap labels. As
+ soon as a standard symbol is encountered (this may also be a local
+ symbol if inside a region defined with the .PROC directive), the
+ cheap local symbol goes out of scope.
+
+ You may use cheap local labels as an easy way to reuse common label
+ names like "Loop". Here is an example:
+
+ Clear: lda #$00 ; Global label
+ ldy #$20
+ @Loop: sta Mem,y ; Local label
+ dey
+ bne @Loop ; Ok
+ rts
+ Sub: ... ; New global label
+ bne @Loop ; ERROR: Unknown identifier!
+
+ - Unnamed labels
+
+ If you really want to write messy code, there are also unnamed
+ labels. These labels do not have a name (you guessed that already,
+ didn't you?). A colon is used to mark the absence of the name.
+
+ Unnamed labels may be accessed by using the colon plus several minus
+ or plus characters as a label designator. Using the '-' characters
+ will create a back reference (use the n'th label backwards), using
+ '+' will create a forward reference (use the n'th label in forward
+ direction. An example will help to understand this:
+
+ : lda (ptr1),y ; #1
+ cmp (ptr2),y
+ bne :+ ; -> #2
+ tax
+ beq :+++ ; -> #4
+ iny
+ bne :- ; -> #1
+ inc ptr1+1
+ inc ptr2+1
+ bne :- ; -> #1
+
+ : bcs :+ ; #2 -> #3
+ ldx #$FF
+ rts
+
+ : ldx #$01 ; #3
+ : rts ; #4
+
+ As you can see from the example, unnamed labels will make even short
+ sections of code hard to understand, because you have to count labels
+ to find branch targets (this is the reason why I for my part do
+ prefer the "cheap" local labels). Nevertheless, unnamed labels are
+ convenient in some situations, so it's your decision.
+
+ - Using macros to define labels and constants
+
+ While there are drawbacks with this approach, it may be handy in some
+ situations. Using .DEFINE, it is possible to define symbols or
+ constants that may be used elsewhere. Since the macro facility works
+ on a very low level, there is no scoping. On the other side, you may
+ also define string constants this way (this is not possible with the
+ other symbol types).
+
+ Example:
+
+ .DEFINE two 2
+ .DEFINE version "SOS V2.3"
+
+ four = two * two ; Ok
+ .byte version ; Ok
+
+ .PROC ; Start local scope
+ two = 3 ; Will give "2 = 3" - invalid!
+ .ENDPROC
+
+
+If .DEBUGINFO is enabled (or -g is given on the command line), global,
+local and cheap local labels are written to the object file and will be
+available in the symbol file via the linker. Unnamed labels are not
+written to the object file, because they don't have a name which would
+allow to access them.
+
+
+
+6. Control commands
+-------------------
+
+Here's a list of all control commands and a description, what they do:
+
+
+.A16
+
+ Valid only in 65816 mode. Switch the accumulator to 16 bit.
+
+ Note: This command will not emit any code, it will tell the assembler to
+ create 16 bit operands for immediate accumulator adressing mode.
+
+ See also: .SMART
+
+
+.A8
+
+ Valid only in 65816 mode. Switch the accumulator to 8 bit.
+
+ Note: This command will not emit any code, it will tell the assembler to
+ create 8 bit operands for immediate accu adressing mode.
+
+ See also: .SMART
+
+
+.ADDR
+
+ Define word sized data. In 6502 mode, this is an alias for .WORD and
+ may be used for better readability if the data words are address values.
+ In 65816 mode, the address is forced to be 16 bit wide to fit into the
+ current segment. See also .FARADDR. The command must be followed by a
+ sequence of (not necessarily constant) expressions.
+
+ Example:
+
+ .addr $0D00, $AF13, _Clear
+
+
+.ALIGN
+
+ Align data to a given boundary. The command expects a constant integer
+ argument that must be a power of two, plus an optional second argument
+ in byte range. If there is a second argument, it is used as fill value,
+ otherwise the value defined in the linker configuration file is used
+ (the default for this value is zero).
+
+ Since alignment depends on the base address of the module, you must
+ give the same (or a greater) alignment for the segment when linking.
+ The linker will give you a warning, if you don't do that.
+
+ Example:
+
+ .align 256
+
+
+.ASCIIZ
+
+ Define a string with a trailing zero.
+
+ Example:
+
+ Msg: .asciiz "Hello world"
+
+ This will put the string "Hello world" followed by a binary zero into
+ the current segment. There may be more strings separated by commas, but
+ the binary zero is only appended once (after the last one).
+
+
+.AUTOIMPORT
+
+ Is followd by a plus or a minus character. When switched on (using a
+ +), undefined symbols are automatically marked as import instead of
+ giving errors. When switched off (which is the default so this does not
+ make much sense), this does not happen and an error message is
+ displayed. The state of the autoimport flag is evaluated when the
+ complete source was translated, before outputing actual code, so it is
+ *not* possible to switch this feature on or off for separate sections of
+ code. The last setting is used for all symbols.
+
+ You should probably not use this switch because it delays error
+ messages about undefined symbols until the link stage. The cc65
+ compiler (which is supposed to produce correct assembler code in all
+ circumstances, something which is not true for most assembler
+ programmers) will insert this command to avoid importing each and every
+ routine from the runtime library.
+
+ Example:
+
+ .autoimport + ; Switch on auto import
+
+
+.BLANK
+
+ Builtin function. The function evaluates its argument in braces and
+ yields "false" if the argument is non blank (there is an argument), and
+ "true" if there is no argument. As an example, the .IFBLANK statement
+ may be replaced by
+
+ .if .blank(arg)
+
+
+.BSS
+
+ Switch to the BSS segment. The name of the BSS segment is always "BSS",
+ so this is a shortcut for
+
+ .segment "BSS"
+
+ See also the .SEGMENT command.
+
+
+.BYTE
+
+ Define byte sized data. Must be followed by a sequence of (byte ranged)
+ expressions or strings.
+
+ Example:
+
+ .byte "Hello world", $0D, $00
+
+
+.CASE
+
+ Switch on or off case sensitivity on identifiers. The default is off
+ (that is, identifiers are case sensitive), but may be changed by the
+ -i switch on the command line.
+ The command must be followed by a '+' or '-' character to switch the
+ option on or off respectively.
+
+ Example:
+
+ .case - ; Identifiers are not case sensitive
+
+
+.CODE
+
+ Switch to the CODE segment. The name of the CODE segment is always
+ "CODE", so this is a shortcut for
+
+ .segment "CODE"
+
+ See also the .SEGMENT command.
+
+
+.CONST
+
+ Builtin function. The function evaluates its argument in braces and
+ yields "true" if the argument is a constant expression (that is, an
+ expression that yields a constant value at assembly time) and "false"
+ otherwise. As an example, the .IFCONST statement may be replaced by
+
+ .if .const(a + 3)
+
+
+.CPU
+
+ Reading this pseudo variable will give a constant integer value that
+ tells which instruction set is currently enabled. Possible values are:
+
+ 0 --> 6502
+ 1 --> 65SC02
+ 2 --> 65SC816
+ 3 --> SunPlus SPC
+
+ It may be used to replace the .IFPxx pseudo instructions or to construct
+ even more complex expressions.
+
+ Example:
+
+ .if (.cpu = 0) .or (.cpu = 1)
+ txa
+ pha
+ tya
+ pha
+ .else
+ phx
+ phy
+ .endif
+
+
+.DATA
+
+ Switch to the DATA segment. The name of the DATA segment is always
+ "DATA", so this is a shortcut for
+
+ .segment "DATA"
+
+ See also the .SEGMENT command.
+
+
+.DBYT
+
+ Define word sized data with the hi and lo bytes swapped (use .WORD to
+ create word sized data in native 65XX format). Must be followed by a
+ sequence of (word ranged) expressions.
+
+ Example:
+
+ .dbyt $1234, $4512
+
+ This will emit the bytes
+
+ $12 $34 $45 $12
+
+ into the current segment in that order.
+
+
+.DEBUGINFO
+
+ Switch on or off debug info generation. The default is off (that is,
+ the object file will not contain debug infos), but may be changed by the
+ -g switch on the command line.
+ The command must be followed by a '+' or '-' character to switch the
+ option on or off respectively.
+
+ Example:
+
+ .debuginfo + ; Generate debug info
+
+
+.DEFINE
+
+ Start a define style macro definition. The command is followed by an
+ identifier (the macro name) and optionally by a list of formal arguments
+ in braces.
+ See separate section about macros.
+
+
+.DEF
+.DEFINED
+
+ Builtin function. The function expects an identifier as argument in
+ braces. The argument is evaluated, and the function yields "true" if the
+ identifier is a symbol that is already defined somewhere in the source
+ file up to the current position. Otherwise the function yields false. As
+ an example, the .IFDEF statement may be replaced by
+
+ .if .defined(a)
+
+
+.DWORD
+
+ Define dword sized data (4 bytes) Must be followed by a sequence of
+ expressions.
+
+ Example:
+
+ .dword $12344512, $12FA489
+
+
+.ELSE
+
+ Conditional assembly: Reverse the current condition.
+
+
+.ELSEIF
+
+ Conditional assembly: Reverse current condition and test a new one.
+
+
+.END
+
+ Forced end of assembly. Assembly stops at this point, even if the command
+ is read from an include file.
+
+
+.ENDIF
+
+ Conditional assembly: Close a .IF... or .ELSE branch.
+
+
+.ENDMAC
+.ENDMACRO
+
+ End of macro definition (see separate section).
+
+
+.ENDPROC
+
+ End of local lexical level (see .PROC).
+
+
+.ERROR
+
+ Force an assembly error. The assembler will output an error message
+ preceeded by "User error" and will *not* produce an object file.
+
+ This command may be used to check for initial conditions that must be
+ set before assembling a source file.
+
+ Example:
+
+ .if foo = 1
+ ...
+ .elseif bar = 1
+ ...
+ .else
+ .error "Must define foo or bar!"
+ .endif
+
+
+.EXITMAC
+.EXITMACRO
+
+ Abort a macro expansion immidiately. This command is often useful in
+ recursive macros. See separate chapter about macros.
+
+
+.EXPORT
+
+ Make symbols accessible from other modules. Must be followed by a comma
+ separated list of symbols to export.
+
+ Example:
+
+ .export foo, bar
+
+
+.EXPORTZP
+
+ Make symbols accessible from other modules. Must be followed by a comma
+ separated list of symbols to export. The exported symbols are explicitly
+ marked as zero page symols.
+
+ Example:
+
+ .exportzp foo, bar
+
+
+.FARADDR
+
+ Define far (24 bit) address data. The command must be followed by a
+ sequence of (not necessarily constant) expressions.
+
+ Example:
+
+ .faraddr DrawCircle, DrawRectangle, DrawHexagon
+
+
+.FEATURE
+
+ This directive may be used to enable one or more compatibility features
+ of the assembler. While the use of .FEATURE should be avoided when
+ possible, it may be useful when porting sources written for other
+ assemblers. There is no way to switch a feature off, once you have
+ enabled it, so using
+
+ .FEATURE xxx
+
+ will enable the feature until end of assembly is reached.
+
+ The following features are available:
+
+ dollar_is_pc
+
+ The dollar sign may be used as an alias for the star (`*'), which
+ gives the value of the current PC in expressions.
+ Note: Assignment to the pseudo variable is not allowed.
+
+ labels_without_colons
+
+ Allow labels without a trailing colon. These labels are only accepted,
+ if they start at the beginning of a line (no leading white space).
+
+ loose_string_term
+
+ Accept single quotes as well as double quotes as terminators for string
+ constants.
+
+ at_in_identifiers
+
+ Accept the at character (`@') as a valid character in identifiers. The
+ at character is not allowed to start an identifier, even with this
+ feature enabled.
+
+ dollar_in_identifiers
+
+ Accept the dollar sign (`$') as a valid character in identifiers. The
+ at character is not allowed to start an identifier, even with this
+ feature enabled.
+
+
+.FILEOPT
+.FOPT
+
+ Insert an option string into the object file. There are two forms of
+ this command, one specifies the option by a keyword, the second
+ specifies it as a number. Since usage of the second one needs knowledge
+ of the internal encoding, its use is not recommended and I will only
+ describe the first form here.
+
+ The command is followed by one of the keywords
+
+ author
+ comment
+ compiler
+
+ a comma and a string. The option is written into the object file
+ together with the string value. This is currently unidirectional and
+ there is no way to actually use these options once they are in the
+ object file.
+
+ Examples:
+
+ .fileopt comment, "Code stolen from my brother"
+ .fileopt compiler, "BASIC 2.0"
+ .fopt author, "J. R. User"
+
+
+.GLOBAL
+
+ Declare symbols as global. Must be followed by a comma separated list
+ of symbols to declare. Symbols from the list, that are defined somewhere
+ in the source, are exported, all others are imported. An additional
+ explicit .IMPORT or .EXPORT command for the same symbol is allowed.
+
+ Example:
+
+ .global foo, bar
+
+
+.GLOBALZP
+
+ Declare symbols as global. Must be followed by a comma separated list
+ of symbols to declare. Symbols from the list, that are defined
+ somewhere in the source, are exported, all others are imported. An
+ additional explicit .IMPORT or .EXPORT command for the same symbol is
+ explicitly allowed. The symbols in the list are explicitly marked as
+ zero page symols.
+
+ Example:
+
+ .globalzp foo, bar
+
+
+.I16
+
+ Valid only in 65816 mode. Switch the index registers to 16 bit.
+
+ Note: This command will not emit any code, it will tell the assembler to
+ create 16 bit operands for immediate operands.
+
+ See also:
+
+ .SMART
+
+
+.I8
+
+ Valid only in 65816 mode. Switch the index registers to 8 bit.
+
+ Note: This command will not emit any code, it will tell the assembler to
+ create 8 bit operands for immediate operands.
+
+ See also:
+
+ .SMART
+
+
+.IF
+
+ Conditional assembly: Evalute an expression and switch assembler output
+ on or off depending on the expression. The expression must be a constant
+ expression, that is, all operands must be defined.
+
+ A expression value of zero evaluates to FALSE, any other value evaluates
+ to TRUE.
+
+
+.IFBLANK
+
+ Conditional assembly: Check if there are any remaining tokens in this
+ line, and evaluate to FALSE if this is the case, and to TRUE otherwise.
+ If the condition is not true, further lines are not assembled until
+ an .ELSE, .ELSEIF or .ENDIF directive.
+
+ This command is often used to check if a macro parameter was given.
+ Since an empty macro parameter will evaluate to nothing, the condition
+ will evaluate to FALSE if an empty parameter was given.
+
+ Example:
+
+ .macro arg1, arg2
+ .ifblank arg2
+ lda #arg1
+ .else
+ lda #arg2
+ .endif
+ .endmacro
+
+ See also:
+
+ .BLANK
+
+
+.IFCONST
+
+ Conditional assembly: Evaluate an expression and switch assembler output
+ on or off depending on the constness of the expression.
+
+ A const expression evaluates to to TRUE, a non const expression (one
+ containing an imported or currently undefined symbol) evaluates to
+ FALSE.
+
+ See also:
+
+ .CONST
+
+
+.IFDEF
+
+ Conditional assembly: Check if a symbol is defined. Must be followed by
+ a symbol name. The condition is true if the the given symbol is already
+ defined, and false otherwise.
+
+ See also:
+
+ .DEFINED
+
+
+.IFNBLANK
+
+ Conditional assembly: Check if there are any remaining tokens in this
+ line, and evaluate to TRUE if this is the case, and to FALSE otherwise.
+ If the condition is not true, further lines are not assembled until
+ an .ELSE, .ELSEIF or .ENDIF directive.
+
+ This command is often used to check if a macro parameter was given.
+ Since an empty macro parameter will evaluate to nothing, the condition
+ will evaluate to FALSE if an empty parameter was given.
+
+ Example:
+
+ .macro arg1, arg2
+ lda #arg1
+ .ifnblank arg2
+ lda #arg2
+ .endif
+ .endmacro
+
+ See also:
+
+ .BLANK
+
+
+.IFNDEF
+
+ Conditional assembly: Check if a symbol is defined. Must be followed by
+ a symbol name. The condition is true if the the given symbol is not
+ defined, and false otherwise.
+
+ See also:
+
+ .DEFINED
+
+
+.IFNREF
+
+ Conditional assembly: Check if a symbol is referenced. Must be followed
+ by a symbol name. The condition is true if if the the given symbol was
+ not referenced before, and false otherwise.
+
+ See also:
+
+ .REFERENCED
+
+
+.IFP02
+
+ Conditional assembly: Check if the assembler is currently in 6502 mode
+ (see .P02 command).
+
+
+.IFP816
+
+ Conditional assembly: Check if the assembler is currently in 65816 mode
+ (see .P816 command).
+
+
+.IFPC02
+
+ Conditional assembly: Check if the assembler is currently in 65C02 mode
+ (see .PC02 command).
+
+
+.IFREF
+
+ Conditional assembly: Check if a symbol is referenced. Must be followed
+ by a symbol name. The condition is true if if the the given symbol was
+ referenced before, and false otherwise.
+
+ This command may be used to build subroutine libraries in include files
+ (you may use separate object modules for this purpose too).
+
+ Example:
+
+ .ifdef ToHex ; If someone used this subroutine
+ ToHex: tay ; Define subroutine
+ lda HexTab,y
+ rts
+ .endif
+
+ See also:
+
+ .REFERENCED
+
+
+.IMPORT
+
+ Import a symbol from another module. The command is followed by a comma
+ separated list of symbols to import.
+
+ Example:
+
+ .import foo, bar
+
+
+.IMPORTZP
+
+ Import a symbol from another module. The command is followed by a comma
+ separated list of symbols to import. The symbols are explicitly imported
+ as zero page symbols (that is, symbols with values in byte range).
+
+ Example:
+
+ .includezp foo, bar
+
+
+.INCBIN
+
+ Include a file as binary data. The command expects a string argument
+ that is the name of a file to include literally in the current segment.
+
+ Example:
+
+ .incbin "sprites.dat"
+
+
+.INCLUDE
+
+ Include another file. Include files may be nested up to a depth of 16.
+
+ Example:
+
+ .include "subs.inc"
+
+
+.LINECONT
+
+ Switch on or off line continuations using the backslash character
+ before a newline. The option is off by default.
+ Note: Line continuations do not work in a comment. A backslash at the
+ end of a comment is treated as part of the comment and does not trigger
+ line continuation.
+ The command must be followed by a '+' or '-' character to switch the
+ option on or off respectively.
+
+ Example:
+
+ .linecont + ; Allow line continuations
+
+ lda \
+ #$20 ; This is legal now
+
+
+.LIST
+
+ Enable output to the listing. The command must be followed by a boolean
+ switch ("on", "off", "+" or "-") and will enable or disable listing
+ output.
+ The option has no effect if the listing is not enabled by the command line
+ switch -l. If -l is used, an internal counter is set to 1. Lines are output
+ to the listing file, if the counter is greater than zero, and suppressed if
+ the counter is zero. Each use of .LIST will increment or decrement the
+ counter.
+
+ Example:
+
+ .list on ; Enable listing output
+
+
+.LISTBYTES
+
+ Set, how many bytes are shown in the listing for one source line. The
+ default is 12, so the listing will show only the first 12 bytes for any
+ source line that generates more than 12 bytes of code or data.
+ The directive needs an argument, which is either "unlimited", or an
+ integer constant in the range 4..255.
+
+ Examples:
+
+ .listbytes unlimited ; List all bytes
+ .listbytes 12 ; List the first 12 bytes
+ .incbin "data.bin" ; Include large binary file
+
+
+.LOCAL
+
+ This command may only be used inside a macro definition. It declares a
+ list of identifiers as local to the macro expansion.
+
+ A problem when using macros are labels: Since they don't change their
+ name, you get a "duplicate symbol" error if the macro is expanded the
+ second time. Labels declared with .LOCAL have their name mapped to an
+ internal unique name (___ABCD__) with each macro invocation.
+
+ Some other assemblers start a new lexical block inside a macro
+ expansion. This has some drawbacks however, since that will not allow
+ *any* symbol to be visible outside a macro, a feature that is sometimes
+ useful. The .LOCAL command is in my eyes a better way to address the
+ problem.
+
+ You get an error when using .LOCAL outside a macro.
+
+
+.LOCALCHAR
+
+ Defines the character that start "cheap" local labels. You may use one
+ of '@' and '?' as start character. The default is '@'.
+
+ Cheap local labels are labels that are visible only between two non
+ cheap labels. This way you can reuse identifiers like "loop" without
+ using explicit lexical nesting.
+
+ Example:
+
+ .localchar '?'
+
+ Clear: lda #$00 ; Global label
+ ?Loop: sta Mem,y ; Local label
+ dey
+ bne ?Loop ; Ok
+ rts
+ Sub: ... ; New global label
+ bne ?Loop ; ERROR: Unknown identifier!
+
+
+.MACPACK
+
+ Insert a predefined macro package. The command is followed by an
+ identifier specifying the macro package to insert. Available macro
+ packages are:
+
+ generic Defines generic macros like add and sub.
+ longbranch Defines conditional long jump macros.
+
+ Including a macro package twice, or including a macro package that
+ redefines already existing macros will lead to an error.
+
+ Example:
+
+ .macpack longbranch ; Include macro package
+
+ cmp #$20 ; Set condition codes
+ jne Label ; Jump long on condition
+
+ See separate section about macros packages.
+
+
+.MAC
+.MACRO
+
+ Start a classic macro definition. The command is followed by an identifier
+ (the macro name) and optionally by a comma separated list of identifiers
+ that are macro parameters.
+ See separate section about macros.
+
+
+.MATCH
+
+ Builtin function. Matches two token lists against each other. This is
+ most useful within macros, since macros are not stored as strings, but
+ as lists of tokens.
+
+ The syntax is
+
+ .MATCH(<token list #1>, <token list #2>)
+
+ Both token list may contain arbitrary tokens with the exception of the
+ terminator token (comma resp. right parenthesis) and
+
+ * end-of-line
+ * end-of-file
+
+ Often a macro parameter is used for any of the token lists.
+
+ Please note that the function does only compare tokens, not token
+ attributes. So any number is equal to any other number, regardless of
+ the actual value. The same is true for strings.
+
+ Example:
+
+ Assume the macro ASR , that will shift right the accumulator by one,
+ while honoring the sign bit. The builtin processor instructions will
+ allow an optional "A" for accu addressing for instructions like ROL
+ and ROR. We will use the .MATCH function to check for this and print
+ and error for invalid calls.
+
+ .macro asr arg
+
+ .if (.not .blank(arg)) .and (.not .match (arg, a))
+ .error "Syntax error"
+ .endif
+
+ cmp #$80 ; Bit 7 into carry
+ lsr a ; Shit carry into bit 7
+
+ .endmacro
+
+ The macro will only accept no arguments, or one argument that must
+ be the reserved keyword "A".
+
+
+.ORG
+
+ Start a section of absolute code. The command is followed by a constant
+ expression that gives the new PC counter location for which the code is
+ assembled. Use .RELOC to switch back to relocatable code.
+
+ You may not switch segments while inside a section of absolute code.
+
+ Example:
+
+ .org $7FF ; Emit code starting at $7FF
+
+
+.OUT
+
+ Output a string to the console without producing an error. This command
+ is similiar to .ERROR, however, it does not force an assembler error
+ that prevents the creation of an object file.
+
+ Example:
+
+ .out "This code was written by the codebuster(tm)"
+
+
+.P02
+
+ Enable the 6502 instruction set, disable 65C02 and 65816 instructions.
+ This is the default if not overridden by the --cpu command line option.
+
+
+.P816
+
+ Enable the 65816 instruction set. This is a superset of the 65C02 and
+ 6502 instruction sets.
+
+
+.PAGELEN
+.PAGELENGTH
+
+ Set the page length for the listing. Must be followed by an integer
+ constant. The value may be "unlimited", or in the range 32 to 127. The
+ statement has no effect if no listing is generated. The default value
+ is -1 but may be overridden by the --pagelength command line option.
+ Beware: Since the listing is generated after assembly is complete, you
+ cannot use multiple line lengths with one source. Instead, the value
+ set with the last .PAGELENGTH is used.
+
+ Examples:
+
+ .pagelength 66 ; Use 66 lines per listing page
+
+ .pagelength unlimited ; Unlimited page length
+
+
+.PARAMCOUNT
+
+ This builtin pseudo variable is only available in macros. It is replaced
+ by the actual number of parameters that were given in the macro
+ invocation.
+
+ Example:
+
+ .macro foo arg1, arg2, arg3
+ .if .paramcount <> 3
+ .error "Too few parameters for macro foo"
+ .endif
+ ...
+ .endmacro
+
+
+.PC02
+
+ Enable the 65C02 instructions set. This instruction set includes all
+ 6502 instructions.
+
+
+.PROC
+
+ Start a nested lexical level. All new symbols from now on are in the
+ local lexical level and are not accessible from outside. Symbols defined
+ outside this local level may be accessed as long as their names are not
+ used for new symbols inside the level. Symbols names in other lexical
+ levels do not clash, so you may use the same names for identifiers. The
+ lexical level ends when the .ENDPROC command is read. Lexical levels may
+ be nested up to a depth of 16.
+
+ The command may be followed by an identifier, in this case the
+ identifier is declared in the outer level as a label having the value of
+ the program counter at the start of the lexical level.
+
+ Note: Macro names are always in the global level and in a separate name
+ space. There is no special reason for this, it's just that I've never
+ had any need for local macro definitions.
+
+ Example:
+
+ .proc Clear ; Define Clear subroutine, start new level
+ lda #$00
+ L1: sta Mem,y ; L1 is local and does not cause a
+ ; duplicate symbol error if used in other
+ ; places
+ dey
+ bne L1 ; Reference local symbol
+ rts
+ .endproc ; Leave lexical level
+
+
+.REF
+.REFERENCED
+
+ Builtin function. The function expects an identifier as argument in
+ braces. The argument is evaluated, and the function yields "true" if the
+ identifier is a symbol that has already been referenced somewhere in the
+ source file up to the current position. Otherwise the function yields
+ false. As an example, the .IFREF statement may be replaced by
+
+ .if .referenced(a)
+
+
+.RELOC
+
+ Switch back to relocatable mode. See the .ORG command.
+
+
+.RES
+
+ Reserve storage. The command is followed by one or two constant
+ expressions. The first one is mandatory and defines, how many bytes of
+ storage should be defined. The second, optional expression must by a
+ constant byte value that will be used as value of the data. If there
+ is no fill value given, the linker will use the value defined in the
+ linker configuration file (default: zero).
+
+ Example:
+
+ ; Reserve 12 bytes of memory with value $AA
+ .res 12, $AA
+
+
+.RODATA
+
+ Switch to the RODATA segment. The name of the RODATA segment is always
+ "RODATA", so this is a shortcut for
+
+ .segment "RODATA"
+
+ The RODATA segment is a segment that is used by the compiler for
+ readonly data like string constants. See also the .SEGMENT command.
+
+
+.SEGMENT
+
+ Switch to another segment. Code and data is always emitted into a
+ segment, that is, a named section of data. The default segment is
+ "CODE". There may be up to 254 different segments per object file
+ (and up to 65534 per executable). There are shortcut commands for
+ the most common segments ("CODE", "DATA" and "BSS").
+
+ The command is followed by a string containing the segment name (there
+ are some constraints for the name - as a rule of thumb use only those
+ segment names that would also be valid identifiers). There may also be
+ an optional attribute separated by a comma. Valid attributes are
+
+ zeropage
+ and absolute
+
+ When specifying a segment for the first time, "absolute" is the
+ default. For all other uses, the attribute specified the first time
+ is the default.
+
+ "absolute" means that this is a segment with absolute addressing. That
+ is, the segment will reside somewhere in core memory outside the zero
+ page. "zeropage" means the opposite: The segment will be placed in the
+ zero page and direct (short) addressing is possible for data in this
+ segment.
+
+ Beware: Only labels in a segment with the zeropage attribute are marked
+ as reachable by short addressing. The `*' (PC counter) operator will
+ work as in other segments and will create absolute variable values.
+
+ Example:
+
+ .segment "ROM2" ; Switch to ROM2 segment
+ .segment "ZP2", zeropage ; New direct segment
+ .segment "ZP2" ; Ok, will use last attribute
+ .segment "ZP2", absolute ; Error, redecl mismatch
+
+
+.SMART
+
+ Switch on or off smart mode. The command must be followed by a '+' or
+ '-' character to switch the option on or off respectively. The default
+ is off (that is, the assembler doesn't try to be smart), but this
+ default may be changed by the -s switch on the command line.
+
+ In smart mode the assembler will track usage of the REP and SEP
+ instructions in 65816 mode and update the operand sizes accordingly. If
+ the operand of such an instruction cannot be evaluated by the assembler
+ (for example, because the operand is an imported symbol), a warning is
+ issued. Beware: Since the assembler cannot trace the execution flow this
+ may lead to false results in some cases. If in doubt, use the .ixx and
+ .axx instructions to tell the assembler about the current settings.
+
+ Example:
+
+ .smart ; Be smart
+ .smart - ; Stop being smart
+
+
+.STRING
+
+ Builtin function. The function accepts an argument in braces and
+ converts this argument into a string constant. The argument may be an
+ identifier, or a constant numeric value.
+ Since you can use a string in the first place, the use of the function
+ may not be obvious. However, it is useful in macros, or more complex
+ setups.
+
+ Example:
+
+ ; Emulate other assemblers:
+ .macro section name
+ .segment .string(name)
+ .endmacro
+
+
+.WORD
+
+ Define word sized data. Must be followed by a sequence of (word ranged,
+ but not necessarily constant) expressions.
+
+ Example:
+
+ .word $0D00, $AF13, _Clear
+
+
+.ZEROPAGE
+
+ Switch to the ZEROPAGE segment and mark it as direct (zeropage) segment.
+ The name of the ZEROPAGE segment is always "ZEROPAGE", so this is a
+ shortcut for
+
+ .segment "ZEROPAGE", zeropage
+
+ Because of the "zeropage" attribute, labels declared in this segment are
+ addressed using direct addressing mode if possible. You MUST instruct
+ the linker to place this segment somewhere in the address range 0..$FF
+ otherwise you will get errors.
+
+
+
+7. Macros
+---------
+
+Macros may be thought of as "parametrized super instructions". Macros are
+sequences of tokens that have a name. If that name is used in the source
+file, the macro is "expanded", that is, it is replaced by the tokens that
+were specified when the macro was defined.
+
+In it's simplest form, a macro does not have parameters. Here's an
+example:
+
+ .macro asr ; Arithmetic shift right
+ cmp #$80 ; Put bit 7 into carry
+ ror ; Rotate right with carry
+ .endmacro
+
+The macro above consists of two real instructions, that are inserted into
+the code, whenever the macro is expanded. Macro expansion is simply done
+by using the name, like this:
+
+ lda $2010
+ asr
+ sta $2010
+
+
+When using macro parameters, macros can be even more useful:
+
+ .macro inc16 addr
+ clc
+ lda addr
+ adc #$01
+ sta addr
+ lda addr+1
+ adc #$00
+ sta addr+1
+ .endmacro
+
+When calling the macro, you may give a parameter, and each occurence of
+the name "addr" in the macro definition will be replaced by the given
+parameter. So
+
+ inc16 $1000
+
+will be expanded to
+
+ clc
+ lda $1000
+ adc #$01
+ sta $1000
+ lda $1000+1
+ adc #$00
+ sta $1000+1
+
+A macro may have more than one parameter, in this case, the parameters
+are separated by commas. You are free to give less parameters than the
+macro actually takes in the definition. You may also leave intermediate
+parameters empty. Empty parameters are replaced by empty space (that is,
+they are removed when the macro is exanded). If you have a look at our
+macro definition above, you will see, that replacing the "addr" parameter
+by nothing will lead to wrong code in most lines. To help you, writing
+macros with a variable parameter list, there are some control commands:
+
+.IFBLANK tests the rest of the line and returns true, if there are any
+tokens on the remainder of the line. Since empty parameters are replaced
+by nothing, this may be used to test if a given parameter is empty.
+.IFNBLANK tests the opposite.
+
+Look at this example:
+
+ .macro ldaxy a, x, y
+ .ifnblank a
+ lda #a
+ .endif
+ .ifnblank x
+ ldx #x
+ .endif
+ .ifnblank y
+ ldy #y
+ .endif
+ .endmacro
+
+This macro may be called as follows:
+
+ ldaxy 1, 2, 3 ; Load all three registers
+
+ ldaxy 1, , 3 ; Load only a and y
+
+ ldaxy , , 3 ; Load y only
+
+There's another helper command for determining, which macro parameters are
+valid: .PARAMCOUNT. This command is replaced by the parameter count given,
+*including* intermediate empty macro parameters:
+
+ ldaxy 1 ; .PARAMCOUNT = 1
+ ldaxy 1,,3 ; .PARAMCOUNT = 3
+ ldaxy 1,2 ; .PARAMCOUNT = 2
+ ldaxy 1, ; .PARAMCOUNT = 2
+ ldaxy 1,2,3 ; .PARAMCOUNT = 3
+
+Macros may be used recursively:
+
+ .macro push r1, r2, r3
+ lda r1
+ pha
+ .if .paramcount > 1
+ push r2, r3
+ .endif
+ .endmacro
+
+There's also a special macro to help writing recursive macros: .EXITMACRO.
+This command will stop macro expansion immidiately:
+
+ .macro push r1, r2, r3, r4, r5, r6, r7
+ .ifblank r1
+ ; First parameter is empty
+ .exitmacro
+ .else
+ lda r1
+ pha
+ .endif
+ push r2, r3, r4, r5, r6, r7
+ .endmacro
+
+When expanding this macro, the expansion will push all given parameters
+until an empty one is encountered. The macro may be called like this:
+
+ push $20, $21, $32 ; Push 3 ZP locations
+ push $21 ; Push one ZP location
+
+Now, with recursive macros, .IFBLANK and .PARAMCOUNT, what else do you need?
+Have a look at the inc16 macro above. Here is it again:
+
+ .macro inc16 addr
+ clc
+ lda addr
+ adc #$01
+ sta addr
+ lda addr+1
+ adc #$00
+ sta addr+1
+ .endmacro
+
+If you have a closer look at the code, you will notice, that it could be
+written more efficiently, like this:
+
+ .macro inc16 addr
+ clc
+ lda addr
+ adc #$01
+ sta addr
+ bcc Skip
+ inc addr+1
+ Skip:
+ .endmacro
+
+But imagine what happens, if you use this macro twice? Since the label
+"Skip" has the same name both times, you get a "duplicate symbol" error.
+Without a way to circumvent this problem, macros are not as useful, as
+they could be. One solution is, to start a new lexical block inside the
+macro:
+
+ .macro inc16 addr
+ .proc
+ clc
+ lda addr
+ adc #$01
+ sta addr
+ bcc Skip
+ inc addr+1
+ Skip:
+ .endproc
+ .endmacro
+
+Now the label is local to the block and not visible outside. However,
+sometimes you want a label inside the macro to be visible outside. To make
+that possible, there's a new command that's only usable inside a macro
+definition: .LOCAL. .LOCAL declares one or more symbols as local to the
+macro expansion. The names of local variables are replaced by a unique
+name in each separate macro expansion. So we could also solve the problem
+above by using .LOCAL:
+
+ .macro inc16 addr
+ .local Skip ; Make Skip a local symbol
+ clc
+ lda addr
+ adc #$01
+ sta addr
+ bcc Skip
+ inc addr+1
+ Skip: ; Not visible outside
+ .endmacro
+
+Starting with version 2.5 of the assembler, there is a second macro type
+available: C style macros using the .DEFINE directive. These macros are
+similar to the classic macro type speified above, but behaviour is
+sometimes different:
+
+ * Macros defined with .DEFINE may not span more than a line. You may
+ use line continuation (.LINECONT) to spread the definition over more
+ than one line for increased readability, but the macro itself does
+ not contain an end-of-line token.
+
+ * Macros defined with .DEFINE share the name space with classic macros,
+ but they are detected and replaced at the scanner level. While classic
+ macros may be used in every place, where a mnemonic or other directive
+ is allowed, .DEFINE style macros are allowed anywhere in a line. So
+ they are more versatile in some situations.
+
+ * .DEFINE style macros may take parameters. While classic macros may
+ have empty parameters, this is not true for .DEFINE style macros. For
+ this macro type, the number of actual parameters must match exactly
+ the number of formal parameters.
+ To make this possible, formal parameters are enclosed in braces when
+ defining the macro. If there are no parameters, the empty braces may
+ be omitted.
+
+ * Since .DEFINE style macros may not contain end-of-line tokens, there
+ are things that cannot be done. They may not contain several processor
+ instructions for example. So, while some things may be done with both
+ macro types, each type has special usages. The types complement each
+ other.
+
+Let's look at a few examples to make the advantages and disadvantages
+clear.
+
+To emulate assemblers that use "EQU" instead of "=" you may use the
+following .DEFINE:
+
+ .define EQU =
+
+ foo EQU $1234 ; This is accepted now
+
+You may use the directive to define string constants use elsewhere:
+
+ ; Define the version number
+ .define VERSION "12.3a"
+
+ ; ... and use it
+ .asciiz VERSION
+
+Macros with parameters may also be useful:
+
+ .define DEBUG(message) .out message
+
+ DEBUG "Assembling include file #3"
+
+Note that, while formal parameters have to be placed in braces, this is
+not true for the actual parameters. Beware: Since the assembler cannot
+detect the end of one parameter, only the first token is used. If you
+don't like that, use classic macros instead:
+
+ .macro message
+ .out message
+ .endmacro
+
+(This is an example where a problem can be solved with both macro types).
+
+
+
+8. Macro packages
+-----------------
+
+Using the .macpack directive, predefined macro packages may be included
+with just one command. Available macro packages are:
+
+ - generic
+
+ This macro package defines macros that are useful in almost any
+ program. Currently, two macros are defined:
+
+ .macro add Arg
+ clc
+ adc Arg
+ .endmacro
+
+ .macro sub Arg
+ sec
+ sbc Arg
+ .endmacro
+
+
+ - longbranch
+
+ This macro package defines long conditional jumps. They are named like
+ the short counterpart but with the 'b' replaced by a 'j'. Here is a
+ sample definition for the "jeq" macro, the other macros are built using
+ the same scheme:
+
+ .macro jeq Target
+ .if .def(Target) .and ((*+2)-(Target) <= 127)
+ beq Target
+ .else
+ bne *+5
+ jmp Target
+ .endif
+ .endmacro
+
+ All macros expand to a short branch, if the label is already defined
+ (back jump) and is reachable with a short jump. Otherwise the macro
+ expands to a conditional branch with the branch condition inverted,
+ followed by an absolute jump to the actual branch target.
+
+ The package defines the following macros:
+
+ jeq, jne, jmi, jpl, jcs, jcc, jvs, jvc
+
+
+
+9. Bugs/Feedback
+----------------
+
+If you have problems using the assembler, if you find any bugs, or if
+you're doing something interesting with the assembler, I would be glad to
+hear from you. Feel free to contact me by email (uz@musoftware.de).
+
+
+
+10. Copyright
+-------------
+
+ca65 (and all cc65 binutils) are (C) Copyright 1998 Ullrich von Bassewitz.
+For usage of the binaries and/or sources the following conditions do
+apply:
+
+This software is provided 'as-is', without any expressed or implied
+warranty. In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not
+ be misrepresented as being the original software.
+3. This notice may not be removed or altered from any source
+ distribution.
+
+
+
+
--- /dev/null
+
+
+ cc65
+
+ A C Compiler for 6502 Systems
+
+ (C) Copyright 1989 John R. Dunning
+ (C) Copyright 1998-2000 Ullrich von Bassewitz
+ (uz@musoftware.de)
+
+
+
+Contents
+--------
+
+ 1. Overview
+
+ 2. Usage
+
+ 3. Input and output
+
+ 4. Differences to the ISO standard
+
+ 5. Extensions
+
+ 6. Predefined macros
+
+ 7. #pragmas
+
+ 8. Bugs/Feedback
+
+ 9. Copyright
+
+
+
+1. Overview
+-----------
+
+cc65 was originally a C compiler for the Atari 8-bit machines written by
+John R. Dunning. In prior releases I've described the compiler by listing
+up the changes made by me. I have made many more changes in the meantime
+(and rewritten major parts of the compiler), so I will no longer do that,
+since the list would be too large and of no use to anyone. Instead I will
+describe the compiler in respect to the ANSI/ISO C standard. In fact, I'm
+planning a complete rewrite (that is, a complete new compiler) for the
+next release, since there are too many limitations in the current code,
+and removing these limitations would mean a rewrite of many more parts of
+the compiler.
+
+There is a separate document named "library.txt" that covers the library
+available for the compiler. If you know C and are interested in doing
+actual programming, the library documentation is probably of much more use
+than this document.
+
+If you need some hints for getting the best code out of the compiler, you
+may have a look at "coding.txt" which covers some code generation issues.
+
+
+
+2. Usage
+--------
+
+The compiler translates C files into files containing assembler code that
+may be translated by the ca65 macroassembler (for more information about
+the assembler, have a look at ca65.txt).
+
+The compiler may be called as follows:
+
+Usage: cc65 [options] file
+ -d Debug mode
+ -g Add debug info to object files
+ -h Print this help
+ -j Default characters are signed
+ -o name Name the output file
+ -s Print some statistics
+ -tx Set target system x
+ -v Verbose mode
+ -A Strict ANSI mode
+ -Cl Make local variables static
+ -Dsym[=defn] Define a symbol
+ -I path Set include directory
+ -O Optimize code
+ -Oi Optimize code, inline more code
+ -Or Enable register variables
+ -Os Inline some known functions
+ -T Include source as comment
+ -V Print version number
+ -W Suppress warnings
+
+The -A option disables any compiler exensions. Have a look at section 5
+for a discussion of compiler extensions. In addition, the macro
+
+ __STRICT_ANSI__
+
+is defined, when compiling with -A.
+
+-d enables debug mode, something that should not be needed for mere
+mortals:-)
+
+-g will cause the compiler to insert a .DEBUGINFO command into the
+generated assembler code. This will cause the assembler to include all
+symbols in a special section in the object file.
+
+-h and -s print some statistics, nothing spectacular.
+
+Using -j you can make the default characters signed. Since the 6502 has
+no provisions for sign extending characters (which is needed on almost
+any load operation), this will make the code larger and slower. A better
+way is to declare characters explicitly as "signed" if needed. You can
+also use "#pragma signedchars" for better control of this option (see
+section 7).
+
+The -t option is used to set the target system. The target system
+determines things like the character set that is used for strings and
+character constants. The following target systems are supported:
+
+ none
+ c64
+ c128
+ ace (no library support)
+ plus4
+ cbm610
+ pet (all CBM PET systems except the 2001)
+ nes (Nintendo Entertainment System)
+ apple2
+ geos
+
+Using -v, the compiler will be somewhat more verbose if errors or warnings
+are encountered.
+
+-Cl will use static storage for local variables instead of storage on the
+stack. Since the stack is emulated in software, this gives shorter and
+usually faster code, but the code is no longer reentrant. The difference
+between -Cl and declaring local variables as static yourself is, that
+initializer code is executed each time, the function is entered. So when
+using
+
+ void f (void)
+ {
+ unsigned a = 1;
+ ...
+ }
+
+the variable a will always have the value 1 when entering the function and
+using -Cl, while in
+
+ void f (void)
+ {
+ static unsigned a = 1;
+ ....
+ }
+
+the variable a will have the value 1 only the first time, the function is
+entered, and will keep the old value from one call of the function to the
+next.
+
+You may also use #pragma staticlocals to change this setting in your
+sources (see section 7).
+
+-I sets the directory where the compiler searches for include files. You
+may use -I multiple times to add more than one directory to the search
+list.
+
+-O will enable an optimizer run over the produced code. Using -Oi, the
+code generator will inline some code where otherwise a runtime functions
+would have been called, even if the generated code is larger. This will
+not only remove the overhead for a function call, but will make the code
+visible for the optimizer.
+
+-Or will make the compiler honor the "register" keyword. Local variables
+may be placed in registers (which are actually zero page locations).
+There is some overhead involved with register variables, since the old
+contents of the registers must be saved and restored. In addition, the
+current implementation does not make good use of register variables, so
+using -Or may make your program even slower and larger. Use with care!
+
+Using -Os will force the compiler to inline some known functions from the
+C library like strlen. Note: This has two consequences:
+
+ * You may not use names of standard C functions in your own code. If
+ you do that, your program is not standard compliant anyway, but
+ using -Os will actually break things.
+
+ * The inlined string and memory functions will not handle strings or
+ memory areas larger than 255 bytes. Similar, the inlined is..()
+ functions will not work with values outside char range.
+
+It is possible to concatenate the modifiers for -O. For example, to
+enable register variables and inlining of known functions, you may use
+-Ors.
+
+-T will include the source code as comments in the generated code. This is
+normally not needed.
+
+-V prints the version number of the compiler. When submitting a bug
+report, please include the operating system you're using, and the compiler
+version.
+
+The -W switch suppresses any warnings generated by the compiler. Since any
+source file may be written in a manner that it will not produce compiler
+warnings, using this option is usually not a good idea.
+
+
+
+3. Input and output
+-------------------
+
+The compiler will accept one C file per invocation and create a file with
+the same base name, but with the extension replaced by ".s". The output
+file contains assembler code suitable for the use with the ca65 macro
+assembler.
+
+In addition to the paths named in the -I option on the command line, the
+directory named in the environment variable CC65_INC is added to the
+search path for include files on startup.
+
+
+
+4. Differences to the ISO standard
+----------------------------------
+
+Here is a list of differences between the language, the compiler accepts,
+and the one defined by the ISO standard:
+
+
+ * The compiler allows single line comments that start with //. This
+ feature is disabled in strict ANSI mode.
+
+ * The compiler allows unnamed parameters in parameter lists. The
+ compiler will not issue warnings about unused parameters that don't
+ have a name. This feature is disabled in strict ANSI mode.
+
+ * The compiler has some additional keywords:
+
+ asm, __asm__, fastcall, __fastcall__, __AX__, __EAX__, __func__
+
+ The keywords without the underlines are disabled in strict ANSI mode.
+
+ * The "const" modifier is available, but has no effect.
+
+ * The datatypes "float" and "double" are not available.
+
+ * The compiler does not support bit fields.
+
+ * Initialization of local variables is only possible for scalar data
+ types (that is, not for arrays and structs).
+
+ * Because of the "wrong" order of the parameters on the stack, there is
+ an additional macro needed to access parameters in a variable
+ parameter list in a C function.
+
+ * The compiler has only one symbol table. Because of that, it's not
+ possible to use the name of a local variable in a nested block in the
+ same function (global and local names are distinct, however).
+
+ + The preprocessor does not understand the "defined" keyword in
+ expressions evaluated in #if statements.
+
+ * Functions may not return structs, struct assignment is not possible.
+
+ * The size of any struct referenced via a pointer may not exceed 256
+ bytes (this is because the Y register is used as index).
+
+ * In a function, the size of the parameters plus the size of all local
+ variables may not exceed 256 bytes (in fact, the limit may be even less
+ depeding on the complexity of your expressions).
+
+ * Part of the C library is available only with fastcall calling
+ conventions (see below). This means, that you may not mix pointers to
+ those functions with pointers to user written functions.
+
+There may be some more minor differences, I'm currently not aware off. The
+biggest problems are the missing const and float data types. With both
+these things in mind, you should be able to write fairly portable code.
+
+
+
+5. Extensions
+-------------
+
+This cc65 version has some extensions to the ISO C standard.
+
+ * The compiler allows // comments (like in C++ and in the proposed C9x
+ standard). This feature is disabled by -A.
+
+ * The compiler allows to insert assembler statements into the output
+ file. The syntax is
+
+ asm (<string literal>) ;
+
+ or
+
+ __asm__ (<string literal>) ;
+
+ The first form is in the user namespace and is disabled if the -A
+ switch is given.
+
+ The given string is inserted literally into the output file, and a
+ newline is appended. The statements in this string are not checked by
+ the compiler, so be careful!
+
+ The asm statement may be used inside a function and on global file
+ level.
+
+ * There is a special calling convention named "fastcall". This calling
+ convention is currently only usable for functions written in
+ assembler. The syntax for a function declaration using fastcall is
+
+ <return type> fastcall <function name> (<parameter list>)
+
+ or
+
+ <return type> __fastcall__ <function name> (<parameter list>)
+
+ An example would be
+
+ void __fastcall__ f (unsigned char c)
+
+ The first form of the fastcall keyword is in the user namespace and is
+ therefore disabled in strict ANSI mode.
+
+ For functions declared as fastcall, the rightmost parameter is not
+ pushed on the stack but left in the primary register when the function
+ is called. This will reduce the cost when calling assembler functions
+ significantly, especially when the function itself is rather small.
+
+ BEWARE: You must not declare C functions as fastcall! This will not
+ work for now and is not checked by the assembler, so you will get
+ wrong code.
+
+ * There are two pseudo variables named __AX__ and __EAX__. Both refer to
+ the primary register that is used by the compiler to evaluate
+ expressions or return function results. __AX__ is of type unsigned int
+ and __EAX__ of type long unsigned int respectively. The pseudo
+ variables may be used as lvalue and rvalue as every other variable.
+ They are most useful together with short sequences of assembler code.
+ For example, the macro
+
+ #define hi(x) (__AX__=(x),asm("\ttxa\n\tldx\t#$00",__AX__)
+
+ will give the high byte of any unsigned value.
+
+ * Inside a function, the identifier __func__ gives the name of the
+ current function as a string. Outside of functions, __func__ is
+ undefined.
+ Example:
+
+ #define PRINT_DEBUG(s) printf ("%s: %s\n", __func__, s);
+
+ The macro will print the name of the current function plus a given
+ string.
+
+
+
+6. Predefined macros
+--------------------
+
+The compiler defines several macros at startup:
+
+
+ __CC65__ This macro is always defined. Its value is the version
+ number of the compiler in hex. Version 2.0.1 of the
+ compiler will have this macro defined as 0x0201.
+
+ __CBM__ This macro is defined if the target system is one of the
+ CBM targets.
+
+ __C64__ This macro is defined if the target is the c64 (-t c64).
+
+ __C128__ This macro is defined if the target is the c128 (-t c128).
+
+ __PLUS4__ This macro is defined if the target is the plus/4
+ (-t plus4).
+
+ __CBM610__ This macro is defined if the target is one of the CBM
+ 600/700 family of computers (called B series in the US).
+
+ __PET__ This macro is defined if the target is the PET family of
+ computers (-t pet).
+
+ __NES__ This macro is defined if the target is the Nintendo
+ Entertainment System (-t nes).
+
+ __ATARI__ This macro is defined if the target is one of the Atari
+ computers (400/800/130XL/800XL). Note that there is no
+ runtime and C library support for atari systems.
+
+ __ACE__ This macro is defined if the target is Bruce Craigs ACE
+ operating system. Note that there is no longer runtime
+ and library support for ACE.
+
+ __APPLE2__ This macro is defined if the target is the Apple ][
+ (-t apple2).
+
+ __GEOS__ This macro is defined if you are compiling for the GEOS
+ system (-t geos).
+
+ __FILE__ This macro expands to a string containing the name of
+ the C source file.
+
+ __LINE__ This macro expands to the current line number.
+
+ __STRICT_ANSI__ This macro is defined to 1 if the -A compiler option was
+ given, and undefined otherwise.
+
+ __OPT__ Is defined if the compiler was called with the -O command
+ line option.
+
+ __OPT_i__ Is defined if the compiler was called with the -Oi command
+ line option.
+
+ __OPT_r__ Is defined if the compiler was called with the -Or command
+ line option.
+
+ __OPT_s__ Is defined if the compiler was called with the -Os command
+ line option.
+
+
+
+7. #pragmas
+-----------
+
+The compiler understands some pragmas that may be used to change code
+generation and other stuff.
+
+
+#pragma bssseg (<name>)
+
+ This pragma changes the name used for the BSS segment (the BSS segment
+ is used to store uninitialized data). The argument is a string enclosed
+ in double quotes.
+
+ Note: The default linker configuration file does only map the standard
+ segments. If you use other segments, you have to create a new linker
+ configuration file.
+
+ Beware: The startup code will zero only the default BSS segment. If you
+ use another BSS segment, you have to do that yourself, otherwise
+ uninitialized variables do not have the value zero.
+
+ Example:
+
+ #pragma bssseg ("MyBSS")
+
+
+#pragma codeseg (<name>)
+
+ This pragma changes the name used for the CODE segment (the CODE segment
+ is used to store executable code). The argument is a string enclosed in
+ double quotes.
+
+ Note: The default linker configuration file does only map the standard
+ segments. If you use other segments, you have to create a new linker
+ configuration file.
+
+ Example:
+
+ #pragma bssseg ("MyCODE")
+
+
+#pragma dataseg (<name>)
+
+ This pragma changes the name used for the DATA segment (the DATA segment
+ is used to store initialized data). The argument is a string enclosed in
+ double quotes.
+
+ Note: The default linker configuration file does only map the standard
+ segments. If you use other segments, you have to create a new linker
+ configuration file.
+
+ Example:
+
+ #pragma bssseg ("MyDATA")
+
+
+#pragma rodataseg (<name>)
+
+ This pragma changes the name used for the RODATA segment (the RODATA
+ segment is used to store readonly data). The argument is a string
+ enclosed in double quotes.
+
+ Note: The default linker configuration file does only map the standard
+ segments. If you use other segments, you have to create a new linker
+ configuration file.
+
+ Example:
+
+ #pragma bssseg ("MyRODATA")
+
+
+#pragma regvaraddr (<const int>)
+
+ The compiler does not allow to take the address of register variables.
+ The regvaraddr pragma changes this. Taking the address of a register
+ variable is allowed after using this pragma, if the argument is not
+ zero. Using an argument of zero changes back to the default behaviour.
+
+ Beware: The C standard does not allow taking the address of a variable
+ declared as register. So your programs become non-portable if you use
+ this pragma. In addition, your program may not work. This is usually the
+ case if a subroutine is called with the address of a register variable,
+ and this subroutine (or a subroutine called from there) uses itself
+ register variables. So be careful with this #pragma.
+
+ Example:
+
+ #pragma regvaraddr(1) /* Allow taking the address
+ * of register variables
+ */
+
+
+#pragma signedchars (<const int>)
+
+ Changed the signedness of the default character type. If the argument
+ is not zero, default characters are signed, otherwise characters are
+ unsigned. The compiler default is to make characters unsigned since this
+ creates a lot better code.
+
+
+#pragma staticlocals (<const int>)
+
+ Use variables in the bss segment instead of variables on the stack. This
+ pragma changes the default set by the compiler option -Cl. If the argument
+ is not zero, local variables are allocated in the BSS segment, leading to
+ shorter and in most cases faster, but non-reentrant code.
+
+
+#pragma zpsym (<name>)
+
+ Tell the compiler that the - previously as external declared - symbol with
+ the given name is a zero page symbol (usually from an assembler file).
+ The compiler will create a matching import declaration for the assembler.
+
+ Example:
+
+ extern int foo;
+ #pragma zpsym ("foo"); /* foo is in the zeropage */
+
+
+
+8. Bugs/Feedback
+----------------
+
+If you have problems using the compiler, if you find any bugs, or if
+you're doing something interesting with the compiler, I would be glad to
+hear from you. Feel free to contact me by email (uz@musoftware.de).
+
+
+
+9. Copyright
+------------
+
+This is the original compiler copyright:
+
+--------------------------------------------------------------------------
+ -*- Mode: Text -*-
+
+ This is the copyright notice for RA65, LINK65, LIBR65, and other
+ Atari 8-bit programs. Said programs are Copyright 1989, by John R.
+ Dunning. All rights reserved, with the following exceptions:
+
+ Anyone may copy or redistribute these programs, provided that:
+
+ 1: You don't charge anything for the copy. It is permissable to
+ charge a nominal fee for media, etc.
+
+ 2: All source code and documentation for the programs is made
+ available as part of the distribution.
+
+ 3: This copyright notice is preserved verbatim, and included in
+ the distribution.
+
+ You are allowed to modify these programs, and redistribute the
+ modified versions, provided that the modifications are clearly noted.
+
+ There is NO WARRANTY with this software, it comes as is, and is
+ distributed in the hope that it may be useful.
+
+ This copyright notice applies to any program which contains
+ this text, or the refers to this file.
+
+ This copyright notice is based on the one published by the Free
+ Software Foundation, sometimes known as the GNU project. The idea
+ is the same as theirs, ie the software is free, and is intended to
+ stay that way. Everybody has the right to copy, modify, and re-
+ distribute this software. Nobody has the right to prevent anyone
+ else from copying, modifying or redistributing it.
+
+--------------------------------------------------------------------------
+
+In acknowledgment of this copyright, I will place my own changes to the
+compiler under the same copyright. Please note however, that the library
+and all binutils are covered by another copyright, and that I'm planning
+to do a complete rewrite of the compiler, after which the compiler
+copyright will also change.
+
+For the list of changes requested by this copyright see newvers.txt.
+
+
+
--- /dev/null
+
+
+ cl65
+
+ Compile and link utility for cc65
+
+ (C) Copyright 1999 Ullrich von Bassewitz
+ (uz@musoftware.de)
+
+
+
+Contents
+--------
+
+ 1. Overview
+
+ 2. Basic Usage
+
+ 3. More usage
+
+ 4. Examples
+
+ 5. Bugs/Feedback
+
+ 6. Copyright
+
+
+
+1. Overview
+-----------
+
+cl65 is a frontend for cc65, ca65 and ld65. While you may not use the full
+power of the tools when calling them through cl65, most features are
+available, and the use of cl65 is much simpler.
+
+
+
+2. Usage
+--------
+
+The cl65 compile and link utility may be used to compile, assemble and
+link files. While the separate tools do just one step, cl65 knows how to
+build object files from C files (by calling the compiler, then the
+assembler) and other things.
+
+ Usage: cl65 [options] file
+ Options:
+ -A Strict ANSI mode
+ -C name Use linker config file
+ -D sym[=defn] Define a preprocessor symbol
+ -I path Set an include directory path
+ -Ln name Create a VICE label file
+ -O Optimize code
+ -Oi Optimize code, inline functions
+ -Or Optimize code, honour the register keyword
+ -Os Optimize code, inline known C funtions
+ -S Compile but don't assemble and link
+ -V Print the version number
+ -W Suppress warnings
+ -c Compiler and assemble but don't link
+ -d Debug mode
+ -g Add debug info
+ -h Help (this text)
+ -m name Create a map file
+ -o name Name the output file
+ -t system Set the target system
+ -v Verbose mode
+ -vm Verbose map file
+
+Most of the options have the same meaning than the corresponding compiler,
+assembler or linker option. If an option is available for more than one
+of the tools, it is set for all tools, where it is available. One example
+for this is -v: The compiler, the assembler and the linker are all called
+with the -v switch.
+
+There are a few remaining options that control the behaviour of cl65:
+
+The -S option forces cl65 to stop after the assembly step. This means that
+C files are translated into assembler files, but nothing more is done.
+Assembler files, object files and libraries given on the command line are
+ignored.
+
+The -c options forces cl65 to stop after the assembly step. This means
+that C and assembler files given on the command line are translated into
+object files, but there is no link step, and object files and libraries
+given on the command line are ignored.
+
+The -o option is used for the target name in the final step. This causes
+problems, if the linker will not be called, and there are several input
+files on the command line. In this case, the name given with -o will be
+used for all of them, which makes the option pretty useless. You shouldn't
+use -o when more than one output file is created.
+
+The default for the -t option is different from the compiler and linker in
+the case that the option is missing: While the compiler and linker will
+use the "none" system settings by default, cl65 will use the C64 as a
+target system by default. This was choosen since most people seem to use
+cc65 to develop for the C64.
+
+
+
+3. More usage
+-------------
+
+Since cl65 was created to simplify the use of the cc65 development
+package, it tries to be smart about several things.
+
+ - If you don't give a target system on the command line, cl65
+ defaults to the C64.
+
+ - When linking, cl65 will supply the names of the startup file and
+ library for the target system to the linker, so you don't have to do
+ that.
+
+ - If the final step is the linker, and the name of the output file was
+ not explicitly given, cl65 will use the name of the first input file
+ without the extension, provided that the name of this file has an
+ extension. So you don't need to name the executable name in most
+ cases, just give the name of your "main" file as first input file.
+
+
+
+4. Examples
+-----------
+
+The morse trainer software, which consists of one C file (morse.c) and one
+assembler file (irq.s) will need the following separate steps to compile
+into an executable named morse:
+
+ cc65 -g -Oi -t c64 morse.c
+ ca65 -g morse.s
+ ca65 -g irq.s
+ ld65 -t c64 -o morse c64.o morse.o irq.o c64.lib
+
+When using cl65, this is simplified to
+
+ cl65 -g -Oi morse.c irq.s
+
+
+As a general rule, you may use cl65 instead of cc65 at most times,
+especially in makefiles to build object files directly from C files. Use
+
+ .c.o:
+ cl65 -g -Oi $<
+
+to do this.
+
+
+
+5. Bugs/Feedback
+----------------
+
+If you have problems using the utility, if you find any bugs, or if you're
+doing something interesting with it, I would be glad to hear from you.
+Feel free to contact me by email (uz@musoftware.de).
+
+
+
+6. Copyright
+------------
+
+cl65 is (C) Copyright 1998 Ullrich von Bassewitz. For usage of the
+binaries and/or sources the following conditions do apply:
+
+This software is provided 'as-is', without any expressed or implied
+warranty. In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not
+ be misrepresented as being the original software.
+3. This notice may not be removed or altered from any source
+ distribution.
+
+
+
--- /dev/null
+
+How to generate the most effective code with cc65.
+
+
+1. Use prototypes.
+
+ This will not only help to find errors between separate modules, it will
+ also generate better code, since the compiler must not assume that a
+ variable sized parameter list is in place and must not pass the argument
+ count to the called function. This will lead to shorter and faster code.
+
+
+
+2. Don't declare auto variables in nested function blocks.
+
+ Variable declarations in nested blocks are usually a good thing. But with
+ cc65, there are several drawbacks:
+
+ a. The compiler has only one symbol table (there's no true nesting).
+ This means that your variables must not have the same names as
+ variables in the enclosing block.
+
+ b. Since the compiler generates code in one pass, it must create the
+ the variables on the stack each time the block is entered and destroy
+ them when the block is left. This causes a speed penalty and larger
+ code.
+
+
+
+3. Remember that the compiler does not optimize.
+
+ The compiler needs hints from you about the code to generate. When
+ accessing indexed data structures, get a pointer to the element and
+ use this pointer instead of calculating the index again and again.
+ If you want to have your loops unrolled, or loop invariant code moved
+ outside the loop, you have to do that yourself.
+
+
+
+4. Longs are slow!
+
+ While long support is necessary for some things, it's really, really slow
+ on the 6502. Remember that any long variable will use 4 bytes of memory,
+ and any operation works on double the data compared to an int.
+
+
+
+5. Use unsigned types wherever possible.
+
+ The CPU has no opcodes to handle signed values greater than 8 bit. So
+ sign extension, test of signedness etc. has to be done by hand. The
+ code to handle signed operations is usually a bit slower than the same
+ code for unsigned types.
+
+
+
+6. Use chars instead of ints if possible.
+
+ While in arithmetic operations, chars are immidiately promoted to ints,
+ they are passed as chars in parameter lists and are accessed as chars
+ in variables. The code generated is usually not much smaller, but it
+ is faster, since accessing chars is faster. For several operations, the
+ generated code may be better if intermediate results that are known not
+ to be larger than 8 bit are casted to chars.
+
+ When doing
+
+ unsigned char a;
+ ...
+ if ((a & 0x0F) == 0)
+
+ the result of the & operator is an int because of the int promotion
+ rules of the language. So the compare is also done with 16 bits. When
+ using
+
+ unsigned char a;
+ ...
+ if ((unsigned char)(a & 0x0F) == 0)
+
+ the generated code is much shorter, since the operation is done with
+ 8 bits instead of 16.
+
+
+
+7. Make the size of your array elements one of 1, 2, 4, 8.
+
+ When indexing into an array, the compiler has to calculate the byte
+ offset into the array, which is the index multiplied by the size of
+ one element. When doing the multiplication, the compiler will do a
+ strength reduction, that is, replace the multiplication by a shift
+ if possible. For the values 2, 4 and 8, there are even more specialized
+ subroutines available. So, array access is fastest when using one of
+ these sizes.
+
+
+
+8. Expressions are evaluated from left to right.
+
+ Since cc65 is not building an explicit expression tree when parsing an
+ expression, constant subexpressions may not be detected and optimized
+ properly if you don't help. Look at this example:
+
+ #define OFFS 4
+ int i;
+ i = i + OFFS + 3;
+
+ The expression is parsed from left to right, that means, the compiler sees
+ 'i', and puts it contents into the secondary register. Next is OFFS, which
+ is constant. The compiler emits code to add a constant to the secondary
+ register. Same thing again for the constant 3. So the code produced
+ contains a fetch of 'i', two additions of constants, and a store (into
+ 'i'). Unfortunately, the compiler does not see, that "OFFS + 3" is a
+ constant for itself, since it does it's evaluation from left to right.
+ There are some ways to help the compiler to recognize expression like
+ this:
+
+ a. Write "i = OFFS + 3 + i;". Since the first and second operand are
+ constant, the compiler will evaluate them at compile time reducing the
+ code to a fetch, one addition (secondary + constant) and one store.
+
+ b. Write "i = i + (OFFS + 3)". When seeing the opening parenthesis, the
+ compiler will start a new expression evaluation for the stuff in the
+ braces, and since all operands in the subexpression are constant, it
+ will detect this and reduce the code to one fetch, one addition and
+ one store.
+
+
+
+9. Case labels in a switch statments are checked in source order.
+
+ Labels that appear first in a switch statement are tested first. So,
+ if your switch statement contains labels that are selected most of
+ the time, put them first in your source code. This will speed up the
+ code.
+
+
+
+10. Use the preincrement and predecrement operators.
+
+ The compiler is currently not smart enough to figure out, if the rvalue of
+ an increment is used or not. So it has to save and restore that value when
+ producing code for the postincrement and postdecrement operators, even if
+ this value is never used. To avoid the additional overhead, use the
+ preincrement and predecrement operators if you don't need the resulting
+ value. That means, use
+
+ ...
+ ++i;
+ ...
+
+ instead of
+
+ ...
+ i++;
+ ...
+
+
+
+11. Use constants to access absolute memory locations.
+
+ The compiler produces optimized code, if the value of a pointer is a
+ constant. So, to access direct memory locations, use
+
+ #define VDC_DATA 0xD601
+ *(char*)VDC_STATUS = 0x01;
+
+ That will be translated to
+
+ lda #$01
+ sta $D600
+
+ The constant value detection works also for struct pointers and arrays,
+ if the subscript is a constant. So
+
+ #define VDC ((unsigned char*)0xD600)
+ #define STATUS 0x01
+ VDC [STATUS] = 0x01;
+
+ will also work.
+
+ If you first load the constant into a variable and use that variable to
+ access an absolute memory location, the generated code will be much
+ slower, since the compiler does not know anything about the contents of
+ the variable.
+
+
+
+12. Use initialized local variables - but use it with care.
+
+ Initialization of local variables when declaring them gives shorter
+ and faster code. So, use
+
+ int i = 1;
+
+ instead of
+
+ int i;
+ i = 1;
+
+ But beware: To maximize your savings, don't mix uninitialized and
+ initialized variables. Create one block of initialized variables and
+ one of uniniitalized ones. The reason for this is, that the compiler
+ will sum up the space needed for uninitialized variables as long as
+ possible, and then allocate the space once for all these variables.
+ If you mix uninitialized and initialized variables, you force the
+ compiler to allocate space for the uninitialized variables each time,
+ it parses an initialized one. So do this:
+
+ int i, j;
+ int a = 3;
+ int b = 0;
+
+ instead of
+
+ int i;
+ int a = 3;
+ int j;
+ int b = 0;
+
+ The latter will work, but will create larger and slower code.
+
+
+
+13. When using the ?: operator, cast values that are not ints.
+
+ The result type of the ?: operator is a long, if one of the second or
+ third operands is a long. If the second operand has been evaluated and
+ it was of type int, and the compiler detects that the third operand is
+ a long, it has to add an additional int->long conversion for the
+ second operand. However, since the code for the second operand has
+ already been emitted, this gives much worse code.
+
+ Look at this:
+
+ long f (long a)
+ {
+ return (a != 0)? 1 : a;
+ }
+
+ When the compiler sees the literal "1", it does not know, that the
+ result type of the ?: operator is a long, so it will emit code to load
+ a integer constant 1. After parsing "a", which is a long, a int->long
+ conversion has to be applied to the second operand. This creates one
+ additional jump, and an additional code for the conversion.
+
+ A better way would have been to write:
+
+ long f (long a)
+ {
+ return (a != 0)? 1L : a;
+ }
+
+ By forcing the literal "1" to be of type long, the correct code is
+ created in the first place, and no additional conversion code is
+ needed.
+
+
+
+14. Use the array operator [] even for pointers.
+
+ When addressing an array via a pointer, don't use the plus and
+ dereference operators, but the array operator. This will generate
+ better code in some common cases.
+
+ Don't use
+
+ char* a;
+ char b, c;
+ char b = *(a + c);
+
+ Use
+
+ char* a;
+ char b, c;
+ char b = a[c];
+
+ instead.
+
+
+
+15. Use register variables with care.
+
+ Register variables may give faster and shorter code, but they do also
+ have an overhead. Register variables are actually zero page
+ locations, so using them saves roughly one cycle per access. Since
+ the old values have to be saved and restored, there is an overhead of
+ about 70 cycles per 2 byte variable. It is easy to see, that - apart
+ from the additional code that is needed to save and restore the
+ values - you need to make heavy use of a variable to justify the
+ overhead.
+
+ An exception are pointers, especially char pointers. The optimizer
+ has code to detect and transform the most common pointer operations
+ if the pointer variable is a register variable. Declaring heavily
+ used character pointers as register may give significant gains in
+ speed and size.
+
+ And remember: Register variables must be enabled with -Or.
+
+
+
+16. Decimal constants greater than 0x7FFF are actually long ints
+
+ The language rules for constant numeric values specify that decimal
+ constants without a type suffix that are not in integer range must be
+ of type long int or unsigned long int. This means that a simple
+ constant like 40000 is of type long int, and may cause an expression
+ to be evaluated with 32 bits.
+
+ An example is:
+
+ unsigned val;
+ ...
+ if (val < 65535) {
+ ...
+ }
+
+ Here, the compare is evaluated using 32 bit precision. This makes the
+ code larger and a lot slower.
+
+ Using
+
+ unsigned val;
+ ...
+ if (val < 0xFFFF) {
+ ...
+ }
+
+ or
+
+ unsigned val;
+ ...
+ if (val < 65535U) {
+ ...
+ }
+
+ instead will give shorter and faster code.
+
+
+
--- /dev/null
+
+
+Instructions for compiling cc65 and the ca65 binutils:
+
+
+Linux (and probably most other Unices)
+--------------------------------------
+
+You need the GNU C compiler. Do a
+
+ make -f make/gcc.mak
+
+twice(!) in each of the directories
+
+ cc65
+ binutils
+
+After that, you need to compile the libraries. Do
+
+ cd lib
+ make clean c64lib
+ make clean c128lib
+ make clean plus4lib
+ make clean cbm610lib
+ make clean petlib
+ make clean apple2lib
+
+Be sure to say "clean" each time, since some of the sources have a
+"#ifdef <target_system>".
+
+
+
+DOS using the DJGPP compiler
+----------------------------
+
+Most information in this section was provided by Keith W. Gerdes
+(kwg@freebird.ghofn.org). Thanks a lot!
+
+The tmpfile() function in DJGPP has a bug and will not open the scratch
+file in binary mode. If you have problems with the archiver (which uses
+the tmpfile() function), you have two choices:
+
+ 1. Get a fix from http://www.cartsys.com/eldredge/djgpp-patches.html
+ and apply it. This will solve the problem once and forever.
+
+ 2. For a temporary solution, in the file binutils/ar65/main.c, add the
+ following lines:
+
+ At top:
+
+ #include <fcntl.h>
+
+ At start of main:
+
+ _fmode = O_BINARY;
+
+ This will switch the default mode to binary and will work around the
+ bug.
+
+Keith sent me the following notes how to build the tools on a DOS system
+using DJGPP (add your system type to CFLAGS if needed):
+
+-------------------------------------------------------------------------
+
+Here's my current batch file:
+
+cd cc65
+if exist .depend goto ahead1
+make -f make\gcc.mak
+:ahead1
+make -f make\gcc.mak
+move *.exe ..\binutils
+
+cd ..\cl65
+if exist .depend goto ahead2
+make -f make\gcc.mak
+:ahead2
+make -f make\gcc.mak
+move *.exe ..\binutils
+
+cd ..\binutils\common
+if exist .depend goto ahead3
+make -f make\gcc.mak
+:ahead3
+make -f make\gcc.mak
+
+cd ..\ca65
+if exist .depend goto ahead4
+make -f make\gcc.mak
+:ahead4
+make -f make\gcc.mak
+move *.exe ..
+
+cd ..\ld65
+if exist .depend goto ahead5
+make -f make\gcc.mak
+:ahead5
+make -f make\gcc.mak
+move *.exe ..
+
+cd ..\ar65
+if exist .depend goto ahead6
+make -f make\gcc.mak
+:ahead6
+make -f make\gcc.mak
+move *.exe ..
+
+cd ..\..\lib\common
+make 'CFLAGS=-Oi -I../../include/'
+ar65 a common.lib *.o
+move common.lib ..
+
+cd ..\runtime
+make 'CFLAGS=-Oi -I../../include/'
+ar65 a runtime.lib *.o
+move runtime.lib ..
+
+ --
+
+In djgpp.env I use:
+
++LFN=Y
+
+for the .depend file.
+
+ --
+
+And in autoexec.bat I have:
+
+set CC65_INC=E:\djgpp_v2\cc65\include
+set CC65_LIB=E:\djgpp_v2\cc65\lib
+PATH=E:\djgpp_v2\cc65\binutils;%PATH%
+
+-------------------------------------------------------------------------
+
+
+DOS, Windows, OS/2 using the Watcom Compiler
+--------------------------------------------
+
+This is what I'm using. You need the Borland make in addition to the
+Watcom tools, or you have to change the makefile.
+
+1. Copy %WATCOM%\src\startup\wildargv.c from your Watcom directory into
+ binutils\common.
+
+2. Enter
+
+ make -f make\watcom.mak
+
+ in each of the directories
+
+ cc65
+ binutils
+
+3. Use Linux to build the libraries:-) If you don't have Linux, get it
+ now! More serious: There is no makefile to build the libraries. Use a
+ batch file similar to the one above, or rewrite the makefile.
+
+
--- /dev/null
+
+
+ Debugging your code using VICE
+
+ Ullrich von Bassewitz, March 1999
+
+
+Contents
+--------
+
+ 1. Overview
+
+ 2. What is VICE?
+
+ 3. How to prepare your sources
+
+ 4. How to use the label file
+
+ 5. Problems and workarounds
+
+
+
+1. Overview
+-----------
+
+This document describes how to debug your programs using the cc65
+development tools and the VICE CBM emulator.
+
+
+
+2. What is VICE?
+----------------
+
+VICE is an emulator for many of the CBM machines. It runs on Unix, DOS and
+Windows 95. It emulates the Commodore 64, 128, VIC20, PET and the 600/700
+machines. For more information see the VICE home page:
+
+ http://www.cs.cmu.edu/~dsladic/vice/vice.html
+
+VICE has a builtin machine language monitor that may be used for debugging
+your programs. Using an emulator for debugging has some advantages:
+
+ - Since you're using a crossassembler/-compiler anyway, you don't need
+ to transfer the program to the real machine until it is done.
+
+ - An emulator allows many things that are almost impossible one of the
+ original machines. You may set watchpoints (detect read or write
+ access to arbitary addresses), debug interrupt handlers and even debug
+ routines that run inside the 1541 floppy.
+
+ - You may use the label file generated by the linker to make much more
+ use from the monitor.
+
+Please note that you need at least VICE version 0.16 for the label file
+feature to work. This version has still some problems (see section 5 for
+descriptions and some workarounds), but older versions had even more
+problems and do NOT work correctly.
+
+
+
+3. How to prepare your programs
+-------------------------------
+
+VICE support is mostly done via a label file that is generated by the
+linker and that may be read by the VICE monitor, so it knows about your
+program. Source level debugging is *not* available, you have to debug your
+programs in the assembler view.
+
+The first step is to generate object files that contain information about
+ALL labels in your sources, not just the exported ones. This can be done
+by several means:
+
+ - Use the -g switch on the assembler command line.
+
+ - Use the
+
+ .debuginfo +
+
+ command in your source.
+
+ - Use the -g switch when invoking the compiler. The compiler will then
+ put the .debuginfo command into the generated assembler source.
+
+So, if you have just C code, all you need is to invoke the compiler with
+-g. If you're using assembler code, you have to use -g for the assembler,
+or add ".debuginfo +" to your source files. Since the generated debug info
+is not appended to the generated executables, it is a good idea to always
+use -g. It makes the object files and libraries slightly larger (~30%),
+but this is usually not a problem.
+
+The second step is to tell the linker that it should generate a VICE label
+file. This is done by the -L switch followed by the name of the label file
+(I'm usually using a .lbl extension for these files). An example for a
+linker command line would be:
+
+ ld65 -t c64 -L hello.lbl -m hello.map -o hello crt0 hello.o c64.lib
+
+This will generate a file named hello.lbl that contains all symbols used
+in your program.
+
+Note: The runtime libraries and startup files were generated with debug
+info, so you don't have to care about this.
+
+
+
+4. How to use the label file
+----------------------------
+
+Load your program, then enter the monitor and use the "pb" command to load
+your label file like this:
+
+ pb "hello.lbl"
+
+You will get lots of warnings and even a few errors. You may ignore safely
+all these warnings and errors as long as they reference any problems VICE
+thinks it has with the labels.
+
+After loading the labels, they are used by VICE in the disassembler
+listing, and you may use them whereever you need to specify an address.
+Try
+
+ d ._main
+
+as an example (note that VICE needs a leading dot before all labels, and
+that the compiler prepends an underline under most named labels).
+
+
+
+5. Problems and workarounds
+---------------------------
+
+Unfortunately, the VICE monitor has several problems with labels. However,
+it is still tremendously useful, and I think that most problems are gone
+in the next version. So, here is a list of the problems known to me as of
+version 0.16.1:
+
+ * The "ll" command does not work. Worse, it seems that internal memory
+ gets corrupted when using this command, so VICE will crash after use.
+ Be sure to use the "pb" command to load the label file.
+
+ * VICE will crash if you use a label that is undefined. This is probably
+ the worst problem of all, since it needs just one typo to kill VICE.
+ So, watch your steps:-)
+
+ * Cheap labels, that is, labels starting with '@' or '?' are not
+ accepted.
+
+ * The disassembly output is somewhat suboptimal. However, most things are
+ just cosmetical, e.g. labels appended to the right side of the
+ disassembled code.
+
--- /dev/null
+
+
+ Internals doc for CC65
+
+
+
+Stacks:
+-------
+
+The program stack used by programs compiled with CC65 is located in high
+memory. The stack starts there and grows down. Arguments to functions, local
+data etc are allocated on this stack, and deallocated when functions exit.
+
+The program code and data is located in low memory. The heap is located
+between the program code and the stack. The default size for the parameter
+stack is 2K, you may change this by declaring an externally visible variable
+named named _stksize that holds the new stack size:
+
+ unsigned _stksize = 4*1024; /* Use 4K stack */
+
+Note: The size of the stack is only needed if you use the heap, or if you
+call the stack checking routine (_stkcheck) from somewhere in your program.
+
+When calling other functions, the return address goes on the normal 6502
+stack, *not* on the parameter stack.
+
+
+
+Registers:
+----------
+
+Since CC65 is a member of the Small-C family of compilers, it uses the notion
+of a 'primary register'. In the CC65 implementation, I used the AX register
+pair as the primary register. Just about everything interesting that the
+library code does is done by somehow getting a value into AX, and then calling
+some routine or other. In places where Small-C would use a secondary
+register, top-of-stack is used, so for instance two argument function like
+integer-multiply work by loading AX, pushing it on the stack, loading the
+second value, and calling the internal function. The stack is popped, and the
+result comes back in AX.
+
+
+
+Calling sequences:
+------------------
+
+C functions are called by pushing their args on the stack, and JSR'ing to the
+entry point. (See ex 1, below) If the function returns a value, it comes back
+in AX. NOTE!!! A potentially significant difference between the CC65
+environment and other C environments is that the CALLEE pops arguments, not
+the CALLER. (This is done so as to generate more compact code) In normal use,
+this doesn't cause any problems, as the normal function entry/exit conventions
+take care of popping the right number of things off the stack, but you may
+have to worry about it when doing things like writing hand-coded assembly
+language routines that take variable numbers of arguments. More about that
+later.
+
+Ex 1: Function call: Assuming 'i' declared int and 'c' declared
+ char, the following C code
+
+ i = baz(i, c);
+
+ in absence of a prototype generates this assembler code. I've added
+ the comments.
+
+ lda _i ; get 'i', low byte
+ ldx _i+1 ; get 'i', hi byte
+ jsr pushax ; push it
+ lda _c ; get 'c'
+ ldx #0 ; fill hi byte with 0
+ jsr pushax ; push it
+ ldy #4 ; arg size
+ jsr _baz ; call the function
+ sta _i ; store the result
+ stx _i+1
+
+ In presence of a prototype, the picture changes slightly, since the
+ compiler is able to do some optimizations:
+
+ lda _i ; get 'i', low byte
+ ldx _i+1 ; get 'i', hi byte
+ jsr pushax ; push it
+ lda _c ; get 'c'
+ jsr pusha ; push it
+ jsr _baz ; call the function
+ sta _i ; store the result
+ stx _i+1
+
+
+Note that the two words of arguments to baz were popped before it exitted.
+The way baz could tell how much to pop was by the argument count in Y at call
+time. Thus, even if baz had been called with 3 args instead of the 2 it was
+expecting, that would not cause stack corruption.
+
+There's another tricky part about all this, though. Note that the args to baz
+are pushed in FORWARD order, ie the order they appear in the C statement.
+That means that if you call a function with a different number of args than it
+was expecting, they wont end up in the right places, ie if you call baz, as
+above, with 3 args, it'll operate on the LAST two, not the first two.
+
+
+
+Symbols:
+--------
+
+CC65 does the usual trick of prepending an underbar ('_') to symbol names when
+compiling them into assembler. Therefore if you have a C function named
+'bar', CC65 will define and refer to it as '_bar'.
+
+
+
+Systems:
+--------
+
+Supported systems at this time are: C64, C128, Plus/4, CBM 600/700, the newer
+PET machines (not 2001), and the Apple ][ (thanks to Kevin Ruland, who did the
+port).
+
+C64: The program runs in a memory configuration, where only the kernal ROM
+ is enabled. The text screen is expected at the usual place ($400), so
+ 54K of memory are available to the program.
+
+C128: The startup code will reprogram the MMU, so that only the kernal ROM
+ is enabled. This means, there are 41K of memory available to the
+ program.
+
+Plus/4: Unfortunately, the Plus/4 is not able to disable only part of it's
+ ROM, it's an all or nothing approach. So, on the Plus/4, the program
+ has only 28K available (16K machines are detected and the amount of
+ free memory is reduced to 12K).
+
+CBM 600/700:
+ The C program runs in a separate segment and has almost full 64K of
+ memory available.
+
+PET: The startup code will adjust the upper memory limit to the installed
+ memory. However, only linear memory is used, this limits the top to
+ $8000, so on a 8032 or similar machine, 31K of memory are available to
+ the program.
+
+APPLE2: The program starts at $800, and of RAM is $8E00, so 33.5K of memory
+ (including stack) are available.
+
+Note: The above numbers do not mean that the remaining memory is unusable.
+However, it is not linear memory and must be accessed by other, nonportable
+methods. I'm thinking about a library extension that allows access to the
+additional memory as a far heap, but these routines do not exist until now.
+
+
+
+Inline Assembly:
+----------------
+
+CC65 allows inline assembly by a special keyword named "asm". Inline assembly
+looks like a function call. The string in parenthesis is output in the
+assembler file.
+
+Example, insert a break instruction into the code:
+
+ asm ("\t.byte\t$00")
+
+Note: The \t in the string is replaced by the tab character, as in all other
+strings.
+
+
+
+Pseudo variables:
+-----------------
+
+There are two special variables available named __AX__ and __EAX__. These
+variables must never be declared (this gives an error), but may be used as any
+other variable. However, accessing these variables will access the primary
+register that is used by the compiler to evaluate expressions, return
+functions results and pass parameters.
+
+This feature is useful with inline assembly and macros. For example, a macro
+that reads a CRTC register may be written like this:
+
+#define wr(idx) (__AX__=(idx),asm("\tsta\t$2000\n\tlda\t$2000\n\tldx\t#$00"),__AX__)
+
+An obvious problem here is that macro definitions may not use more than one
+line.
+
+
+
--- /dev/null
+
+
+ How to use the cc65 C compiler
+
+ Ullrich von Bassewitz, 1998/1999
+
+
+
+Contents
+--------
+
+ 1. Overview
+
+ 2. The compiler
+
+ 3. The assembler
+
+ 4. The linker
+
+ 5. The easy way (using the cl65 utility)
+
+
+
+1. Overview
+-----------
+
+This is a short intro, how to use the compiler and the binutils. It
+contains a step-by-step example, how to build a complete application from
+one C and one assembler module. This file does *NOT* contain a complete
+reference for the tools used in the process. There are separate files
+describing these tools in detail.
+
+Note: There is a much simpler way to compile this example using the cl65
+compiler and link utility. However, it makes sense to understand how the
+separate steps work. How to do the example with the cl65 utility is
+described in section 5.
+
+To explain the development flow, I will use the following example modules:
+
+
+hello.c:
+
+ #include <stdio.h>
+ #include <stdlib.h>
+
+ extern const char text[]; /* In text.s */
+
+ int main (void)
+ {
+ printf ("%s\n", text);
+ return EXIT_SUCCESS;
+ }
+
+
+text.s:
+
+ .export _text
+ _text: .asciiz "Hello world!"
+
+
+We assume that the target file should be named "hello", and the target
+system is the C64.
+
+
+ +---------+
+ | hello.c |
+ +---------+
+ |
+ cc65
+ \/
+ +---------+ +---------+
+ | hello.s | | text.s |
+ +---------+ +---------+
+ | |
+ ca65 ca65
+ \/ \/
+ +---------+ +---------+ +----------+ +---------+
+ | hello.o | | text.o | | c64.o | | c64.lib |
+ +---------+ +---------+ +----------+ +---------+
+ | \ / |
+ | \ / |
+ | \ / |
+ +----------------------->ld65<-------------------------+
+ \/
+ hello
+
+
+c64.o (the startup code) and c64.lib (the c64 version of the runtime and C
+library) are provided in binary form in the cc65 package.
+
+
+
+2. The compiler
+---------------
+
+The compiler translates one C source into one assembler source for each
+invocation. It does *NOT* create object files directly, and it is *NOT*
+able to translate more than one file per run.
+
+In the example above, we would use the following command line, to
+translate hello.c into hello.s:
+
+ cc65 -O -I ../include -t c64 hello.c
+
+The -O switch tells the compiler to do an additional optimizer run, which
+is usually a good idea, since it makes the code smaller. If you don't care
+about the size, but want to have slightly faster code, use -Oi to inline
+some runtime functions.
+
+The -I switch gives a search path for the include files. You may also set
+the environment variable CC65_INC to the search path.
+
+The -t switch is followed by the target system.
+
+If the compiler does not complain about errors in our hello world, we will
+have a file named "hello.s" in our directory that contains the assembler
+source for the hello module.
+
+For more information about the compiler see cc65.txt.
+
+
+
+3. The assembler
+----------------
+
+The assembler translates one assembler source into an object file for each
+invocation. The assembler is *NOT* able to translate more than one source
+file per run.
+
+Let's translate the hello.s and text.s files from our example:
+
+ ca65 hello.s
+ ca65 text.s
+
+If the assembler does not complain, we should now have two object files
+(named hello.o and text.o) in the current directory.
+
+For more information about the assembler see ca65.txt.
+
+
+
+4. The linker
+-------------
+
+The linker combines several object and library file into one output file.
+ld65 is very configurable, but fortunately has a builtin configuration for
+the C64, so we don't need to mess with configuration files here.
+
+The compiler uses small functions to do things that cannot be done inline
+without big impact on code size. These runtime functions, together with
+the C library are in an object file archive named after the system, in
+this case "c64.lib". We have to specify this file on the command line so
+that the linker can resolve these functions.
+
+A second file (this time an object file) needed, is the startup code that
+prepares the grounds for the C program to run. The startup file must be
+executed first, so it must be the first file on the linker command line.
+
+Let's link our files to get the final executable:
+
+ ld65 -t c64 -o hello c64.o hello.o text.o c64.lib
+
+The argument after -o specifies the name of the output file, the argument
+after -t gives the target system. As discussed, the startup file must be the
+first file on the command line (you may have to add a path here, if c64.o is
+not in your current directory). Since the library resolves imports in hello.o
+and text.o, it must be specified *after* these files.
+
+After a successful linker run, we have a file named "hello", ready for our
+C64!
+
+For more information about the linker see ld65.txt.
+
+
+
+5. The easy way (using the cl65 utility)
+----------------------------------------
+
+The cl65 utility is able to do all of the steps described above in just
+one call, and it has defaults for some options that are very well suited
+for our example.
+
+To compile both files into one executable enter
+
+ cl65 -O -I ../include hello.c test.s
+
+(The -I switch is not needed if you are working under Linux with the
+include files in the default path, or the CC65_INC environment variable is
+set correctly).
+
+The cl65 utility knows, how to translate C files into object files (it
+will call the compiler and then the assembler). It does also know how to
+create object files from assembler files (it will call the assember for
+that). It knows how to build an executable (it will pass all object files
+to the linker). And, finally, it has the C64 as a default target and will
+supply the correct startup file and runtime library names to the linker,
+so you don't have to care about that.
+
+The one-liner above should give you a C64 executable named "hello" in the
+current directory.
+
+For more information about the compile & link utility see cl65.txt.
+
+
+
+
--- /dev/null
+
+
+ ld65
+
+ A Linker for ca65 Object modules
+
+ (C) Copyright 1998-1999 Ullrich von Bassewitz
+ (uz@musoftware.de)
+
+
+
+Contents
+--------
+
+ 1. Overview
+
+ 2. Usage
+
+ 3. Detailed workings
+
+ 4. Output configuration files
+ 4.1 Introduction
+ 4.2 Reference
+ 4.3 Builtin configurations
+
+ 5. Bugs/Feedback
+
+ 6. Copyright
+
+
+
+1. Overview
+-----------
+
+ld65 is a replacement for the link65 linker that was part of the cc65 C
+compiler suite developed by John R. Dunning. link65 had some problems and
+the copyright does not permit some things which I wanted to be possible,
+so I decided to write a completely new assembler/linker/archiver suite
+for the cc65 compiler. ld65 is part of this suite.
+
+The ld65 linker combines several object modules, producing an executable
+file. The object modules may be read from a library created by the ar65
+archiver (this is somewhat faster and more convenient). The linker was
+designed to be as flexible as possible. It complements the features that
+are built into the ca65 macroassembler:
+
+ * Accept any number of segments to form an executable module.
+
+ * Resolve arbitrary expressions stored in the object files.
+
+ * In case of errors, use the meta information stored in the object
+ files to produce helpful error messages. In case of undefined
+ symbols, expression range errors, or symbol type mismatches, ld65 is
+ able to tell you the exact location in the source, where the symbol
+ was referenced.
+
+ * Flexible output. The output of ld65 is highly configurable by a
+ config file. More common platforms are supported by builtin
+ configurations that may be activated by naming the target system.
+ The output generation was designed with different output formats in
+ mind, so adding other formats shouldn't be a great problem.
+
+
+
+2. Usage
+--------
+
+The linker is called as follows:
+
+ Usage: ld65 [options] module ...
+ Options are:
+ -m name Create a map file
+ -o name Name the default output file
+ -t type Type of target system
+ -v Verbose mode
+ -vm Verbose map file
+ -C name Use linker config file
+ -Ln name Create a VICE label file
+ -Lp Mark write protected segments as such (VICE)
+ -S addr Set the default start address
+ -V Print linker version
+
+The -m switch (which needs an argument that will used as a filename for
+the generated map file) will cause the linker to generate a map file. The
+map file does contain a detailed overview over the modules used, the
+sizes for the different segments, and a table containing exported
+symbols.
+
+The -o switch is used to give the name of the default output file.
+Depending on your output configuration, this name may NOT be used as name
+for the output file. However, for the builtin configurations, this name
+is used for the output file name.
+
+The argument for the -t switch is the name of the target system. Since
+this switch will activate a builtin configuration, it may not be used
+together with the -C option.
+The following target systems are defined (* = currently unsupported):
+
+ none
+ atari
+ c64
+ c128
+ ace
+ plus4
+ cbm610
+ pet
+ nes
+ apple2
+
+See section 4.3 for more information about the builtin configurations.
+
+Using the -v option, you may enable more output that may help you to
+locate problems. If an undefined symbol is encountered, -v causes the
+linker to print a detailed list of the references (that is, source file
+and line) for this symbol.
+
+-C gives the name of an output config file to use. See section 4 for more
+information about config files. -C may not be used together with -t.
+
+-L allows you to create a file that contains all global labels and may be
+loaded into VICE emulator using the pb (playback) command. You may use
+this to debug your code with VICE. Note: The label feature is very new in
+VICE and has some bugs. If you have problems, please get the latest VICE
+version.
+
+Using -S you may define the default starting address. If and how this
+address is used depends on the config file in use. For the builtin
+configurations, only the "none" system honors an explicit start address,
+all other builtin config provide their own.
+
+-V prints the version number of the linker. If you send any suggestions or
+bugfixes, please include this number.
+
+
+If one of the modules is not found in the current directory, and the
+module name does not have a path component, the value of the environment
+variable CC65_LIB is prepended to the name, and the linker tries to open
+the module with this new name.
+
+
+
+3. Detailed workings
+--------------------
+
+The linker does several things when combining object modules:
+
+First, the command line is parsed from left to right. For each object file
+encountered (object files are recognized by a magic word in the header, so
+the linker does not care about the name), imported and exported
+identifiers are read from the file and inserted in a table. If a library
+name is given (libraries are also recognized by a magic word, there are no
+special naming conventions), all modules in the library are checked if an
+export from this module would satisfy an import from other modules. All
+modules where this is the case are marked. If duplicate identifiers are
+found, the linker issues a warning.
+
+This procedure (parsing and reading from left to right) does mean, that a
+library may only satisfy references for object modules (given directly or
+from a library) named BEFORE that library. With the command line
+
+ ld65 crt0.o clib.lib test.o
+
+the module test.o may not contain references to modules in the library
+clib.lib. If this is the case, you have to change the order of the modules
+on the command line:
+
+ ld65 crt0.o test.o clib.lib
+
+Step two is, to read the configuration file, and assign start addresses
+for the segments and define any linker symbols (see section 4).
+
+After that, the linker is ready to produce an output file. Before doing
+that, it checks it's data for consistency. That is, it checks for
+unresolved externals (if the output format is not relocatable) and for
+symbol type mismatches (for example a zero page symbol is imported by a
+module as absolute symbol).
+
+Step four is, to write the actual target files. In this step, the linker
+will resolve any expressions contained in the segment data. Circular
+references are also detected in this step (a symbol may have a circular
+reference that goes unnoticed if the symbol is not used).
+
+Step five is to output a map file with a detailed list of all modules,
+segments and symbols encountered.
+
+And, last step, if you give the -v switch twice, you get a dump of the
+segment data. However, this may be quite unreadable if you're not a
+developer:-)
+
+
+
+4. Output configuration files
+-----------------------------
+
+Configuration files are used to describe the layout of the output file(s).
+Two major topics are covered in a config file: The memory layout of the
+target architecture, and the assignment of segments to memory areas. In
+addition, several other attributes may be specified.
+
+Case is ignored for keywords, that is, section or attribute names, but it
+is NOT ignored for names and strings.
+
+
+
+4.1 Introduction
+----------------
+
+Memory areas are specified in a "MEMORY" section. Lets have a look at an
+example (this one describes the usable memory layout of the C64):
+
+ MEMORY {
+ RAM1: start = $0800, size = $9800;
+ ROM1: start = $A000, size = $2000;
+ RAM2: start = $C000, size = $1000;
+ ROM2: start = $E000, size = $2000;
+ }
+
+As you can see, there are two ram areas and two rom areas. The names
+(before the colon) are arbitrary names that must start with a letter, with
+the remaining characters being letters or digits. The names of the memory
+areas are used when assigning segments. As mentioned above, case is
+significant for these names.
+
+The syntax above is used in all sections of the config file. The name
+("ROM1" etc.) is said to be an identifier, the remaining tokens up to the
+semicolon specify attributes for this identifier. You may use the equal
+sign to assign values to attributes, and you may use a comma to separate
+attributes, you may also leave both out. But you MUST use a semicolon to
+mark the end of the attributes for one identifier. The section above may
+also have looked like this:
+
+ # Start of memory section
+ MEMORY
+ {
+ RAM1:
+ start $0800
+ size $9800;
+ ROM1:
+ start $A000
+ size $2000;
+ RAM2:
+ start $C000
+ size $1000;
+ ROM2:
+ start $E000
+ size $2000;
+ }
+
+There are of course more attributes for a memory section than just start
+and size. Start and size are mandatory attributes, that means, each memory
+area defined MUST have these attributes given (the linker will check
+that). I will cover other attributes later. As you may have noticed, I've
+used a comment in the example above. Comments start with a hash mark
+(`#'), the remainder of the line is ignored if this character is found.
+
+Let's assume you have written a program for your trusty old C64, and you
+would like to run it. For testing purposes, it should run in the RAM area.
+So we will start to assign segments to memory sections in the SEGMENTS
+section:
+
+ SEGMENTS {
+ CODE: load = RAM1, type = ro;
+ RODATA: load = RAM1, type = ro;
+ DATA: load = RAM1, type = rw;
+ BSS: load = RAM1, type = bss, define = yes;
+ }
+
+What we are doing here is telling the linker, that all segments go into
+the RAM1 memory area in the order specified in the SEGMENTS section. So
+the linker will first write the CODE segment, then the RODATA segment,
+then the DATA segment - but it will not write the BSS segment. Why? Enter
+the segment type: For each segment specified, you may also specify a
+segment attribute. There are five possible segment attributes:
+
+ ro means readonly
+ wprot same as ro but will be marked as write protected in
+ the VICE label file if -Lp is given
+ rw means read/write
+ bss means that this is an uninitialized segment
+ empty will not go in any output file
+
+So, because we specified that the segment with the name BSS is of type
+bss, the linker knows that this is uninitialized data, and will not write
+it to an output file. This is an important point: For the assembler, the
+BSS segment has no special meaning. You specify, which segments have the
+bss attribute when linking. This approach is much more flexible than
+having one fixed bss segment, and is a result of the design decision to
+supporting an arbitrary segment count.
+
+If you specify "type = bss" for a segment, the linker will make sure that
+this segment does only contain uninitialized data (that is, zeroes), and
+issue a warning if this is not the case.
+
+For a bss type segment to be useful, it must be cleared somehow by your
+program (this happens usually in the startup code - for example the
+startup code for cc65 generated programs takes care about that). But how
+does your code know, where the segment starts, and how big it is? The
+linker is able to give that information, but you must request it. This is,
+what we're doing with the "define = yes" attribute in the BSS definitions.
+For each segment, where this attribute is true, the linker will export
+three symbols.
+
+ __NAME_LOAD__ This is set to the address where the segment is
+ loaded.
+ __NAME_RUN__ This is set to the run address of the segment.
+ We will cover run addresses later.
+ __NAME_SIZE__ This is set to the segment size.
+
+Replace "NAME" by the name of the segment, in the example above, this
+would be "BSS". These symbols may be accessed by your code.
+
+Now, as we've configured the linker to write the first three segments and
+create symbols for the last one, there's only one question left: Where
+does the linker put the data? It would be very convenient to have the data
+in a file, wouldn't it?
+
+We don't have any files specified above, and indeed, this is not needed in
+a simple configuration like the one above. There is an additional
+attribute "file" that may be specified for a memory area, that gives a
+file name to write the area data into. If there is no file name given, the
+linker will assign the default file name. This is "a.out" or the one given
+with the -o option on the command line. Since the default behaviour is ok
+for our purposes, I did not use the attribute in the example above. Let's
+have a look at it now.
+
+The "file" attribute (the keyword may also be written as "FILE" if you
+like that better) takes a string enclosed in double quotes (`"') that
+specifies the file, where the data is written. You may specifiy the same
+file several times, in that case the data for all memory areas having this
+file name is written into this file, in the order of the memory areas
+defined in the MEMORY section. Let's specify some file names in the MEMORY
+section used above:
+
+ MEMORY {
+ RAM1: start = $0800, size = $9800, file = %O;
+ ROM1: start = $A000, size = $2000, file = "rom1.bin";
+ RAM2: start = $C000, size = $1000, file = %O;
+ ROM2: start = $E000, size = $2000, file = "rom2.bin";
+ }
+
+The %O used here is a way to specify the default behaviour explicitly: %O
+is replaced by a string (including the quotes) that contains the default
+output name, that is, "a.out" or the name specified with the -o option on
+the command line. Into this file, the linker will first write any segments
+that go into RAM1, and will append then the segments for RAM2, because the
+memory areas are given in this order. So, for the RAM areas, nothing has
+really changed.
+
+We've not used the ROM areas, but we will do that below, so we give the
+file names here. Segments that go into ROM1 will be written to a file
+named "rom1.bin", and segments that go into ROM2 will be written to a file
+named "rom2.bin". The name given on the command line is ignored in both
+cases.
+
+Let us look now at a more complex example. Say, you've successfully tested
+your new "Super Operating System" (SOS for short) for the C64, and you
+will now go and replace the ROMs by your own code. When doing that, you
+face a new problem: If the code runs in RAM, we need not to care about
+read/write data. But now, if the code is in ROM, we must care about it.
+Remember the default segments (you may of course specify your own):
+
+ CODE read only code
+ RODATA read only data
+ DATA read/write data
+ BSS uninitialized data, read/write
+
+Since the BSS is not initialized, we must not care about it now, but what
+about DATA? DATA contains initialized data, that is, data that was
+explicitly assigned a value. And your program will rely on these values on
+startup. Since there's no other way to remember the contents of the data
+segment, than storing it into one of the ROMs, we have to put it there.
+But unfortunately, ROM is not writeable, so we have to copy it into RAM
+before running the actual code.
+
+The linker cannot help you copying the data from ROM into RAM (this must
+be done by the startup code of your program), but it has some features
+that will help you in this process.
+
+First, you may not only specify a "load" attribute for a segment, but also
+a "run" attribute. The "load" attribute is mandatory, and, if you don't
+specify a "run" attribute, the linker assumes that load area and run area
+are the same. We will use this feature for our data area:
+
+ SEGMENTS {
+ CODE: load = ROM1, type = ro;
+ RODATA: load = ROM2, type = ro;
+ DATA: load = ROM2, run = RAM2, type = rw, define = yes;
+ BSS: load = RAM2, type = bss, define = yes;
+ }
+
+Let's have a closer look at this SEGMENTS section. We specify that the
+CODE segment goes into ROM1 (the one at $A000). The readonly data goes
+into ROM2. Read/write data will be loaded into ROM2 but is run in RAM2.
+That means that all references to labels in the DATA segment are relocated
+to be in RAM2, but the segment is written to ROM2. All your startup code
+has to do is, to copy the data from it's location in ROM2 to the final
+location in RAM2.
+
+So, how do you know, where the data is located? This is the second point,
+where you get help from the linker. Remember the "define" attribute? Since
+we have set this attribute to true, the linker will define three external
+symbols for the data segment that may be accessed from your code:
+
+ __DATA_LOAD__ This is set to the address where the segment is
+ loaded, in this case, it is an address in ROM2.
+ __DATA_RUN__ This is set to the run address of the segment, in
+ this case, it is an address in RAM2.
+ __DATA_SIZE__ This is set to the segment size.
+
+So, what your startup code must do, is to copy __DATA_SIZE__ bytes from
+__DATA_LOAD__ to __DATA_RUN__ before any other routines are called. All
+references to labels in the DATA segment are relocated to RAM2 by the
+linker, so things will work properly.
+
+There are some other attributes not covered above. Before starting the
+reference section, I will discuss the remaining things here.
+
+You may request symbols definitions also for memory areas. This may be
+useful for things like a software stack, or an i/o area.
+
+ MEMORY {
+ STACK: start = $C000, size = $1000, define = yes;
+ }
+
+This will define three external symbols that may be used in your code:
+
+ __STACK_START__ This is set to the start of the memory
+ area, $C000 in this example.
+
+ __STACK_SIZE__ The size of the area, here $1000.
+
+
+ __STACK_LAST__ This is NOT the same as START+SIZE.
+ Instead, it it defined as the first
+ address that is not used by data. If we
+ don't define any segments for this area,
+ the value will be the same as START.
+
+A memory section may also have a type. Valid types are
+
+ ro for readonly memory
+and rw for read/write memory.
+
+The linker will assure, that no segment marked as read/write or bss is put
+into a memory area that is marked as readonly.
+
+Unused memory in a memory area may be filled. Use the "fill = yes"
+attribute to request this. The default value to fill unused space is zero.
+If you don't like this, you may specify a byte value that is used to fill
+these areas with the "fillval" attribute. This value is also used to fill
+unfilled areas generated by the assemblers .ALIGN and .RES directives.
+
+Segments may be aligned to some memory boundary. Specify "align = num" to
+request this feature. Num must be a power of two. To align all segments on
+a page boundary, use
+
+ SEGMENTS {
+ CODE: load = ROM1, type = ro, align = $100;
+ RODATA: load = ROM2, type = ro, align = $100;
+ DATA: load = ROM2, run = RAM2, type = rw, define = yes,
+ align = $100;
+ BSS: load = RAM2, type = bss, define = yes, align = $100;
+ }
+
+If an alignment is requested, the linker will add enough space to the
+output file, so that the new segment starts at an address that is
+divideable by the given number without a remainder. All addresses are
+adjusted accordingly. To fill the unused space, bytes of zero are used,
+or, if the memory area has a "fillval" attribute, that value. Alignment is
+always needed, if you have the used the .ALIGN command in the assembler.
+The alignment of a segment must be equal or greater than the alignment
+used in the .ALIGN command. The linker will check that, and issue a
+warning, if the alignment of a segment is lower than the alignment
+requested in a .ALIGN command of one of the modules making up this
+segment.
+
+For a given segment you may also specify a fixed offset into a memory area or
+a fixed start address. Use this if you want the code to run at a specific
+address (a prominent case is the interrupt vector table which must go at
+address $FFFA). Only one of ALIGN or OFFSET or START may be specified. If the
+directive creates empty space, it will be filled with zero, of with the value
+specified with the "fillval" attribute if one is given. The linker will warn
+you if it is not possible to put the code at the specified offset (this may
+happen if other segments in this area are too large). Here's an example:
+
+ SEGMENTS {
+ VECTORS: load = ROM2, type = ro, start = $FFFA;
+ }
+
+or (for the segment definitions from above)
+
+ SEGMENTS {
+ VECTORS: load = ROM2, type = ro, offset = $1FFA;
+ }
+
+File names may be empty, data from segments assigned to a memory area with
+an empty file name is discarded. This is useful, if the a memory area has
+segments assigned that are empty (for example because they are of type
+bss). In that case, the linker will create an empty output file. This may
+be suppressed by assigning an empty file name to that memory area.
+
+The symbol %S may be used to access the default start address (that is,
+$200 or the value given on the command line with the -S option).
+
+
+
+4.2 Reference
+-------------
+
+
+
+4.3 Builtin configurations
+--------------------------
+
+Here is a list of the builin configurations for the different target
+types:
+
+none:
+ MEMORY {
+ RAM: start = %S, size = $10000, file = %O;
+ }
+ SEGMENTS {
+ CODE: load = RAM, type = rw;
+ RODATA: load = RAM, type = rw;
+ DATA: load = RAM, type = rw;
+ BSS: load = RAM, type = bss, define = yes;
+ }
+
+atari:
+ (non-existent)
+
+c64:
+ MEMORY {
+ RAM: start = $7FF, size = $c801, file = %O;
+ }
+ SEGMENTS {
+ CODE: load = RAM, type = ro;
+ RODATA: load = RAM, type = ro;
+ DATA: load = RAM, type = rw;
+ BSS: load = RAM, type = bss, define = yes;
+ }
+
+c128:
+ MEMORY {
+ RAM: start = $1bff, size = $a401, file = %O;
+ }
+ SEGMENTS {
+ CODE: load = RAM, type = ro;
+ RODATA: load = RAM, type = ro;
+ DATA: load = RAM, type = rw;
+ BSS: load = RAM, type = bss, define = yes;
+ }
+
+ace:
+ (non-existent)
+
+plus4:
+ MEMORY {
+ RAM: start = $0fff, size = $7001, file = %O;
+ }
+ SEGMENTS {
+ CODE: load = RAM, type = ro;
+ RODATA: load = RAM, type = ro;
+ DATA: load = RAM, type = rw;
+ BSS: load = RAM, type = bss, define = yes;
+ }
+
+cbm610:
+ MEMORY {
+ RAM: start = $0001, size = $FFF0, file = %O;
+ }
+ SEGMENTS {
+ CODE: load = RAM, type = ro;
+ RODATA: load = RAM, type = ro;
+ DATA: load = RAM, type = rw;
+ BSS: load = RAM, type = bss, define = yes;
+ }
+
+pet:
+ MEMORY {
+ RAM: start = $03FF, size = $7BFF, file = %O;
+ }
+ SEGMENTS {
+ CODE: load = RAM, type = ro;
+ RODATA: load = RAM, type = ro;
+ DATA: load = RAM, type = rw;
+ BSS: load = RAM, type = bss, define = yes;
+ }
+
+nes:
+ MEMORY {
+ RAM: start = $0200, size = $0600, file = "";
+ ROM: start = $8000, size = $8000, file = %O;
+ }
+ SEGMENTS {
+ CODE: load = ROM, type = ro;
+ RODATA: load = ROM, type = ro;
+ DATA: load = ROM, run = RAM, type = rw, define = yes;
+ BSS: load = RAM, type = bss, define = yes;
+ VECTORS: load = ROM, type = ro, start = $FFFA;
+ }
+
+apple2:
+ MEMORY {
+ RAM: start = $800, size = $8E00, file = %O;
+ }
+ SEGMENTS {
+ CODE: load = RAM, type = ro;
+ RODATA: load = RAM, type = ro;
+ DATA: load = RAM, type = rw;
+ BSS: load = RAM, type = bss, define = yes;
+ }
+
+The "start" attribute for the RAM memory area of the CBM systems is two
+less than the actual start of the basic RAM to account for the two bytes
+load address that is needed on disk and supplied by the startup code.
+
+
+
+5. Bugs/Feedback
+----------------
+
+If you have problems using the linker, if you find any bugs, or if you're
+doing something interesting with it, I would be glad to hear from you.
+Feel free to contact me by email (uz@musoftware.de).
+
+
+
+6. Copyright
+------------
+
+ld65 (and all cc65 binutils) are (C) Copyright 1998 Ullrich von Bassewitz.
+For usage of the binaries and/or sources the following conditions do
+apply:
+
+This software is provided 'as-is', without any expressed or implied
+warranty. In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not
+ be misrepresented as being the original software.
+3. This notice may not be removed or altered from any source
+ distribution.
+
+
+
+
--- /dev/null
+
+
+ Description of the C library for the cc65 C compiler
+
+ (C) Copyright 1998-1999 Ullrich von Bassewitz
+ (uz@musoftware.de)
+
+
+
+Contents
+--------
+
+ 1. Overview
+
+ 2. ISO C compatible library
+
+ 3. CPU specific stuff - 6502.h
+
+ 4. System specific stuff
+
+ 5. Direct console I/O - conio.h
+
+ 6. Using the joystick - joystick.h
+
+ 7. Bugs/Feedback
+
+ 8. Copyright
+
+
+
+1. Overview
+-----------
+
+This file contains a description of the library routines available for the
+cc65 C compiler. It is not complete in some areas, so if you miss
+something, have a look into the header files. All functions, that are not
+defined by the ISO C standard have a short comment in the headers,
+explaining their use.
+
+
+
+2. ISO C compatible library
+---------------------------
+
+The C library contains a large subset of the ISO C library. Functions are
+usually missing in areas, where there is no support on typical 6502
+systems. Wide character sets are an example for this.
+
+I will not go into detail about the ISO functions. If a function is not
+mentioned here explicitly, expect it to be available and to behave as
+defined in the C standard.
+
+
+Functions that are NOT available:
+
+ * ftell/fseek/fgetpos/fsetpos
+
+ * tmpfile/tmpnam
+
+ * The scanf family of functions
+
+ * time/asctime/ctime/difftime/asctime/gmtime/localtime/mktime/strftime
+
+ * system
+
+ * All functions that handle floating point numbers in some manner.
+
+ * The div and ldiv functions (because cc65 is not able to return
+ structs).
+
+ * All functions handling wide character strings.
+
+ * Signals and all related functions (having SIGSEGV would be cool:-)
+
+ * rename/remove/rewind
+
+ * setbuf/setvbuf/ungetc
+
+
+
+Functions that are limited in any way:
+
+ * fopen/fread/fwrite/fclose/fputs/fgets/fscanf....
+
+ These functions are built on open/read/write/close. Neither of these
+ low level functions is currently available for the supported systems,
+ and so, fopen and friends do not work. However, the functions exist
+ and are tested to some degree under the ACE operating systems (which
+ is no longer supported).
+
+
+ * The va_... family of macros
+
+ The macros do not work completely as defined by the standard. Since cc65
+ has the wrong calling order, the (non-standard) va_fix macro must be used
+ to access fixed parameters in functions with a variable parameter size.
+ See newvers.txt for a discussion of the problem.
+
+
+ * The character classification functions (is...)
+
+ These functions have unexpected results when called with arguments that
+ are not really chars (are outside the 0..255 range).
+
+
+ * The strerror function
+
+ The function will return "error #n" where n is the error number.
+
+
+ * strcspn/strpbrk/strspn
+
+ These functions have a length limitation of 256 for the second string
+ argument. Since this string gives a character set, and there are only 256
+ distinct characters, this shouldn't be a problem.
+
+
+ * Since there is no such thing as an environment on all supported
+ systems, the getenv function will always return a NULL pointer.
+
+
+ * There is no other locale than the "C" locale. The native locale is
+ identical to the "C" locale.
+
+
+
+3. CPU specific stuff - 6502.h
+------------------------------
+
+The header file 6502.h contains some functions that make only sense with
+the 6502 CPU. Examples are macros to insert more or less useful
+instructions into your C code, or a function to call arbitrary machine
+language subroutines, passing registers in and out.
+
+
+
+4. System specific stuff
+------------------------
+
+For each supported system there's a header file that contains calls or
+defines specific for this system. So, when programming for the C64,
+include c64.h, for the C128, include c128.h and so on. To make the task
+for the Commodore systems easier, there is also a header file named cbm.h
+that will define stuff common for all CBM systems, and include the header
+file for the specific target system.
+
+The header files contain
+
+ * Defines for special keys (like function keys)
+
+ * Defines for special characters (like the graphics characters)
+
+ * Variables with a fixed address in memory that may be used to access
+ special hardware. For the C64 and C128 there is a variable struct
+ named "sid". Writing to the fields of this struct will write to the
+ SID device instead. Using these variables will make your program more
+ readable and more portable. Don't fear ineffective code when using
+ these variables, the compiler will translate reads and writes to these
+ structs into direct memory accesses.
+
+ * Other routines that make only sense for a specific system. One example
+ are routines to write memory locations in the system bank for the CBM
+ 600/700 family (called B128/B256 in the US).
+
+
+
+5. Direct console I/O - conio.h
+-------------------------------
+
+The conio header file contains a large set of functions that do screen and
+keyboard I/O. The functions will write directly to the screen or poll the
+keyboard directly with no more help from the operating system than needed.
+This has some disadvantages, but on the other side it's fast and
+reasonably portable. conio implementations exist for the following
+targets:
+
+ c64
+ c128
+ plus/4
+ cbm610 (that is, the complete 600/700 series)
+ pet (all PETs except the 2001)
+ apple 2
+
+The conio.h header file does also include the system specific header files
+which define constants for special characters and keys.
+
+
+
+6. Using the joystick - joystick.h
+----------------------------------
+
+For systems that have a joystick, joystick.h will define a subroutine to
+read the current value, including constants to evaluate the result of this
+function. To help in writing portable code, the header file will define
+the symbol __JOYSTICK__ on systems that have a joystick.
+
+
+
+7. Bugs/Feedback
+----------------
+
+If you have problems using the library, if you find any bugs, or if you've
+written some extensions or otherwise interesting programs, I would be glad
+to hear from you. Feel free to contact me by email (uz@musoftware.de).
+
+
+
+8. Copyright
+------------
+
+This C runtime library implementation for the cc65 compiler is (C)
+Copyright 1998-1999 Ullrich von Bassewitz. For usage of the binaries
+and/or sources the following conditions do apply:
+
+This software is provided 'as-is', without any expressed or implied
+warranty. In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not
+ be misrepresented as being the original software.
+3. This notice may not be removed or altered from any source
+ distribution.
+
+
+
+
+
--- /dev/null
+
+This document is slightly outdated! See cc65.txt and library.txt for a more
+up-to-date discussion.
+
+
+
+Discussion of some of the features/non features of the current cc65 version
+---------------------------------------------------------------------------
+
+ 1. Copyright
+
+ 2. Differences to the original version
+
+ 3. Known bugs and limitations
+
+ 4. Library
+
+ 5. Bugs
+
+
+
+
+1. Copyright
+-----------
+
+This is the original compiler copyright:
+
+--------------------------------------------------------------------------
+ -*- Mode: Text -*-
+
+ This is the copyright notice for RA65, LINK65, LIBR65, and other
+ Atari 8-bit programs. Said programs are Copyright 1989, by John R.
+ Dunning. All rights reserved, with the following exceptions:
+
+ Anyone may copy or redistribute these programs, provided that:
+
+ 1: You don't charge anything for the copy. It is permissable to
+ charge a nominal fee for media, etc.
+
+ 2: All source code and documentation for the programs is made
+ available as part of the distribution.
+
+ 3: This copyright notice is preserved verbatim, and included in
+ the distribution.
+
+ You are allowed to modify these programs, and redistribute the
+ modified versions, provided that the modifications are clearly noted.
+
+ There is NO WARRANTY with this software, it comes as is, and is
+ distributed in the hope that it may be useful.
+
+ This copyright notice applies to any program which contains
+ this text, or the refers to this file.
+
+ This copyright notice is based on the one published by the Free
+ Software Foundation, sometimes known as the GNU project. The idea
+ is the same as theirs, ie the software is free, and is intended to
+ stay that way. Everybody has the right to copy, modify, and re-
+ distribute this software. Nobody has the right to prevent anyone
+ else from copying, modifying or redistributing it.
+
+--------------------------------------------------------------------------
+
+In acknowledgment of this copyright, I will place my own changes to the
+compiler under the same copyright.
+
+However, since the library and all binutils (assembler, archiver, linker)
+are a complete rewrite, they are covered by another copyright:
+
+
+--------------------------------------------------------------------------
+
+ CC65 C Library and Binutils
+
+ (C) Copyright 1998 Ullrich von Bassewitz
+
+ COPYING CONDITIONS
+
+
+ This software is provided 'as-is', without any expressed or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not
+ be misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source
+ distribution
+
+
+--------------------------------------------------------------------------
+
+I will try to contact John, maybe he is also willing to place his sources
+under a less restrictive copyright, after all these years:-)
+
+
+
+
+2. Differences to the original version
+--------------------------------------
+
+This is a list of changes against the cc65 archives. I got the originals
+from:
+
+ http://www.umich.edu/~archive/atari/8bit/Languages/Cc65/
+
+
+
+ * Removed all assembler code from the compiler. It was unportable because
+ it made assumptions about the character set (ATASCII) and made the
+ sources hard to read and to debug.
+
+ * All programs do return an error code, so they may be used by make. All
+ programs try to remove the target file, if there were errors.
+
+ * The assembler now checks several error conditions (others still go
+ undetected - see "known bugs").
+
+ * Removed many bugs from the compiler. One error was invalid code
+ produced by the compiler that went through the assembler since the
+ assembler did not check for ranges itself.
+
+ * Removed many non-portable constructs from the compiler. Code cleanups,
+ rewrite of the function headers and more.
+
+ * New style function prototypes supported instead of the old K&R syntax.
+ The new syntax is a must, that is, the old style syntax is no longer
+ understood. As an extension, unnamed parameters may be used to avoid
+ warnings about unused parameters.
+
+ * New void type. May also be used as a function return type.
+
+ * Changed the memory management in the compiler. Use malloc/free instead
+ of the old homebrew (and unportable) stuff.
+
+ * Default character type is unsigned. This is much more what you want in
+ small systems environments, since a char is often used to represent a
+ small numerical value, and the integer promotion does the wrong thing
+ in those cases. Look at the follwing piece of code:
+
+ char c = read_char ();
+ switch (c) {
+ case 0x80: printf ("c is 0x80\n"); break;
+ default: printf ("c is something else\n"); break;
+ }
+
+ With signed chars, the code above, will *always* run into the default
+ selector. c is promoted to int, and since it is signed, 0x80 will get
+ promoted to 0xFF80 - which will select the default label. With unsigned
+ chars, the code works as intended (but note: the code works for cc65
+ but it is non portable anyway, since many other compilers have signed
+ chars by default, so be careful! Having unsigned chars is just a
+ convenience thing).
+
+ * Shorter code when using the builtin operators and the lhs of an expr
+ is a constant (e.g. expressions like "c == 0x80" are encoded two
+ bytes shorter).
+
+ * Some optimizations when pushing constants.
+
+ * Character set translation by the compiler. A new -t option was added
+ to set the target system type. Use
+
+ -t0 For no spefic target system (default)
+ -t1 For the atari (does not work completely, since I did not
+ have an ATASCII translation table).
+ -t2 Target system is C64.
+ -t3 Target system is C128.
+ -t4 Target system is ACE.
+ -t5 Target system is Plus/5.
+
+ * Dito for the linker: Allow an option to set the target system and add
+ code to the linker to produce different headers and set the correct
+ start address.
+
+ * Complete rewrite of the C library. See extra chapter.
+
+ * Many changes in the runtime library. Splitted it into more than one
+ file to allow for smaller executables if not all of the code is needed.
+
+ * Allow longer names. Now the first 12 characters are sigificant at the
+ expense of some more memory used at runtime.
+
+ * String constants are now concatenated in all places. This allows
+ things like:
+
+ fputs ("Options:\n"
+ " -b bomb computer\n"
+ " -f format hard disk\n"
+ " -k kill init\n",
+ stderr);
+
+ saving code for more than one call to the function.
+
+ * Several new macros are defined:
+
+ M6502 This one is old - don't use!
+ __CC65__ Use this instead. Defined when compiling with cc65.
+ __ATARI__ Defined when the target system is atari.
+ __CBM__ Defined when compiling for a CBM system as target.
+ __C64__ Defined when the C64 is the target system.
+ __C128__ Defined when compiling for the 128.
+ __ACE__ Defined when compiling for ACE.
+ __PLUS4__ Defined when compiling for the Plus/4.
+
+ The __CC65__ macro has the compiler version as its value, version
+ 1.0 of the compiler will define this macro as 0x100.
+
+ * The -a option is gone.
+
+ * The compiler will generate external references (via .globl) only if a
+ function is defined as extern in a module, or not defined but called
+ from a module. The old behaviour was to generate a reference for every
+ function prototype ever seen, which meant that using a header file like
+ stdio.h got most of the C library linked in, even if it was never used.
+
+ * Many new warnings added (about unused parameters, unused variables,
+ compares of unsigneds against zero, function call without prototype
+ and much more).
+
+ * Added a new compiler option (-W) to suppress all warnings.
+
+ * New internal variable __fixargs__ that gives the size of fixed
+ arguments, a function takes. This allows to work (somehow) around the
+ problem, that cc65 has the "wrong" (that is, pascal) calling order. See
+ below ("Known problems") for a discussion.
+
+ * The "empty" preprocessor directive ("#" on a line) is now ignored.
+
+ * Added a "#error" directive to force user errors.
+
+ * Optimization of the code generation. Constant parts of expressions are
+ now detected in many places where the old compiler evaluated the
+ constants at runtime.
+
+ * Allow local static variables (there was code in the original compiler for
+ that, but it did not work). Allow also initialization in this case (no
+ code for that in the original). Local static variables in the top level
+ function block have no penalty, for static variables in nested blocks, the
+ compiler generates a jump around the variable space. To eliminate this,
+ an assembler/linker with support for segments is needed.
+
+ * You cannot return a value from a void function, and must return a value
+ in a non-void function. Violations are flagged as an error.
+
+ * Typedefs added.
+
+ * The nonstandard evaluation of the NOARGC and FIXARGC macros has been
+ replaced by a smart algorithm that does the same thing automagically
+ and without user help (provided there are function prototypes).
+
+ * Function pointers may now be used to call a function without
+ dereferencing. Given a function
+
+ void f1 (void (*f2) ())
+
+ the following was valid before:
+
+ (*f2) ();
+
+ The ANSI standard allows a second form (because there's no ambiguity)
+ which is now also allowed:
+
+ f2 ();
+
+ * Pointer subtraction was completely messed up and did not work (that is,
+ subtraction of a pointer from a pointer produced wrong results).
+
+ * Local struct definitions are allowed.
+
+ * Check types in assignments, parameters for function calls and more.
+
+ * A new long type (32 bit) is available. The integer promotion rules
+ are applied if needed. This includes much more type checking and a
+ better handling of chars (they are handled as chars, not as ints, in
+ all places where this is possible).
+
+ * Integer constants now have an associated type, 'U' and 'L' modifers
+ may be used.
+
+ * The old #asm statement is gone. Instead, there's now a asm ("xxx")
+ statement that has the syntax that is defined by the C++ standard
+ (the C standard does not define an ASM statement). The string literal
+ in parenthesis is inserted in the assembler output. You may also
+ use __asm__ instead of asm (see below).
+
+ * Allow // comments.
+
+ * New compiler option -A (ANSI) that disables several extensions (asm
+ directive, // comments, unnamed function parameters) and also defines
+ a macro named __STRICT_ANSI__. The header files will exclude some
+ non-ANSI functions if __STRICT_ANSI__ is defined (that is, -A is given
+ on the command line).
+ -A will not disable the __asm__ directive (identifiers starting with
+ __ are in the namespace of the implementation).
+
+ * Create optimized code if the address of a variable is a constant. This
+ may be achieved by constructs like "*(char*)0x200 = 0x01" and is used
+ to access absolute memory locations. The compiler detects this case
+ also if structs or arrays are involved and generates direct stores and
+ fetches.
+
+
+
+3. Known problems
+-----------------
+
+ * No floats.
+
+ * Only simple automatic variables may be initialized (no arrays).
+
+ * "Wrong" order of arguments on the stack. The arguments are pushed in
+ the order, the arguments are parsed. That means that the va_xxx macros
+ in stdarg.h are ok (they work as expected), but the fixed parameters of
+ a function with a variable argument list do not match and must be
+ determined with the (non-standard) va_fix macro.
+
+ Using the __fixargs__ kludge, it is possible to write standard conform
+ va_xxx macros to work with variable sized argument lists. However, the
+ fixed parameters in the function itself usually have the wrong values,
+ because the order of the arguments on the stack is reversed compared to
+ a stock C compiler. Pushing the args the other way round requires much
+ work and a more elaborated intermediate code than cc65 has.
+
+ To understand the problem, have a look at this (non working!) sprintf
+ function:
+
+ int sprintf (char* buf, char* format, ...)
+ /* Non working version */
+ {
+ int count;
+ va_list ap;
+ va_start (ap, format);
+ count = vsprintf (buf, format, ap);
+ va_end (ap);
+ return count;
+ }
+
+ The problem here is in the "format" and "buf" parameters. They do (in
+ most cases) not contain, what the caller gave us as arguments. To
+ access the "real" arguments, use the va_fix macro. It is only valid
+ before the first call to va_arg, and takes the va_list and the number
+ of the fixed argument as parameters. So the right way would be
+
+ int sprintf (char* buf, char* format, ...)
+ /* Working version */
+ {
+ int count;
+ va_list ap;
+ va_start (ap, format);
+ count = vsprintf (va_fix (ap, 1), va_fix (ap, 2), ap);
+ va_end (ap);
+ return count;
+ }
+
+ The fixed parameter are obtained by using the va_fix macro with the
+ number of the parameter given as second argument. Beware: Since the
+ fixed arguments declared are usually one of the additional parameters,
+ the following code, which tries to be somewhat portable, does *not*
+ work. The assignment will overwrite the other parameters instead,
+ causing unexpected results:
+
+ int sprintf (char* buf, char* format, ...)
+ /* Non working version */
+ {
+ int count;
+ va_list ap;
+ va_start (ap, format);
+ #ifdef __CC65__
+ buf = va_fix (ap, 1);
+ format = va_fix (ap, 2);
+ #endif
+ count = vsprintf (buf, format, ap);
+ va_end (ap);
+ return count;
+ }
+
+ To write a portable version of sprintf, use code like this instead:
+
+ int sprintf (char* buf, char* format, ...)
+ /* Working version */
+ {
+ int count;
+ va_list ap;
+ va_start (ap, format);
+ #ifdef __CC65__
+ count = vsprintf (va_fix (ap, 1), va_fix (ap, 2), ap);
+ #else
+ count = vsprintf (buf, format, ap);
+ #endif
+ va_end (ap);
+ return count;
+ }
+
+ I know, va_fix is a kludge, but at least it *is* possible to write
+ functions with variable sized argument lists in a comfortable manner.
+
+ * The assembler still accepts lots of illegal stuff without an error (and
+ creates wrong code). Be careful!
+
+ * When starting a compiled program twice on the C64 (or 128), you may get
+ other results or the program may even crash. This is because static
+ variables do not have their startup values, they were changed in the
+ first run.
+
+ * There's only *one* symbol table level. It is - via a flag - used for both,
+ locals and global symbols. However, if you have variables in nested
+ blocks, the names may collide with the ones in the upper block. I will
+ probably add real symbol tables some time to remove this problem.
+
+ * Variables in nested blocks are handled inefficiently, especially in loops.
+ The frame on the stack is allocated and deallocated for each loop
+ iteration. There's no way around this, since the compiler has not enough
+ memory to hold a complete function body in memory (it would be able to
+ backpatch the frame generating code on function entry).
+
+
+
+
+4. Library
+----------
+
+The C library is a complete rewrite and has nothing in common with the old
+Atari stuff. When rewriting the library, I was guided by the following
+rules:
+
+ * Use standard conform functions as far as possible. In addition, if
+ there's a ANSI-C compatible function, it should act as defined in the
+ ANSI standard. If if does not act as defined, this is an error.
+
+ * Do not use non-standard functions if the functionality of those
+ functions is covered by a standard function. Use exceptions only, if
+ there is a non-ANSI function that is very popular (example: itoa).
+
+ * Use new style prototpyes and header files.
+
+ * Make the library portable. For example, the complete stdio stuff is
+ based on only four system dependent functions:
+
+ open, read, write, close
+
+ So, if you rewrite these functions for a new system, all others
+ (printf, fprintf, fgets, fputc ...) will work, too.
+
+ * Do not expect a common character set. Unfortunately, I was not able to
+ be completely consequent in this respect. C sources are no problem
+ since the compiler does character translation, but the assembler
+ sources make assumptions about the following characters:
+
+ 0 --> code $30
+ + --> code $2B
+ - --> code $2D
+
+ All other functions (especially the isxxx ones) are table driven, so
+ only the classification table is system dependent.
+
+
+The first port was for the ACE operating system. The current version has also
+support for the C64, the C128 and the Plus/4 in native mode. The ACE port has
+disk support but no conio module, all others don't have disk support but
+direct console I/O.
+
+Currently the following limitations the are known:
+
+ * getwd (ace) does not work. I get an error (carry flag) with an error
+ code of zero (aceErrStopped). Maybe my code is wrong...
+
+ * The error codes are currently system error codes. They should be
+ translated to something system independent. The ace codes are a good
+ starting point. However, I don't like the idea, that zero is a valid
+ error code, and some other codes are missing ("invalid parameter" and
+ more). As soon as this is done, it is also possible to write a
+ strerror() function to give more descriptive error messages to the
+ user.
+
+ * Many functions not very good tested.
+
+ * The printf and heap functions are way too big. Rewritting _printf
+ and malloc/free in assembler will probably squeeze 2K out of the
+ code.
+
+ * The isxxx functions do not handle EOF correctly. This is probably
+ a permanent restriction, even if it is non-standard. It would require
+ extra code in each of the isxxx functions, since EOF is defined as -1
+ and cannot be handled effectively with the table approach and 8 bit
+ index registers.
+
+ * The strcspn, strpbrk and strspn functions have a string length limitation
+ of 256 for the second argument. This is usually not a problem since the
+ second argument gives a character set, and a character set cannot be
+ larger than 256 chars for all known 6502 systems.
+
+
+
+
+5. Bugs
+-------
+
+Please note that the compiler and the libraries are beta! Send bug reports to
+uz@musoftware.de.
+
+
+
+
--- /dev/null
+
+If you have got the source package, see
+
+ doc/compile.txt
+
+for instructions how to compile the stuff for the different systems.
+
+
+If you have a binary package: Have a look in the doc directory for
+information on how to use the tools. If you are new to cc65, the file
+intro.txt may be of interest to you.
+
+To avoid having to mess with paths, you may want to set the environment
+variables
+
+ CC65_LIB
+ and CC65_INC
+
+to the directory containing the libraries and the system include files
+respectively. If you have installed cc65 in C:\cc65 (assuming a DOS or
+Windows system), you should use
+
+ set CC65_LIB=c:\cc65\lib
+ and set CC65_INC=c:\cc65\include
+
+Unix people probably know, how to translate these lines into the
+appropriate Unix commands:-)
+
+Have fun!
+
+
+ Uz
+
+
--- /dev/null
+
+Documentation overview:
+
+
+ ar65.txt - Describes the ar65 archiver.
+
+ debugging.txt - Debug programs using the VICE emulator.
+
+ ca65.txt - Describes the ca65 macro assembler.
+
+ cc65.txt - Describes the cc65 C compiler.
+
+ cl65.txt - Describes the cl65 compile & link utility.
+
+ coding.txt - Containes hints on creating the most effective code
+ with cc65.
+
+ intro.txt - Describes the use of the tools by a short "hello world"
+ example.
+
+ ld65.txt - Describes the ld65 linker.
+
+ library.txt - Describes the cc65 runtime and C libraries.
+
+ newvers.txt - Somewhat outdated. Lists the differences between the
+ current cc65 release and the original atari version
+ created by J.R Dunning.
+
+ readme.txt - This file.
+
+
--- /dev/null
+/*
+ * 6502.h
+ *
+ * Ullrich von Bassewitz, 20.09.1998
+ */
+
+
+
+#ifndef _6502_H
+#define _6502_H
+
+
+
+/* Possible returns of getcpu() */
+#define CPU_6502 0
+#define CPU_65C02 1
+#define CPU_65816 2
+
+unsigned char getcpu (void);
+/* Detect the CPU the program is running on */
+
+
+
+/* Macros for CPU instructions */
+#define BRK() __asm__ ("\tbrk")
+#define CLI() __asm__ ("\tcli")
+#define SEI() __asm__ ("\tsei")
+#define JAM() __asm__ ("\t.byte\t$02")
+
+
+
+/* Struct that holds the registers for the sys function */
+struct regs {
+ unsigned char a; /* A register value */
+ unsigned char x; /* X register value */
+ unsigned char y; /* Y register value */
+ unsigned char flags; /* Flags value */
+ unsigned pc; /* Program counter */
+};
+
+/* Defines for the flags in the regs structure */
+#define F_NEG 0x80 /* N flag */
+#define F_OVF 0x40 /* V flag */
+#define F_BRK 0x10 /* B flag */
+#define F_DEC 0x08 /* D flag */
+#define F_IEN 0x04 /* I flag */
+#define F_ZERO 0x02 /* Z flag */
+#define F_CARRY 0x01 /* C flag */
+
+/* Function to call any machine language subroutine. All registers in the
+ * regs structure are passed into the routine and the results are passed
+ * out. Some of the flags are ignored on input. The called routine must
+ * end with an RTS.
+ */
+void __fastcall__ _sys (struct regs* r);
+
+
+
+/* Set and reset the break vector. The given user function is called if
+ * a break occurs. The values of the registers may be read from the brk_...
+ * variables. The value in brk_pc will point to the address that contains
+ * the brk instruction.
+ * The set_brk function will install an exit handler that will reset the
+ * vector if the program ends.
+ */
+
+extern unsigned char brk_a; /* A register value */
+extern unsigned char brk_x; /* X register value */
+extern unsigned char brk_y; /* Y register value */
+extern unsigned char brk_sr; /* Status register */
+extern unsigned brk_pc; /* PC value */
+
+typedef void (*brk_handler) (void);
+/* Type of the break handler */
+
+void __fastcall__ set_brk (brk_handler f);
+/* Set the break vector to the given address, return the old address */
+
+void reset_brk (void);
+/* Reset the break vector to the original value */
+
+
+
+/* End of 6502.h */
+#endif
+
+
+
--- /dev/null
+/*
+ * _6525.h
+ *
+ * Ullrich von Bassewitz, 22.09.1998
+ *
+ * Internal include file, do not use directly.
+ *
+ */
+
+
+
+#ifndef __6525_H
+#define __6525_H
+
+
+
+/* Define a structure with the 6525 register offsets. The shadow registers
+ * (if port C is unused) are currently not implemented, we would need a
+ * union to do that, however that would introduce an additional name.
+ */
+struct __6525 {
+ unsigned char pra; /* Port register A */
+ unsigned char prb; /* Port register B */
+ unsigned char prc; /* Port register C */
+ unsigned char ddra; /* Data direction register A */
+ unsigned char ddrb; /* Data direction register B */
+ unsigned char ddrc; /* Data direction register C */
+ unsigned char cr; /* Control register */
+ unsigned char air; /* Active interrupt register */
+};
+
+
+
+/* End of _6525.h */
+#endif
+
+
+
--- /dev/null
+/*
+ * _6526.h
+ *
+ * Ullrich von Bassewitz, 22.09.1998
+ *
+ * Internal include file, do not use directly.
+ *
+ */
+
+
+
+#ifndef __6526_H
+#define __6526_H
+
+
+
+/* Define a structure with the 6526 register offsets */
+struct __6526 {
+ unsigned char pra; /* Port register A */
+ unsigned char prb; /* Port register B */
+ unsigned char ddra; /* Data direction register A */
+ unsigned char ddrb; /* Data direction register B */
+ unsigned char ta_lo; /* Timer A, low byte */
+ unsigned char ta_hi; /* Timer A, high byte */
+ unsigned char tb_lo; /* Timer B, low byte */
+ unsigned char tb_hi; /* Timer B, high byte */
+ unsigned char tod_10; /* TOD, 1/10 sec. */
+ unsigned char tod_sec; /* TOD, seconds */
+ unsigned char tod_min; /* TOD, minutes */
+ unsigned char tod_hour; /* TOD, hours */
+ unsigned char sdr; /* Serial data register */
+ unsigned char icr; /* Interrupt control register */
+ unsigned char cra; /* Control register A */
+ unsigned char crb; /* Control register B */
+};
+
+
+
+/* End of _6526.h */
+#endif
+
+
+
--- /dev/null
+/*
+ * _6545.h
+ *
+ * Ullrich von Bassewitz, 22.09.1998
+ *
+ * Internal include file, do not use directly.
+ *
+ */
+
+
+
+#ifndef __6545_H
+#define __6545_H
+
+
+
+/* Define a structure with the 6545 register offsets */
+struct __6545 {
+ unsigned char ctrl; /* Control register */
+ unsigned char data; /* Data register */
+};
+
+
+
+/* End of _6545.h */
+#endif
+
+
+
--- /dev/null
+/*
+ * _6551.h
+ *
+ * Ullrich von Bassewitz, 22.09.1998
+ *
+ * Internal include file, do not use directly.
+ *
+ */
+
+
+
+#ifndef __6551_H
+#define __6551_H
+
+
+
+/* Define a structure with the 6551 register offsets */
+struct __6551 {
+ unsigned char data; /* Data register */
+ unsigned char status; /* Status register */
+ unsigned char cmd; /* Command register */
+ unsigned char ctrl; /* Control register */
+};
+
+
+
+/* End of _6551.h */
+#endif
+
+
+
--- /dev/null
+/*
+ * _antic.h
+ *
+ * Freddy Offenga, 4/9/2000
+ *
+ * Internal include file, do not use directly.
+ *
+ */
+
+
+#ifndef __ANTIC_H
+#define __ANTIC_H
+
+
+/* Define a structure with the antic register offsets */
+struct __antic {
+ unsigned char dmactl; /* direct memory access control */
+ unsigned char chactl; /* character mode control */
+ unsigned char dlistl; /* display list pointer low-byte */
+ unsigned char dlisth; /* display list pointer high-byte */
+ unsigned char hscrol; /* horizontal scroll enable */
+ unsigned char vscrol; /* vertical scroll enable */
+ unsigned char unuse0; /* unused */
+ unsigned char pmbase; /* msb of p/m base address */
+ unsigned char unuse1; /* unused */
+ unsigned char chbase; /* character base address */
+ unsigned char wsync; /* wait for horizontal synchronization */
+ unsigned char vcount; /* vertical line counter */
+ unsigned char penh; /* light pen horizontal position */
+ unsigned char penv; /* light pen vertical position */
+ unsigned char nmien; /* non-maskable interrupt enable */
+ unsigned char nmires; /* nmi reset/status */
+};
+
+/* End of _antic.h */
+#endif
+
--- /dev/null
+/*
+ * _gtia.h
+ *
+ * Freddy Offenga, 4/9/2000
+ *
+ * Internal include file, do not use directly.
+ *
+ */
+
+
+#ifndef __GTIA_H
+#define __GTIA_H
+
+
+/* Define a structure with the gtia register offsets */
+struct __gtia_write {
+ unsigned char hposp0; /* horizontal position player 0 */
+ unsigned char hposp1; /* horizontal position player 1 */
+ unsigned char hposp2; /* horizontal position player 2 */
+ unsigned char hposp3; /* horizontal position player 3 */
+ unsigned char hposm0; /* horizontal position missile 0 */
+ unsigned char hposm1; /* horizontal position missile 1 */
+ unsigned char hposm2; /* horizontal position missile 2 */
+ unsigned char hposm3; /* horizontal position missile 3 */
+ unsigned char sizep0; /* size of player 0 */
+ unsigned char sizep1; /* size of player 1 */
+ unsigned char sizep2; /* size of player 2 */
+ unsigned char sizep3; /* size of player 3 */
+ unsigned char sizem; /* size of missiles */
+ unsigned char grafp0; /* graphics shape player 0 */
+ unsigned char grafp1; /* graphics shape player 1 */
+ unsigned char grafp2; /* graphics shape player 2 */
+ unsigned char grafp3; /* graphics shape player 3 */
+ unsigned char grafm; /* graphics shape missiles */
+ unsigned char colpm0; /* color player and missile 0 */
+ unsigned char colpm1; /* color player and missile 1 */
+ unsigned char colpm2; /* color player and missile 2 */
+ unsigned char colpm3; /* color player and missile 3 */
+ unsigned char colpf0; /* color playfield 0 */
+ unsigned char colpf1; /* color playfield 1 */
+ unsigned char colpf2; /* color playfield 2 */
+ unsigned char colpf3; /* color playfield 3 */
+ unsigned char colbk; /* color background */
+ unsigned char prior; /* priority selection */
+ unsigned char vdelay; /* vertical delay */
+ unsigned char gractl; /* stick/paddle latch, p/m control */
+ unsigned char hitclr; /* clear p/m collision */
+ unsigned char consol; /* console buttons */
+};
+
+/* Define a structure with the gtia register offsets */
+struct __gtia_read {
+ unsigned char m0pf; /* missile 0 to playfield collision */
+ unsigned char m1pf; /* missile 1 to playfield collision */
+ unsigned char m2pf; /* missile 2 to playfield collision */
+ unsigned char m3pf; /* missile 3 to playfield collision */
+ unsigned char p0pf; /* player 0 to playfield collision */
+ unsigned char p1pf; /* player 1 to playfield collision */
+ unsigned char p2pf; /* player 2 to playfield collision */
+ unsigned char p3pf; /* player 3 to playfield collision */
+ unsigned char m0pl; /* missile 0 to player collision */
+ unsigned char m1pl; /* missile 1 to player collision */
+ unsigned char m2pl; /* missile 2 to player collision */
+ unsigned char m3pl; /* missile 3 to player collision */
+ unsigned char p0pl; /* player 0 to player collision */
+ unsigned char p1pl; /* player 1 to player collision */
+ unsigned char p2pl; /* player 2 to player collision */
+ unsigned char p3pl; /* player 3 to player collision */
+ unsigned char trig0; /* joystick trigger 0 */
+ unsigned char trig1; /* joystick trigger 1 */
+ unsigned char trig2; /* joystick trigger 2 */
+ unsigned char trig3; /* joystick trigger 3 */
+ unsigned char pal; /* pal/ntsc flag */
+};
+
+/* End of _gtia.h */
+#endif
+
--- /dev/null
+/*
+ * _pbi.h
+ *
+ * Freddy Offenga, 4/25/2000
+ *
+ * Internal include file, do not use directly.
+ * Atari parallel bus definitions
+ *
+ */
+
+
+#ifndef __PBI_H
+#define __PBI_H
+
+/* parallel bus interface area */
+#define PBI ((unsigned char*)0xD100)
+
+/* parallel device IRQ status */
+#define PDVI ((unsigned char*)0xD1FF)
+
+/* parallel device select */
+#define PDVS ((unsigned char*)0xD1FF)
+
+/* parallel bus interface RAM area */
+#define PBIRAM ((unsigned char*)0xD600)
+
+/* parallel device ID 1 */
+#define PDID1 ((unsigned char*)0xD803)
+
+/* parallel device I/O vector */
+#define PDIDV ((unsigned char*)0xD805)
+
+/* parallel device IRQ vector */
+#define PDIRQV ((unsigned char*)0xD808)
+
+/* parallel device ID 2 */
+#define PDID2 ((unsigned char*)0xD80B)
+
+/* parallel device vector table */
+#define PDVV ((unsigned char*)0xD80D)
+
+/* End of _pbi.h */
+#endif
+
--- /dev/null
+/*
+ * _pia.h
+ *
+ * Freddy Offenga, 4/9/2000
+ *
+ * Internal include file, do not use directly.
+ *
+ */
+
+
+#ifndef __PIA_H
+#define __PIA_H
+
+
+/* Define a structure with the pia register offsets */
+struct __pia {
+ unsigned char porta; /* port A data r/w */
+ unsigned char portb; /* port B data r/w */
+ unsigned char pactl; /* port A control */
+ unsigned char pbctl; /* port B control */
+};
+
+/* End of _pia.h */
+#endif
+
--- /dev/null
+/*
+ * _pokey.h
+ *
+ * Freddy Offenga, 4/9/2000
+ *
+ * Internal include file, do not use directly.
+ *
+ */
+
+
+#ifndef __POKEY_H
+#define __POKEY_H
+
+
+/* Define a structure with the pokey register offsets */
+struct __pokey_write {
+ unsigned char audf1; /* audio channel #1 frequency */
+ unsigned char audc1; /* audio channel #1 control */
+ unsigned char audf2; /* audio channel #2 frequency */
+ unsigned char audc2; /* audio channel #2 control */
+ unsigned char audf3; /* audio channel #3 frequency */
+ unsigned char audc3; /* audio channel #3 control */
+ unsigned char audf4; /* audio channel #4 frequency */
+ unsigned char audc4; /* audio channel #4 control */
+ unsigned char audctl; /* audio control */
+ unsigned char stimer; /* start pokey timers */
+ unsigned char skrest; /* reset serial port status reg. */
+ unsigned char potgo; /* start paddle scan sequence */
+ unsigned char unuse1; /* unused */
+ unsigned char serout; /* serial port data output */
+ unsigned char irqen; /* interrupt request enable */
+ unsigned char skctl; /* serial port control */
+};
+struct __pokey_read {
+ unsigned char pot0; /* paddle 0 value */
+ unsigned char pot1; /* paddle 1 value */
+ unsigned char pot2; /* paddle 2 value */
+ unsigned char pot3; /* paddle 3 value */
+ unsigned char pot4; /* paddle 4 value */
+ unsigned char pot5; /* paddle 5 value */
+ unsigned char pot6; /* paddle 6 value */
+ unsigned char pot7; /* paddle 7 value */
+ unsigned char allpot; /* eight paddle port status */
+ unsigned char kbcode; /* keyboard code */
+ unsigned char random; /* random number generator */
+ unsigned char unuse2; /* unused */
+ unsigned char unuse3; /* unused */
+ unsigned char serin; /* serial port input */
+ unsigned char irqst; /* interrupt request status */
+ unsigned char skstat; /* serial port status */
+};
+
+/* End of _pokey.h */
+#endif
+
--- /dev/null
+/*
+ * _sid.h
+ *
+ * Ullrich von Bassewitz, 22.09.1998
+ *
+ * Internal include file, do not use directly.
+ *
+ */
+
+
+
+#ifndef __SID_H
+#define __SID_H
+
+
+
+/* Define a structure with the sid register offsets */
+struct __sid_voice {
+ unsigned freq; /* Frequency */
+ unsigned pw; /* Pulse width */
+ unsigned char ctrl; /* Control register */
+ unsigned char ad; /* Attack/decay */
+ unsigned char sr; /* Sustain/release */
+};
+struct __sid {
+ struct __sid_voice v1; /* Voice 1 */
+ struct __sid_voice v2; /* Voice 2 */
+ struct __sid_voice v3; /* Voice 3 */
+ unsigned flt_freq; /* Filter frequency */
+ unsigned char flt_ctrl; /* Filter control register */
+ unsigned char amp; /* Amplitude */
+ unsigned char ad1; /* A/D converter 1 */
+ unsigned char noise; /* Noise generator */
+ unsigned char read3; /* Value of voice 3 */
+};
+
+
+
+/* End of _sid.h */
+#endif
+
+
+
--- /dev/null
+/*
+ * _vdc.h
+ *
+ * Ullrich von Bassewitz, 22.09.1998
+ *
+ * Internal include file, do not use directly.
+ *
+ */
+
+
+
+#ifndef __VDC_H
+#define __VDC_H
+
+
+
+/* Define a structure with the vdc register offsets */
+struct __vdc {
+ unsigned char ctrl; /* Control register */
+ unsigned char data; /* Data register */
+};
+
+
+
+/* End of _vdc.h */
+#endif
+
+
+
--- /dev/null
+/*
+ * _vic.h
+ *
+ * Ullrich von Bassewitz, 12.08.1998
+ *
+ * Internal include file, do not use directly.
+ *
+ */
+
+
+
+#ifndef __VIC_H
+#define __VIC_H
+
+
+
+/* Define a structure with the vic register offsets */
+struct __vic {
+ unsigned char spr0_x; /* Sprite 0, X coordinate */
+ unsigned char spr0_y; /* Sprite 0, Y coordinate */
+ unsigned char spr1_x; /* Sprite 1, X coordinate */
+ unsigned char spr1_y; /* Sprite 1, Y coordinate */
+ unsigned char spr2_x; /* Sprite 2, X coordinate */
+ unsigned char spr2_y; /* Sprite 2, Y coordinate */
+ unsigned char spr3_x; /* Sprite 3, X coordinate */
+ unsigned char spr3_y; /* Sprite 3, Y coordinate */
+ unsigned char spr4_x; /* Sprite 4, X coordinate */
+ unsigned char spr4_y; /* Sprite 4, Y coordinate */
+ unsigned char spr5_x; /* Sprite 5, X coordinate */
+ unsigned char spr5_y; /* Sprite 5, Y coordinate */
+ unsigned char spr6_x; /* Sprite 6, X coordinate */
+ unsigned char spr6_y; /* Sprite 6, Y coordinate */
+ unsigned char spr7_x; /* Sprite 7, X coordinate */
+ unsigned char spr7_y; /* Sprite 7, Y coordinate */
+ unsigned char spr_hi_x; /* High bits of X coordinate */
+ unsigned char ctrl1; /* Control register 1 */
+ unsigned char rasterline; /* Current raster line */
+ unsigned char strobe_x; /* Light pen, X position */
+ unsigned char strobe_y; /* Light pen, Y position */
+ unsigned char spr_ena; /* Enable sprites */
+ unsigned char ctrl2; /* Control register 2 */
+ unsigned char spr_exp_x; /* Expand sprites in X dir */
+ unsigned char addr; /* Address of chargen and video ram */
+ unsigned char irr; /* Interrupt request register */
+ unsigned char imr; /* Interrupt mask register */
+ unsigned char spr_bg_prio; /* Priority to background */
+ unsigned char spr_mcolor; /* Sprite multicolor bits */
+ unsigned char spr_exp_y; /* Expand sprites in Y dir */
+ unsigned char spr_coll; /* Sprite/sprite collision reg */
+ unsigned char spr_bg_coll; /* Sprite/background collision reg */
+ unsigned char bordercolor; /* Border color */
+ unsigned char bgcolor0; /* Background color 0 */
+ unsigned char bgcolor1; /* Background color 1 */
+ unsigned char bgcolor2; /* Background color 2 */
+ unsigned char bgcolor3; /* Background color 3 */
+ unsigned char spr_mcolor0; /* Color 0 for multicolor sprites */
+ unsigned char spr_mcolor1; /* Color 1 for multicolor sprites */
+ unsigned char spr0_color; /* Color sprite 0 */
+ unsigned char spr1_color; /* Color sprite 1 */
+ unsigned char spr2_color; /* Color sprite 2 */
+ unsigned char spr3_color; /* Color sprite 3 */
+ unsigned char spr4_color; /* Color sprite 4 */
+ unsigned char spr5_color; /* Color sprite 5 */
+ unsigned char spr6_color; /* Color sprite 6 */
+ unsigned char spr7_color; /* Color sprite 7 */
+
+ /* The following ones are only valid in the C128: */
+ unsigned char x_kbd; /* Additional keyboard lines */
+ unsigned char clock; /* Clock switch bit */
+};
+
+
+
+/* End of _vic.h */
+#endif
+
+
+
--- /dev/null
+/*
+ * ace.h
+ *
+ * Ullrich von Bassewitz, 06.06.1998
+ *
+ */
+
+
+
+#ifndef _ACE_H
+#define _ACE_H
+
+
+
+#ifndef _STDDEF_H
+#include <stddef.h>
+#endif
+
+
+
+struct aceDirentBuf {
+ unsigned long ad_size; /* Size in bytes */
+ unsigned char ad_date [8]; /* YY:YY:MM:DD:HH:MM:SS:TW */
+ char ad_type [4]; /* File type as ASCIIZ string */
+ unsigned char ad_flags; /* File flags */
+ unsigned char ad_usage; /* More flags */
+ unsigned char ad_namelen; /* Length of name */
+ char ad_name [17]; /* Name itself, ASCIIZ */
+};
+
+int aceDirOpen (char* dir);
+int aceDirClose (int handle);
+int aceDirRead (int handle, struct aceDirentBuf* buf);
+
+/* Type of an ACE key. Key in low byte, shift mask in high byte */
+typedef unsigned int aceKey;
+
+/* #defines for the shift mask returned by aceConGetKey */
+#define aceSH_KEY 0x00FF /* Mask key itself */
+#define aceSH_MASK 0xFF00 /* Mask shift mask */
+#define aceSH_EXT 0x2000 /* Extended key */
+#define aceSH_CAPS 0x1000 /* Caps lock key */
+#define aceSH_ALT 0x0800 /* Alternate key */
+#define aceSH_CTRL 0x0400 /* Ctrl key */
+#define aceSH_CBM 0x0200 /* Commodore key */
+#define aceSH_SHIFT 0x0100 /* Shift key */
+
+/* #defines for the options in aceConSetOpt/aceConGetOpt */
+#define aceOP_PUTMASK 1 /* Console put mask */
+#define aceOP_CHARCOLOR 2 /* Character color */
+#define aceOP_CHARATTR 3 /* Character attribute */
+#define aceOP_FILLCOLOR 4 /* Fill color */
+#define aceOP_FILLATTR 5 /* Fill attribute */
+#define aceOP_CRSCOLOR 6 /* Cursor color */
+#define aceOP_CRSWRAP 7 /* Force cursor wrap */
+#define aceOP_SHSCROLL 8 /* Shift keys for scrolling */
+#define aceOP_MOUSCALE 9 /* Mouse scaling */
+#define aceOP_RPTDELAY 10 /* Key repeat delay */
+#define aceOP_RPTRATE 11 /* Key repeat rate */
+
+/* Console functions */
+void aceConWrite (char* buf, size_t count);
+void aceConPutLit (int c);
+void aceConPos (unsigned x, unsigned y);
+void aceConGetPos (unsigned* x, unsigned* y);
+unsigned aceConGetX (void);
+unsigned aceConGetY (void);
+char* aceConInput (char* buf, unsigned initial);
+int aceConStopKey (void);
+aceKey aceConGetKey (void);
+int aceConKeyAvail (aceKey* key);
+void aceConKeyMat (char* matrix);
+void aceConSetOpt (unsigned char opt, unsigned char val);
+int aceConGetOpt (unsigned char opt);
+
+/* Misc stuff */
+int aceMiscIoPeek (unsigned addr);
+void aceMiscIoPoke (unsigned addr, unsigned char val);
+
+
+
+/* End of ace.h */
+#endif
+
+
+
--- /dev/null
+/*
+ * apple2.h
+ *
+ * Written by Kevin Ruland.
+ */
+
+
+
+#ifndef _APPLE2_H
+#define _APPLE2_H
+
+
+
+/* Color Defines
+ * Since Apple2 does not support color text these defines are only
+ * used to get the library to compile correctly. They should not be used
+ * in user code
+ */
+#define COLOR_BLACK 0x00
+#define COLOR_WHITE 0x01
+
+
+
+/* Characters codes */
+#define CH_DEL 0x7F
+#define CH_ESC 0x1B
+#define CH_CURS_UP 0x0B
+#define CH_CURS_DOWN 0x0A
+
+/* These are defined to be OpenApple + NumberKey */
+#define CH_F1 0xB1
+#define CH_F2 0xB2
+#define CH_F3 0xB3
+#define CH_F4 0xB4
+#define CH_F5 0xB5
+#define CH_F6 0xB6
+#define CH_F7 0xB7
+#define CH_F8 0xB8
+#define CH_F9 0xB9
+#define CH_F10 0xB0
+
+#define CH_ULCORNER '+'
+#define CH_URCORNER '+'
+#define CH_LLCORNER '+'
+#define CH_LRCORNER '+'
+#define CH_TTEE '+'
+#define CH_BTEE '+'
+#define CH_LTEE '+'
+#define CH_RTEE '+'
+#define CH_CROSS '+'
+
+
+
+/* End of apple2.h */
+#endif
+
+
+
--- /dev/null
+/*
+ * assert.h
+ *
+ * Ullrich von Bassewitz, 06.06.1998
+ *
+ */
+
+
+
+#ifndef _ASSERT_H
+#define _ASSERT_H
+
+
+
+#undef assert
+#ifdef NDEBUG
+# define assert(expr)
+#else
+extern void _afailed (const char*, unsigned);
+# define assert(expr) if ((expr) == 0) _afailed (__FILE__, __LINE__)
+#endif
+
+
+
+/* End of assert.h */
+#endif
+
+
+
--- /dev/null
+/*
+ * atari.h
+ *
+ * Contributing authors:
+ * Mark Keates
+ * Freddy Offenga
+ * Christian Groessler
+ */
+
+#ifndef _ATARI_H
+#define _ATARI_H
+
+/* Color Defines */
+#define COLOR_BLACK 0x00
+#define COLOR_WHITE 0x0E
+
+/* Characters codes */
+#define CH_DEL 0xFE
+#define CH_ESC 0x1B
+#define CH_CURS_UP 28
+#define CH_CURS_DOWN 29
+#define CH_CURS_LEFT 30
+#define CH_CURS_RIGHT 31
+
+#define CH_TAB 0x7F /* tabulator */
+#define CH_EOL 0x0B /* end-of-line marker */
+#define CH_CLR 0x7D /* clear screen */
+#define CH_BEL 0xFD /* bell */
+#define CH_RUBOUT 0x7E /* back space (rubout) */
+#define CH_DELLINE 0x9C /* delete line */
+#define CH_INSLINE 0x9D /* insert line */
+
+/* These are defined to be Atari + NumberKey */
+#define CH_F1 177
+#define CH_F2 178
+#define CH_F3 179
+#define CH_F4 180
+#define CH_F5 181
+#define CH_F6 182
+#define CH_F7 183
+#define CH_F8 184
+#define CH_F9 185
+#define CH_F10 176
+
+#define CH_ULCORNER 0x11
+#define CH_URCORNER 0x05
+#define CH_LLCORNER 0x1A
+#define CH_LRCORNER 0x03
+#define CH_TTEE 0x17
+#define CH_BTEE 0x18
+#define CH_LTEE 0x01
+#define CH_RTEE 0x04
+#define CH_CROSS 0x19
+#define CH_HLINE 0x12
+#define CH_VLINE 0x16
+
+/* Define hardware */
+#include <_gtia.h>
+#define GTIA (*(struct __gtia_write*)0xD000)
+#define GTIA (*(struct __gtia_read*)0xD000)
+
+#include <_pbi.h>
+
+#include <_pokey.h>
+#define POKEY (*(struct __pokey_write*)0xD200)
+#define POKEY (*(struct __pokey_read*)0xD200)
+
+#include <_pia.h>
+#define PIA (*(struct __pia*)0xD300)
+
+#include <_antic.h>
+#define ANTIC (*(struct __antic*)0xD400)
+
+/* End of atari.h */
+#endif
--- /dev/null
+/*
+ * c128.h
+ *
+ * Ullrich von Bassewitz, 12.08.1998
+ */
+
+
+
+#ifndef _C128_H
+#define _C128_H
+
+
+
+/* Additional key defines */
+#define CH_F1 133
+#define CH_F2 137
+#define CH_F3 134
+#define CH_F4 138
+#define CH_F5 135
+#define CH_F6 139
+#define CH_F7 136
+#define CH_F8 140
+
+
+
+/* Color defines */
+#define COLOR_BLACK 0x00
+#define COLOR_WHITE 0x01
+#define COLOR_RED 0x02
+#define COLOR_CYAN 0x03
+#define COLOR_VIOLET 0x04
+#define COLOR_GREEN 0x05
+#define COLOR_BLUE 0x06
+#define COLOR_YELLOW 0x07
+#define COLOR_ORANGE 0x08
+#define COLOR_BROWN 0x09
+#define COLOR_LIGHTRED 0x0A
+#define COLOR_GRAY1 0x0B
+#define COLOR_GRAY2 0x0C
+#define COLOR_LIGHTGREEN 0x0D
+#define COLOR_LIGHTBLUE 0x0E
+#define COLOR_GRAY3 0x0F
+
+
+
+/* Define hardware */
+#include <_vic.h>
+#define VIC (*(struct __vic*)0xD000)
+
+#include <_sid.h>
+#define SID (*(struct __sid*)0xD400)
+
+#include <_6526.h>
+#define CIA1 (*(struct __6526*)0xDC00)
+#define CIA2 (*(struct __6526*)0xDD00)
+
+
+
+/* Define special memory areas */
+#define COLOR_RAM ((unsigned char*)0xD800)
+
+
+
+/* End of c128.h */
+#endif
+
+
+
--- /dev/null
+/*
+ * c64.h
+ *
+ * Ullrich von Bassewitz, 12.08.1998
+ */
+
+
+
+#ifndef _C64_H
+#define _C64_H
+
+
+
+/* Additional key defines */
+#define CH_F1 133
+#define CH_F2 137
+#define CH_F3 134
+#define CH_F4 138
+#define CH_F5 135
+#define CH_F6 139
+#define CH_F7 136
+#define CH_F8 140
+
+
+
+/* Color defines */
+#define COLOR_BLACK 0x00
+#define COLOR_WHITE 0x01
+#define COLOR_RED 0x02
+#define COLOR_CYAN 0x03
+#define COLOR_VIOLET 0x04
+#define COLOR_GREEN 0x05
+#define COLOR_BLUE 0x06
+#define COLOR_YELLOW 0x07
+#define COLOR_ORANGE 0x08
+#define COLOR_BROWN 0x09
+#define COLOR_LIGHTRED 0x0A
+#define COLOR_GRAY1 0x0B
+#define COLOR_GRAY2 0x0C
+#define COLOR_LIGHTGREEN 0x0D
+#define COLOR_LIGHTBLUE 0x0E
+#define COLOR_GRAY3 0x0F
+
+
+
+/* Define hardware */
+#include <_vic.h>
+#define VIC (*(struct __vic*)0xD000)
+
+#include <_sid.h>
+#define SID (*(struct __sid*)0xD400)
+
+#include <_6526.h>
+#define CIA1 (*(struct __6526*)0xDC00)
+#define CIA2 (*(struct __6526*)0xDD00)
+
+
+
+/* Define special memory areas */
+#define COLOR_RAM ((unsigned char*)0xD800)
+
+
+
+/* End of c64.h */
+#endif
+
+
+
--- /dev/null
+/*
+ * cbm.h
+ *
+ * Ullrich von Bassewitz, 07.08.1998
+ */
+
+
+
+#ifndef _CBM_H
+#define _CBM_H
+
+
+
+/* Load the system specific files here, if needed */
+#ifdef __C64__
+#ifndef _C64_H
+#include <c64.h>
+#endif
+#endif
+
+#ifdef __C128__
+#ifndef _C128_H
+#include <c128.h>
+#endif
+#endif
+
+#ifdef __PLUS4__
+#ifndef _PLUS4_H
+#include <plus4.h>
+#endif
+#endif
+
+#ifdef __CBM610__
+#ifndef _CBM610_H
+#include <cbm610.h>
+#endif
+#endif
+
+#ifdef __PET__
+#ifndef _PET_H
+#include <pet.h>
+#endif
+#endif
+
+
+
+/* Characters codes (CBM charset) */
+#define CH_HLINE 96
+#define CH_VLINE 125
+#define CH_ULCORNER 176
+#define CH_URCORNER 174
+#define CH_LLCORNER 173
+#define CH_LRCORNER 189
+#define CH_TTEE 178
+#define CH_RTEE 179
+#define CH_BTEE 177
+#define CH_LTEE 171
+#define CH_CROSS 123
+#define CH_CURS_UP 145
+#define CH_CURS_DOWN 17
+#define CH_CURS_LEFT 157
+#define CH_CURS_RIGHT 29
+#define CH_PI 126
+#define CH_DEL 20
+#define CH_INS 148
+#define CH_ESC 95
+
+
+
+/* End of cbm.h */
+#endif
+
+
+
--- /dev/null
+/*
+ * cbm610.h
+ *
+ * Ullrich von Bassewitz, 12.08.1998
+ */
+
+
+
+#ifndef _CBM610_H
+#define _CBM610_H
+
+
+
+/* Additional key defines */
+#define CH_F1 224
+#define CH_F2 225
+#define CH_F3 226
+#define CH_F4 227
+#define CH_F5 228
+#define CH_F6 229
+#define CH_F7 230
+#define CH_F8 231
+#define CH_F9 232
+#define CH_F10 233
+#define CH_F11 234
+#define CH_F12 235
+#define CH_F13 236
+#define CH_F14 237
+#define CH_F15 238
+#define CH_F16 239
+#define CH_F17 240
+#define CH_F18 241
+#define CH_F19 242
+#define CH_F20 243
+
+
+
+/* Color defines */
+#define COLOR_BLACK 0x00
+#define COLOR_WHITE 0x01
+
+
+
+/* Special routines to write bytes and words in the system bank */
+void __fastcall__ pokebsys (unsigned addr, unsigned char val);
+void __fastcall__ pokewsys (unsigned addr, unsigned val);
+
+
+
+/* Define hardware */
+#include <_6545.h>
+#define CRTC (*(struct __6545)0xD800)
+
+#include <_sid.h>
+#define SID (*(struct __sid*)0xDA00)
+
+#include <_6526.h>
+#define CIA (*(struct __cia*)0xDC00)
+
+#include <_6551.h>
+#define ACIA (*(struct __6551*)0xDD00)
+
+#include <_6525.h>
+#define TPI1 (*(struct __6525*)0xDE00)
+#define TPI2 (*(struct __6525*)0xDF00)
+
+
+
+/* End of cbm610.h */
+#endif
+
+
+
--- /dev/null
+/*
+ * conio.h
+ *
+ * Ullrich von Bassewitz, 06.08.1998
+ *
+ *
+ * This is the direct console interface for cc65. I do not like the function
+ * names very much, but the first version started as a rewrite of Borlands
+ * conio, and, even if the interface has changed, the names did not.
+ *
+ * The interface does direct screen I/O, so it is fast enough for most
+ * programs. I did not implement text windows, since many applications do
+ * not need them and should not pay for the additional overhead. It should
+ * be easy to add text windows on a higher level if needed,
+ *
+ * Most routines do not check the parameters. This may be unfortunate but is
+ * also related to speed. The coordinates are always 0/0 based.
+ *
+ */
+
+
+
+#ifndef _CONIO_H
+#define _CONIO_H
+
+
+
+#ifndef _STDARG_H
+# include <stdarg.h>
+#endif
+
+/* Read the CBM file if we're compiling for a CBM machine */
+#ifdef __CBM__
+# ifndef _CBM_H
+# include <cbm.h>
+# endif
+#endif
+
+#ifdef __APPLE2__
+# ifndef _APPLE2_H
+# include <apple2.h>
+# endif
+#endif
+
+#ifdef __ATARI__
+# ifndef _ATARI_H
+# include <atari.h>
+# endif
+#endif
+
+
+
+/*****************************************************************************/
+/* Functions */
+/*****************************************************************************/
+
+
+
+void clrscr (void);
+/* Clear the whole screen and put the cursor into the top left corner */
+
+unsigned char kbhit (void);
+/* Return true if there's a key waiting, return false if not */
+
+void __fastcall__ gotox (unsigned char x);
+/* Set the cursor to the specified X position, leave the Y position untouched */
+
+void __fastcall__ gotoy (unsigned char y);
+/* Set the cursor to the specified Y position, leave the X position untouched */
+
+void __fastcall__ gotoxy (unsigned char x, unsigned char y);
+/* Set the cursor to the specified position */
+
+unsigned char wherex (void);
+/* Return the X position of the cursor */
+
+unsigned char wherey (void);
+/* Return the Y position of the cursor */
+
+void __fastcall__ cputc (char c);
+/* Output one character at the current cursor position */
+
+void __fastcall__ cputcxy (unsigned char x, unsigned char y, char c);
+/* Same as "gotoxy (x, y); cputc (c);" */
+
+void __fastcall__ cputs (const char* s);
+/* Output a NUL terminated string at the current cursor position */
+
+void __fastcall__ cputsxy (unsigned char x, unsigned char y, const char* s);
+/* Same as "gotoxy (x, y); puts (s);" */
+
+int cprintf (const char* format, ...);
+/* Like printf, but uses direct screen I/O */
+
+int vcprintf (const char* format, va_list ap);
+/* Like vprintf, but uses direct screen I/O */
+
+char cgetc (void);
+/* Return a character from the keyboard. If there is no character available,
+ * the functions waits until the user does press a key. If cursor is set to
+ * 1 (see below), a blinking cursor is displayed while waiting.
+ */
+
+unsigned char __fastcall__ cursor (unsigned char onoff);
+/* If onoff is 1, a cursor is display when waiting for keyboard input. If
+ * onoff is 0, the cursor is hidden when waiting for keyboard input. The
+ * function returns the old cursor setting.
+ */
+
+unsigned char __fastcall__ revers (unsigned char onoff);
+/* Enable/disable reverse character display. This may not be supported by
+ * the output device. Return the old setting.
+ */
+
+unsigned char __fastcall__ textcolor (unsigned char color);
+/* Set the color for text output. The old color setting is returned. */
+
+unsigned char __fastcall__ bgcolor (unsigned char color);
+/* Set the color for the background. The old color setting is returned. */
+
+unsigned char __fastcall__ bordercolor (unsigned char color);
+/* Set the color for the border. The old color setting is returned. */
+
+void __fastcall__ chline (unsigned char length);
+/* Output a horizontal line with the given length starting at the current
+ * cursor position.
+ */
+
+void __fastcall__ chlinexy (unsigned char x, unsigned char y, unsigned char length);
+/* Same as "gotoxy (x, y); chline (length);" */
+
+void __fastcall__ cvline (unsigned char length);
+/* Output a vertical line with the given length at the current cursor
+ * position.
+ */
+
+void __fastcall__ cvlinexy (unsigned char x, unsigned char y, unsigned char length);
+/* Same as "gotoxy (x, y); cvline (length);" */
+
+void __fastcall__ cclear (unsigned char length);
+/* Clear part of a line (write length spaces). */
+
+void __fastcall__ cclearxy (unsigned char x, unsigned char y, unsigned char length);
+/* Same as "gotoxy (x, y); cclear (length);" */
+
+void __fastcall__ screensize (unsigned char* x, unsigned char* y);
+/* Return the current screen size. */
+
+void __fastcall__ cputhex8 (unsigned char val);
+void __fastcall__ cputhex16 (unsigned val);
+/* These shouldn't be here... */
+
+
+/* End of conio.h */
+#endif
+
+
+
--- /dev/null
+/*
+ * ctype.h
+ *
+ * Ullrich von Bassewitz, 03.06.1998
+ *
+ */
+
+
+
+#ifndef _CTYPE_H
+#define _CTYPE_H
+
+
+
+int __fastcall__ isalnum (int c);
+int __fastcall__ isalpha (int c);
+int __fastcall__ iscntrl (int c);
+int __fastcall__ isdigit (int c);
+int __fastcall__ isgraph (int c);
+int __fastcall__ islower (int c);
+int __fastcall__ isprint (int c);
+int __fastcall__ ispunct (int c);
+int __fastcall__ isspace (int c);
+int __fastcall__ isupper (int c);
+int __fastcall__ isxdigit (int c);
+#ifndef __STRICT_ANSI__
+int __fastcall__ isblank (int c); /* cc65 (and GNU) extension */
+#endif
+
+int __fastcall__ toupper (int c); /* Always external */
+int __fastcall__ tolower (int c); /* Always external */
+
+
+
+/* When inlining of known function is enabled, overload most of the above
+ * functions by macros. The function prototypes are again available after
+ * #undef'ing the macros.
+*/
+#ifdef __OPT_s__
+
+
+extern unsigned char _ctype[256];
+
+#define isalnum(c) (__AX__ = (c), __asm__ ("\ttay\n\tlda\t__ctype,y\n\tand\t#$07"), __AX__)
+#define isalpha(c) (__AX__ = (c), __asm__ ("\ttay\n\tlda\t__ctype,y\n\tand\t#$03"), __AX__)
+#define iscntrl(c) (__AX__ = (c), __asm__ ("\ttay\n\tlda\t__ctype,y\n\tand\t#$10"), __AX__)
+#define isdigit(c) (__AX__ = (c), __asm__ ("\ttay\n\tlda\t__ctype,y\n\tand\t#$04"), __AX__)
+#define isgraph(c) (__AX__ = (c), __asm__ ("\ttay\n\tlda\t__ctype,y\n\teor\t#$30\n\tand\t#$30"), __AX__)
+#define islower(c) (__AX__ = (c), __asm__ ("\ttay\n\tlda\t__ctype,y\n\tand\t#$01"), __AX__)
+#define isprint(c) (__AX__ = (c), __asm__ ("\ttay\n\tlda\t__ctype,y\n\teor\t#$10\n\tand\t#$10"), __AX__)
+#define ispunct(c) (__AX__ = (c), __asm__ ("\ttay\n\tlda\t__ctype,y\n\teor\t#$37\n\tand\t#$37"), __AX__)
+#define isspace(c) (__AX__ = (c), __asm__ ("\ttay\n\tlda\t__ctype,y\n\tand\t#$60"), __AX__)
+#define isupper(c) (__AX__ = (c), __asm__ ("\ttay\n\tlda\t__ctype,y\n\tand\t#$02"), __AX__)
+#define isxdigit(c) (__AX__ = (c), __asm__ ("\ttay\n\tlda\t__ctype,y\n\tand\t#$08"), __AX__)
+
+#ifndef __STRICT_ANSI__
+/* cc65 and GNU extension */
+#define isblank(c) (__AX__ = (c), __asm__ ("\ttay\n\tlda\t__ctype,y\n\tand\t#$80"), __AX__)
+#endif
+
+
+#endif
+
+
+
+/* End of ctype.h */
+#endif
+
+
+
--- /dev/null
+/*
+ * dbg.h
+ *
+ * Ullrich von Bassewitz, 08.08.1998
+ *
+ *
+ * This is the interface to the cc65 debugger. Since many of the functions
+ * used for the debugger are quite usable even in another context, they
+ * are declared here.
+ *
+ * To use the debugger, just call DbgStart in your application. This will
+ * clear the screen and startup the debugger with the program counter
+ * pointing to the next instruction after the call to DbgStart. Once DbgStart
+ * has been executed, the debugger will also catch any BRK opcode. Use the
+ * BREAK function declared below to insert additional breakpoints into your
+ * code.
+ *
+ * There are currently a lot of things that cannot be debugged, graphical
+ * applications are an example. The debugger does not save your screen
+ * contents, so even your text screen gets destroyed. However, you can
+ * debug the C and runtime library, even if the debugger is using this
+ * stuff itself.
+ *
+ * Note: When using the debugger, there are some other identifiers with
+ * external linkage, that start with Dbg. Avoid those names if you use the
+ * module.
+ */
+
+
+
+#ifndef _DBG_H
+#define _DBG_H
+
+
+
+/*****************************************************************************/
+/* Utuility functions */
+/*****************************************************************************/
+
+
+
+unsigned __fastcall__ DbgDisAsm (unsigned Addr, char* Buf, unsigned char Len);
+/* Disassemble one instruction at address addr into the given buffer.
+ * The resulting line has the format, "AAAA__BB_BB_BB___OPC_OPERAND",
+ * where AAAA is the hexadecimal representation of addr, BB are the
+ * bytes (in hex) that make the instruction, OPC is the mnemonic, and
+ * OPERAND is an operand for the instruction.
+ * The buffer is filled with spaces up to the given length and terminated as
+ * a usual C string. NOTE: Buf must be able to hold Len+1 characters.
+ * The function returns the length of the disassembled instruction, so,
+ * to disassemble the next instruction, add the return value to addr
+ * and call the function again.
+ */
+
+unsigned __fastcall__ DbgDisAsmLen (unsigned Addr);
+/* Disassemble one instruction, but do only return the length, do not
+ * create a visible representation. This function is useful when
+ * disassembling backwards, it is much faster than DbgDisAsm.
+ */
+
+int __fastcall__ DbgIsRAM (unsigned Addr);
+/* Return true if we can read and write the given address */
+
+char* DbgMemDump (unsigned Addr, char* Buf, unsigned char Len);
+/* Create a line of a memory dump in the given buffer. The buffer contains
+ * the starting address (4 digits hex), then Len bytes in this format:
+ * "AAAA__XX_YY_ZZ_...". The passed char buffer must hold Len*3+5 bytes
+ * plus a terminator byte.
+ * The function does not work correctly if the created string is longer
+ * than 255 bytes.
+ * The return value is Buf.
+ */
+
+
+
+/*****************************************************************************/
+/* High level user interface */
+/*****************************************************************************/
+
+
+
+void __fastcall__ DbgInit (unsigned unused);
+/* Initialize the debugger. Use 0 as parameter. The debugger will popup on
+ * next brk encountered.
+ */
+
+#define BREAK() __asm__ ("\tbrk")
+/* Use this to insert breakpoints into your code */
+
+
+
+/* End of dbg.h */
+#endif
+
+
+
--- /dev/null
+/*
+ * errno.h
+ *
+ * Ullrich von Bassewitz, 18.08.1998
+ *
+ */
+
+
+
+#ifndef _ERRNO_H
+#define _ERRNO_H
+
+
+
+/* Operating system specific error codes */
+extern unsigned char _oserror;
+
+/* Mapper function, don't call directly */
+void _maperrno (void);
+
+/* This one is called under the hood. User callable. */
+int __fastcall__ _osmaperrno (unsigned char oserror);
+
+/* System error codes go here */
+extern int _errno;
+
+/* errno must be a macro, here the mapper is called */
+#define errno (_maperrno(), _errno)
+
+
+
+/* Possible error codes */
+#define ENOENT 1 /* No such file or directory */
+#define ENOMEM 2 /* Out of memory */
+#define EACCES 3 /* Permission denied */
+#define ENODEV 4 /* No such device */
+#define EMFILE 5 /* Too many open files */
+#define EBUSY 6 /* Device or resource busy */
+#define EINVAL 7 /* Invalid argument */
+#define ENOSPC 8 /* No space left on device */
+#define EEXIST 9 /* File exists */
+#define EAGAIN 10 /* Try again */
+#define EIO 11 /* I/O error */
+#define EINTR 12 /* Interrupted system call */
+#define ENOSYS 13 /* Function not implemented */
+#define ESPIPE 14 /* Illegal seek */
+#define EUNKNOWN 15 /* Unknown OS specific error */
+
+
+
+#endif
+
+
+
--- /dev/null
+/*
+ * fcntl.h
+ *
+ * Ullrich von Bassewitz, 30.05.1998
+ *
+ */
+
+
+
+#ifndef _FCNTL_H
+#define _FCNTL_H
+
+
+
+/* Flag values for the open() call */
+#define O_RDONLY 0x01
+#define O_WRONLY 0x02
+#define O_RDWR 0x03
+#define O_CREAT 0x10
+#define O_TRUNC 0x20
+#define O_APPEND 0x40
+
+
+
+/* Functions */
+int open (const char* name, int flags, ...); /* May take a mode argument */
+int close (int fd);
+int write (int fd, const void* buf, unsigned count);
+int read (int fd, void* buf, unsigned count);
+int mkdir (const char* name, ...); /* May take a mode argument */
+int rmdir (const char* name);
+
+
+
+/* End of fcntl.h */
+#endif
+
+
+
--- /dev/null
+/*
+ Supreme GEOS header file
+ includes all other headers
+
+ Maciej 'YTM/Alliance' Witkowiak, 27.10.1999
+*/
+
+
+
+#ifndef _GEOS_H
+#define _GEOS_H
+
+
+
+#ifndef _GCONST_H
+#include <geos/gconst.h>
+#endif
+
+#ifndef _GSTRUCT_H
+#include <geos/gstruct.h>
+#endif
+
+#ifndef _GSYM_H
+#include <geos/gsym.h>
+#endif
+
+#ifndef _GDISK_H
+#include <geos/gdisk.h>
+#endif
+
+#ifndef _GFILE_H
+#include <geos/gfile.h>
+#endif
+
+#ifndef _GPROCESS_H
+#include <geos/gprocess.h>
+#endif
+
+#ifndef _GGRAPH_H
+#include <geos/ggraph.h>
+#endif
+
+#ifndef _GMENU_H
+#include <geos/gmenu.h>
+#endif
+
+#ifndef _GSPRITE_H
+#include <geos/gsprite.h>
+#endif
+
+#ifndef _GMEMORY_H
+#include <geos/gmemory.h>
+#endif
+
+#ifndef _GSYS_H
+#include <geos/gsys.h>
+#endif
+
+#ifndef _GDLGBOX_H
+#include <geos/gdlgbox.h>
+#endif
+
+
+
+/* End of geos.h */
+#endif
+
+
+
--- /dev/null
+/*
+ GEOS constants, 4-2-99, 18-3-99
+
+ small C version: 25-27.10.99
+ reassembled by Maciej 'YTM/Alliance' Witkowiak
+*/
+
+/* Here are constants which didn't fit into any other cathegory... */
+
+#ifndef _GCONST_H
+#define _GCONST_H
+
+#define NULL 0
+#define FALSE NULL
+#define TRUE 0xff
+#define MOUSE_SPRNUM 0
+#define DISK_DRV_LGH 0x0d80
+
+/* drivetypes */
+#define DRV_NULL 0
+#define DRV_1541 1
+#define DRV_1571 2
+#define DRV_1581 3
+#define DRV_NETWORK 15
+
+/* various disk constants */
+#define REL_FILE_NUM 9
+#define CMND_FILE_NUM 15
+#define MAX_CMND_STR 32
+#define DIR_1581_TRACK 40
+#define DIR_ACC_CHAN 13
+#define DIR_TRACK 18
+#define N_TRACKS 35
+#define DK_NM_ID_LEN 18
+#define TRACK 9
+#define SECTOR 12
+#define TOTAL_BLOCKS 664
+
+/* offset to something */
+#define OFF_INDEX_PTR 1
+
+/* values for MMU config - C128 */
+#define CIOIN 0x7E
+#define CRAM64K 0x7F
+#define CKRNLBASIOIN 0x40
+#define CKRNLIOIN 0x4E
+
+/* alarmSetFlag */
+#define ALARMMASK 4
+
+#define CLR_SAVE 0x40
+#define CONSTRAINED 0x40
+#define UN_CONSTRAINED 0
+#define FG_SAVE 0x80
+
+#define FUTURE1 7
+#define FUTURE2 8
+#define FUTURE3 9
+#define FUTURE4 10
+#define USELAST 127
+#define SHORTCUT 128
+
+#endif
--- /dev/null
+/*
+ GEOS functions from disk driver
+
+ ported to small C on 21.12.1999
+ by Maciej 'YTM/Alliance' Witkowiak
+*/
+
+#ifndef _GDISK_H
+#define _GDISK_H
+
+#ifndef _GSTRUCT_H
+#include <geos/gstruct.h>
+#endif
+
+char __fastcall__ ReadBuff(struct tr_se *myTrSe);
+char __fastcall__ WriteBuff(struct tr_se *myTrSe);
+
+char __fastcall__ GetBlock(struct tr_se *myTrSe, char *buffer);
+char __fastcall__ PutBlock(struct tr_se *myTrSe, char *buffer);
+char __fastcall__ ReadBlock(struct tr_se *myTrSe, char *buffer);
+char __fastcall__ WriteBlock(struct tr_se *myTrSe, char *buffer);
+char __fastcall__ VerWriteBlock(struct tr_se *myTrSe, char *buffer);
+
+int __fastcall__ CalcBlksFree(void);
+char __fastcall__ ChkDkGEOS(void);
+char __fastcall__ SetGEOSDisk(void);
+char __fastcall__ NewDisk(void);
+char __fastcall__ OpenDisk(void);
+
+char __fastcall__ FindBAMBit(struct tr_se *myTrSe);
+char __fastcall__ BlkAlloc(struct tr_se output[], int length);
+char __fastcall__ NxtBlkAlloc(struct tr_se *startTrSe,
+ struct tr_se output[], int length);
+char __fastcall__ FreeBlock(struct tr_se *myTrSe);
+struct tr_se __fastcall__ SetNextFree(struct tr_se *myTrSe);
+// above needs (int) casts on both sides of '='
+
+char __fastcall__ GetDirHead(void);
+char __fastcall__ PutDirHead(void);
+void __fastcall__ GetPtrCurDkNm(char *name);
+
+void __fastcall__ EnterTurbo(void);
+void __fastcall__ ExitTurbo(void);
+void __fastcall__ PurgeTurbo(void);
+
+char __fastcall__ ChangeDiskDevice(char newdev);
+
+/* disk header offsets */
+#define OFF_TO_BAM 4
+#define OFF_DISK_NAME 144
+#define OFF_GS_DTYPE 189
+#define OFF_OP_TR_SC 171
+#define OFF_GS_ID 173
+/* disk errors */
+#define ANY_FAULT 0xf0
+#define NO_BLOCKS 1
+#define INV_TRACK 2
+#define INSUFF_SPACE 3
+#define FULL_DIRECTORY 4
+#define FILE_NOT_FOUND 5
+#define BAD_BAM 6
+#define UNOPENED_VLIR 7
+#define INV_RECORD 8
+#define OUT_OF_RECORDS 9
+#define STRUCT_MISMAT 10
+#define BFR_OVERFLOW 11
+#define CANCEL_ERR 12
+#define DEV_NOT_FOUND 13
+#define INCOMPATIBLE 14
+#define HDR_NOT_THERE 0x20
+#define NO_SYNC 0x21
+#define DBLK_NOT_THERE 0x22
+#define DAT_CHKSUM_ERR 0x23
+#define WR_VER_ERR 0x25
+#define WR_PR_ON 0x26
+#define HDR_CHKSUM_ERR 0x27
+#define DSK_ID_MISMAT 0x29
+#define BYTE_DEC_ERR 0x2e
+#define DOS_MISMATCH 0x73
+
+#endif
--- /dev/null
+/*
+ GEOS dialog box functions
+
+ ported to small C on 26.12.1999
+ by Maciej 'YTM/Alliance' Witkowiak
+ 10.03.2000 - update
+*/
+
+#ifndef _GDLGBOX_H
+#define _GDLGBOX_H
+
+char __fastcall__ DoDlgBox(char *dboxstring);
+char __fastcall__ RstrFrmDialogue(void);
+
+/* These are custom, predefined dialog boxes, I'm sure you'll find them usable
+ Most of them show 2 lines of text */
+
+char __fastcall__ DlgBoxYesNo(char *line1, char *line2);
+char __fastcall__ DlgBoxOkCancel(char *line1, char *line2);
+void __fastcall__ DlgBoxOk(char *line1, char *line2);
+char __fastcall__ DlgBoxGetString(char *myString, char strLength,
+ char *line1, char *line2);
+char __fastcall__ DlgBoxFileSelect(char *classtxt, char ftype,
+ char *fname);
+
+/* Now the command string type */
+
+typedef void dlgBoxStr;
+
+/* and command string commands - macros */
+
+#define DB_DEFPOS(pattern) (char)(DEF_DB_POS | (pattern))
+#define DB_SETPOS(pattern,top,bot,left,right) \
+ (char)(SET_DB_POS | (pattern)), (char)(top), (char)(bot), \
+ (unsigned)(left), (unsigned)(right)
+#define DB_ICON(i,x,y) (char)(i), (char)(x), (char)(y)
+#define DB_TXTSTR(x,y,text) (char)DBTXTSTR, (char)(x), (char)(y), (text)
+#define DB_VARSTR(x,y,ptr) (char)DBVARSTR, (char)(x), (char)(y), (char)(ptr)
+#define DB_GETSTR(x,y,ptr,length) (char)DBGETSTRING, (char)(x), (char)(y), (char)(ptr), (char)(length)
+#define DB_SYSOPV(ptr) (char)DBSYSOPV, (unsigned)(ptr)
+#define DB_GRPHSTR(ptr) (char)DBGRPHSTR, (unsigned)(ptr)
+#define DB_GETFILES(x,y) (char)DBGETFILES, (char)(x), (char)(y)
+#define DB_OPVEC(ptr) (char)DBOPVEC, (unsigned)(ptr)
+#define DB_USRICON(x,y,ptr) (char)DBUSRICON, (char)(x), (char)(y), (unsigned)(ptr)
+#define DB_USRROUT(ptr) (char)DB_USR_ROUT, (unsigned)(ptr)
+#define DB_END (char)NULL
+
+/*
+ part of constants below is used internally, but some are useful for macros above
+*/
+
+/* icons for DB_ICON */
+#define OK 1
+#define CANCEL 2
+#define YES 3
+#define NO 4
+#define OPEN 5
+#define DISK 6
+/* commands - internally used by command macros */
+#define DBTXTSTR 11
+#define DBVARSTR 12
+#define DBGETSTRING 13
+#define DBSYSOPV 14
+#define DBGRPHSTR 15
+#define DBGETFILES 16
+#define DBOPVEC 17
+#define DBUSRICON 18
+#define DB_USR_ROUT 19
+/* icons tabulation in standard window */
+#define DBI_X_0 1
+#define DBI_X_1 9
+#define DBI_X_2 17
+#define DBI_Y_0 8
+#define DBI_Y_1 40
+#define DBI_Y_2 72
+/* standard window size defaults */
+#define SET_DB_POS 0
+#define DEF_DB_POS 0x80
+#define DEF_DB_TOP 32
+#define DEF_DB_BOT 127
+#define DEF_DB_LEFT 64
+#define DEF_DB_RIGHT 255
+/* text tabulation in standard window */
+#define TXT_LN_1_Y 16
+#define TXT_LN_2_Y 32
+#define TXT_LN_3_Y 48
+#define TXT_LN_4_Y 64
+#define TXT_LN_5_Y 80
+#define TXT_LN_X 16
+/* system icons size */
+#define SYSDBI_HEIGHT 16
+#define SYSDBI_WIDTH 6
+/* dialogbox string offsets */
+#define OFF_DB_FORM 0
+#define OFF_DB_TOP 1
+#define OFF_DB_BOT 2
+#define OFF_DB_LEFT 3
+#define OFF_DB_RIGHT 5
+#define OFF_DB_1STCMD 7
+
+#endif
+
--- /dev/null
+/*
+ GEOS filesystem functions
+
+ ported to small C on 25.12.1999
+ by Maciej 'YTM/Alliance' Witkowiak
+*/
+
+#ifndef _GFILE_H
+#define _GFILE_H
+
+#ifndef _GSTRUCT_H
+#include <geos/gstruct.h>
+#endif
+
+struct filehandle *__fastcall__ Get1stDirEntry(void);
+struct filehandle *__fastcall__ GetNxtDirEntry(void);
+
+char __fastcall__ FindFTypes(char *buffer, char ftype, char fmaxnum, char *classtxt);
+
+char __fastcall__ FindFile(char *fname);
+char __fastcall__ ReadFile(struct tr_se *myTrSe, char *buffer, int flength);
+char __fastcall__ SaveFile(struct fileheader *myHeader);
+char __fastcall__ FreeFile(struct tr_se myTable[]);
+char __fastcall__ DeleteFile(char *fname);
+char __fastcall__ RenameFile(char *source, char *target);
+
+char __fastcall__ ReadByte(void);
+
+char __fastcall__ FollowChain(struct tr_se *startTrSe, char *buffer);
+char __fastcall__ GetFHdrInfo(struct filehandle *myFile);
+
+char __fastcall__ OpenRecordFile(char *fname);
+char __fastcall__ CloseRecordFile(void);
+char __fastcall__ NextRecord(void);
+char __fastcall__ PreviousRecord(void);
+char __fastcall__ PointRecord(char);
+char __fastcall__ DeleteRecord(void);
+char __fastcall__ InsertRecord(void);
+char __fastcall__ AppendRecord(void);
+char __fastcall__ ReadRecord(char *buffer, int flength);
+char __fastcall__ WriteRecord(char *buffer, int flength);
+char __fastcall__ UpdateRecordFile(void);
+
+/* GEOS filetypes */
+#define NOT_GEOS 0
+#define BASIC 1
+#define ASSEMBLY 2
+#define DATA 3
+#define SYSTEM 4
+#define DESK_ACC 5
+#define APPLICATION 6
+#define APPL_DATA 7
+#define FONT 8
+#define PRINTER 9
+#define INPUT_DEVICE 10
+#define DISK_DEVICE 11
+#define SYSTEM_BOOT 12
+#define TEMPORARY 13
+#define AUTO_EXEC 14
+#define INPUT_128 15
+#define NUMFILETYPES 16
+/* supported structures */
+#define SEQUENTIAL 0
+#define VLIR 1
+/* DOS filetypes */
+#define DEL 0
+#define SEQ 1
+#define PRG 2
+#define USR 3
+#define REL 4
+#define CBM 5
+/* directory offsets */
+/* offsets in dir entry */
+#define FRST_FILE_ENTRY 2
+#define OFF_CFILE_TYPE 0
+#define OFF_DE_TR_SC 1
+#define OFF_FNAME 3
+#define OFF_GHDR_PTR 19
+#define OFF_GSTRUC_TYPE 21
+#define OFF_GFILE_TYPE 22
+#define OFF_YEAR 23
+#define OFF_SIZE 28
+#define OFF_NXT_FILE 32
+/* offsets in file header */
+#define O_GHIC_WIDTH 2
+#define O_GHIC_HEIGHT 3
+#define O_GHIC_PIC 4
+#define O_GHCMDR_TYPE 68
+#define O_GHGEOS_TYPE 69
+#define O_GHSTR_TYPE 70
+#define O_GHST_ADDR 71
+#define O_GHEND_ADDR 73
+#define O_GHST_VEC 75
+#define O_GHFNAME 77
+#define O_128_FLAGS 96
+#define O_GH_AUTHOR 97
+#define O_GHP_DISK 97
+#define O_GHP_FNAME 117
+#define O_GHINFO_TXT 0xa0
+
+#endif
--- /dev/null
+/*
+ GEOS graphic (non icon/menu/sprite) functions
+
+ ported to small C on 29.10.1999
+ by Maciej 'YTM/Alliance' Witkowiak
+ 10,11.03.2000 - updates
+*/
+
+#ifndef _GGRAPH_H
+#define _GGRAPH_H
+
+#ifndef _GSTRUCT_H
+#include <geos/gstruct.h>
+#endif
+
+void __fastcall__ SetPattern(char newpattern);
+
+void __fastcall__ HorizontalLine(char pattern, char y, int xstart, int xend);
+void __fastcall__ InvertLine(char y, int xstart, int xend);
+void __fastcall__ RecoverLine(char y, int xstart, int xend);
+void __fastcall__ VerticalLine(char pattern, char ystart, char yend, int x);
+
+void __fastcall__ InitDrawWindow(struct window *myRectangle);
+void __fastcall__ Rectangle(void);
+void __fastcall__ FrameRectangle(char pattern);
+void __fastcall__ InvertRectangle(void);
+void __fastcall__ ImprintRectangle(void);
+void __fastcall__ RecoverRectangle(void);
+
+void __fastcall__ DrawLine(struct window *topBotCoords);
+
+void __fastcall__ DrawPoint(struct pixel *myPixel);
+char __fastcall__ TestPoint(struct pixel *myPixel);
+
+void __fastcall__ PutChar(char character, char y, int x);
+void __fastcall__ PutString(char *myString, char y, int x);
+void __fastcall__ PutDecimal(char style, int value, char y, int x);
+
+char __fastcall__ GetCharWidth(char character);
+void __fastcall__ LoadCharSet(struct fontdesc *myFont);
+void __fastcall__ UseSystemFont(void);
+
+void __fastcall__ BitmapUp(struct iconpic *myIcon);
+void __fastcall__ BitmapClip(char skipl, char skipr, int skiptop,
+ struct iconpic *myIcon);
+void __fastcall__ BitOtherClip(void *proc1, void *proc2, char skipl,
+ char skipr, int skiptop,
+ struct iconpic *myIcon);
+
+void __fastcall__ GraphicsString(char *myGfxString);
+
+/* VIC colour constants */
+#define BLACK 0
+#define WHITE 1
+#define RED 2
+#define CYAN 3
+#define PURPLE 4
+#define GREEN 5
+#define BLUE 6
+#define YELLOW 7
+#define ORANGE 8
+#define BROWN 9
+#define LTRED 10
+#define DKGREY 11
+#define GREY 12
+#define MEDGREY 12
+#define LTGREEN 13
+#define LTBLUE 14
+#define LTGREY 15
+/* VIC memory banks */
+#define GRBANK0 3
+#define GRBANK1 2
+#define GRBANK2 1
+#define GRBANK3 0
+/* VIC screen sizes */
+#define VIC_X_POS_OFF 24
+#define VIC_Y_POS_OFF 50
+#define SC_BYTE_WIDTH 40
+#define SC_PIX_HEIGHT 200
+#define SC_PIX_WIDTH 320
+#define SC_SIZE 8000
+/* VDC screen constants */
+#define SCREENBYTEWIDTH 80
+#define SCREENPIXELWIDTH 640
+/* control characters for use as numbers, not chars */
+#define EOF 0
+#define BACKSPACE 8
+#define FORWARDSPACE 9
+#define TAB 9
+#define LF 10
+#define HOME 11
+#define PAGE_BREAK 12
+#define UPLINE 12
+#define CR 13
+#define ULINEON 14
+#define ULINEOFF 15
+#define ESC_GRAPHICS 16
+#define ESC_RULER 17
+#define REV_ON 18
+#define REV_OFF 19
+#define GOTOX 20
+#define GOTOY 21
+#define GOTOXY 22
+#define NEWCARDSET 23
+#define BOLDON 24
+#define ITALICON 25
+#define OUTLINEON 26
+#define PLAINTEXT 27
+/* control characters for use in
+ strings: eg: str[10]=BOLD "Hello"; */
+#define CCR "\015"
+#define CULINEON "\016"
+#define CULINEOFF "\017"
+#define CREV_ON "\022"
+#define CREV_OFF "\023"
+#define CBOLDON "\030"
+#define CITALICON "\031"
+#define COUTLINEON "\032"
+#define CPLAINTEXT "\033"
+
+/*values of currentMode */
+/* bitNumbers */
+#define UNDERLINE_BIT 7
+#define BOLD_BIT 6
+#define REVERSE_BIT 5
+#define ITALIC_BIT 4
+#define OUTLINE_BIT 3
+#define SUPERSCRIPT_BIT 2
+#define SUBSCRIPT_BIT 1
+/* bitMasks */
+#define SET_UNDERLINE 0x80
+#define SET_BOLD 0x40
+#define SET_REVERSE 0x20
+#define SET_ITALIC 0x10
+#define SET_OUTLINE 0x08
+#define SET_SUPERSCRIPT 0x04
+#define SET_SUBSCRIPT 0x02
+#define SET_PLAINTEXT 0
+/* values of dispBufferOn */
+#define ST_WRGS_FORE 0x20
+#define ST_WR_BACK 0x40
+#define ST_WR_FORE 0x80
+/* PutDecimal parameters */
+/* leading 0s? */
+#define SET_NOSURPRESS 0
+#define SET_SURPRESS 0x40
+/* justification */
+#define SET_RIGHTJUST 0
+#define SET_LEFTJUST 0x80
+/* C128 x flags */
+#define ADD1_W 0x2000
+#define DOUBLE_B 0x80
+#define DOUBLE_W 0x8000
+
+typedef void graphicStr;
+
+#define MOVEPENTO(x,y) (char)1, (unsigned)(x), (char)(y)
+#define LINETO(x,y) (char)2, (unsigned)(x), (char)(y)
+#define RECTANGLETO(x,y) (char)3, (unsigned)(x), (char)(y)
+#define NEWPATTERN(p) (char)5, (char)(p)
+#define FRAME_RECTO(x,y) (char)7, (unsigned)(x), (char)(y)
+#define PEN_X_DELTA(x) (char)8, (unsigned)(x)
+#define PEN_Y_DELTA(y) (char)9, (char)(y)
+#define PEN_XY_DELTA(x,y) (char)10, (unsigned)(x), (char)(y)
+#define GSTR_END (char)NULL
+/* ESC_PUTSTRING can't be implemented - it needs text, not pointer to it
+ #define ESC_PUTSTRING(x,y,text) (char)6, (unsigned)(x), (char)(y), (text), (char)NULL
+*/
+
+#endif
--- /dev/null
+/*
+ GEOS memory and string functions
+
+ ported to small C on 27.10.1999
+ by Maciej 'YTM/Alliance' Witkowiak
+*/
+
+#ifndef _GMEMORY_H
+#define _GMEMORY_H
+
+#ifndef _GSTRUCT_H
+#include <geos/gstruct.h>
+#endif
+
+void __fastcall__ CopyString(char *dest, char *source);
+void __fastcall__ CmpString(char *dest, char *source);
+void __fastcall__ CopyFString(char len, char *dest, char *source);
+void __fastcall__ CmpFString(char len, char *dest, char *source);
+
+int __fastcall__ CRC(char *buffer, int len);
+void __fastcall__ ClearRam(char *dest, int len);
+void __fastcall__ FillRam(char what, char *dest, int len);
+
+void __fastcall__ MoveData(char *source, char *dest, int len);
+
+void __fastcall__ InitRam(char *myInitTab);
+
+void __fastcall__ StashRAM(char REUBank, int len, char *reuaddy, char *cpuaddy);
+void __fastcall__ FetchRAM(char REUBank, int len, char *reuaddy, char *cpuaddy);
+void __fastcall__ SwapRAM(char REUBank, int len, char *reuaddy, char *cpuaddy);
+char __fastcall__ VerifyRAM(char REUBank, int len, char *reuaddy, char *cpuaddy);
+
+#endif
--- /dev/null
+/*
+ GEOS menu and icon functions
+
+ ported to small C on 27.10.1999
+ by Maciej 'YTM/Alliance' Witkowiak
+*/
+
+#ifndef _GMENU_H
+#define _GMENU_H
+
+#ifndef _GSTRUCT_H
+#include <geos/gstruct.h>
+#endif
+
+void __fastcall__ DoMenu(struct menu *myMenu);
+void __fastcall__ ReDoMenu(void);
+void __fastcall__ RecoverMenu(void);
+void __fastcall__ RecoverAllMenus(void);
+void __fastcall__ DoPreviousMenu(void);
+void __fastcall__ GotoFirstMenu(void);
+
+void __fastcall__ DoIcons(struct icontab *myIconTab);
+
+/* DoMenu - menutypes */
+#define MENU_ACTION 0x00
+#define DYN_SUB_MENU 0x40
+#define SUB_MENU 0x80
+#define HORIZONTAL 0x00
+#define VERTICAL 0x80
+/* menu string offsets */
+#define OFF_MY_TOP 0
+#define OFF_MY_BOT 1
+#define OFF_MX_LEFT 2
+#define OFF_MX_RIGHT 4
+#define OFF_NUM_M_ITEMS 6
+#define OFF_1ST_M_ITEM 7
+/* icon string offsets */
+#define OFF_NM_ICNS 0
+#define OFF_IC_XMOUSE 1
+#define OFF_IC_YMOUSE 3
+#define OFF_PIC_ICON 0
+#define OFF_X_ICON_POS 2
+#define OFF_Y_ICON_POS 3
+#define OFF_WDTH_ICON 4
+#define OFF_HEIGHT_ICON 5
+#define OFF_SRV_RT_ICON 6
+#define OFF_NX_ICON 8
+/* icons, menus status flags */
+#define ST_FLASH 0x80
+#define ST_INVERT 0x40
+#define ST_LD_AT_ADDR 0x01
+#define ST_LD_DATA 0x80
+#define ST_PR_DATA 0x40
+#define ST_WR_PR 0x40
+
+#endif
--- /dev/null
+/*
+ GEOS processes (~multitasking) functions
+
+ ported to small C on 27.10.1999
+ by Maciej 'YTM/Alliance' Witkowiak
+*/
+
+#ifndef _GPROCESS_H
+#define _GPROCESS_H
+
+#ifndef _GSTRUCT_H
+#include <geos/gstruct.h>
+#endif
+
+void __fastcall__ InitProcesses(char number, struct process *proctab);
+void __fastcall__ RestartProcess(char number);
+void __fastcall__ EnableProcess(char number);
+void __fastcall__ BlockProcess(char number);
+void __fastcall__ UnBlockProcess(char number);
+void __fastcall__ FreezeProcess(char number);
+void __fastcall__ UnFreezeProcess(char number);
+
+void __fastcall__ Sleep(int jiffies);
+
+/* Process control variable
+ these probably should be removed from here, as they are
+ internal GEOS information which is updated by functions above
+*/
+
+/* bit numbers */
+#define RUNABLE_BIT 7
+#define BLOCKED_BIT 6
+#define FROZEN_BIT 5
+#define NOTIMER_BIT 4
+/* bit masks */
+#define SET_RUNABLE 0x80
+#define SET_BLOCKED 0x40
+#define SET_FROZEN 0x20
+#define SET_NOTIMER 0x10
+
+#endif
--- /dev/null
+/*
+ GEOS mouse and sprite functions
+
+ ported to small C on 27.10.1999
+ by Maciej 'YTM/Alliance' Witkowiak
+*/
+
+#ifndef _GSPRITE_H
+#define _GSPRITE_H
+
+void __fastcall__ StartMouseMode(void);
+void __fastcall__ ClearMouseMode(void);
+void __fastcall__ MouseUp(void);
+void __fastcall__ MouseOff(void);
+char __fastcall__ IsMseInRegion(struct window *region);
+
+void __fastcall__ DrawSprite(char spritenum, char *spritepic);
+void __fastcall__ PosSprite(char spritenum, struct pixel *position);
+void __fastcall__ EnablSprite(char spritenum);
+void __fastcall__ DisablSprite(char spritenum);
+
+void __fastcall__ InitTextPrompt(char height);
+void __fastcall__ PromptOn(struct pixel *position);
+void __fastcall__ PromptOff(void);
+char __fastcall__ GetNextChar(void);
+
+/* keyboard constants */
+#define KEY_F1 1
+#define KEY_F2 2
+#define KEY_F3 3
+#define KEY_F4 4
+#define KEY_F5 5
+#define KEY_F6 6
+#define KEY_NOSCRL 7
+#define KEY_ENTER 11
+#define KEY_F7 14
+#define KEY_F8 15
+#define KEY_UP 16
+#define KEY_DOWN 17
+#define KEY_HOME 18
+#define KEY_CLEAR 19
+#define KEY_LARROW 20
+#define KEY_UPARROR 21
+#define KEY_STOP 22
+#define KEY_RUN 23
+#define KEY_BPS 24
+#define KEY_HELP 25
+#define KEY_ALT 26
+#define KEY_ESC 27
+#define KEY_INSERT 28
+#define KEY_DELETE 29
+#define KEY_RIGHT 30
+#define KEY_INVALID 31
+#define KEY_LEFT BACKSPACE
+
+/* values of faultData - pointer position vs. mouseWindow */
+/* bit numbers */
+#define OFFTOP_BIT 7
+#define OFFBOTTOM_BIT 6
+#define OFFLEFT_BIT 5
+#define OFFRIGHT_BIT 4
+#define OFFMENU_BIT 3
+/* bit masks */
+#define SET_OFFTOP 0x80
+#define SET_OFFBOTTOM 0x40
+#define SET_OFFLEFT 0x20
+#define SET_OFFRIGHT 0x10
+#define SET_OFFMENU 0x08
+
+/* mouseOn */
+/* bit numbers */
+#define MOUSEON_BIT 7
+#define MENUON_BIT 6
+#define ICONSON_BIT 5
+/* bit masks */
+#define SET_MSE_ON 0x80
+#define SET_MENUON 0x40
+#define SET_ICONSON 0x20
+
+/* pressFlag */
+/* bit numbers */
+#define KEYPRESS_BIT 7
+#define INPUT_BIT 6
+#define MOUSE_BIT 5
+/* bit masks */
+#define SET_KEYPRESS 0x80
+#define SET_INPUTCHG 0x40
+#define SET_MOUSE 0x20
+
+#endif
--- /dev/null
+/*
+ GEOS structs
+
+ ported to small C on 25-27.10.1999
+ by Maciej 'YTM/Alliance' Witkowiak
+*/
+
+#ifndef _GSTRUCT_H
+#define _GSTRUCT_H
+
+struct f_date { /* date in filedesctiptor */
+ char f_year;
+ char f_month;
+ char f_day;
+ char f_hour;
+ char f_minute;
+};
+
+struct s_date { /* system date & time */
+ char s_year;
+ char s_month;
+ char s_day;
+ char s_hour;
+ char s_minutes;
+ char s_seconds;
+};
+
+struct tr_se { /* track and sector */
+ char track;
+ char sector;
+};
+
+struct fileheader { /* header block (like fileHeader) */
+ struct tr_se n_block;
+ char icon_desc[3];
+ char icon_pic[63];
+ char dostype;
+ char type;
+ char structure;
+ int load_address;
+ int end_address;
+ int exec_address;
+ char class_name[19];
+ char column_flag;
+ char author[64];
+ char note[95];
+};
+
+struct filehandle { /* filehandle in directory sectors */
+ char dostype; /* or in dirEntryBuf */
+ struct tr_se n_block;
+ char name[16];
+ struct tr_se header;
+ char structure;
+ char type;
+ struct f_date date;
+ int size;
+};
+
+struct pixel { /* describes point */
+ int x;
+ char y;
+};
+
+struct fontdesc { /* describes font */
+ char baseline;
+ char width;
+ char height;
+ char *index_tbl;
+ char *data_ptr;
+};
+
+struct window { /* describes screen region */
+ char top;
+ char bot;
+ int left;
+ int right;
+};
+
+struct VLIR_info { /* VLIR information */
+ char curRecord; /* currently only used in VLIR */
+ char usedRecords; /* as system info (curRecord is mainly of your interest */
+ char fileWritten;
+ int fileSize;
+};
+
+struct process { /* process info, declare table of that type */
+ int pointer; /* (like: struct process proctab[2]=... */
+ int jiffies; /* last entry HAVE TO BE {0,0} */
+};
+
+
+struct iconpic { /* icon/encoded bitmap description */
+ char *pic_ptr; /* ptr to a photo scrap (or encoded bitmap) */
+ char x; /* position in cards (*8 pixels) */
+ char y;
+ char width; /* in cards */
+ char heigth; /* in lines (pixels) */
+};
+
+struct icondef { /* icon definition for DoIcons */
+ char *pic_ptr; /* ptr to a photo scrap (or encoded bitmap) */
+ char x; /* position in cards (*8 pixels) */
+ char y;
+ char width; /* of icon (in cards) */
+ char heigth; /* of icon in lines (pixels) */
+ int proc_ptr; /* pointer to function handling that icon */
+};
+
+struct icontab {
+ char number; /* number of declared icons */
+ struct pixel mousepos; /* position of mouse after DoIcons */
+ struct icondef tab[]; /* table of size declared by icontab.number */
+};
+
+/* everything below is obsolete and kept for unknown reasons */
+
+struct menuitem {
+ char *name;
+ char type;
+ int rest; /* may be ptr to function, or if submenu ptr to struct menu */
+};
+
+struct menu {
+ struct window size;
+ char number;
+ struct menuitem items[];
+};
+
+struct inittab { /* use struct inittab mytab[n] for initram */
+ int ptr; /* ptr to 1st byte */
+ char number; /* number of following bytes */
+ char values[]; /* warning - in table size of this is same for all! */
+};
+
+#endif
--- /dev/null
+/*
+ GEOS constants reassembled 4-2-99
+ ported to small C 26.8.99, 25-26.10.99
+ Maciej 'YTM/Alliance' Witkowiak
+ ytm@friko.onet.pl
+*/
+
+#ifndef _GSYM_H
+#define _GSYM_H
+
+#ifndef _GSTRUCT_H
+#include <geos/gstruct.h>
+#endif
+
+#define nameBuf char[17]
+#define blockBuf char[256]
+
+#define zpage *(char*)0x0000
+
+#define CPU_DDR *(char*)0x00
+#define CPU_DATA *(char*)0x01
+
+#define r0 *(unsigned int*)0x02
+#define r0L *(char*)0x02
+#define r0H *(char*)0x03
+#define r1 *(unsigned int*)0x04
+#define r1L *(char*)0x04
+#define r1H *(char*)0x05
+#define drawWindow (*(struct window*)0x06)
+#define r2 *(unsigned int*)0x06
+#define r2L *(char*)0x06
+#define r2H *(char*)0x07
+#define r3 *(unsigned int*)0x08
+#define r3L *(char*)0x08
+#define r3H *(char*)0x09
+#define r4 *(unsigned int*)0x0a
+#define r4L *(char*)0x0a
+#define r4H *(char*)0x0b
+#define r5 *(unsigned int*)0x0c
+#define r5L *(char*)0x0c
+#define r5H *(char*)0x0d
+#define r6 *(unsigned int*)0x0e
+#define r6L *(char*)0x0e
+#define r6H *(char*)0x0f
+#define r7 *(unsigned int*)0x10
+#define r7L *(char*)0x10
+#define r7H *(char*)0x11
+#define r8 *(unsigned int*)0x12
+#define r8L *(char*)0x12
+#define r8H *(char*)0x13
+#define r9 *(unsigned int*)0x14
+#define r9L *(char*)0x14
+#define r9H *(char*)0x15
+#define r10 *(unsigned int*)0x16
+#define r10L *(char*)0x16
+#define r10H *(char*)0x17
+#define r11 *(unsigned int*)0x18
+#define r11L *(char*)0x18
+#define r11H *(char*)0x19
+#define r12 *(unsigned int*)0x1a
+#define r12L *(char*)0x1a
+#define r12H *(char*)0x1b
+#define r13 *(unsigned int*)0x1c
+#define r13L *(char*)0x1c
+#define r13H *(char*)0x1d
+#define r14 *(unsigned int*)0x1e
+#define r14L *(char*)0x1e
+#define r14H *(char*)0x1f
+#define r15 *(unsigned int*)0x20
+#define r15L *(char*)0x20
+#define r15H *(char*)0x21
+/* WARNING - these are used by C as temporary registers! */
+#define a0 *(unsigned int*)0xfb
+#define a0L *(char*)0xfb
+#define a0H *(char*)0xfc
+#define a1 *(unsigned int*)0xfd
+#define a1L *(char*)0xfd
+#define a1H *(char*)0xfe
+#define a2 *(unsigned int*)0x70
+#define a2L *(char*)0x70
+#define a2H *(char*)0x71
+#define a3 *(unsigned int*)0x72
+#define a3L *(char*)0x72
+#define a3H *(char*)0x73
+#define a4 *(unsigned int*)0x74
+#define a4L *(char*)0x74
+#define a4H *(char*)0x75
+#define a5 *(unsigned int*)0x76
+#define a5L *(char*)0x76
+#define a5H *(char*)0x77
+#define a6 *(unsigned int*)0x78
+#define a6L *(char*)0x78
+#define a6H *(char*)0x79
+#define a7 *(unsigned int*)0x7a
+#define a7L *(char*)0x7a
+#define a7H *(char*)0x7b
+#define a8 *(unsigned int*)0x7c
+#define a8L *(char*)0x7c
+#define a8H *(char*)0x7d
+#define a9 *(unsigned int*)0x7e
+#define a9L *(char*)0x7e
+#define a9H *(char*)0x7f
+
+#define curPattern *(unsigned int*)0x22
+#define string *(unsigned int*)0x24
+#define curFontDesc (*(struct fontdesc*)0x26)
+#define currentMode *(char*)0x2e
+#define dispBufferOn *(char*)0x2f
+#define mouseOn *(char*)0x30
+#define RAM_64K *(char*)0x30
+#define msePicPtr *(unsigned int*)0x31
+#define curWindow (*(struct window*)0x33)
+/*#define IO_IN *(char*)0x35
+ #define KRNL_IO_IN *(char*)0x36
+ #define KRNL_BAS_IO_IN *(char*)0x37*/
+#define pressFlag *(char*)0x39
+#define mousePos (*(struct pixel*)0x3a)
+#define returnAddress *(unsigned int*)0x3d
+#define graphMode *(char*)0x3f
+/*#define TURBO_DD00 *(char*)0x8e
+ #define TURBO_DD00_CPY *(char*)0x8f*/
+#define STATUS *(char*)0x90
+#define curDevice *(char*)0xba
+
+/* Here's my own errno location, I hope this won't confilct with anything... */
+#define errno *(char*)0x91
+
+#define irqvec *(unsigned int*)0x0314
+#define bkvec *(unsigned int*)0x0316
+#define nmivec *(unsigned int*)0x0318
+
+#define APP_RAM *(char*)0x0400
+#define BACK_SCR_BASE *(char*)0x6000
+#define PRINTBASE *(char*)0x7900
+#define OS_VARS *(char*)0x8000
+
+#define diskBlkBuf ((blockBuf)0x8000)
+#define fileHeader (*(struct fileheader*)0x8100)
+#define curDirHead ((blockBuf)0x8200)
+#define fileTrScTab ((struct tr_se[128])0x8300)
+#define dirEntryBuf (*(struct filehandle*)0x8400)
+
+#define DrACurDkNm ((nameBuf)0x841e)
+#define DrBCurDkNm ((nameBuf)0x8430)
+#define dataFileName ((nameBuf)0x8442)
+#define dataDiskName ((nameBuf)0x8453)
+#define PrntFileName ((nameBuf)0x8465)
+#define PrntDiskName ((nameBuf)0x8476)
+
+#define curDrive *(char*)0x8489
+#define diskOpenFlg *(char*)0x848a
+#define isGEOS *(char*)0x848b
+#define interleave *(char*)0x848c
+#define NUMDRV *(char*)0x848d
+
+#define driveType ((char[4])0x848e)
+#define turboFlags ((char[4])0x8492)
+
+#define VLIRInfo (*(struct VLIR_info*)0x8496)
+
+#define appMain *(unsigned int*)0x849b
+#define intTopVector *(unsigned int*)0x849d
+#define intBotVector *(unsigned int*)0x849f
+#define mouseVector *(unsigned int*)0x84a1
+#define keyVector *(unsigned int*)0x84a3
+#define inputVector *(unsigned int*)0x84a5
+#define mouseFaultVec *(unsigned int*)0x84a7
+#define otherPressVec *(unsigned int*)0x84a9
+#define StringFaultVec *(unsigned int*)0x84ab
+#define alarmTmtVector *(unsigned int*)0x84ad
+#define BRKVector *(unsigned int*)0x84af
+#define RecoverVector *(unsigned int*)0x84b1
+#define selectionFlash *(char*)0x84b3
+#define alphaFlag *(char*)0x84b4
+#define iconSelFlg *(char*)0x84b5
+#define faultData *(char*)0x84b6
+#define menuNumber *(char*)0x84b7
+#define mouseWindow (*(struct window*)0x84b8)
+#define stringXY (*(struct pixel*)0x84be)
+#define mousePicData *(char*)0x84c1
+
+#define maxMouseSpeed *(char*)0x8501
+#define minMouseSpeed *(char*)0x8502
+#define mouseAccel *(char*)0x8503
+#define keyData *(char*)0x8504
+#define mouseData *(char*)0x8505
+#define inputData *(char*)0x8506
+#define mouseSpeed *(char*)0x8507
+#define random *(char*)0x850a
+#define saveFontTab (*(struct fontdesc*)0x850c)
+
+#define dblClickCount *(char*)0x8515
+#define system_date (*(struct s_date*)0x8516)
+#define alarmSetFlag *(char*)0x851c
+#define sysDBData *(char*)0x851d
+#define screencolors *(char*)0x851e
+#define dlgBoxRamBuf *(char*)0x851f
+
+#define savedmoby2 *(char*)0x88bb
+#define scr80polar *(char*)0x88bc
+#define scr80colors *(char*)0x88bd
+#define vdcClrMode *(char*)0x88be
+#define driveData ((char[4])0x88bf)
+#define ramExpSize *(char*)0x88c3
+#define sysRAMFlg *(char*)0x88c4
+#define firstBoot *(char*)0x88c5
+#define curType *(char*)0x88c6
+#define ramBase *(char*)0x88c7
+/*Original:
+ #define inputDevName *(char*)0x88cb
+ #define memBase *(char*)0x88cf*/
+#define inputDevName ((nameBuf)0x88cb)
+#define DrCCurDkNm ((nameBuf)0x88dc)
+#define DrDCurDkNm ((nameBuf)0x88ee)
+#define dir2Head ((blockBuf)0x8900)
+#define SPRITE_PICS *(char*)0x8a00
+#define sprpic ((char[8][64])0x8a00)
+#define COLOR_MATRIX ((char[1000])0x8c00)
+#define objPointer ((char[8])0x8ff8)
+
+#define DISK_BASE *(char*)0x9000
+#define SCREEN_BASE *(char*)0xa000
+#define OS_ROM *(char*)0xc000
+#define OS_JUMPTAB *(char*)0xc100
+#define RAMC_BASE *(char*)0xde00
+#define RAMC_WINDOW *(char*)0xdf00
+#define EXP_BASE *(char*)0xdf00
+#define MOUSE_BASE_128 *(char*)0xfd00
+#define MOUSE_JMP_128 *(char*)0xfd00
+#define END_MOUSE_128 *(char*)0xfe80
+#define MOUSE_BASE *(char*)0xfe80
+#define MOUSE_JMP *(char*)0xfe80
+
+#define config *(char*)0xff00
+#define END_MOUSE *(char*)0xfffa
+#define NMI_VECTOR *(unsigned int*)0xfffa
+#define RESET_VECTOR *(unsigned int*)0xfffc
+#define IRQ_VECTOR *(unsigned int*)0xfffe
+
+#define vicbase *(char*)0xd000
+#define sidbase *(char*)0xd400
+#define mmu *(char*)0xd500
+#define VDC *(char*)0xd600
+#define ctab *(char*)0xd800
+#define cia1base *(char*)0xdc00
+#define cia2base *(char*)0xdd00
+
+#define mob0xpos *(char*)0xd000
+#define mob0ypos *(char*)0xd001
+#define mob1xpos *(char*)0xd002
+#define mob1ypos *(char*)0xd003
+#define mob2xpos *(char*)0xd004
+#define mob2ypos *(char*)0xd005
+#define mob3xpos *(char*)0xd006
+#define mob3ypos *(char*)0xd007
+#define mob4xpos *(char*)0xd008
+#define mob4ypos *(char*)0xd009
+#define mob5xpos *(char*)0xd00a
+#define mob5ypos *(char*)0xd00b
+#define mob6xpos *(char*)0xd00c
+#define mob6ypos *(char*)0xd00d
+#define mob7xpos *(char*)0xd00e
+#define mob7ypos *(char*)0xd00f
+#define msbxpos *(char*)0xd010
+#define grcntrl1 *(char*)0xd011
+#define rasreg *(char*)0xd012
+#define lpxpos *(char*)0xd013
+#define lpypos *(char*)0xd014
+#define mobenble *(char*)0xd015
+#define grcntrl2 *(char*)0xd016
+#define grmemptr *(char*)0xd018
+#define grirq *(char*)0xd019
+#define grirqen *(char*)0xd01a
+#define moby2 *(char*)0xd017
+#define mobprior *(char*)0xd01b
+#define mobmcm *(char*)0xd01c
+#define mobx2 *(char*)0xd01d
+#define mobmobcol *(char*)0xd01e
+#define mobbakcol *(char*)0xd01f
+#define extclr *(char*)0xd020
+#define bakclr0 *(char*)0xd021
+#define bakclr1 *(char*)0xd022
+#define bakclr2 *(char*)0xd023
+#define bakclr3 *(char*)0xd024
+#define mcmclr0 *(char*)0xd025
+#define mcmclr1 *(char*)0xd026
+#define mob0clr *(char*)0xd027
+#define mob1clr *(char*)0xd028
+#define mob2clr *(char*)0xd029
+#define mob3clr *(char*)0xd02a
+#define mob4clr *(char*)0xd02b
+#define mob5clr *(char*)0xd02c
+#define mob6clr *(char*)0xd02d
+#define mob7clr *(char*)0xd02e
+#define keyreg *(char*)0xd02f
+#define clkreg *(char*)0xd030
+
+#define vdcreg *(char*)0xd600
+#define vdcdata *(char*)0xd601
+
+#endif
+
--- /dev/null
+/*
+ GEOS system functions
+
+ ported to small C on 27.10.1999
+ by Maciej 'YTM/Alliance' Witkowiak
+*/
+
+#ifndef _GSYS_H
+#define _GSYS_H
+
+void __fastcall__ FirstInit(void);
+void __fastcall__ InitForIO(void);
+void __fastcall__ DoneWithIO(void);
+void __fastcall__ MainLoop(void);
+void __fastcall__ EnterDeskTop(void);
+void __fastcall__ ToBASIC(void);
+void __fastcall__ Panic(void);
+
+void __fastcall__ CallRoutine(void *myRoutine);
+
+int __fastcall__ GetSerialNumber(void);
+char __fastcall__ GetRandom(void);
+
+void __fastcall__ SetDevice(char newdev);
+
+#endif
--- /dev/null
+/*
+ * iso646.h
+ *
+ * Ullrich von Bassewitz, 11.12.1998
+ *
+ */
+
+
+
+#ifndef _ISO646_H
+#define _ISO646_H
+
+
+
+/* Operator tokens */
+#define and &&
+#define and_eq &=
+#define bitand &
+#define bitor |
+#define compl ~
+#define not !
+#define not_eq !=
+#define or ||
+#define or_eq |=
+#define xor ^
+#define xor_eq ^=
+
+
+
+/* End of iso646.h */
+#endif
+
+
+
--- /dev/null
+/*
+ * joystick.h
+ *
+ * Ullrich von Bassewitz, 24.09.1998
+ *
+ * Read the joystick on systems that support it.
+ *
+ */
+
+
+
+#ifndef _JOYSTICK_H
+#define _JOYSTICK_H
+
+
+
+/* Define __JOYSTICK__ for systems that support a joystick */
+#ifdef __C64__
+# define __JOYSTICK__
+#endif
+#ifdef __C128__
+# define __JOYSTICK__
+#endif
+#ifdef __PLUS4__
+# define __JOYSTICK__
+#endif
+#ifdef __NES__
+# define __JOYSTICK__
+#endif
+
+/* Argument for the function */
+#define JOY_1 0
+#define JOY_2 1
+
+/* Result codes of the function. The actual code is a bitwise or
+ * of one or more of the following values.
+ */
+#ifdef __NES__
+# define JOY_A 0x01
+# define JOY_B 0x02
+# define JOY_SELECT 0x04
+# define JOY_START 0x08
+# define JOY_UP 0x10
+# define JOY_DOWN 0x20
+# define JOY_LEFT 0x40
+# define JOY_RIGHT 0x80
+#else
+# define JOY_UP 0x01
+# define JOY_DOWN 0x02
+# define JOY_LEFT 0x04
+# define JOY_RIGHT 0x08
+# define JOY_FIRE 0x10
+#endif
+
+
+
+unsigned __fastcall__ readjoy (unsigned char joy);
+/* Read the joystick. The argument is one of JOY_1/JOY2 */
+
+
+
+/* End of joystick.h */
+#endif
+
+
+
--- /dev/null
+/*
+ * limits.h
+ *
+ * Ullrich von Bassewitz, 04.06.1998
+ *
+ */
+
+
+
+#ifndef _LIMITS_H
+#define _LIMITS_H
+
+
+
+#define CHAR_BIT 8
+
+#define SCHAR_MIN (-128)
+#define SCHAR_MAX 127
+
+#define UCHAR_MAX 255
+
+#define CHAR_MIN 0
+#define CHAR_MAX 255
+
+#define SHRT_MIN (-32768)
+#define SHRT_MAX 32767
+
+#define USHRT_MAX 65535U
+
+#define INT_MIN (-32768)
+#define INT_MAX 32767
+
+#define UINT_MAX 65535U
+
+#define LONG_MAX 2147483647L
+#define LONG_MIN (-2147483648L)
+
+#define ULONG_MAX 4294967295UL
+
+
+
+/* End of limits.h */
+#endif
+
+
+
--- /dev/null
+/*
+ * locale.h
+ *
+ * Ullrich von Bassewitz, 11.12.1998
+ *
+ */
+
+
+
+#ifndef _LOCALE_H
+#define _LOCALE_H
+
+
+
+/* NULL pointer */
+#ifdef NULL
+# undef NULL
+#endif
+#define NULL 0
+
+/* Locale information constants */
+#define LC_ALL 0
+#define LC_COLLATE 1
+#define LC_CTYPE 2
+#define LC_MONETARY 3
+#define LC_NUMERIC 4
+#define LC_TIME 5
+
+/* Struct containing locale settings */
+struct lconv {
+ char* currency_symbol;
+ char* decimal_point;
+ char* grouping;
+ char* int_curr_symbol;
+ char* mon_decimal_point;
+ char* mon_grouping;
+ char* mon_thousands_sep;
+ char* negative_sign;
+ char* positive_sign;
+ char* thousands_sep;
+ char frac_digits;
+ char int_frac_digits;
+ char n_cs_precedes;
+ char n_sep_by_space;
+ char n_sign_posn;
+ char p_cs_precedes;
+ char p_sep_by_space;
+ char p_sign_posn;
+};
+
+/* Function prototypes */
+struct lconv* localeconv (void);
+char* setlocale (int category, const char* locale);
+
+
+
+/* End of locale.h */
+#endif
+
+
+
--- /dev/null
+/*
+ * mouse.h
+ *
+ * Ullrich von Bassewitz, 24.04.1999
+ */
+
+
+
+#ifndef _MOUSE_H
+#define _MOUSE_H
+
+
+
+/* Define __MOUSE__ for systems that support a proportional mouse */
+#ifdef __C64__
+# define __MOUSE__
+#endif
+#ifdef __C128__
+# define __MOUSE__
+#endif
+
+
+
+void __fastcall__ mouse_init (unsigned char port, unsigned char sprite);
+/* Setup the mouse interrupt handler. If the sprite value is != zero, the
+ * mouse routines will manage the sprite with this number. That means, it
+ * is moved if the mouse is moved (provided that the mouse cursor is visible),
+ * and switch on and off in the show and hide functions.
+ * The port parameter gives the joystick port used for the mouse and is only
+ * needed to read the mouse button state.
+ * After calling this function, the mouse is invisble, the cursor is placed
+ * at 0/0 (upper left corner), and the bounding box is reset to cover the
+ * whole screen. Call mouse_show once to make the mouse cursor visible.
+ */
+
+void mouse_done (void);
+/* Disable the mouse, remove the interrupt handler. This function MUST be
+ * called before terminating the program, otherwise odd things may happen.
+ * If in doubt, install an exit handler (using atexit) that calls this
+ * function.
+ */
+
+void mouse_hide (void);
+/* Hide the mouse. This function doesn't do anything visible if no sprite is
+ * used. The function manages a counter and may be called more than once.
+ * For each call to mouse_hide there must be a call to mouse_show to make
+ * the mouse visible again.
+ */
+
+void mouse_show (void);
+/* Show the mouse. This function doesn't do anything visible if no sprite is
+ * used. See mouse_hide for more information.
+ */
+
+void __fastcall__ mouse_box (int minx, int miny, int maxx, int maxy);
+/* Set the bounding box for the mouse pointer movement. The mouse X and Y
+ * coordinates will never go outside the given box.
+ * NOTE: The function does *not* check if the mouse is currently inside the
+ * given margins. The proper way to use this function therefore is:
+ *
+ * - Hide the mouse
+ * - Set the bounding box
+ * - Place the mouse at the desired position
+ * - Show the mouse again.
+ *
+ * NOTE2: When setting the box to something that is larger than the actual
+ * screen, the positioning of the mouse cursor will fail. If such margins
+ * are really what you want, you have to use your own cursor routines.
+ */
+
+void __fastcall__ mouse_move (int x, int y);
+/* Set the mouse cursor to the given position. If a mouse cursor is defined
+ * and currently visible, the mouse cursor is also moved.
+ * NOTE: This function does not check if the given position is valid and
+ * inside the bounding box.
+ */
+
+void mouse_info (void);
+/* Hmmm...
+ */
+
+
+
+/* End of mouse.h */
+#endif
+
+
+
--- /dev/null
+/*
+ * pet.h
+ *
+ * Ullrich von Bassewitz, 26.11.1998
+ */
+
+
+
+#ifndef _PET_H
+#define _PET_H
+
+
+
+/* Color defines */
+#define COLOR_BLACK 0x00
+#define COLOR_WHITE 0x01
+
+
+
+/* End of pet.h */
+#endif
+
+
+
--- /dev/null
+/*
+ * plus4.h
+ *
+ * Ullrich von Bassewitz, 12.08.1998
+ */
+
+
+
+#ifndef _PLUS4_H
+#define _PLUS4_H
+
+
+
+/* Additional key defines */
+#define CH_F1 133
+#define CH_F2 137
+#define CH_F3 134
+#define CH_F4 138
+#define CH_F5 135
+#define CH_F6 139
+#define CH_F7 136
+#define CH_F8 140
+
+
+
+/* Color attributes */
+#define CATTR_LUMA0 0x00
+#define CATTR_LUMA1 0x10
+#define CATTR_LUMA2 0x20
+#define CATTR_LUMA3 0x30
+#define CATTR_LUMA4 0x40
+#define CATTR_LUMA5 0x50
+#define CATTR_LUMA6 0x60
+#define CATTR_LUMA7 0x70
+#define CATTR_BLINK 0x80
+
+/* Base colors */
+#define BCOLOR_BLACK 0x00
+#define BCOLOR_WHITE 0x01
+#define BCOLOR_RED 0x02
+#define BCOLOR_CYAN 0x03
+#define BCOLOR_VIOLET 0x04
+#define BCOLOR_GREEN 0x05
+#define BCOLOR_BLUE 0x06
+#define BCOLOR_YELLOW 0x07
+#define BCOLOR_ORANGE 0x08
+#define BCOLOR_BROWN 0x09
+#define BCOLOR_LEMON 0x0A /* What's that color? */
+#define BCOLOR_LIGHTVIOLET 0x0B
+#define BCOLOR_BLUEGREEN 0x0C
+#define BCOLOR_LIGHTBLUE 0x0D
+#define BCOLOR_DARKBLUE 0x0E
+#define BCOLOR_LIGHTGREEN 0x0F
+
+
+
+/* Now try to mix up a C64/C128 compatible palette */
+#define COLOR_BLACK (BCOLOR_BLACK)
+#define COLOR_WHITE (BCOLOR_WHITE | CATTR_LUMA7)
+#define COLOR_RED (BCOLOR_RED | CATTR_LUMA4)
+#define COLOR_CYAN (BCOLOR_CYAN | CATTR_LUMA7)
+#define COLOR_VIOLET (BCOLOR_VIOLET | CATTR_LUMA7)
+#define COLOR_GREEN (BCOLOR_GREEN | CATTR_LUMA7)
+#define COLOR_BLUE (BCOLOR_BLUE | CATTR_LUMA7)
+#define COLOR_YELLOW (BCOLOR_YELLOW | CATTR_LUMA7)
+#define COLOR_ORANGE (BCOLOR_ORANGE | CATTR_LUMA7)
+#define COLOR_BROWN (BCOLOR_BROWN | CATTR_LUMA7)
+#define COLOR_LIGHTRED (BCOLOR_RED | CATTR_LUMA7)
+#define COLOR_GRAY1 (BCOLOR_WHITE | CATTR_LUMA1)
+#define COLOR_GRAY2 (BCOLOR_WHITE | CATTR_LUMA3)
+#define COLOR_LIGHTGREEN (BCOLOR_LIGHTGREEN | CATTR_LUMA7)
+#define COLOR_LIGHTBLUE (BCOLOR_LIGHTBLUE | CATTR_LUMA7)
+#define COLOR_GRAY3 (BCOLOR_WHITE | CATTR_LUMA5)
+
+
+
+/* End of plus4.h */
+#endif
+
+
+
--- /dev/null
+/*
+ * rs232.h
+ *
+ * Ullrich von Bassewitz, 19.3.1999
+ *
+ * This module is based upon the public domain swiftlink module written by
+ * Craig Bruce. Thanks a lot!
+ *
+ */
+
+
+
+#ifndef _RS232_H
+#define _RS232_h
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Baudrate settings */
+#define RS_BAUD_50 0x00
+#define RS_BAUD_110 0x01
+#define RS_BAUD_134_5 0x02
+#define RS_BAUD_300 0x03
+#define RS_BAUD_600 0x04
+#define RS_BAUD_1200 0x05
+#define RS_BAUD_2400 0x06
+#define RS_BAUD_4800 0x07
+#define RS_BAUD_9600 0x08
+#define RS_BAUD_19200 0x09
+#define RS_BAUD_38400 0x0A
+#define RS_BAUD_57600 0x0B
+#define RS_BAUD_115200 0x0C
+#define RS_BAUD_230400 0x0D
+
+/* Stop bit settings */
+#define RS_STOP_1 0x00
+#define RS_STOP_2 0x80
+
+/* Data bit settings */
+#define RS_BITS_5 0x60
+#define RS_BITS_6 0x40
+#define RS_BITS_7 0x20
+#define RS_BITS_8 0x00
+
+/* Parity settings */
+#define RS_PAR_NONE 0x00
+#define RS_PAR_ODD 0x20
+#define RS_PAR_EVEN 0x60
+#define RS_PAR_MARK 0xA0
+#define RS_PAR_SPACE 0xE0
+
+/* Bit masks to mask out things from the status returned by rs232_status */
+#define RS_STATUS_PE 0x01 /* Parity error */
+#define RS_STATUS_FE 0x02 /* Framing error */
+#define RS_STATUS_OVERRUN 0x04 /* Overrun error */
+#define RS_STATUS_RDRF 0x08 /* Receiver data register full */
+#define RS_STATUS_THRE 0x10 /* Transmit holding reg. empty */
+#define RS_STATUS_DCD 0x20 /* NOT data carrier detect */
+#define RS_STATUS_DSR 0x40 /* NOT data set ready */
+#define RS_STATUS_IRQ 0x80 /* IRQ condition */
+
+/* Error codes returned by all functions */
+#define RS_ERR_OK 0x00 /* Not an error - relax */
+#define RS_ERR_NOT_INITIALIZED 0x01 /* Module not initialized */
+#define RS_ERR_BAUD_TOO_FAST 0x02 /* Cannot handle baud rate */
+#define RS_ERR_BAUD_NOT_AVAIL 0x03 /* Baud rate not available */
+#define RS_ERR_NO_DATA 0x04 /* Nothing to read */
+#define RS_ERR_OVERFLOW 0x05 /* No room in send buffer */
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+unsigned char __fastcall__ rs232_init (char hacked);
+/* Initialize the serial port, install the interrupt handler. The parameter
+ * must be true (non zero) for a hacked swiftlink and false (zero) otherwise.
+ */
+
+unsigned char __fastcall__ rs232_params (unsigned char params, unsigned char parity);
+/* Set the port parameters. Use a combination of the #defined values above. */
+
+unsigned char __fastcall__ rs232_done (void);
+/* Close the port, deinstall the interrupt hander. You MUST call this function
+ * before terminating the program, otherwise the machine may crash later. If
+ * in doubt, install an exit handler using atexit(). The function will do
+ * nothing, if it was already called.
+ */
+
+unsigned char __fastcall__ rs232_get (char* b);
+/* Get a character from the serial port. If no characters are available, the
+ * function will return RS_ERR_NO_DATA, so this is not a fatal error.
+ */
+
+unsigned char __fastcall__ rs232_put (char b);
+/* Send a character via the serial port. There is a transmit buffer, but
+ * transmitting is not done via interrupt. The function returns
+ * RS_ERR_OVERFLOW if there is no space left in the transmit buffer.
+ */
+
+unsigned char __fastcall__ rs232_pause (void);
+/* Assert flow control and disable interrupts. */
+
+unsigned char __fastcall__ rs232_unpause (void);
+/* Re-enable interrupts and release flow control */
+
+unsigned char __fastcall__ rs232_status (unsigned char* status,
+ unsigned char* errors);
+/* Return the serial port status. */
+
+
+
+/* End of rs232.h */
+#endif
+
+
+
--- /dev/null
+/*
+ * setjmp.h
+ *
+ * Ullrich von Bassewitz, 06.06.1998
+ *
+ */
+
+
+
+#ifndef _SETJMP_H
+#define _SETJMP_H
+
+
+
+typedef char jmp_buf [5];
+
+
+
+int __fastcall__ _setjmp (jmp_buf buf);
+#define setjmp _setjmp /* ISO insists on a macro */
+void __fastcall__ longjmp (jmp_buf buf, int retval);
+
+
+
+/* End of stddef.h */
+#endif
+
+
+
--- /dev/null
+/*
+ * stdarg.h
+ *
+ * Ullrich von Bassewitz, 31.05.1998
+ *
+ */
+
+
+
+#ifndef _STDARG_H
+#define _STDARG_H
+
+
+
+typedef unsigned char* va_list;
+
+#define va_start(ap, fix) ap = (va_list)&fix + *(((va_list)&fix)-1) - __fixargs__
+#define va_arg(ap,type) ((type)*(ap -= ((sizeof (type) + 1) & ~1)))
+#define va_end(ap)
+
+/* This is only valid *before* the first call to va_arg. It will also work
+ * only for int sized parameters.
+ */
+#define va_fix(ap, offs) *(ap+(__fixargs__-2*offs))
+
+
+
+/* End of stdarg.h */
+#endif
+
+
+
+
--- /dev/null
+/*
+ * stddef.h
+ *
+ * Ullrich von Bassewitz, 06.06.1998
+ *
+ */
+
+
+
+#ifndef _STDDEF_H
+#define _STDDEF_H
+
+
+
+/* Standard data types */
+typedef int ptrdiff_t;
+typedef unsigned size_t;
+
+/* NULL pointer */
+#ifdef NULL
+# undef NULL
+#endif
+#define NULL 0
+
+/* offsetof macro */
+#define offsetof(type, member) (size_t) (&((type*) 0)->member)
+
+
+
+/* End of stddef.h */
+#endif
+
+
+
--- /dev/null
+/*
+ * stdio.h
+ *
+ * Ullrich von Bassewitz, 30.05.1998
+ *
+ */
+
+
+
+#ifndef _STDIO_H
+#define _STDIO_H
+
+
+
+#ifndef _STDDEF_H
+# include <stddef.h>
+#endif
+#ifndef _STDARG_H
+# include <stdarg.h>
+#endif
+
+
+
+/* Types */
+typedef struct _FILE FILE;
+typedef unsigned long fpos_t;
+
+/* Standard file descriptors */
+extern FILE* stdin;
+extern FILE* stdout;
+extern FILE* stderr;
+
+/* Standard defines */
+#define _IOFBF 0
+#define _IOLBF 1
+#define _IONBF 2
+#define BUFSIZ 256
+#define EOF -1
+#define FILENAME_MAX 16
+#define FOPEN_MAX 8
+#define L_tmpnam (FILENAME_MAX + 1)
+#define SEEK_CUR 0
+#define SEEK_END 1
+#define SEEK_SET 2
+#define TMP_MAX 256
+
+
+
+/* Functions */
+void __fastcall__ clearerr (FILE* f);
+int fclose (FILE* f);
+int __fastcall__ feof (FILE* f);
+int __fastcall__ ferror (FILE* f);
+int __fastcall__ fflush (FILE* f);
+int fgetc (FILE* f);
+char* fgets (char* buf, size_t size, FILE* f);
+FILE* fopen (const char* name, const char* mode);
+int fprintf (FILE* f, const char* format, ...);
+int fputc (int c, FILE* f);
+int fputs (const char* s, FILE* f);
+size_t fread (void* buf, size_t size, size_t count, FILE* f);
+FILE* freopen (const char* name, const char* mode, FILE* f);
+size_t fwrite (const void* buf, size_t size, size_t count, FILE* f);
+int getchar (void);
+char* gets (char* s);
+void perror (const char* s);
+int printf (const char* format, ...);
+int putchar (int c);
+int puts (const char* s);
+int remove (const char* name);
+int rename (const char* old, const char* new);
+int sprintf (char* buf, const char* format, ...);
+int vfprintf (FILE* f, const char* format, va_list ap);
+int vprintf (const char* format, va_list ap);
+int vsprintf (char* buf, const char* format, va_list ap);
+
+#ifndef __STRICT_ANSI__
+FILE* fdopen (int fd, const char* mode); /* Unix */
+int __fastcall__ fileno (FILE* f); /* Unix */
+#endif
+
+
+/* Masking macros for some functions */
+#define getchar() fgetc (stdin) /* ANSI */
+#define putchar(c) fputc (c, stdout) /* ANSI */
+#define getc(f) fgetc (f) /* ANSI */
+#define putc(c, f) fputc (c, f) /* ANSI */
+
+/* Non-standard function like macros */
+#ifndef __STRICT_ANSI__
+#define flushall() /* Unix */
+#define unlink(name) remove (name) /* Unix */
+#endif
+
+
+
+/* End of stdio.h */
+#endif
+
+
+
--- /dev/null
+/*
+ * stdlib.h
+ *
+ * Ullrich von Bassewitz, 02.06.1998
+ *
+ */
+
+
+
+#ifndef _STDLIB_H
+#define _STDLIB_H
+
+
+
+#include <stddef.h>
+
+
+
+/* Standard exit codes */
+#define EXIT_SUCCESS 0
+#define EXIT_FAILURE 1
+
+
+
+/* Memory management */
+void* malloc (size_t size);
+void* calloc (size_t count, size_t size);
+void* realloc (void* block, size_t size);
+void free (void* block);
+#ifndef __STRICT_ANSI__
+void _hadd (void* mem, size_t size); /* Non-standard */
+#endif
+
+/* Random numbers */
+#define RAND_MAX 0x7FFF
+int rand (void);
+void __fastcall__ srand (unsigned seed);
+
+/* Other standard stuff */
+void abort (void);
+int __fastcall__ abs (int val);
+long __fastcall__ labs (long val);
+int __fastcall__ atoi (char* s);
+long __fastcall__ atol (char* s);
+int __fastcall__ atexit (void (*exitfunc) (void));
+void* bsearch (const void* key, const void* base, size_t n,
+ size_t size, int (*cmp) (const void*, const void*));
+void exit (int ret);
+char* __fastcall__ getenv (const char* name);
+void qsort (void* base, size_t count, size_t size,
+ int (*compare) (const void*, const void*));
+
+/* Non-ANSI functions */
+#ifndef __STRICT_ANSI__
+void __fastcall__ _swap (void* p, void* q, size_t size);
+char* __fastcall__ itoa (int val, char* buf, int radix);
+char* __fastcall__ utoa (unsigned val, char* buf, int radix);
+char* __fastcall__ ltoa (long val, char* buf, int radix);
+char* __fastcall__ ultoa (unsigned long val, char* buf, int radix);
+#endif
+
+
+
+/* End of stdlib.h */
+#endif
+
+
+
--- /dev/null
+/*
+ * string.h
+ *
+ * Ullrich von Bassewitz, 04.06.1998
+ *
+ */
+
+
+
+#ifndef _STRING_H
+#define _STRING_H
+
+
+
+#include <stddef.h>
+
+
+
+char* __fastcall__ strcat (char* dest, const char* src);
+char* __fastcall__ strchr (const char* s, int c);
+int __fastcall__ strcmp (const char* s1, const char* s2);
+int __fastcall__ strcoll (const char* s1, const char* s2);
+char* __fastcall__ strcpy (char* dest, const char* src);
+size_t __fastcall__ strcspn (const char* s1, const char* s2);
+char* __fastcall__ strerror (int errcode);
+size_t __fastcall__ strlen (const char* s);
+char* __fastcall__ strncat (char* s1, const char* s2, size_t count);
+int __fastcall__ strncmp (const char* s1, const char* s2, size_t count);
+char* __fastcall__ strncpy (char* dest, const char* src, size_t count);
+char* __fastcall__ strrchr (const char* s, int c);
+size_t __fastcall__ strspn (const char* s1, const char* s2);
+char* __fastcall__ strstr (const char* str, const char* substr);
+char* strtok (char* s1, const char* s2);
+size_t strxfrm (char* s1, const char* s2, size_t count);
+void* __fastcall__ memchr (const void* mem, int c, size_t count);
+int __fastcall__ memcmp (const void* p1, const void* p2, size_t count);
+void* __fastcall__ memcpy (void* dest, const void* src, size_t count);
+void* __fastcall__ memmove (void* dest, const void* src, size_t count);
+void* __fastcall__ memset (void* s, int c, size_t count);
+
+/* Non standard: */
+#ifndef __STRICT_ANSI__
+char* strdup (const char* s); /* SYSV/BSD */
+int __fastcall__ stricmp (const char* s1, const char* s2); /* DOS/Windows */
+int __fastcall__ strcasecmp (const char* s1, const char* s2); /* Same for Unix */
+char* __fastcall__ strlwr (char* s);
+char* __fastcall__ strlower (char* s);
+char* __fastcall__ strupr (char* s);
+char* __fastcall__ strupper (char* s);
+#endif
+
+
+
+/* End of string.h */
+#endif
+
+
+
--- /dev/null
+/*
+ * time.h
+ *
+ * Ullrich von Bassewitz, 17.06.1998
+ *
+ */
+
+
+
+#ifndef _TIME_H
+#define _TIME_H
+
+
+
+#include <stddef.h>
+
+
+
+typedef unsigned long time_t;
+typedef unsigned long clock_t;
+
+/* Structure for broken down time */
+struct tm {
+ int tm_sec;
+ int tm_min;
+ int tm_hour;
+ int tm_mday;
+ int tm_mon;
+ int tm_year;
+ int tm_wday;
+ int tm_yday;
+ int tm_isdst;
+};
+
+/* The 610 gets its clock from the AC current */
+#ifdef __CBM__
+# ifdef __CBM610__
+# define CLK_TCK 50 /* POSIX */
+# define CLOCKS_PER_TICK 50 /* ANSI */
+# else
+# define CLK_TCK 60 /* POSIX */
+# define CLOCKS_PER_TICK 60 /* ANSI */
+# endif
+#endif
+
+
+
+/* Function prototypes */
+clock_t clock (void);
+
+
+
+/* End of time.h */
+
+#endif
+
+
+
--- /dev/null
+libr65.tmp
+*.lib
--- /dev/null
+#
+# makefile for CC65 runtime library
+#
+
+.SUFFIXES: .o .obj .s .c
+
+# Defines used by the submakes:
+export CC = ../../src/cc65/cc65
+export AS = ../../src/ca65/ca65
+
+# Define used within this makefile
+AR = ../src/ar65/ar65
+
+#-----------------------------------------------------------------------------
+
+all : apple2lib c64lib c128lib cbm610lib geoslib petlib plus4lib
+
+#-----------------------------------------------------------------------------
+# Apple ][
+
+apple2lib:
+ export CFLAGS="-Osir -g -t apple2 -I../../include";\
+ for i in apple2 common runtime conio dbg; do $(MAKE) -C $$i; done
+ mv apple2/crt0.o apple2.o
+ for i in apple2 common runtime conio dbg; do \
+ $(AR) a apple2.lib $$i/*.o;\
+ done
+
+#-----------------------------------------------------------------------------
+# Atari
+
+atarilib:
+ export CFLAGS="-Osir -g -t atari -I../../include";\
+ for i in atari common runtime conio dbg; do $(MAKE) -C $$i; done
+ mv atari/crt0.o atari.o
+ for i in atari common runtime conio dbg; do \
+ $(AR) a atari.lib $$i/*.o;\
+ done
+
+#-----------------------------------------------------------------------------
+# C64
+
+c64lib:
+ export CFLAGS="-Osir -g -t c64 -I../../include";\
+ for i in c64 cbm common runtime conio dbg; do $(MAKE) -C $$i; done
+ mv c64/crt0.o c64.o
+ for i in c64 cbm common runtime conio dbg; do \
+ $(AR) a c64.lib $$i/*.o;\
+ done
+
+#-----------------------------------------------------------------------------
+# C128
+
+c128lib:
+ export CFLAGS="-Osir -g -t c128 -I../../include";\
+ for i in c128 cbm common runtime conio dbg; do $(MAKE) -C $$i; done
+ mv c128/crt0.o c128.o
+ for i in c128 cbm common runtime conio dbg; do \
+ $(AR) a c128.lib $$i/*.o;\
+ done
+
+#-----------------------------------------------------------------------------
+# PET-II series
+
+cbm610lib:
+ export CFLAGS="-Osir -g -t cbm610 -I../../include";\
+ for i in cbm610 cbm common runtime conio dbg; do $(MAKE) -C $$i; done
+ mv cbm610/crt0.o cbm610.o
+ for i in cbm610 cbm common runtime conio dbg; do \
+ $(AR) a cbm610.lib $$i/*.o;\
+ done
+
+#-----------------------------------------------------------------------------
+# GEOS on the C64/128
+
+geoslib:
+ export CFLAGS="-Osir -g -t geos -I../../include";\
+ for i in geos common runtime; do $(MAKE) -C $$i; done
+ for i in common runtime; do \
+ $(AR) a geos.lib $$i/*.o;\
+ done
+
+#-----------------------------------------------------------------------------
+# CBM PET machines
+
+petlib:
+ export CFLAGS="-Osir -g -t pet -I../../include";\
+ for i in pet cbm common runtime conio dbg; do $(MAKE) -C $$i; done
+ mv pet/crt0.o pet.o
+ for i in pet cbm common runtime conio dbg; do \
+ $(AR) a pet.lib $$i/*.o;\
+ done
+
+#-----------------------------------------------------------------------------
+# Commodore C116, C16 and Plus/4
+
+plus4lib:
+ export CFLAGS="-Osir -g -t plus4 -I../../include";\
+ for i in plus4 cbm common runtime conio dbg; do $(MAKE) -C $$i; done
+ mv plus4/crt0.o plus4.o
+ for i in plus4 cbm common runtime conio dbg; do \
+ $(AR) a plus4.lib $$i/*.o;\
+ done
+
+#-----------------------------------------------------------------------------
+# Dummy targets
+
+.PHONY: clean
+clean:
+ @for i in apple2 atari c128 c64 cbm cbm610 common conio dbg geos pet plus4 runtime; do \
+ $(MAKE) -C $$i clean; \
+ done
+
+.PHONY: zap
+zap: clean
+ @rm -f *.lib
+
+
+
+
--- /dev/null
+#
+# makefile for CC65 runtime library
+#
+
+.SUFFIXES: .o .s .c
+
+%.o: %.c
+ @echo $<
+ @$(CC) $(CFLAGS) $<
+ @$(AS) -o $@ $(AFLAGS) $(*).s
+
+%.o: %.s
+ @echo $<
+ @$(AS) -g -o $@ $(AFLAGS) $<
+
+C_OBJS =
+
+S_OBJS = break.o clrscr.o cclear.o cgetc.o chline.o color.o \
+ cputc.o crt0.o ctype.o \
+ cvline.o kbhit.o read.o revers.o where.o write.o
+
+all: $(C_OBJS) $(S_OBJS)
+
+clean:
+ @rm -f $(C_OBJS:.c=.s)
+ @rm -f $(C_OBJS)
+ @rm -f $(S_OBJS)
+ @rm -f crt0.o
+
--- /dev/null
+; Break vector
+BRKVec = $03F0
+
+; Goto Dos
+RESTOR = $03D0
+
+; Top of available memory
+; This is actually for DOS 3.3 need to change it for ProDos
+TOPMEM = $9600
+
+; Soft switches
+;
+; write to USEROM to enable apple rom C000-CFFF
+USEROM = $C007
+; 80 column card switches
+C80ON = $C00C
+C80OFF = $C00D
+RD80COL = $C01F
+PG2OFF = $C054
+PG2ON = $C055
+RDPAGE2 = $C01C
+
+; Text routines
+MIN_X = $20
+MAX_X = $21
+MIN_Y = $22
+MAX_Y = $23
+CH = $24
+CV = $25
+BASL = $28
+TEXTTYP = $32
+HOME = $FC58
+VTABZ = $FC24
+COUT = $FDED
+
+; Keyboard entries
+RDKEY = $FD0C
+CLEAR_KEY_STROBE = $C010
+KEY_STROBE = $C000
+
+; Game controller
+OPEN_APPLE = $C061
+CLOSED_APPLE = $C062
--- /dev/null
+;
+; Ullrich von Bassewitz, 27.09.1998
+;
+; void set_brk (unsigned Addr);
+; void reset_brk (void);
+;
+
+ .export _set_brk, _reset_brk
+ .export _brk_a, _brk_x, _brk_y, _brk_sr, _brk_pc
+ .import _atexit
+
+ .include "apple2.inc"
+
+_brk_a = $45
+_brk_x = $46
+_brk_y = $47
+_brk_sr = $48
+_brk_sp = $49
+_brk_pc = $3A
+
+.bss
+oldvec: .res 2 ; Old vector
+
+
+.data
+uservec: jmp $FFFF ; Patched at runtime
+
+
+.code
+
+; Set the break vector
+.proc _set_brk
+
+ sta uservec+1
+ stx uservec+2 ; Set the user vector
+
+ lda oldvec
+ ora oldvec+1 ; Did we save the vector already?
+ bne L1 ; Jump if we installed the handler already
+
+ lda BRKVec
+ sta oldvec
+ lda BRKVec+1
+ sta oldvec+1 ; Save the old vector
+
+ lda #<_reset_brk
+ ldx #>_reset_brk
+ jsr _atexit ; Install an exit handler
+
+L1: lda #<brk_handler ; Set the break vector to our routine
+ sta BRKVec
+ lda #>brk_handler
+ sta BRKVec+1
+ rts
+
+.endproc
+
+
+; Reset the break vector
+.proc _reset_brk
+
+ lda oldvec
+ sta BRKVec
+ lda oldvec+1
+ sta BRKVec+1
+ rts
+
+.endproc
+
+
+
+; Break handler, called if a break occurs
+
+.proc brk_handler
+
+ sec
+ lda _brk_pc
+ sbc #$02 ; Point to start of brk
+ sta _brk_pc
+ lda _brk_pc+1
+ sbc #$00
+ sta _brk_pc+1
+
+ clc
+ lda _brk_sp
+ adc #$04 ; Adjust stack pointer
+ sta _brk_sp
+
+ lda _brk_sr ; Clear brk
+ and #$EF
+ sta _brk_sr
+
+ jsr uservec ; Call the user's routine
+
+ lda _brk_pc+1
+ pha
+ lda _brk_pc
+ pha
+ lda _brk_sr
+ pha
+
+ ldx _brk_x
+ ldy _brk_y
+ lda _brk_a
+
+ rti ; Jump back...
+
+.endproc
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 08.08.1998
+;
+; void cclearxy (unsigned char x, unsigned char y, unsigned char length);
+; void cclear (unsigned char length);
+;
+
+ .export _cclearxy, _cclear
+ .import popa, _gotoxy, cputdirect
+ .importzp tmp1
+
+_cclearxy:
+ pha ; Save the length
+ jsr popa ; Get y
+ jsr _gotoxy ; Call this one, will pop params
+ pla ; Restore the length and run into _cclear
+
+_cclear:
+ cmp #0 ; Is the length zero?
+ beq L9 ; Jump if done
+ sta tmp1
+L1: lda #$20 ; Blank - screen code
+ jsr cputdirect ; Direct output
+ dec tmp1
+ bne L1
+L9: rts
+
+
+
+
--- /dev/null
+ ;;
+ ;; Kevin Ruland
+ ;;
+ ;; char cgetc (void);
+ ;;
+ ;; If open_apple key is pressed then the high-bit of the
+ ;; key is set.
+
+ .export _cgetc
+
+ .include "apple2.inc"
+
+_cgetc:
+ lda KEY_STROBE
+ bpl _cgetc ; if < 128, no key pressed
+ ;; At this time, the high bit of the key pressed
+ ;; is set
+ sta CLEAR_KEY_STROBE; clear keyboard strobe
+ bit OPEN_APPLE ; check if OpenApple is down
+ bmi pressed
+ and #$7F ; If not down, then clear high bit
+pressed:
+ ldx #0
+ rts
+
\ No newline at end of file
--- /dev/null
+;
+; Ullrich von Bassewitz, 08.08.1998
+;
+; void chlinexy (unsigned char x, unsigned char y, unsigned char length);
+; void chline (unsigned char length);
+;
+
+ .export _chlinexy, _chline
+ .import popa, _gotoxy, cputdirect
+ .importzp tmp1
+
+_chlinexy:
+ pha ; Save the length
+ jsr popa ; Get y
+ jsr _gotoxy ; Call this one, will pop params
+ pla ; Restore the length
+
+_chline:
+ cmp #0 ; Is the length zero?
+ beq L9 ; Jump if done
+ sta tmp1
+L1: lda #$2D ; Horizontal line, screen code
+ jsr cputdirect ; Direct output
+ dec tmp1
+ bne L1
+L9: rts
+
+
+
+
--- /dev/null
+ ;;
+ ;; Kevin Ruland
+ ;;
+ ;; void clrscr (void);
+
+ .export _clrscr
+
+ .include "apple2.inc"
+
+_clrscr = HOME
\ No newline at end of file
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; unsigned char __fastcall__ textcolor (unsigned char color);
+; unsigned char __fastcall__ bgcolor (unsigned char color);
+; unsigned char __fastcall__ bordercolor (unsigned char color);
+;
+
+ .export _textcolor, _bgcolor, _bordercolor
+ .import return0, _revers
+
+ .include "apple2.inc"
+
+_textcolor = _revers
+
+_bgcolor = return0
+
+_bordercolor = return0
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; void cputcxy (unsigned char x, unsigned char y, char c);
+; void cputc (char c);
+;
+
+ .export _cputcxy, _cputc
+ .export _gotoxy, cputdirect
+ .export newline, putchar
+
+ .import popa
+
+ .include "apple2.inc"
+
+; Plot a character - also used as internal function
+
+_cputcxy:
+ pha ; Save C
+ jsr popa ; Get Y
+ jsr _gotoxy
+ pla ; Restore C
+
+_cputc:
+ cmp #$0D ; Test for \r = carrage return
+ bne L1
+ lda #$00 ; Goto left edge of screen
+ sta CH
+ rts ; That's all we do
+L1:
+ cmp #$0A ; Test for \n = line feed
+ beq newline
+
+cputdirect:
+ jsr putchar
+ ;; Bump to next column
+ inc CH
+ lda CH
+ cmp MAX_X
+ bne return
+ lda #$00
+ sta CH
+return:
+ rts
+
+putchar:
+ ora #$80 ; Turn on high bit
+ and TEXTTYP ; Apply normal, inverse, flash
+ ldy CH
+ ldx RD80COL ; In 80 column mode?
+ bpl col40 ; No, in 40 cols
+ pha
+ tya
+ lsr ; Div by 2
+ tay
+ pla
+ bcs col40 ; odd cols go in 40 col memory
+ sta PG2ON
+col40: sta (BASL),Y
+ sta PG2OFF
+ rts
+
+newline:
+ lda CH
+ pha
+ inc CV
+ lda CV
+ cmp MAX_Y
+ bne L2
+ lda #$00
+ sta CV
+L2:
+ jsr VTABZ
+ pla
+ sta CH
+ rts
+
+_gotoxy:
+ sta CV ; Store Y
+ jsr VTABZ
+ jsr popa ; Get X
+ sta CH ; Store X
+ rts
+
+
--- /dev/null
+;
+; Startup code for cc65 (Apple2 version)
+;
+; This must be the *first* file on the linker command line
+;
+
+ .export _exit
+ .import __hinit
+ .import zerobss, push0, doatexit
+ .import _main
+
+ .include "apple2.inc"
+
+; ------------------------------------------------------------------------
+; Define and export the ZP variables for the C64 runtime
+
+ .exportzp sp, sreg, regsave
+ .exportzp ptr1, ptr2, ptr3, ptr4
+ .exportzp tmp1, tmp2, tmp3, tmp4
+ .exportzp regbank, zpspace
+
+; These zero page entries overlap with the sweet-16 registers.
+; must be changed if sweet-16 is to be supported
+sp = $00 ; stack pointer
+sreg = $02 ; secondary register/high 16 bit for longs
+regsave = $04 ; slot to save/restore (E)AX into
+ptr1 = $08 ;
+ptr2 = $0A
+ptr3 = $0C
+ptr4 = $0E
+tmp1 = $10
+tmp2 = $11
+tmp3 = $12
+tmp4 = $13
+regbank = $14 ; 6 byte register bank
+zpspace = $1A ; Zero page space allocated
+
+; ------------------------------------------------------------------------
+; Actual code
+
+ ldy #zpspace-1
+L1: lda sp,y
+ sta zpsave,y ; Save the zero page locations we need
+ dey
+ bpl L1
+
+; Clear the BSS data
+
+ jsr zerobss
+
+; Save system stuff and setup the stack
+
+ tsx
+ stx spsave ; Save the system stack ptr
+
+ lda #<TOPMEM
+ sta sp
+ lda #>TOPMEM
+ sta sp+1 ; Set argument stack ptr
+
+; Initialize the heap
+
+ jsr __hinit
+
+; Initialize conio stuff
+
+ lda #$ff
+ sta TEXTTYP
+
+; Set up to use Apple ROM $C000-$CFFF
+
+ ;; sta USEROM
+
+; Pass an empty command line
+
+ jsr push0 ; argc
+ jsr push0 ; argv
+
+ ldy #4 ; Argument size
+ jsr _main ; call the users code
+
+; fall thru to exit...
+
+_exit:
+ lda #$ff
+ sta TEXTTYP
+
+ jsr doatexit ; call exit functions
+
+ ldx spsave
+ txs ; Restore stack pointer
+
+; Copy back the zero page stuff
+
+ ldy #zpspace-1
+L2: lda zpsave,y
+ sta sp,y
+ dey
+ bpl L2
+
+; Reset changed vectors, back to basic
+
+ jmp RESTOR
+
+
+.data
+
+zpsave: .res zpspace
+
+.bss
+
+spsave: .res 1
--- /dev/null
+;
+; Ullrich von Bassewitz, 02.06.1998
+;
+; Character specification table.
+;
+
+; The tables are readonly, put them into the code segment
+
+.code
+
+; Value that must be added to an upper case char to make it lower case
+; char (example: for ASCII, this must be $E0).
+
+
+ .export __cdiff
+
+__cdiff:
+ .byte $E0
+
+
+; The following 256 byte wide table specifies attributes for the isxxx type
+; of functions. Doing it by a table means some overhead in space, but it
+; has major advantages:
+;
+; * It is fast. If it were'nt for the slow parameter passing of cc65, one
+; could even define macros for the isxxx functions (this is usually
+; done on other platforms).
+;
+; * It is highly portable. The only unportable part is the table itself,
+; all real code goes into the common library.
+;
+; * We save some code in the isxxx functions.
+;
+;
+; Bit assignments:
+;
+; 0 - Lower case char
+; 1 - Upper case char
+; 2 - Numeric digit
+; 3 - Hex digit (both, lower and upper)
+; 4 - Control character
+; 5 - The space character itself
+; 6 - Other whitespace (that is: '\f', '\n', '\r', '\t' and '\v')
+; 7 - Space or tab character
+
+ .export __ctype
+
+__ctype:
+ .byte $10 ; 0/00 ___ctrl_@___
+ .byte $10 ; 1/01 ___ctrl_A___
+ .byte $10 ; 2/02 ___ctrl_B___
+ .byte $10 ; 3/03 ___ctrl_C___
+ .byte $10 ; 4/04 ___ctrl_D___
+ .byte $10 ; 5/05 ___ctrl_E___
+ .byte $10 ; 6/06 ___ctrl_F___
+ .byte $10 ; 7/07 ___ctrl_G___
+ .byte $10 ; 8/08 ___ctrl_H___
+ .byte $D0 ; 9/09 ___ctrl_I___
+ .byte $50 ; 10/0a ___ctrl_J___
+ .byte $50 ; 11/0b ___ctrl_K___
+ .byte $50 ; 12/0c ___ctrl_L___
+ .byte $50 ; 13/0d ___ctrl_M___
+ .byte $10 ; 14/0e ___ctrl_N___
+ .byte $10 ; 15/0f ___ctrl_O___
+ .byte $10 ; 16/10 ___ctrl_P___
+ .byte $10 ; 17/11 ___ctrl_Q___
+ .byte $10 ; 18/12 ___ctrl_R___
+ .byte $10 ; 19/13 ___ctrl_S___
+ .byte $10 ; 20/14 ___ctrl_T___
+ .byte $10 ; 21/15 ___ctrl_U___
+ .byte $10 ; 22/16 ___ctrl_V___
+ .byte $10 ; 23/17 ___ctrl_W___
+ .byte $10 ; 24/18 ___ctrl_X___
+ .byte $10 ; 25/19 ___ctrl_Y___
+ .byte $10 ; 26/1a ___ctrl_Z___
+ .byte $10 ; 27/1b ___ctrl_[___
+ .byte $10 ; 28/1c ___ctrl_\___
+ .byte $10 ; 29/1d ___ctrl_]___
+ .byte $10 ; 30/1e ___ctrl_^___
+ .byte $10 ; 31/1f ___ctrl_____
+ .byte $A0 ; 32/20 ___SPACE___
+ .byte $00 ; 33/21 _____!_____
+ .byte $00 ; 34/22 _____"_____
+ .byte $00 ; 35/23 _____#_____
+ .byte $00 ; 36/24 _____$_____
+ .byte $00 ; 37/25 _____%_____
+ .byte $00 ; 38/26 _____&_____
+ .byte $00 ; 39/27 _____'_____
+ .byte $00 ; 40/28 _____(_____
+ .byte $00 ; 41/29 _____)_____
+ .byte $00 ; 42/2a _____*_____
+ .byte $00 ; 43/2b _____+_____
+ .byte $00 ; 44/2c _____,_____
+ .byte $00 ; 45/2d _____-_____
+ .byte $00 ; 46/2e _____._____
+ .byte $00 ; 47/2f _____/_____
+ .byte $0C ; 48/30 _____0_____
+ .byte $0C ; 49/31 _____1_____
+ .byte $0C ; 50/32 _____2_____
+ .byte $0C ; 51/33 _____3_____
+ .byte $0C ; 52/34 _____4_____
+ .byte $0C ; 53/35 _____5_____
+ .byte $0C ; 54/36 _____6_____
+ .byte $0C ; 55/37 _____7_____
+ .byte $0C ; 56/38 _____8_____
+ .byte $0C ; 57/39 _____9_____
+ .byte $00 ; 58/3a _____:_____
+ .byte $00 ; 59/3b _____;_____
+ .byte $00 ; 60/3c _____<_____
+ .byte $00 ; 61/3d _____=_____
+ .byte $00 ; 62/3e _____>_____
+ .byte $00 ; 63/3f _____?_____
+
+ .byte $00 ; 64/40 _____@_____
+ .byte $0A ; 65/41 _____A_____
+ .byte $0A ; 66/42 _____B_____
+ .byte $0A ; 67/43 _____C_____
+ .byte $0A ; 68/44 _____D_____
+ .byte $0A ; 69/45 _____E_____
+ .byte $0A ; 70/46 _____F_____
+ .byte $02 ; 71/47 _____G_____
+ .byte $02 ; 72/48 _____H_____
+ .byte $02 ; 73/49 _____I_____
+ .byte $02 ; 74/4a _____J_____
+ .byte $02 ; 75/4b _____K_____
+ .byte $02 ; 76/4c _____L_____
+ .byte $02 ; 77/4d _____M_____
+ .byte $02 ; 78/4e _____N_____
+ .byte $02 ; 79/4f _____O_____
+ .byte $02 ; 80/50 _____P_____
+ .byte $02 ; 81/51 _____Q_____
+ .byte $02 ; 82/52 _____R_____
+ .byte $02 ; 83/53 _____S_____
+ .byte $02 ; 84/54 _____T_____
+ .byte $02 ; 85/55 _____U_____
+ .byte $02 ; 86/56 _____V_____
+ .byte $02 ; 87/57 _____W_____
+ .byte $02 ; 88/58 _____X_____
+ .byte $02 ; 89/59 _____Y_____
+ .byte $02 ; 90/5a _____Z_____
+ .byte $00 ; 91/5b _____[_____
+ .byte $00 ; 92/5c _____\_____
+ .byte $00 ; 93/5d _____]_____
+ .byte $00 ; 94/5e _____^_____
+ .byte $00 ; 95/5f _UNDERLINE_
+ .byte $00 ; 96/60 ___grave___
+ .byte $09 ; 97/61 _____a_____
+ .byte $09 ; 98/62 _____b_____
+ .byte $09 ; 99/63 _____c_____
+ .byte $09 ; 100/64 _____d_____
+ .byte $09 ; 101/65 _____e_____
+ .byte $09 ; 102/66 _____f_____
+ .byte $01 ; 103/67 _____g_____
+ .byte $01 ; 104/68 _____h_____
+ .byte $01 ; 105/69 _____i_____
+ .byte $01 ; 106/6a _____j_____
+ .byte $01 ; 107/6b _____k_____
+ .byte $01 ; 108/6c _____l_____
+ .byte $01 ; 109/6d _____m_____
+ .byte $01 ; 110/6e _____n_____
+ .byte $01 ; 111/6f _____o_____
+ .byte $01 ; 112/70 _____p_____
+ .byte $01 ; 113/71 _____q_____
+ .byte $01 ; 114/72 _____r_____
+ .byte $01 ; 115/73 _____s_____
+ .byte $01 ; 116/74 _____t_____
+ .byte $01 ; 117/75 _____u_____
+ .byte $01 ; 118/76 _____v_____
+ .byte $01 ; 119/77 _____w_____
+ .byte $01 ; 120/78 _____x_____
+ .byte $01 ; 121/79 _____y_____
+ .byte $01 ; 122/7a _____z_____
+ .byte $00 ; 123/7b _____{_____
+ .byte $00 ; 124/7c _____|_____
+ .byte $00 ; 125/7d _____}_____
+ .byte $00 ; 126/7e _____~_____
+ .byte $40 ; 127/7f ____DEL____
+
+ .byte $00 ; 128/80 ___________
+ .byte $00 ; 129/81 ___________
+ .byte $00 ; 130/82 ___________
+ .byte $00 ; 131/83 ___________
+ .byte $00 ; 132/84 ___________
+ .byte $00 ; 133/85 ___________
+ .byte $00 ; 134/86 ___________
+ .byte $00 ; 135/87 ___________
+ .byte $00 ; 136/88 ___________
+ .byte $00 ; 137/89 ___________
+ .byte $00 ; 138/8a ___________
+ .byte $00 ; 139/8b ___________
+ .byte $00 ; 140/8c ___________
+ .byte $00 ; 141/8d ___________
+ .byte $00 ; 142/8e ___________
+ .byte $00 ; 143/8f ___________
+ .byte $00 ; 144/90 ___________
+ .byte $00 ; 145/91 ___________
+ .byte $00 ; 146/92 ___________
+ .byte $10 ; 147/93 ___________
+ .byte $00 ; 148/94 ___________
+ .byte $00 ; 149/95 ___________
+ .byte $00 ; 150/96 ___________
+ .byte $00 ; 151/97 ___________
+ .byte $00 ; 152/98 ___________
+ .byte $00 ; 153/99 ___________
+ .byte $00 ; 154/9a ___________
+ .byte $00 ; 155/9b ___________
+ .byte $00 ; 156/9c ___________
+ .byte $00 ; 157/9d ___________
+ .byte $00 ; 158/9e ___________
+ .byte $00 ; 159/9f ___________
+
+ .byte $00 ; 160/a0 ___________
+ .byte $00 ; 161/a1 ___________
+ .byte $00 ; 162/a2 ___________
+ .byte $00 ; 163/a3 ___________
+ .byte $00 ; 164/a4 ___________
+ .byte $00 ; 165/a5 ___________
+ .byte $00 ; 166/a6 ___________
+ .byte $00 ; 167/a7 ___________
+ .byte $00 ; 168/a8 ___________
+ .byte $00 ; 169/a9 ___________
+ .byte $00 ; 170/aa ___________
+ .byte $00 ; 171/ab ___________
+ .byte $00 ; 172/ac ___________
+ .byte $00 ; 173/ad ___________
+ .byte $00 ; 174/ae ___________
+ .byte $00 ; 175/af ___________
+ .byte $00 ; 176/b0 ___________
+ .byte $00 ; 177/b1 ___________
+ .byte $00 ; 178/b2 ___________
+ .byte $00 ; 179/b3 ___________
+ .byte $00 ; 180/b4 ___________
+ .byte $00 ; 181/b5 ___________
+ .byte $00 ; 182/b6 ___________
+ .byte $00 ; 183/b7 ___________
+ .byte $00 ; 184/b8 ___________
+ .byte $00 ; 185/b9 ___________
+ .byte $00 ; 186/ba ___________
+ .byte $00 ; 187/bb ___________
+ .byte $00 ; 188/bc ___________
+ .byte $00 ; 189/bd ___________
+ .byte $00 ; 190/be ___________
+ .byte $00 ; 191/bf ___________
+
+ .byte $02 ; 192/c0 ___________
+ .byte $02 ; 193/c1 ___________
+ .byte $02 ; 194/c2 ___________
+ .byte $02 ; 195/c3 ___________
+ .byte $02 ; 196/c4 ___________
+ .byte $02 ; 197/c5 ___________
+ .byte $02 ; 198/c6 ___________
+ .byte $02 ; 199/c7 ___________
+ .byte $02 ; 200/c8 ___________
+ .byte $02 ; 201/c9 ___________
+ .byte $02 ; 202/ca ___________
+ .byte $02 ; 203/cb ___________
+ .byte $02 ; 204/cc ___________
+ .byte $02 ; 205/cd ___________
+ .byte $02 ; 206/ce ___________
+ .byte $02 ; 207/cf ___________
+ .byte $02 ; 208/d0 ___________
+ .byte $02 ; 209/d1 ___________
+ .byte $02 ; 210/d2 ___________
+ .byte $02 ; 211/d3 ___________
+ .byte $02 ; 212/d4 ___________
+ .byte $02 ; 213/d5 ___________
+ .byte $02 ; 214/d6 ___________
+ .byte $02 ; 215/d7 ___________
+ .byte $02 ; 216/d8 ___________
+ .byte $02 ; 217/d9 ___________
+ .byte $02 ; 218/da ___________
+ .byte $02 ; 219/db ___________
+ .byte $02 ; 220/dc ___________
+ .byte $02 ; 221/dd ___________
+ .byte $02 ; 222/de ___________
+ .byte $00 ; 223/df ___________
+ .byte $01 ; 224/e0 ___________
+ .byte $01 ; 225/e1 ___________
+ .byte $01 ; 226/e2 ___________
+ .byte $01 ; 227/e3 ___________
+ .byte $01 ; 228/e4 ___________
+ .byte $01 ; 229/e5 ___________
+ .byte $01 ; 230/e6 ___________
+ .byte $01 ; 231/e7 ___________
+ .byte $01 ; 232/e8 ___________
+ .byte $01 ; 233/e9 ___________
+ .byte $01 ; 234/ea ___________
+ .byte $01 ; 235/eb ___________
+ .byte $01 ; 236/ec ___________
+ .byte $01 ; 237/ed ___________
+ .byte $01 ; 238/ee ___________
+ .byte $01 ; 239/ef ___________
+ .byte $01 ; 240/f0 ___________
+ .byte $01 ; 241/f1 ___________
+ .byte $01 ; 242/f2 ___________
+ .byte $01 ; 243/f3 ___________
+ .byte $01 ; 244/f4 ___________
+ .byte $01 ; 245/f5 ___________
+ .byte $01 ; 246/f6 ___________
+ .byte $01 ; 247/f7 ___________
+ .byte $01 ; 248/f8 ___________
+ .byte $01 ; 249/f9 ___________
+ .byte $01 ; 250/fa ___________
+ .byte $01 ; 251/fb ___________
+ .byte $01 ; 252/fc ___________
+ .byte $01 ; 253/fd ___________
+ .byte $01 ; 254/fe ___________
+ .byte $00 ; 255/ff ___________
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 08.08.1998
+;
+; void cvlinexy (unsigned char x, unsigned char y, unsigned char length);
+; void cvline (unsigned char length);
+;
+
+ .export _cvlinexy, _cvline
+ .import popa, _gotoxy, putchar, newline
+ .importzp tmp1
+
+_cvlinexy:
+ pha ; Save the length
+ jsr popa ; Get y
+ jsr _gotoxy ; Call this one, will pop params
+ pla ; Restore the length and run into _cvline
+
+_cvline:
+ cmp #0 ; Is the length zero?
+ beq L9 ; Jump if done
+ sta tmp1
+L1: lda #$7C ; Vertical bar
+ jsr putchar ; Write, no cursor advance
+ jsr newline ; Advance cursor to next line
+ dec tmp1
+ bne L1
+L9: rts
+
+
+
--- /dev/null
+ ;;
+ ;; Kevin Ruland
+ ;;
+ ;; int kbhit (void);
+ ;;
+
+ .export _kbhit
+
+ .import return0, return1
+
+ .include "apple2.inc"
+
+_kbhit:
+ bit KEY_STROBE ; Reading strobe checks for keypress
+ bmi L1 ; if KEY_STROBE > 127 key was pressed
+ jmp return0
+L1:
+ jmp return1
--- /dev/null
+;
+; Ullrich von Bassewitz, 30.05.1998
+;
+; int read (int fd, void* buf, int count);
+;
+; THIS IS A HACK!
+;
+
+ .export _read
+ .import popax, _cputc
+ .importzp ptr1, ptr2, ptr3
+
+ .include "apple2.inc"
+
+_read: jsr popax ; get count
+ sta ptr2
+ stx ptr2+1 ; save it for later
+ jsr popax ; get buf
+ sta ptr1
+ stx ptr1+1
+ jsr popax ; get fd and discard it
+ lda #0
+ sta ptr3
+ sta ptr3+1 ; set count
+
+L1: lda ptr2
+ ora ptr2+1 ; count zero?
+ beq L9
+ jsr RDKEY
+ and #$7f ; clear high bit.
+ pha
+ jsr _cputc
+ pla
+ ldy #0 ; offset into string
+ sta (ptr1),y ; save char
+ inc ptr1
+ bne L2
+ inc ptr1+1
+L2: inc ptr3 ; increment count
+ bne L3
+ inc ptr3+1
+L3: cmp #$0D ; CR?
+ bne L1
+
+; Done, return the count
+
+L9: lda ptr3
+ ldx ptr3+1
+ rts
+
+
+
--- /dev/null
+ ;;
+ ;; Kevin Ruland
+ ;;
+ ;; unsigned char __fastcall__ revers (unsigned char onoff)
+ ;;
+
+ .export _revers
+
+ .include "apple2.inc"
+
+_revers:
+ ldy TEXTTYP ; Stash old value
+ and #$FF ; Test for any bit
+ bne reverse ; Nothing set
+ lda #$FF
+reverse:
+ ora #$3F
+ sta TEXTTYP
+ tya ; What was the old value?
+ eor #$FF ; Normal = $FF, Reverse = $3F
+ beq L2
+ lda #01
+L2:
+ rts
+
--- /dev/null
+
+ ;; Keivn Ruland
+ ;;
+ ;; unsigned char wherex( void );
+ ;; unsigned char wherey( void );
+
+ .export _wherex, _wherey
+
+ .include "apple2.inc"
+
+_wherex:
+ lda CH
+ rts
+
+_wherey:
+ lda CV
+ rts
+
\ No newline at end of file
--- /dev/null
+ ;;
+ ;; Kevin Ruland
+ ;;
+ ;; int write (int fd, const void* buf, int count);
+ ;;
+ ;; for now will only write to fd = stdout
+ ;;
+
+ .export _write
+
+ .import popax
+
+ .importzp ptr1, ptr2, ptr3
+
+ .include "apple2.inc"
+
+_write:
+ jsr popax ; get count
+ sta ptr2
+ stx ptr2+1 ; save for later
+ sta ptr3
+ sta ptr3+1 ; save for result
+ jsr popax ; get buf
+ sta ptr1
+ stx ptr1+1
+ jsr popax ; get fd and discard
+L1: lda ptr2
+ ora ptr2+1 ; count zero?
+ beq L9
+ ldy #0
+ lda (ptr1),y
+ cmp #$0A ; Check for \n = Crtl-j
+ bne rawout
+ lda #$0D ; Issue cr
+rawout:
+ ora #$80
+ jsr COUT
+ inc ptr1
+ bne L2
+ inc ptr1+1
+L2: lda ptr2
+ bne L3
+ dec ptr2
+ dec ptr2+1
+ jmp L1
+L3: dec ptr2
+ jmp L1
+
+; No error, return count
+
+L9: lda ptr3
+ ldx ptr3+1
+ rts
--- /dev/null
+#
+# makefile for CC65 Atari runtime library
+#
+
+ATARIDEFS = -DDIRECT_SCREEN
+
+.SUFFIXES: .o .s .c
+
+%.o: %.c
+ @echo $<
+ @$(CC) $(CFLAGS) $(ATARIDEFS) $<
+ @$(AS) -o $@ $(AFLAGS) $(*).s
+
+%.o: %.s
+ @echo $<
+ @$(AS) -g -o $@ $(AFLAGS) $(ATARIDEFS) $<
+
+C_OBJS =
+
+S_OBJS = crt0.o kbhit.o conio.o clrscr.o cputc.o ctype.o chline.o cvline.o \
+ color.o gotoxy.o cclear.o revers.o readjoy.o break.o where.o write.o \
+ gotox.o gotoy.o savevec.o rwcommon.o cgetc.o read.o getargs.o close.o \
+ open.o oserror.o fdtable.o
+
+all: $(C_OBJS) $(S_OBJS)
+
+clean:
+ @rm -f $(C_OBJS:.c=.s)
+ @rm -f $(C_OBJS)
+ @rm -f $(S_OBJS)
+ @rm -f crt0.o
+
--- /dev/null
+;-------------------------------------------------------------------------
+; Atari System Equates -- Version 1.0.0
+; By Freddy Offenga, 4/15/2000
+;
+; References:
+; - Atari 400/800 OS rev.B source code, Atari 1979
+; - Atari OS manual - XL addendum
+; - Atari XL/XE rev.2 source code, Atari 1984
+; - Mapping the Atari - revised edition, Ian Chadwick 1985
+;
+; ##old## old OS rev.B label - moved or deleted
+; ##1200xl## new label introduced in 1200XL OS (rev.10/11)
+; ##rev2## new label introduced in XL/XE OS rev.2
+;-------------------------------------------------------------------------
+
+;-------------------------------------------------------------------------
+; Configuration Equates
+;-------------------------------------------------------------------------
+
+MAXDEV = 33 ;offset to last possible entry of HATABS
+IOCBSZ = 16 ;length of IOCB
+
+SEIOCB = 0*IOCBSZ ;##rev2## screen editor IOCB index
+MAXIOC = 8*IOCBSZ ;first invalid IOCB index
+
+DSCTSZ = 128 ;##rev2## disk sector size
+
+LEDGE = 2 ;left edge
+REDGE = 39 ;right edge
+
+INIML = $0700 ;##rev2## initial MEMLO
+
+ICSORG = $CC00 ;##rev2## international character set origin
+DCSORG = $E000 ;##rev2## domestic character set origin
+
+; IOCB Command Code Equates
+
+OPEN = $03 ;open
+GETREC = $05 ;get record
+GETCHR = $07 ;get character(s)
+PUTREC = $09 ;put record
+PUTCHR = $0B ;put character(s)
+CLOSE = $0C ;close
+STATIS = $0D ;status
+SPECIL = $0E ;special
+
+; Special Entry Command Equates
+
+; Screen Commands
+
+DRAWLN = $11 ;draw line
+FILLIN = $12 ;draw line with right fill
+
+; ICAX1 Auxiliary Byte 1 Equates
+
+APPEND = $01 ;open write append (D:)
+DIRECT = $02 ;open for directory access (D:)
+OPNIN = $04 ;open for input (all devices)
+OPNOT = $08 ;open for output (all devices)
+MXDMOD = $10 ;open for mixed mode (E:, S:)
+INSCLR = $20 ;open for input without clearing screen
+
+; Device Code Equates
+
+CASSET = 'C' ;cassette
+DISK = 'D' ;disk
+SCREDT = 'E' ;screen editor
+KBD = 'K' ;keyboard
+PRINTR = 'P' ;printer
+DISPLY = 'S' ;screen display
+
+; Character and Key Code Equates
+
+CLS = $7D ;##rev2## clear screen
+EOL = $9B ;end of line (RETURN)
+
+HELP = $11 ;##1200xl## key code for HELP
+CNTLF1 = $83 ;##1200xl## key code for CTRL-F1
+CNTLF2 = $84 ;##1200xl## key code for CTRL-F2
+CNTLF3 = $93 ;##1200xl## key code for CTRL-F3
+CNTLF4 = $94 ;##1200xl## key code for CTRL-F4
+CNTL1 = $9F ;##1200xl## key code for CTRL-1
+
+; Status Code Equates
+
+SUCCES = 1 ;($01) succesful operation
+
+BRKABT = 128 ;($80) BREAK key abort
+PRVOPN = 129 ;($81) IOCB already open error
+NONDEV = 130 ;($82) nonexistent device error
+WRONLY = 131 ;($83) IOCB opened for write only error
+NVALID = 132 ;($84) invalid command error
+NOTOPN = 133 ;($85) device/file not open error
+BADIOC = 134 ;($86) invalid IOCB index error
+RDONLY = 135 ;($87) IOCB opened for read only error
+EOFERR = 136 ;($88) end of file error
+TRNRCD = 137 ;($89) truncated record error
+TIMOUT = 138 ;($8A) peripheral device timeout error
+DNACK = 139 ;($8B) device does not acknowledge command
+FRMERR = 140 ;($8C) serial bus framing error
+CRSROR = 141 ;($8D) cursor overrange error
+OVRRUN = 142 ;($8E) serial bus data overrun error
+CHKERR = 143 ;($8F) serial bus checksum error
+DERROR = 144 ;($90) device done (operation incomplete)
+BADMOD = 145 ;($91) bad screen mode number error
+FNCNOT = 146 ;($92) function not implemented in handler
+SCRMEM = 147 ;($93) insufficient memory for screen mode
+
+; DCB Device Bus Equates
+
+DISKID = $31 ;##rev2## disk bus ID
+PDEVN = $40 ;##rev2## printer bus ID
+CASET = $60 ;##rev2## cassette bus ID
+
+; Bus Command Equates
+
+FOMAT = '!' ;##rev2## format command
+PUTSEC = 'P' ;##rev2## put sector command
+READ = 'R' ;##rev2## read command
+STATC = 'S' ;##rev2## status command
+WRITE = 'W' ;##rev2## write command
+
+; Command Auxiliary Byte Equates
+
+DOUBLE = 'D' ;##rev2## print 20 characters double width
+NORMAL = 'N' ;##rev2## print 40 characters normally
+PLOT = 'P' ;##rev2## plot
+SIDWAY = 'S' ;##rev2## print 16 characters sideways
+
+; Bus Response Equates
+
+ACK = 'A' ;##rev2## device acknowledged
+COMPLT = 'C' ;##rev2## device succesfully completed operation
+ERROR = 'E' ;##rev2## device incurred error
+NACK = 'N' ;##rev2## device did not understand
+
+; Floating Point Miscellaneous Equates
+
+FPREC = 6 ;precision
+
+FMPREC = FPREC-1 ;##rev2## length of mantissa
+
+; Cassette Record Type Equates
+
+HDR = $FB ;##rev2## header
+DTA = $FC ;##rev2## data record
+DT1 = $FA ;##rev2## last data record
+EOT = $FE ;##rev2## end of tape (file)
+
+TONE1 = 2 ;##rev2## record
+TONE2 = 1 ;##rev2## playback
+
+; Cassette Timing Equates
+
+WLEADN = 1152 ;##rev2## NTSC 19.2 second WRITE file leader
+RLEADN = 576 ;##rev2## NTSC 9.6 second READ file leader
+WIRGLN = 180 ;##rev2## NTSC 3.0 second WRITE IRG
+RIRGLN = 120 ;##rev2## NTSC 2.0 second READ IRG
+WSIRGN = 15 ;##rev2## NTSC 0.25 second WRITE short IRG
+RSIRGN = 10 ;##rev2## NTSC 0.16 second READ short IRG
+BEEPNN = 30 ;##rev2## NTSC 0.5 second beep duration
+BEEPFN = 10 ;##rev2## NTSC 0.16 seconrd beep duration
+
+WLEADP = 960 ;##rev2## PAL 19.2 second WRITE file leader
+RLEADP = 480 ;##rev2## PAL 9.6 second READ file leader
+WIRGLP = 150 ;##rev2## PAL 3.0 second WRITE IRG
+RIRGLP = 100 ;##rev2## PAL 2.0 second READ IRG
+WSIRGP = 13 ;##rev2## PAL 0.25 second WRITE short IRG
+RSIRGP = 8 ;##rev2## PAL 0.16 second READ short IRG
+BEEPNP = 25 ;##rev2## PAL 0.5 second beep duration
+BEEPFP = 8 ;##rev2## PAL 0.16 seconrd beep duration
+
+WIRGHI = 0 ;##rev2## high WRITE IRG
+RIRGHI = 0 ;##rev2## high READ IRG
+
+; Power-up Validation Byte Value Equates
+
+PUPVL1 = $5C ;##rev2## power-up validation value 1
+PUPVL2 = $93 ;##rev2## power-up validation value 2
+PUPVL3 = $25 ;##rev2## power-up validation value 3
+
+; Relocating Loader Miscellaneous Equates
+
+DATAER = 156 ;##rev2## end of record appears before END
+MEMERR = 157 ;##rev2## memory insufficient for load error
+
+; Miscellaneous Equates
+
+IOCFRE = $FF ;IOCB free indication
+
+B19200 = $0028 ;##rev2## 19200 baud POKEY counter value
+B00600 = $05CC ;##rev2## 600 baud POKEY counter value
+
+HITONE = $05 ;##rev2## FSK high freq. POKEY counter value
+LOTONE = $07 ;##rev2## FSK low freq. POKEY counter value
+
+NCOMLO = $34 ;##rev2## PIA lower NOT COMMAND line command
+NCOMHI = $3C ;##rev2## PIA raise NOT COMMAND line command
+
+MOTRGO = $34 ;##rev2## PIA cassette motor ON command
+MOTRST = $3C ;##rev2## PIA cassette motor OFF command
+
+NODAT = $00 ;##rev2## SIO immediate operation
+GETDAT = $40 ;##rev2## SIO read data frame
+PUTDAT = $80 ;##rev2## SIO write data frame
+
+CRETRI = 13 ;##rev2## number of command frame retries
+DRETRI = 1 ;##rev2## number of device retries
+CTIM = 2 ;##rev2## command frame ACK timeout
+
+NBUFSZ = 40 ;##rev2## print normal buffer size
+DBUFSZ = 20 ;##rev2## print double buffer size
+SBUFSZ = 29 ;##rev2## print sideways buffer size
+
+;-------------------------------------------------------------------------
+; Page Zero Address Equates
+;-------------------------------------------------------------------------
+
+LINZBS = $00 ;LINBUG RAM (WILL BE REPLACED BY MONITOR RAM)
+LNFLG = $00 ;##1200xl## 1-byte LNBUG flag (0 = not LNBUG)
+NGFLAG = $01 ;##1200xl## 1-byte memory status (0 = failure)
+
+; Not Cleared
+
+CASINI = $02 ;CASSETTE INIT LOCATION
+RAMLO = $04 ;RAM POINTER FOR MEMORY TEST
+TRAMSZ = $06 ;TEMPORARY REGISTER FOR RAM SIZE
+;TSTDAT = $07 ;##old## RAM TEST DATA REGISTER
+CMCMD = $07 ;##rev2## 1-byte command communications
+
+; Cleared upon Coldstart only
+
+WARMST = $08 ;WARM START FLAG
+BOOTQ = $09 ;SUCCESSFUL BOOT FLAG
+DOSVEC = $0A ;DISK SOFTWARE START VECTOR
+DOSINI = $0C ;DISK SOFTWARE INIT ADDRESS
+APPMHI = $0E ;APPLICATIONS MEMORY HI LIMIT
+
+; Cleared upon Coldstart or Warmstart
+
+INTZBS = $10 ;INTERRUPT HANDLER
+
+POKMSK = $10 ;SYSTEM MASK FOR POKEY IRG ENABLE
+BRKKEY = $11 ;BREAK KEY FLAG
+RTCLOK = $12 ;REAL TIME CLOCK (IN 16 MSEC UNITS>
+BUFADR = $15 ;INDIRECT BUFFER ADDRESS REGISTER
+ICCOMT = $17 ;COMMAND FOR VECTOR
+DSKFMS = $18 ;DISK FILE MANAGER POINTER
+DSKUTL = $1A ;DISK UTILITIES POINTER
+ABUFPT = $1C ;##1200xl## 4-byte ACMI buffer pointer area
+
+;PTIMOT = $1C ;##old## PRINTER TIME OUT REGISTER
+;PBPNT = $1D ;##old## PRINT BUFFER POINTER
+;PBUFSZ = $1E ;##old## PRINT BUFFER SIZE
+;PTEMP = $1F ;##old## TEMPORARY REGISTER
+
+ZIOCB = $20 ;ZERO PAGE I/O CONTROL BLOCK
+IOCBAS = $20 ;16-byte page zero IOCB
+ICHIDZ = $20 ;HANDLER INDEX NUMBER (FF = IOCB FREE)
+ICDNOZ = $21 ;DEVICE NUMBER (DRIVE NUMBER)
+ICCOMZ = $22 ;COMMAND CODE
+ICSTAZ = $23 ;STATUS OF LAST IOCB ACTION
+ICBALZ = $24 ;BUFFER ADDRESS LOW BYTE
+ICBAHZ = $25 ;1-byte high buffer address
+ICPTLZ = $26 ;PUT BYTE ROUTINE ADDRESS -1
+ICPTHZ = $27 ;1-byte high PUT-BYTE routine address
+ICBLLZ = $28 ;BUFFER LENGTH LOW BYTE
+ICBLHZ = $29 ;1-byte high buffer length
+ICAX1Z = $2A ;AUXILIARY INFORMATION FIRST BYTE
+ICAX2Z = $2B ;1-byte second auxiliary information
+ICSPRZ = $2C ;4-byte spares
+
+ENTVEC = $2C ;##rev2## 2-byte (not used)
+ICIDNO = $2E ;IOCB NUMBER X 16
+CIOCHR = $2F ;CHARACTER BYTE FOR CURRENT OPERATION
+
+STATUS = $30 ;INTERNAL STATUS STORAGE
+CHKSUM = $31 ;CHECKSUM (SINGLE BYTE SUM WITH CARRY)
+BUFRLO = $32 ;POINTER TO DATA BUFFER (LO BYTE)
+BUFRHI = $33 ;POINTER TO DATA BUFFER (HI BYTE)
+BFENLO = $34 ;NEXT BYTE PAST END OF THE DATA BUFFER LO
+BFENHI = $35 ;NEXT BYTE PAST END OF THE DATA BUFFER HI
+;CRETRY = $36 ;##old## NUMBER OF COMMAND FRAME RETRIES
+;DRETRY = $37 ;##old## NUMBER OF DEVICE RETRIES
+LTEMP = $36 ;##1200xl## 2-byte loader temporary
+BUFRFL = $38 ;DATA BUFFER FULL FLAG
+RECVDN = $39 ;RECEIVE DONE FLAG
+XMTDON = $3A ;TRANSMISSION DONE FLAG
+CHKSNT = $3B ;CHECKSUM SENT FLAG
+NOCKSM = $3C ;NO CHECKSUM FOLLOWS DATA FLAG
+BPTR = $3D ;1-byte cassette buffer pointer
+FTYPE = $3E ;1-byte cassette IRG type
+FEOF = $3F ;1-byte cassette EOF flag (0 = quiet)
+FREQ = $40 ;1-byte cassette beep counter
+SOUNDR = $41 ;NOISY I/0 FLAG. (ZERO IS QUIET)
+
+CRITIC = $42 ;DEFINES CRITICAL SECTION (CRITICAL IF NON-Z)
+
+FMSZPG = $43 ;DISK FILE MANAGER SYSTEM ZERO PAGE
+
+;CKEY = $4A ;##old## FLAG SET WHEN GAME START PRESSED
+ZCHAIN = $4A ;##1200xl## 2-byte handler linkage chain pointer
+;CASSBT = $4B ;##old## CASSETTE BOOT FLAG
+DSTAT = $4C ;DISPLAY STATUS
+ATRACT = $4D ;ATRACT FLAG
+DRKMSK = $4E ;DARK ATRACT MASK
+COLRSH = $4F ;ATRACT COLOR SHIFTER (EOR'ED WITH PLAYFIELD
+
+
+TMPCHR = $50 ;1-byte temporary character
+HOLD1 = $51 ;1-byte temporary
+LMARGN = $52 ;LEFT MARGIN (SET TO 1 AT POWER ON>
+RMARGN = $53 ;RIGHT MARGIN (SET TO 38 AT POWER ON)
+ROWCRS = $54 ;1-byte cursor row
+COLCRS = $55 ;2-byte cursor column
+DINDEX = $57 ;1-byte display mode
+SAVMSC = $58 ;2-byte saved memory scan counter
+OLDROW = $5A ;1-byte prior row
+OLDCOL = $5B ;2-byte prior column
+OLDCHR = $5D ;DATA UNDER CURSOR
+OLDADR = $5E ;2-byte saved cursor memory address
+FKDEF = $60 ;##1200xl## 2-byte function key definition table
+;NEWROW = $60 ;##old## POINT DRAW GOES TO
+;NEWCOL = $61 ;##old##
+PALNTS = $62 ;##1200xl## 1-byte PAL/NTSC indicator (0 = NTSC)
+LOGCOL = $63 ;POINTS AT COLUMN IN LOGICAL LINE
+ADRESS = $64 ;2-byte temporary address
+
+MLTTMP = $66 ;1-byte temporary
+OPNTMP = $66 ;FIRST BYTE IS USED IN OPEN AS TEMP
+TOADR = $66 ;##rev2## 2-byte destination address
+
+SAVADR = $68 ;2-byte saved address
+FRMADR = $68 ;##rev2## 2-byte source address
+
+RAMTOP = $6A ;RAM SIZE DEFINED BY POWER ON LOGIC
+BUFCNT = $6B ;BUFFER COUNT
+BUFSTR = $6C ;EDITOR GETCH POINTER
+BITMSK = $6E ;BIT MASK
+SHFAMT = $6F ;1-byte shift amount for pixel justifucation
+ROWAC = $70 ;2-byte draw working row
+COLAC = $72 ;2-byte draw working column
+ENDPT = $74 ;2-byte end point
+DELTAR = $76 ;1-byte row difference
+DELTAC = $77 ;2-byte column difference
+KEYDEF = $79 ;##1200xl## 2-byte key definition table address
+;ROWINC = $79 ;##old##
+;COLINC = $7A ;##old##
+SWPFLG = $7B ;NON-0 1F TXT AND REGULAR RAM IS SWAPPED
+HOLDCH = $7C ;CH IS MOVED HERE IN KGETCH BEFORE CNTL & SH
+INSDAT = $7D ;1-byte temporary
+COUNTR = $7E ;2-byte draw iteration count
+
+; Floating Point Package Page Zero Address Equates
+
+FR0 = $D4 ;6-byte register 0
+FR0M = $D5 ;##rev2## 5-byte register 0 mantissa
+QTEMP = $D9 ;##rev2## 1-byte temporary
+
+FRE = $DA ;6-byte (internal) register E
+
+FR1 = $E0 ;FP REG1
+FR1M = $E1 ;##rev2## 5-byte register 1 mantissa
+
+FR2 = $E6 ;6-byte (internal) register 2
+
+FRX = $EC ;1-byte temporary
+
+EEXP = $ED ;VALUE OF E
+
+FRSIGN = $EE ;##rev2## 1-byte floating point sign
+NSIGN = $EE ;SIGN OF #
+
+PLYCNT = $EF ;##rev2## 1-byte polynomial degree
+ESIGN = $EF ;SIGN OF EXPONENT
+
+SGNFLG = $F0 ;##rev2## 1-byte sign flag
+FCHRFLG = $F0 ;1ST CHAR FLAG
+
+XFMFLG = $F1 ;##rev2## 1-byte transform flag
+DIGRT = $F1 ;# OF DIGITS RIGHT OF DECIMAL
+
+CIX = $F2 ;CURRENT INPUT INDEX
+INBUFF = $F3 ;POINTS TO USER'S LINE INPUT BUFFER
+
+ZTEMP1 = $F5 ;2-byte temporary
+ZTEMP4 = $F7 ;2-byte temporary
+ZTEMP3 = $F9 ;2-byte temporary
+
+;DEGFLG = $FB ;##old## same as RADFLG
+;RADFLG = $FB ;##old## 0=RADIANS, 6=DEGREES
+
+FLPTR = $FC ;2-byte floating point number pointer
+FPTR2 = $FE ;2-byte floating point number pointer
+
+;-------------------------------------------------------------------------
+; Page Two Address Equates
+;-------------------------------------------------------------------------
+
+INTABS = $0200 ;INTERRUPT RAM
+
+VDSLST = $0200 ;DISPLAY LIST NMI VECTOR
+VPRCED = $0202 ;PROCEED LINE IRQ VECTOR
+VINTER = $0204 ;INTERRUPT LINE IRQ VECTOR
+VBREAK = $0206 ;SOFTWARE BREAK (00) INSTRUCTION IRQ VECTOR
+VKEYBD = $0208 ;POKEY KEYBOARD IRQ VECTOR
+VSERIN = $020A ;POKEY SERIAL INPUT READY IRQ
+VSEROR = $020C ;POKEY SERIAL OUTPUT READY IRQ
+VSEROC = $020E ;POKEY SERIAL OUTPUT COMPLETE IRQ
+VTIMR1 = $0210 ;POKEY TIMER 1 IRG
+VTIMR2 = $0212 ;POKEY TIMER 2 IRG
+VTIMR4 = $0214 ;POKEY TIMER 4 IRG
+VIMIRQ = $0216 ;IMMEDIATE IRG VECTOR
+CDTMV1 = $0218 ;COUNT DOWN TIMER 1
+CDTMV2 = $021A ;COUNT DOWN TIMER 2
+CDTMV3 = $021C ;COUNT DOWN TIMER 3
+CDTMV4 = $021E ;COUNT DOWN TIMER 4
+CDTMV5 = $0220 ;COUNT DOWN TIMER 5
+VVBLKI = $0222 ;IMMEDIATE VERTICAL BLANK NMI VECTOR
+VVBLKD = $0224 ;DEFERRED VERTICAL BLANK NMI VECTOR
+CDTMA1 = $0226 ;COUNT DOWN TIMER 1 JSR ADDRESS
+CDTMA2 = $0228 ;COUNT DOWN TIMER 2 JSR ADDRESS
+CDTMF3 = $022A ;COUNT DOWN TIMER 3 FLAG
+SRTIMR = $022B ;SOFTWARE REPEAT TIMER
+CDTMF4 = $022C ;COUNT DOWN TIMER 4 FLAG
+INTEMP = $022D ;IAN'S TEMP
+CDTMF5 = $022E ;COUNT DOWN TIMER FLAG 5
+SDMCTL = $022F ;SAVE DMACTL REGISTER
+SDLSTL = $0230 ;SAVE DISPLAY LIST LOW BYTE
+SDLSTH = $0231 ;SAVE DISPLAY LIST HI BYTE
+SSKCTL = $0232 ;SKCTL REGISTER RAM
+LCOUNT = $0233 ;##1200xl## 1-byte relocating loader record
+LPENH = $0234 ;LIGHT PEN HORIZONTAL VALUE
+LPENV = $0235 ;LIGHT PEN VERTICAL VALUE
+BRKKY = $0236 ;BREAK KEY VECTOR
+;RELADR = $0238 ;##1200xl## 2-byte relocatable loader address
+VPIRQ = $0238 ;##rev2## 2-byte parallel device IRQ vector
+CDEVIC = $023A ;COMMAND FRAME BUFFER - DEVICE
+CCOMND = $023B ;COMMAND
+CAUX1 = $023C ;COMMAND AUX BYTE 1
+CAUX2 = $023D ;COMMAND AUX BYTE 2
+
+TEMP = $023E ;TEMPORARY RAM CELL
+
+ERRFLG = $023F ;ERROR FLAG - ANY DEVICE ERROR EXCEPT TIME OUT
+
+DFLAGS = $0240 ;DISK FLAGS FROM SECTOR ONE
+DBSECT = $0241 ;NUMBER OF DISK BOOT SECTORS
+BOOTAD = $0242 ;ADDRESS WHERE DISK BOOT LOADER WILL 13E PUT
+COLDST = $0244 ;COLDSTART FLAG (1=IN MIDDLE OF COLDSTART>
+RECLEN = $0245 ;##1200xl## 1-byte relocating loader record length
+DSKTIM = $0246 ;DISK TIME OUT REGISTER
+;LINBUF = $0247 ;##old## CHAR LINE BUFFER
+PDVMSK = $0247 ;##rev2## 1-byte parallel device selection mask
+SHPDVS = $0248 ;##rev2## 1-byte PDVS (parallel device select)
+PDIMSK = $0249 ;##rev2## 1-byte parallel device IRQ selection
+RELADR = $024A ;##rev2## 2-byte relocating loader relative adr.
+PPTMPA = $024C ;##rev2## 1-byte parallel device handler temporary
+PPTMPX = $024D ;##rev2## 1-byte parallel device handler temporary
+
+CHSALT = $026B ;##1200xl## 1-byte character set alternate
+VSFLAG = $026C ;##1200xl## 1-byte fine vertical scroll count
+KEYDIS = $026D ;##1200xl## 1-byte keyboard disable
+FINE = $026E ;##1200xl## 1-byte fine scrolling mode
+GPRIOR = $026F ;GLOBAL PRIORITY CELL
+
+PADDL0 = $0270 ;1-byte potentiometer 0
+PADDL1 = $0271 ;1-byte potentiometer 1
+PADDL2 = $0272 ;1-byte potentiometer 2
+PADDL3 = $0273 ;1-byte potentiometer 3
+PADDL4 = $0274 ;1-byte potentiometer 4
+PADDL5 = $0275 ;1-byte potentiometer 5
+PADDL6 = $0276 ;1-byte potentiometer 6
+PADDL7 = $0277 ;1-byte potentiometer 7
+
+STICK0 = $0278 ;1-byte joystick 0
+STICK1 = $0279 ;1-byte joystick 1
+STICK2 = $027A ;1-byte joystick 2
+STICK3 = $027B ;1-byte joystick 3
+
+PTRIG0 = $027C ;1-byte paddle trigger 0
+PTRIG1 = $027D ;1-byte paddle trigger 1
+PTRIG2 = $027E ;1-byte paddle trigger 2
+PTRIG3 = $027F ;1-byte paddle trigger 3
+PTRIG4 = $0280 ;1-byte paddle trigger 4
+PTRIG5 = $0281 ;1-byte paddle trigger 5
+PTRIG6 = $0281 ;1-byte paddle trigger 6
+PTRIG7 = $0283 ;1-byte paddle trigger 7
+
+STRIG0 = $0284 ;1-byte joystick trigger 0
+STRIG1 = $0285 ;1-byte joystick trigger 1
+STRIG2 = $0286 ;1-byte joystick trigger 2
+STRIG3 = $0287 ;1-byte joystick trigger 3
+
+;CSTAT = $0288 ;##old## cassette status register
+HIBYTE = $0288 ;##1200xl## 1-byte relocating loader high byte
+WMODE = $0289 ;1-byte cassette WRITE mode
+BLIM = $028A ;1-byte cassette buffer limit
+IMASK = $028B ;##rev2## (not used)
+JVECK = $028C ;2-byte jump vector or temporary
+NEWADR = $028E ;##1200xl## 2-byte relocating address
+TXTROW = $0290 ;TEXT ROWCRS
+TXTCOL = $0291 ;TEXT COLCRS
+TINDEX = $0293 ;TEXT INDEX
+TXTMSC = $0294 ;FOOLS CONVRT INTO NEW MSC
+TXTOLD = $0296 ;OLDROW & OLDCOL FOR TEXT (AND THEN SOME)
+;TMPX1 = $029C ;##old## 1-byte temporary register
+CRETRY = $029C ;##1200xl## 1-byte number of command frame retries
+HOLD3 = $029D ;1-byte temporary
+SUBTMP = $029E ;1-byte temporary
+HOLD2 = $029F ;1-byte (not used)
+DMASK = $02A0 ;1-byte display (pixel location) mask
+TMPLBT = $02A1 ;1-byte (not used)
+ESCFLG = $02A2 ;ESCAPE FLAG
+TABMAP = $02A3 ;15-byte (120 bit) tab stop bit map
+LOGMAP = $02B2 ;LOGICAL LINE START BIT MAP
+INVFLG = $02B6 ;INVERSE VIDEO FLAG (TOGGLED BY ATARI KEY)
+FILFLG = $02B7 ;RIGHT FILL FLAG FOR DRAW
+TMPROW = $02B8 ;1-byte temporary row
+TMPCOL = $02B9 ;2-byte temporary column
+SCRFLG = $02BB ;SET IF SCROLL OCCURS
+HOLD4 = $02BC ;TEMP CELL USED IN DRAW ONLY
+;HOLD5 = $02BD ;##old## DITTO
+DRETRY = $02BD ;##1200xl## 1-byte number of device retries
+SHFLOK = $02BE ;1-byte shift/control lock flags
+BOTSCR = $02BF ;BOTTOM OF SCREEN 24 NORM 4 SPLIT
+
+PCOLR0 = $02C0 ;1-byte player-missile 0 color/luminance
+PCOLR1 = $02C1 ;1-byte player-missile 1 color/luminance
+PCOLR2 = $02C2 ;1-byte player-missile 2 color/luminance
+PCOLR3 = $02C3 ;1-byte player-missile 3 color/luminance
+
+COLOR0 = $02C4 ;1-byte playfield 0 color/luminance
+COLOR1 = $02C5 ;1-byte playfield 1 color/luminance
+COLOR2 = $02C6 ;1-byte playfield 2 color/luminance
+COLOR3 = $02C7 ;1-byte playfield 3 color/luminance
+
+COLOR4 = $02C8 ;1-byte background color/luminance
+
+PARMBL = $02C9 ;##rev2## 6-byte relocating loader parameter
+RUNADR = $02C9 ;##1200xl## 2-byte run address
+HIUSED = $02CB ;##1200xl## 2-byte highest non-zero page address
+ZHIUSE = $02CD ;##1200xl## 2-byte highest zero page address
+
+OLDPAR = $02CF ;##rev2## 6-byte relocating loader parameter
+GBYTEA = $02CF ;##1200xl## 2-byte GET-BYTE routine address
+LOADAD = $02D1 ;##1200xl## 2-byte non-zero page load address
+ZLOADA = $02D3 ;##1200xl## 2-byte zero page load address
+
+DSCTLN = $02D5 ;##1200xl## 2-byte disk sector length
+ACMISR = $02D7 ;##1200xl## 2-byte ACMI interrupt service routine
+KRPDEL = $02D9 ;##1200xl## 1-byte auto-repeat delay
+KEYREP = $02DA ;##1200xl## 1-byte auto-repeat rate
+NOCLIK = $02DB ;##1200xl## 1-byte key click disable
+HELPFG = $02DC ;##1200xl## 1-byte HELP key flag (0 = no HELP)
+DMASAV = $02DD ;##1200xl## 1-byte SDMCTL save/restore
+PBPNT = $02DE ;##1200xl## 1-byte printer buffer pointer
+PBUFSZ = $02DF ;##1200xl## 1-byte printer buffer size
+
+GLBABS = $02E0 ;4-byte global variables for non-DOS users
+RUNAD = $02E0 ;##map## 2-byte binary file run address
+INITAD = $02E2 ;##map## 2-byte binary file initialization address
+
+RAMSIZ = $02E4 ;RAM SIZE (HI BYTE ONLY)
+MEMTOP = $02E5 ;TOP OF AVAILABLE USER MEMORY
+MEMLO = $02E7 ;BOTTOM OF AVAILABLE USER MEMORY
+HNDLOD = $02E9 ;##1200xl## 1-byte user load flag
+DVSTAT = $02EA ;STATUS BUFFER
+CBAUDL = $02EE ;1-byte low cassette baud rate
+CBAUDH = $02EF ;1-byte high cassette baud rate
+CRSINH = $02F0 ;CURSOR INHIBIT (00 = CURSOR ON)
+KEYDEL = $02F1 ;KEY DELAY
+CH1 = $02F2 ;1-byte prior keyboard character
+CHACT = $02F3 ;CHACTL REGISTER RAM
+CHBAS = $02F4 ;CHBAS REGISTER RAM
+
+NEWROW = $02F5 ;##1200xl## 1-byte draw destination row
+NEWCOL = $02F6 ;##1200xl## 2-byte draw destination column
+ROWINC = $02F8 ;##1200xl## 1-byte draw row increment
+COLINC = $02F9 ;##1200xl## 1-byte draw column increment
+
+CHAR = $02FA ;1-byte internal character
+ATACHR = $02FB ;ATASCII CHARACTER
+CH = $02FC ;GLOBAL VARIABLE FOR KEYBOARD
+FILDAT = $02FD ;RIGHT FILL DATA <DRAW>
+DSPFLG = $02FE ;DISPLAY FLAG DISPLAY CNTLS IF NON-ZERO
+SSFLAG = $02FF ;START/STOP FLAG FOR PAGING (CNTL 1). CLEARE
+
+;-------------------------------------------------------------------------
+; Page Three Address Equates
+;-------------------------------------------------------------------------
+
+DCB = $0300 ;DEVICE CONTROL BLOCK
+DDEVIC = $0300 ;PERIPHERAL UNIT 1 BUS I.D. NUMBER
+DUNIT = $0301 ;UNIT NUMBER
+DCOMND = $0302 ;BUS COMMAND
+DSTATS = $0303 ;COMMAND TYPE/STATUS RETURN
+DBUFLO = $0304 ;1-byte low data buffer address
+DBUFHI = $0305 ;1-byte high data buffer address
+DTIMLO = $0306 ;DEVICE TIME OUT IN 1 SECOND UNITS
+DUNUSE = $0307 ;UNUSED BYTE
+DBYTLO = $0308 ;1-byte low number of bytes to transfer
+DBYTHI = $0309 ;1-byte high number of bytes to transfer
+DAUX1 = $030A ;1-byte first command auxiliary
+DAUX2 = $030B ;1-byte second command auxiliary
+
+TIMER1 = $030C ;INITIAL TIMER VALUE
+;ADDCOR = $030E ;##old## ADDITION CORRECTION
+JMPERS = $030E ;##1200xl## 1-byte jumper options
+CASFLG = $030F ;CASSETTE MODE WHEN SET
+TIMER2 = $0310 ;2-byte final baud rate timer value
+TEMP1 = $0312 ;TEMPORARY STORAGE REGISTER
+;TEMP2 = $0314 ;##old## TEMPORARY STORAGE REGISTER
+TEMP2 = $0313 ;##1200xl## 1-byte temporary
+PTIMOT = $0314 ;##1200xl## 1-byte printer timeout
+TEMP3 = $0315 ;TEMPORARY STORAGE REGISTER
+SAVIO = $0316 ;SAVE SERIAL IN DATA PORT
+TIMFLG = $0317 ;TIME OUT FLAG FOR BAUD RATE CORRECTION
+STACKP = $0318 ;SIO STACK POINTER SAVE CELL
+TSTAT = $0319 ;TEMPORARY STATUS HOLDER
+
+HATABS = $031A ;35-byte handler address table (was 38 bytes)
+PUPBT1 = $033D ;##1200xl## 1-byte power-up validation byte 1
+PUPBT2 = $033E ;##1200xl## 1-byte power-up validation byte 2
+PUPBT3 = $033F ;##1200xl## 1-byte power-up validation byte 3
+
+IOCB = $0340 ;I/O CONTROL BLOCKS
+ICHID = $0340 ;HANDLER INDEX NUMBER (FF=IOCB FREE)
+ICDNO = $0341 ;DEVICE NUMBER (DRIVE NUMBER)
+ICCOM = $0342 ;COMMAND CODE
+ICSTA = $0343 ;STATUS OF LAST IOCB ACTION
+ICBAL = $0344 ;1-byte low buffer address
+ICBAH = $0345 ;1-byte high buffer address
+ICPTL = $0346 ;1-byte low PUT-BYTE routine address - 1
+ICPTH = $0347 ;1-byte high PUT-BYTE routine address - 1
+ICBLL = $0348 ;1-byte low buffer length
+ICBLH = $0349 ;1-byte high buffer length
+ICAX1 = $034A ;1-byte first auxiliary information
+ICAX2 = $034B ;1-byte second auxiliary information
+ICSPR = $034C ;FOUR SPARE BYTES
+
+PRNBUF = $03C0 ;PRINTER BUFFER
+SUPERF = $03E8 ;##1200xl## 1-byte editor super function flag
+CKEY = $03E9 ;##1200xl## 1-byte cassette boot request flag
+CASSBT = $03EA ;##1200xl## 1-byte cassette boot flag
+CARTCK = $03EB ;##1200xl## 1-byte cartridge equivalence check
+DERRF = $03EC ;##rev2## 1-byte screen OPEN error flag
+
+; Remainder of Page Three Not Cleared upon Reset
+
+ACMVAR = $03ED ;##1200xl## 11 bytes reserved for ACMI
+BASICF = $03F8 ;##rev2## 1-byte BASIC switch flag
+MINTLK = $03F9 ;##1200xl## 1-byte ACMI module interlock
+GINTLK = $03FA ;##1200xl## 1-byte cartridge interlock
+CHLINK = $03FB ;##1200xl## 2-byte loaded handler chain link
+CASBUF = $03FD ;CASSETTE BUFFER
+
+;-------------------------------------------------------------------------
+; Page Four/Five Address Equates
+;-------------------------------------------------------------------------
+
+; USER AREA STARTS HERE AND GOES TO END OF PAGE FIVE
+USAREA = $0480 ;128 bytes reserved for application
+
+LBPR1 = $057E ;LBUFF PREFIX 1
+LBPR2 = $057F ;LBUFF PREFIX 2
+LBUFF = $0580 ;128-byte line buffer
+
+PLYARG = $05E0 ;6-byte floating point polynomial argument
+FPSCR = $05E6 ;6-byte floating point temporary
+FPSCR1 = $05EC ;6-byte floating point temporary
+
+;LBFEND = $05FF ;##old## END OF LBUFF
+
+;-------------------------------------------------------------------------
+; Cartridge Address Equates
+;-------------------------------------------------------------------------
+
+CARTCS = $BFFA ;##rev2## 2-byte cartridge coldstart address
+CART = $BFFC ;##rev2## 1-byte cartridge present indicator
+CARTFG = $BFFD ;##rev2## 1-byte cartridge flags
+CARTAD = $BFFE ;##rev2## 2-byte cartridge start vector
+
+;-------------------------------------------------------------------------
+; CTIA/GTIA Address Equates
+;-------------------------------------------------------------------------
+
+GTIA = $D000 ;CTIA/GTIA area
+
+; Read/Write Addresses
+
+CONSOL = $D01F ;console switches and speaker control
+
+; Read Addresses
+
+M0PF = $D000 ;missile 0 and playfield collision
+M1PF = $D001 ;missile 1 and playfield collision
+M2PF = $D002 ;missile 2 and playfield collision
+M3PF = $D003 ;missile 3 and playfield collision
+
+P0PF = $D004 ;player 0 and playfield collision
+P1PF = $D005 ;player 1 and playfield collision
+P2PF = $D006 ;player 2 and playfield collision
+P3PF = $D007 ;player 3 and playfield collision
+
+M0PL = $D008 ;missile 0 and player collision
+M1PL = $D009 ;missile 1 and player collision
+M2PL = $D00A ;missile 2 and player collision
+M3PL = $D00B ;missile 3 and player collision
+
+P0PL = $D00C ;player 0 and player collision
+P1PL = $D00D ;player 1 and player collision
+P2PL = $D00E ;player 2 and player collision
+P3PL = $D00F ;player 3 and player collision
+
+TRIG0 = $D010 ;joystick trigger 0
+TRIG1 = $D011 ;joystick trigger 1
+
+TRIG2 = $D012 ;cartridge interlock
+TRIG3 = $D013 ;ACMI module interlock
+
+PAL = $D014 ;##rev2## PAL/NTSC indicator
+
+; Write Addresses
+
+HPOSP0 = $D000 ;player 0 horizontal position
+HPOSP1 = $D001 ;player 1 horizontal position
+HPOSP2 = $D002 ;player 2 horizontal position
+HPOSP3 = $D003 ;player 3 horizontal position
+
+HPOSM0 = $D004 ;missile 0 horizontal position
+HPOSM1 = $D005 ;missile 1 horizontal position
+HPOSM2 = $D006 ;missile 2 horizontal position
+HPOSM3 = $D007 ;missile 3 horizontal position
+
+SIZEP0 = $D008 ;player 0 size
+SIZEP1 = $D009 ;player 1 size
+SIZEF2 = $D00A ;player 2 size
+SIZEP3 = $D00B ;player 3 size
+
+SIZEM = $D00C ;missile sizes
+
+GRAFP0 = $D00D ;player 0 graphics
+GRAFP1 = $D00E ;player 1 graphics
+GRAFP2 = $D00F ;player 2 graphics
+GRAFP3 = $D010 ;player 3 graphics
+
+GRAFM = $D011 ;missile graphics
+
+COLPM0 = $D012 ;player-missile 0 color/luminance
+COLPM1 = $D013 ;player-missile 1 color/luminance
+COLPM2 = $D014 ;player-missile 2 color/luminance
+COLPM3 = $D015 ;player-missile 3 color/luminance
+
+COLPF0 = $D016 ;playfield 0 color/luminance
+COLPF1 = $D017 ;playfield 1 color/luminance
+COLPF2 = $D018 ;playfield 2 color/luminance
+COLPF3 = $D019 ;playfield 3 color/luminance
+
+COLBK = $D01A ;background color/luminance
+
+PRIOR = $D01B ;priority select
+VDELAY = $D01C ;vertical delay
+GRACTL = $D01D ;graphic control
+HITCLR = $D01E ;collision clear
+
+;-------------------------------------------------------------------------
+; PBI Address Equates
+;-------------------------------------------------------------------------
+
+PBI = $D100 ;##rev2## parallel bus interface area
+
+; Read Addresses
+
+PDVI = $D1FF ;##rev2## parallel device IRQ status
+
+; Write Addresses
+
+PDVS = $D1FF ;##rev2## parallel device select
+
+; PBI RAM Address Equates
+
+PBIRAM = $D600 ;##rev2## parallel bus interface RAM area
+
+; Parallel Device Address Equates
+
+PDID1 = $D803 ;##rev2## parallel device ID 1
+PDIDV = $D805 ;##rev2## parallel device I/O vector
+PDIRQV = $D808 ;##rev2## parallel device IRQ vector
+PDID2 = $D80B ;##rev2## parallel device ID 2
+PDVV = $D80D ;##rev2## parallel device vector table
+
+;-------------------------------------------------------------------------
+; POKEY Address Equates
+;-------------------------------------------------------------------------
+
+POKEY = $D200 ;POKEY area
+
+; Read Addresses
+
+POT0 = $D200 ;potentiometer 0
+POT1 = $D201 ;potentiometer 1
+POT2 = $D202 ;potentiometer 2
+POT3 = $D203 ;potentiometer 3
+POT4 = $D204 ;potentiometer 4
+POT5 = $D205 ;potentiometer 5
+POT6 = $D206 ;potentiometer 6
+POT7 = $D207 ;potentiometer 7
+
+ALLPOT = $D208 ;potentiometer port status
+KBCODE = $D209 ;keyboard code
+RANDOM = $D20A ;random number generator
+SERIN = $D20D ;serial port input
+IRQST = $D20E ;IRQ interrupt status
+SKSTAT = $D20F ;serial port and keyboard status
+
+; Write Addresses
+
+AUDF1 = $D200 ;channel 1 audio frequency
+AUDC1 = $D201 ;channel 1 audio control
+
+AUDF2 = $D202 ;channel 2 audio frequency
+AUDC2 = $D203 ;channel 2 audio control
+
+AUDF3 = $D204 ;channel 3 audio frequency
+AUDC3 = $D205 ;channel 3 audio control
+
+AUDF4 = $D206 ;channel 4 audio frequency
+AUDC4 = $D207 ;channel 4 audio control
+
+AUDCTL = $D208 ;audio control
+STIMER = $D209 ;start timers
+SKRES = $D20A ;reset SKSTAT status
+POTGO = $D20B ;start potentiometer scan sequence
+SEROUT = $D20D ;serial port output
+IRQEN = $D20E ;IRQ interrupt enable
+SKCTL = $D20F ;serial port and keyboard control
+
+;-------------------------------------------------------------------------
+; PIA Address Equates
+;-------------------------------------------------------------------------
+
+PIA = $D300 ;PIA area
+
+PORTA = $D300 ;port A direction register or jacks one/two
+PORTB = $D301 ;port B direction register or memory management
+
+PACTL = $D302 ;port A control
+PBCTL = $D303 ;port B control
+
+;-------------------------------------------------------------------------
+; ANTIC Address Equates
+;-------------------------------------------------------------------------
+
+ANTIC = $D400 ;ANTIC area
+
+; Read Addresses
+
+VCOUNT = $D40B ;vertical line counter
+PENH = $D40C ;light pen horizontal position
+PENV = $D40D ;light pen vertical position
+NMIST = $D40F ;NMI interrupt status
+
+; Write Addresses
+
+DMACTL = $D400 ;DMA control
+CHACTL = $D401 ;character control
+DLISTL = $D402 ;low display list address
+DLISTH = $D403 ;high display list address
+HSCROL = $D404 ;horizontal scroll
+VSCROL = $D405 ;vertical scroll
+PMBASE = $D407 ;player-missile base address
+CHBASE = $D409 ;character base address
+WSYNC = $D40A ;wait for HBLANK synchronization
+NMIEN = $D40E ;NMI enable
+NMIRES = $D40F ;NMI iterrupt reset
+
+;-------------------------------------------------------------------------
+; Floating Point Package Address Equates
+;-------------------------------------------------------------------------
+
+AFP = $D800 ;convert ASCII to floating point
+FASC = $D8E6 ;convert floating point to ASCII
+IFP = $D9AA ;convert integer to floating point
+FPI = $D9D2 ;convert floating point to integer
+ZFR0 = $DA44 ;zero FR0
+ZF1 = $DA46 ;zero floating point number
+FSUB = $DA60 ;subtract floating point numbers
+FADD = $DA66 ;add floating point numbers
+FMUL = $DADB ;multiply floating point numbers
+FDIV = $DB28 ;divide floating point numbers
+PLYEVL = $DD40 ;evaluate floating point polynomial
+FLD0R = $DD89 ;load floating point number
+FLD0P = $DD8D ;load floating point number
+FLD1R = $DD98 ;load floating point number
+PLD1P = $DD9C ;load floating point number
+FST0R = $DDA7 ;store floating point number
+FST0P = $DDAB ;store floating point number
+FMOVE = $DDB6 ;move floating point number
+LOG = $DECD ;calculate floating point logarithm
+LOG10 = $DED1 ;calculate floating point base 10 logarithm
+EXP = $DDC0 ;calculate floating point exponential
+EXP10 = $DDCC ;calculate floating point base 10 exponential
+
+;-------------------------------------------------------------------------
+; Device Handler Vector Table Address Equates
+;-------------------------------------------------------------------------
+
+EDITRV = $E400 ;editor handler vector table
+SCRENV = $E410 ;screen handler vector table
+KEYBDV = $E420 ;keyboard handler vector table
+PRINTV = $E430 ;printer handler vector table
+CASETV = $E440 ;cassette handler vector table
+
+;-------------------------------------------------------------------------
+; Jump Vector Address Equates
+;-------------------------------------------------------------------------
+
+DISKIV = $E450 ;vector to initialize DIO
+DSKINV = $E453 ;vector to DIO
+CIOV = $E456 ;vector to CIO
+SIOV = $E459 ;vector to SIO
+SETVBV = $E45C ;vector to set VBLANK parameters
+SYSVBV = $E45F ;vector to process immediate VBLANK
+XITVBV = $E462 ;vector to process deferred VBLANK
+SIOINV = $E465 ;vector to initialize SIO
+SENDEV = $E468 ;vector to enable SEND
+INTINV = $E46B ;vector to initialize interrupt handler
+CIOINV = $E46E ;vector to initialize CIO
+BLKBDV = $E471 ;vector to power-up display
+WARMSV = $E474 ;vector to warmstart
+COLDSV = $E477 ;vector to coldstart
+RBLOKV = $E47A ;vector to read cassette block
+CSOPIV = $E47D ;vector to open cassette for input
+VCTABL = $E480 ;RAM vector initial value table
+PUPDIV = $E480 ;##rev2## vector to power-up display
+SLFTSV = $E483 ;##rev2## vector to self-test
+PHENTV = $E486 ;##rev2## vector to enter peripheral handler
+PHUNLV = $E489 ;##rev2## vector to unlink peripheral handler
+PHINIV = $E48C ;##rev2## vector to initialize peripheral handler
+GPDVV = $E48F ;##rev2## generic parallel device handler vector
+
+; NOTE: OS rom self-test labels are not included in this file
+
+;-------------------------------------------------------------------------
+; Some misc. stuff from the 400/800 rev.B source
+;-------------------------------------------------------------------------
+
+; THE FOLLOWING ARE IN BASIC CARTRIDGE:
+SIN = $BD81 ;FR0 <- SIN (FR0) DEGFLG (0=RAD,6=DEG) CARRY
+COS = $BD73 ;FR0 <- COS (FR0) CARRY
+ATAN = $BE43 ;FR0 <- ATAN(FR0) CARRY
+SQR = $BEB1 ;FR0 <- ROOT(FR0) CARRY
+
+RADON = 0 ;INDICATES RADIANS
+DEGON = 6 ;INDICATES DEGREES
+
+ASCZER = '0' ;ASCII ZERO
+COLON = $3A ;ASCII COLON
+CR = $9B ;SYSTEM EOL (CARRIAGE RETURN)
+
+;-------------------------------------------------------------------------
+; 6502
+;-------------------------------------------------------------------------
+
+NMIVEC = $FFFA
+RESVEC = $FFFC
+IRQVEC = $FFFE
+
+;-------------------------------------------------------------------------
+; BASIC
+;-------------------------------------------------------------------------
+
+LOMEM = $80 ;2-byte low memory pointer
+VNTP = $82 ;2-byte variable name table address
+VNTD = $84 ;2-byte variable name table end + 1
+VVTP = $86 ;2-byte variable value table
+STMTAB = $88 ;2-byte statement table address
+STMCUR = $8A ;2-byte current statement pointer
+STARP = $8C ;2-byte string and array table pointer
+RUNSTK = $8E ;2-byte runtime stack address
+;MEMTOP = $90 ;2-byte top of memory pointer
+STOPLN = $BA ;2-byte stopped line number
+ERRSAVE = $C3 ;1-byte error code
+PTABW = $C9 ;1-byte tab width
+
+;-------------------------------------------------------------------------
+; DOS
+;-------------------------------------------------------------------------
+
+DOS = $0700
+
+RENAME = $20 ;RENAME DISK FILE
+DELETE = $21 ;DELETE DISK FILE
+FORMAT = $21 ;FORMAT
+LOCKFL = $23 ;LOCK FILE TO READ ONLY
+UNLOCK = $24 ;UNLOCK LOCKED FILE
+POINT = $25 ;POINT SECTOR
+NOTE = $26 ;NOTE SECTOR
+
+; Command line table, Index values for (DOSVEC),Y -- COMTAB
+; Compatible with OS/A+, DOS XL and SpartaDOS
+
+COMTAB = 0 ;DOS entry jump vector
+ZCRNAME = 3 ;file name crunch routine jump vector
+BUFOFF = 10 ;next parameter buffer offset
+COMFNAM = 33 ;destination buffer for crunch routine
+LBUF = 63 ;command line input buffer
+
+;-------------------------------------------------------------------------
+; ATASCII CHARACTER DEFS
+;-------------------------------------------------------------------------
+
+ATCLR = $7D ;CLEAR SCREEN CHARACTER
+ATRUB = $7E ;BACK SPACE (RUBOUT)
+ATTAB = $7F ;TAB
+ATEOL = $9B ;END-OF-LINE
+ATDELL = $9C ;Delete line
+ATBEL = $FD ;CONSOLE BELL
+ATURW = $1C ;UP-ARROW
+ATDRW = $1D ;DOWN-ARROW
+ATLRW = $1E ;LEFT-ARROW
+ATRRW = $1F ;RIGHT-ARROW
+
+;-------------------------------------------------------------------------
+; End of atari.inc
+;-------------------------------------------------------------------------
+
--- /dev/null
+;
+; Christian Groessler, 27-Feb-2000
+;
+; void set_brk (unsigned Addr);
+; void reset_brk (void);
+;
+
+ .export _set_brk, _reset_brk
+ .export _brk_a, _brk_x, _brk_y, _brk_sr, _brk_pc
+ .import _atexit
+
+ .include "atari.inc"
+
+
+.bss
+_brk_a: .res 1
+_brk_x: .res 1
+_brk_y: .res 1
+_brk_sr: .res 1
+_brk_pc: .res 2
+
+oldvec: .res 2 ; Old vector
+
+
+.data
+uservec: jmp $FFFF ; Patched at runtime
+
+
+.code
+
+; Set the break vector
+.proc _set_brk
+
+ sta uservec+1
+ stx uservec+2 ; Set the user vector
+
+ lda oldvec
+ ora oldvec+1 ; Did we save the vector already?
+ bne L1 ; Jump if we installed the handler already
+
+ lda VBREAK
+ sta oldvec
+ lda VBREAK+1
+ sta oldvec+1 ; Save the old vector
+
+ lda #<_reset_brk
+ ldx #>_reset_brk
+ jsr _atexit ; Install an exit handler
+
+L1: lda #<brk_handler ; Set the break vector to our routine
+ sta VBREAK
+ lda #>brk_handler
+ sta VBREAK+1
+ rts
+
+.endproc
+
+
+; Reset the break vector
+.proc _reset_brk
+
+ lda oldvec
+ sta VBREAK
+ lda oldvec+1
+ sta VBREAK+1
+ rts
+
+.endproc
+
+
+
+; Break handler, called if a break occurs
+
+.proc brk_handler
+
+ sty _brk_y
+ stx _brk_x
+ pla
+ sta _brk_a
+ pla
+ and #$EF ; Clear break bit
+ sta _brk_sr
+ pla ; PC low
+ sec
+ sbc #2 ; Point to start of brk
+ sta _brk_pc
+ pla ; PC high
+ sbc #0
+ sta _brk_pc+1
+
+ jsr uservec ; Call the user's routine
+
+ lda _brk_pc+1
+ pha
+ lda _brk_pc
+ pha
+ lda _brk_sr
+ pha
+ ldx _brk_x
+ ldy _brk_y
+ lda _brk_a
+ rti ; Jump back...
+
+.endproc
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 08.08.1998
+;
+; void cclearxy (unsigned char x, unsigned char y, unsigned char length);
+; void cclear (unsigned char length);
+;
+
+ .export _cclearxy, _cclear
+ .import popa, _gotoxy, cputdirect
+ .importzp tmp1
+
+_cclearxy:
+ pha ; Save the length
+ jsr popa ; Get y
+ jsr _gotoxy ; Call this one, will pop params
+ pla ; Restore the length and run into _cclear
+
+_cclear:
+ cmp #0 ; Is the length zero?
+ beq L9 ; Jump if done
+ sta tmp1
+.ifdef DIRECT_SCREEN
+L1: lda #0 ; Blank - screen code
+.else
+L1: lda #$20 ; Blank
+.endif
+ jsr cputdirect ; Direct output
+ dec tmp1
+ bne L1
+L9: rts
+
+
+
+
--- /dev/null
+;
+; get a kbd char.
+;
+; char cgetc(void)
+;
+
+ .include "atari.inc"
+ .export _cgetc
+
+_cgetc:
+ lda KEYBDV+5
+ pha
+ lda KEYBDV+4
+ pha
+ rts
+ ldx #0
+ rts
--- /dev/null
+;
+; Ullrich von Bassewitz, 08.08.1998
+;
+; void chlinexy (unsigned char x, unsigned char y, unsigned char length);
+; void chline (unsigned char length);
+;
+
+ .export _chlinexy, _chline
+ .import popa, _gotoxy, cputdirect
+ .importzp tmp1
+
+_chlinexy:
+ pha ; Save the length
+ jsr popa ; Get y
+ jsr _gotoxy ; Call this one, will pop params
+ pla ; Restore the length
+
+_chline:
+ cmp #0 ; Is the length zero?
+ beq L9 ; Jump if done
+ sta tmp1
+.ifdef DIRECT_SCREEN
+L1: lda #$12+64 ; Horizontal line, screen code
+.else
+L1: lda #$12 ; Horizontal line
+.endif
+ jsr cputdirect ; Direct output
+ dec tmp1
+ bne L1
+L9: rts
+
+
+
+
--- /dev/null
+;
+; Christian Groessler, May-2000
+;
+; int close(int fd);
+;
+
+ .include "atari.inc"
+ .export _close
+ .import __do_oserror,popax,__oserror
+ .import fdtoiocb_down,__inviocb
+
+.proc _close
+ jsr popax
+ jsr fdtoiocb_down ; get iocb index into X and decr. usage count
+ bmi inverr
+ bne ok ; not last one -> don't close yet
+; asl a
+; asl a
+; asl a
+; asl a
+; tax
+ lda #CLOSE
+ sta ICCOM,x
+ jsr CIOV
+ bpl ok
+ jmp __do_oserror
+
+ok: ldx #0
+ stx __oserror ; clear system specific error code
+ txa
+ rts
+
+inverr: jmp __inviocb
+
+.endproc
+
--- /dev/null
+;
+; Christian Groessler, Apr-2000
+;
+; void clrscr (void);
+;
+
+ .export _clrscr
+
+ .include "atari.inc"
+
+.ifdef DIRECT_SCREEN
+
+ .importzp ptr1
+
+_clrscr:lda SAVMSC ; screen memory
+ sta ptr1
+ lda SAVMSC+1
+ clc
+ adc #>(40*24)
+ sta ptr1+1
+ lda #0 ; screen code of space char
+ ldy #<(40*24) ; 40x24: size of default atari screen
+ ldx #>(40*24)
+_clr1: sta (ptr1),y
+ dey
+ bne _clr1
+ sta (ptr1),y
+ dex
+ bmi done
+ ldy ptr1+1
+ dey
+ sty ptr1+1
+ ldy #255
+ jmp _clr1
+
+done: sta COLCRS
+ sta ROWCRS
+ rts
+
+.else
+
+ .import putchar
+_clrscr:
+ lda #ATCLR
+ jmp putchar
+
+.endif
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; unsigned char __fastcall__ textcolor (unsigned char color);
+; unsigned char __fastcall__ bgcolor (unsigned char color);
+; unsigned char __fastcall__ bordercolor (unsigned char color);
+;
+
+
+ .export _textcolor, _bgcolor, _bordercolor
+
+ .include "atari.inc"
+
+_textcolor:
+ ldx COLOR1 ; get old value
+ sta COLOR1 ; set new value
+ txa
+ rts
+
+
+_bgcolor:
+ ldx COLOR2 ; get old value
+ sta COLOR2 ; set new value
+ txa
+ rts
+
+
+_bordercolor:
+ ldx COLOR4 ; get old value
+ sta COLOR4 ; set new value
+ txa
+ rts
+
--- /dev/null
+;
+; Christian Groessler
+;
+; Low level stuff for screen output/console input
+;
+
+ .export initconio
+ .import xsize, ysize, plot
+
+ .include "atari.inc"
+
+.code
+
+initconio:
+ ldx #40
+ ldy #24
+ stx xsize
+ sty ysize
+ rts
+
--- /dev/null
+;
+; Mark Keates, Christian Groessler
+;
+; void cputcxy (unsigned char x, unsigned char y, char c);
+; void cputc (char c);
+;
+
+ .export _cputcxy, _cputc
+ .export plot, cputdirect, putchar
+ .import popa, _gotoxy
+
+ .include "atari.inc"
+
+_cputcxy:
+ pha ; Save C
+ jsr popa ; Get Y
+ jsr _gotoxy ; Set cursor, drop x
+ pla ; Restore C
+
+.ifdef DIRECT_SCREEN
+
+ .importzp tmp4,ptr4
+
+_cputc:
+ cmp #$0D ; CR
+ bne L4
+ lda #0
+ sta COLCRS
+ beq plot ; return
+
+L4: cmp #$0A ; LF
+ beq newline
+ cmp #ATEOL ; Atari-EOL?
+ beq newline
+
+ tay
+ rol a
+ rol a
+ rol a
+ rol a
+ and #3
+ tax
+ tya
+ and #$9f
+ ora ataint,x
+
+cputdirect: ; accepts screen code
+ jsr putchar
+
+; advance cursor
+ inc COLCRS
+ lda COLCRS
+ cmp #40
+ bcc plot
+ lda #0
+ sta COLCRS
+
+ .export newline
+newline:
+ inc ROWCRS
+ lda ROWCRS
+ cmp #24
+ bne plot
+ lda #0
+ sta ROWCRS
+plot: ldy COLCRS
+ ldx ROWCRS
+ rts
+
+putchar:
+ pha ; save char
+ lda #0
+ sta tmp4
+ lda ROWCRS
+ asl a
+ rol tmp4
+ asl a
+ rol tmp4 ; row * 4
+ adc ROWCRS
+ bcc L1
+ inc tmp4 ; row * 5
+L1: asl a
+ rol tmp4 ; row * 10
+ asl a
+ rol tmp4
+ asl a
+ rol tmp4 ; row * 40
+L3: clc
+ adc SAVMSC ; add start of screen memory
+ sta ptr4
+ lda tmp4
+ adc SAVMSC+1
+ sta ptr4+1
+ pla ; get char again
+ ora INVFLG
+ ldy COLCRS
+ sta (ptr4),y
+ rts
+
+ .rodata
+ataint: .byte 64,0,32,96
+
+;****************************************************************
+.else ;***** above DIRECT_SCREEN, below thru OS ***************
+;****************************************************************
+
+ .import __do_oserror,cursor,__oserror
+
+
+; Plot a character - also used as internal function
+
+_cputc: cmp #$0D ; CR?
+ bne L1
+ lda #0
+ sta COLCRS
+ beq plot ; Recalculate pointers
+
+; don't know whether this is needed. the compiler generates
+; already ATEOL chars for \n
+
+L1: cmp #$0A ; LF?
+ bne L2
+ lda #ATEOL
+
+; Printable char of some sort
+
+L2:
+cputdirect:
+ pha
+ and #$7f
+ cmp #32 ; control char?
+ bcs goon
+ lda #$1b
+ jsr putchar
+goon: pla
+ jsr putchar ; Write the character to the screen
+
+plot: ldy COLCRS
+ ldx ROWCRS
+ rts
+
+; Write one character to the screen without doing anything else, return X
+; position in Y
+
+putchar:
+.if 0
+ tax
+ lda #>(retr-1)
+ pha
+ lda #<(retr-1)
+ pha
+ lda ICPTH
+ pha
+ lda ICPTL
+ pha
+ lda #0
+ sta LOGCOL
+ txa
+ rts
+retr:
+.endif
+.if 1
+ pha
+ ldx #0 ; iocb #0 (screen editor)
+ txa
+ sta ICBLL,x
+ sta ICBLH,x
+ sta ICBAL,x
+ sta ICBAH,x
+ lda #PUTCHR
+ sta ICCOM,x
+ lda cursor
+ beq putc7
+ lda #0
+ beq putc8
+putc7: lda #1
+putc8: sta CRSINH
+ pla
+ jsr CIOV
+ bpl putc9
+ jmp __do_oserror ; update system specific error code
+
+putc9: tya
+ ldx #0
+ stx __oserror
+ ldy COLCRS
+.endif
+ rts
+
+.endif ; not defined DIRECT_SCREEN
--- /dev/null
+;
+; Startup code for cc65 (ATARI version)
+;
+; Contributing authors:
+; Mark Keates
+; Freddy Offenga
+; Christian Groessler
+;
+; This must be the *first* file on the linker command line
+;
+
+ .export _exit
+ .import getargs, argc, argv
+ .import __hinit, initconio, zerobss, pushax, doatexit
+ .import _main,__filetab
+ .import __CODE_LOAD__, __BSS_LOAD__
+
+ .include "atari.inc"
+
+; ------------------------------------------------------------------------
+; Define and export the ZP variables for the runtime
+
+ .exportzp sp, sreg, regsave
+ .exportzp ptr1, ptr2, ptr3, ptr4
+ .exportzp tmp1, tmp2, tmp3, tmp4
+ .exportzp fntemp, regbank, zpspace
+
+sp = $D2 ; (2bytes) stack pointer
+sreg = $D4 ; (2bytes) secondary register/high 16 bit for longs
+regsave = $D6 ; (4bytes) slot to save/restore (E)AX into
+ptr1 = $DA ; (2bytes)
+ptr2 = $DC ; (2bytes)
+ptr3 = $DE ; (2bytes)
+ptr4 = $E0 ; (2bytes)
+tmp1 = $E2 ; (1byte)
+tmp2 = $E3 ; (1byte)
+tmp3 = $E4 ; (1byte)
+tmp4 = $E5 ; (1byte)
+fntemp = $E6 ; (2bytes) pointer to file name
+regbank = $E8 ; (6bytes) 6 byte register bank
+zpspace = $EE - sp ; Zero page space allocated
+
+; ------------------------------------------------------------------------
+; EXE header
+
+ .segment "EXEHDR"
+ .word $FFFF
+ .word __CODE_LOAD__
+ .word __BSS_LOAD__ - 1
+ .code
+ .reloc
+
+; ------------------------------------------------------------------------
+; Actual code
+
+ rts ; fix for SpartaDOS / OS/A+
+ ; they first call the entry point from AUTOSTRT and
+ ; then the load addess (this rts here).
+ ; We point AUTOSTRT directly after the rts.
+
+; Real entry point:
+
+; Save the zero page locations we need
+
+ ldy #zpspace-1
+L1: lda sp,y
+ sta zpsave,y
+ dey
+ bpl L1
+
+; Clear the BSS data
+
+ jsr zerobss
+
+; setup the stack
+
+ tsx
+ stx spsave
+
+; report memory usage and initialize stack pointer
+
+ lda APPMHI
+ sta appmsav
+ lda APPMHI+1
+ sta appmsav+1
+
+ lda #<$8000
+ sta sp
+ sta APPMHI
+ lda #>$8000
+ sta sp+1 ; Set argument stack ptr
+ sta APPMHI+1
+
+; set left margin to 0
+
+ lda LMARGN
+ sta old_lmargin
+ lda #0
+ sta LMARGN
+
+; set keyb to upper/lowercase mode
+
+ ldx SHFLOK
+ stx old_shflok
+ sta SHFLOK
+
+; Initialize the heap
+
+ jsr __hinit
+
+; Initialize conio stuff
+
+ jsr initconio
+
+ lda #$FF
+ sta CH
+
+; ugly hack for now: set stdio stream handles
+; all to iocb #0
+; until we know where to go with fd<->iocb relation
+; this won't stay here!
+
+ lda #0
+ sta __filetab + 2
+ sta __filetab + 4
+
+; Pass command line if present
+
+ jsr getargs
+
+ lda argc
+ ldx argc+1
+ jsr pushax ; argc
+ lda #<argv
+ ldx #>argv
+ jsr pushax ; argv
+
+ ldy #4 ; Argument size
+ jsr _main ; call the users code
+
+; fall thru to exit...
+
+_exit: jsr doatexit ; call exit functions
+
+ ldx spsave
+ txs ; Restore stack pointer
+
+; restore left margin
+
+ lda old_lmargin
+ sta LMARGN
+
+; restore kb mode
+
+ lda old_shflok
+ sta SHFLOK
+
+; restore APPMHI
+
+ lda appmsav
+ sta APPMHI
+ lda appmsav+1
+ sta APPMHI+1
+
+; Copy back the zero page stuff
+
+ ldy #zpspace-1
+L2: lda zpsave,y
+ sta sp,y
+ dey
+ bpl L2
+
+; Back to DOS
+
+ rts
+
+.data
+
+zpsave: .res zpspace
+
+.bss
+
+spsave: .res 1
+appmsav: .res 1
+old_shflok: .res 1
+old_lmargin: .res 1
+
+ .segment "AUTOSTRT"
+ .word $02E0
+ .word $02E1
+ .word __CODE_LOAD__ + 1
--- /dev/null
+;
+; Ullrich von Bassewitz, 02.06.1998
+;
+; Character specification table.
+;
+
+; The tables are readonly, put them into the code segment
+
+.code
+
+; Value that must be added to an upper case char to make it lower case
+; char (example: for ASCII, this must be $E0).
+
+
+ .export __cdiff
+
+__cdiff:
+ .byte $E0
+
+
+; The following 256 byte wide table specifies attributes for the isxxx type
+; of functions. Doing it by a table means some overhead in space, but it
+; has major advantages:
+;
+; * It is fast. If it were'nt for the slow parameter passing of cc65, one
+; could even define macros for the isxxx functions (this is usually
+; done on other platforms).
+;
+; * It is highly portable. The only unportable part is the table itself,
+; all real code goes into the common library.
+;
+; * We save some code in the isxxx functions.
+;
+;
+; Bit assignments:
+;
+; 0 - Lower case char
+; 1 - Upper case char
+; 2 - Numeric digit
+; 3 - Hex digit (both, lower and upper)
+; 4 - Control character
+; 5 - The space character itself
+; 6 - Other whitespace (that is: '\f', '\n', '\r', '\t' and '\v')
+; 7 - Space or tab character
+
+ .export __ctype
+
+__ctype:
+ .byte $10 ; 0/00 ___ctrl_@___
+ .byte $10 ; 1/01 ___ctrl_A___
+ .byte $10 ; 2/02 ___ctrl_B___
+ .byte $10 ; 3/03 ___ctrl_C___
+ .byte $10 ; 4/04 ___ctrl_D___
+ .byte $10 ; 5/05 ___ctrl_E___
+ .byte $10 ; 6/06 ___ctrl_F___
+ .byte $10 ; 7/07 ___ctrl_G___
+ .byte $10 ; 8/08 ___ctrl_H___
+ .byte $D0 ; 9/09 ___ctrl_I___
+ .byte $50 ; 10/0a ___ctrl_J___
+ .byte $50 ; 11/0b ___ctrl_K___
+ .byte $50 ; 12/0c ___ctrl_L___
+ .byte $50 ; 13/0d ___ctrl_M___
+ .byte $10 ; 14/0e ___ctrl_N___
+ .byte $10 ; 15/0f ___ctrl_O___
+ .byte $10 ; 16/10 ___ctrl_P___
+ .byte $10 ; 17/11 ___ctrl_Q___
+ .byte $10 ; 18/12 ___ctrl_R___
+ .byte $10 ; 19/13 ___ctrl_S___
+ .byte $10 ; 20/14 ___ctrl_T___
+ .byte $10 ; 21/15 ___ctrl_U___
+ .byte $10 ; 22/16 ___ctrl_V___
+ .byte $10 ; 23/17 ___ctrl_W___
+ .byte $10 ; 24/18 ___ctrl_X___
+ .byte $10 ; 25/19 ___ctrl_Y___
+ .byte $10 ; 26/1a ___ctrl_Z___
+ .byte $10 ; 27/1b ___ctrl_[___
+ .byte $10 ; 28/1c ___ctrl_\___
+ .byte $10 ; 29/1d ___ctrl_]___
+ .byte $10 ; 30/1e ___ctrl_^___
+ .byte $10 ; 31/1f ___ctrl_____
+ .byte $A0 ; 32/20 ___SPACE___
+ .byte $00 ; 33/21 _____!_____
+ .byte $00 ; 34/22 _____"_____
+ .byte $00 ; 35/23 _____#_____
+ .byte $00 ; 36/24 _____$_____
+ .byte $00 ; 37/25 _____%_____
+ .byte $00 ; 38/26 _____&_____
+ .byte $00 ; 39/27 _____'_____
+ .byte $00 ; 40/28 _____(_____
+ .byte $00 ; 41/29 _____)_____
+ .byte $00 ; 42/2a _____*_____
+ .byte $00 ; 43/2b _____+_____
+ .byte $00 ; 44/2c _____,_____
+ .byte $00 ; 45/2d _____-_____
+ .byte $00 ; 46/2e _____._____
+ .byte $00 ; 47/2f _____/_____
+ .byte $0C ; 48/30 _____0_____
+ .byte $0C ; 49/31 _____1_____
+ .byte $0C ; 50/32 _____2_____
+ .byte $0C ; 51/33 _____3_____
+ .byte $0C ; 52/34 _____4_____
+ .byte $0C ; 53/35 _____5_____
+ .byte $0C ; 54/36 _____6_____
+ .byte $0C ; 55/37 _____7_____
+ .byte $0C ; 56/38 _____8_____
+ .byte $0C ; 57/39 _____9_____
+ .byte $00 ; 58/3a _____:_____
+ .byte $00 ; 59/3b _____;_____
+ .byte $00 ; 60/3c _____<_____
+ .byte $00 ; 61/3d _____=_____
+ .byte $00 ; 62/3e _____>_____
+ .byte $00 ; 63/3f _____?_____
+
+ .byte $00 ; 64/40 _____@_____
+ .byte $0A ; 65/41 _____A_____
+ .byte $0A ; 66/42 _____B_____
+ .byte $0A ; 67/43 _____C_____
+ .byte $0A ; 68/44 _____D_____
+ .byte $0A ; 69/45 _____E_____
+ .byte $0A ; 70/46 _____F_____
+ .byte $02 ; 71/47 _____G_____
+ .byte $02 ; 72/48 _____H_____
+ .byte $02 ; 73/49 _____I_____
+ .byte $02 ; 74/4a _____J_____
+ .byte $02 ; 75/4b _____K_____
+ .byte $02 ; 76/4c _____L_____
+ .byte $02 ; 77/4d _____M_____
+ .byte $02 ; 78/4e _____N_____
+ .byte $02 ; 79/4f _____O_____
+ .byte $02 ; 80/50 _____P_____
+ .byte $02 ; 81/51 _____Q_____
+ .byte $02 ; 82/52 _____R_____
+ .byte $02 ; 83/53 _____S_____
+ .byte $02 ; 84/54 _____T_____
+ .byte $02 ; 85/55 _____U_____
+ .byte $02 ; 86/56 _____V_____
+ .byte $02 ; 87/57 _____W_____
+ .byte $02 ; 88/58 _____X_____
+ .byte $02 ; 89/59 _____Y_____
+ .byte $02 ; 90/5a _____Z_____
+ .byte $00 ; 91/5b _____[_____
+ .byte $00 ; 92/5c _____\_____
+ .byte $00 ; 93/5d _____]_____
+ .byte $00 ; 94/5e _____^_____
+ .byte $00 ; 95/5f _UNDERLINE_
+ .byte $00 ; 96/60 ___grave___
+ .byte $09 ; 97/61 _____a_____
+ .byte $09 ; 98/62 _____b_____
+ .byte $09 ; 99/63 _____c_____
+ .byte $09 ; 100/64 _____d_____
+ .byte $09 ; 101/65 _____e_____
+ .byte $09 ; 102/66 _____f_____
+ .byte $01 ; 103/67 _____g_____
+ .byte $01 ; 104/68 _____h_____
+ .byte $01 ; 105/69 _____i_____
+ .byte $01 ; 106/6a _____j_____
+ .byte $01 ; 107/6b _____k_____
+ .byte $01 ; 108/6c _____l_____
+ .byte $01 ; 109/6d _____m_____
+ .byte $01 ; 110/6e _____n_____
+ .byte $01 ; 111/6f _____o_____
+ .byte $01 ; 112/70 _____p_____
+ .byte $01 ; 113/71 _____q_____
+ .byte $01 ; 114/72 _____r_____
+ .byte $01 ; 115/73 _____s_____
+ .byte $01 ; 116/74 _____t_____
+ .byte $01 ; 117/75 _____u_____
+ .byte $01 ; 118/76 _____v_____
+ .byte $01 ; 119/77 _____w_____
+ .byte $01 ; 120/78 _____x_____
+ .byte $01 ; 121/79 _____y_____
+ .byte $01 ; 122/7a _____z_____
+ .byte $00 ; 123/7b _____{_____
+ .byte $00 ; 124/7c _____|_____
+ .byte $00 ; 125/7d _____}_____
+ .byte $00 ; 126/7e _____~_____
+ .byte $40 ; 127/7f ____DEL____
+
+ .byte $00 ; 128/80 ___________
+ .byte $00 ; 129/81 ___________
+ .byte $00 ; 130/82 ___________
+ .byte $00 ; 131/83 ___________
+ .byte $00 ; 132/84 ___________
+ .byte $00 ; 133/85 ___________
+ .byte $00 ; 134/86 ___________
+ .byte $00 ; 135/87 ___________
+ .byte $00 ; 136/88 ___________
+ .byte $00 ; 137/89 ___________
+ .byte $00 ; 138/8a ___________
+ .byte $00 ; 139/8b ___________
+ .byte $00 ; 140/8c ___________
+ .byte $00 ; 141/8d ___________
+ .byte $00 ; 142/8e ___________
+ .byte $00 ; 143/8f ___________
+ .byte $00 ; 144/90 ___________
+ .byte $00 ; 145/91 ___________
+ .byte $00 ; 146/92 ___________
+ .byte $10 ; 147/93 ___________
+ .byte $00 ; 148/94 ___________
+ .byte $00 ; 149/95 ___________
+ .byte $00 ; 150/96 ___________
+ .byte $00 ; 151/97 ___________
+ .byte $00 ; 152/98 ___________
+ .byte $00 ; 153/99 ___________
+ .byte $00 ; 154/9a ___________
+ .byte $00 ; 155/9b ___________
+ .byte $00 ; 156/9c ___________
+ .byte $00 ; 157/9d ___________
+ .byte $00 ; 158/9e ___________
+ .byte $00 ; 159/9f ___________
+
+ .byte $00 ; 160/a0 ___________
+ .byte $00 ; 161/a1 ___________
+ .byte $00 ; 162/a2 ___________
+ .byte $00 ; 163/a3 ___________
+ .byte $00 ; 164/a4 ___________
+ .byte $00 ; 165/a5 ___________
+ .byte $00 ; 166/a6 ___________
+ .byte $00 ; 167/a7 ___________
+ .byte $00 ; 168/a8 ___________
+ .byte $00 ; 169/a9 ___________
+ .byte $00 ; 170/aa ___________
+ .byte $00 ; 171/ab ___________
+ .byte $00 ; 172/ac ___________
+ .byte $00 ; 173/ad ___________
+ .byte $00 ; 174/ae ___________
+ .byte $00 ; 175/af ___________
+ .byte $00 ; 176/b0 ___________
+ .byte $00 ; 177/b1 ___________
+ .byte $00 ; 178/b2 ___________
+ .byte $00 ; 179/b3 ___________
+ .byte $00 ; 180/b4 ___________
+ .byte $00 ; 181/b5 ___________
+ .byte $00 ; 182/b6 ___________
+ .byte $00 ; 183/b7 ___________
+ .byte $00 ; 184/b8 ___________
+ .byte $00 ; 185/b9 ___________
+ .byte $00 ; 186/ba ___________
+ .byte $00 ; 187/bb ___________
+ .byte $00 ; 188/bc ___________
+ .byte $00 ; 189/bd ___________
+ .byte $00 ; 190/be ___________
+ .byte $00 ; 191/bf ___________
+
+ .byte $02 ; 192/c0 ___________
+ .byte $02 ; 193/c1 ___________
+ .byte $02 ; 194/c2 ___________
+ .byte $02 ; 195/c3 ___________
+ .byte $02 ; 196/c4 ___________
+ .byte $02 ; 197/c5 ___________
+ .byte $02 ; 198/c6 ___________
+ .byte $02 ; 199/c7 ___________
+ .byte $02 ; 200/c8 ___________
+ .byte $02 ; 201/c9 ___________
+ .byte $02 ; 202/ca ___________
+ .byte $02 ; 203/cb ___________
+ .byte $02 ; 204/cc ___________
+ .byte $02 ; 205/cd ___________
+ .byte $02 ; 206/ce ___________
+ .byte $02 ; 207/cf ___________
+ .byte $02 ; 208/d0 ___________
+ .byte $02 ; 209/d1 ___________
+ .byte $02 ; 210/d2 ___________
+ .byte $02 ; 211/d3 ___________
+ .byte $02 ; 212/d4 ___________
+ .byte $02 ; 213/d5 ___________
+ .byte $02 ; 214/d6 ___________
+ .byte $02 ; 215/d7 ___________
+ .byte $02 ; 216/d8 ___________
+ .byte $02 ; 217/d9 ___________
+ .byte $02 ; 218/da ___________
+ .byte $02 ; 219/db ___________
+ .byte $02 ; 220/dc ___________
+ .byte $02 ; 221/dd ___________
+ .byte $02 ; 222/de ___________
+ .byte $00 ; 223/df ___________
+ .byte $01 ; 224/e0 ___________
+ .byte $01 ; 225/e1 ___________
+ .byte $01 ; 226/e2 ___________
+ .byte $01 ; 227/e3 ___________
+ .byte $01 ; 228/e4 ___________
+ .byte $01 ; 229/e5 ___________
+ .byte $01 ; 230/e6 ___________
+ .byte $01 ; 231/e7 ___________
+ .byte $01 ; 232/e8 ___________
+ .byte $01 ; 233/e9 ___________
+ .byte $01 ; 234/ea ___________
+ .byte $01 ; 235/eb ___________
+ .byte $01 ; 236/ec ___________
+ .byte $01 ; 237/ed ___________
+ .byte $01 ; 238/ee ___________
+ .byte $01 ; 239/ef ___________
+ .byte $01 ; 240/f0 ___________
+ .byte $01 ; 241/f1 ___________
+ .byte $01 ; 242/f2 ___________
+ .byte $01 ; 243/f3 ___________
+ .byte $01 ; 244/f4 ___________
+ .byte $01 ; 245/f5 ___________
+ .byte $01 ; 246/f6 ___________
+ .byte $01 ; 247/f7 ___________
+ .byte $01 ; 248/f8 ___________
+ .byte $01 ; 249/f9 ___________
+ .byte $01 ; 250/fa ___________
+ .byte $01 ; 251/fb ___________
+ .byte $01 ; 252/fc ___________
+ .byte $01 ; 253/fd ___________
+ .byte $01 ; 254/fe ___________
+ .byte $00 ; 255/ff ___________
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 08.08.1998
+;
+; void cvlinexy (unsigned char x, unsigned char y, unsigned char length);
+; void cvline (unsigned char length);
+;
+ .include "atari.inc"
+
+ .export _cvlinexy, _cvline
+ .import popa, _gotoxy, putchar, newline
+ .importzp tmp1
+
+_cvlinexy:
+ pha ; Save the length
+ jsr popa ; Get y
+ jsr _gotoxy ; Call this one, will pop params
+ pla ; Restore the length and run into _cvline
+
+_cvline:
+ cmp #0 ; Is the length zero?
+ beq L9 ; Jump if done
+ sta tmp1
+L1: lda COLCRS
+ pha
+ lda #$7C ; Vertical bar
+ jsr putchar ; Write, no cursor advance
+ pla
+ sta COLCRS
+ inc ROWCRS
+ dec tmp1
+ bne L1
+L9: rts
+
+
+
--- /dev/null
+;
+; Christian Groessler, May-2000
+;
+; fd indirection table & helper functions
+;
+
+ .include "atari.inc"
+ .export fdtoiocb
+ .export fdtoiocb_down
+ .export fd_table
+
+ .data
+
+fd_table:
+ .byte 0,$ff,0,0
+ .byte 0,$ff,0,0
+ .byte 0,$ff,0,0
+ .byte 0,$ff,0,0
+ .byte 0,$ff,0,0
+ .byte 0,$ff,0,0
+ .byte 0,$ff,0,0
+ .byte 0,$ff,0,0
+ .byte 0,$ff,0,0
+ .byte 0,$ff,0,0
+ .byte 0,$ff,0,0
+ .byte 0,$ff,0,0
+
+MAX_FD_VAL = (* - fd_table) / 4
+
+ft_usa = 0 ; usage counter
+ft_iocb = 1 ; iocb index (0,$10,$20,etc.), $ff for empty entry
+ft_dev = 2 ; device of open iocb
+ft_flag = 3 ; flags
+
+ .code
+
+; gets fd in ax, decrements usage counter
+; return iocb index in X
+; return N bit set for invalid fd
+; return Z bit set if last user
+; all registers destroyed
+.proc fdtoiocb_down
+
+ cpx #0
+ bne inval
+ cmp #MAX_FD_VAL
+ bcs inval
+ asl a ; create index into fd table
+ asl a
+ tax
+ lda #$ff
+ cmp fd_table+ft_iocb,x ; entry in use?
+ beq inval ; no, return error
+ lda fd_table+ft_usa,x ; get usage counter
+ beq ok_notlast ; 0?
+ sec
+ sbc #1 ; decr usage counter
+ sta fd_table+ft_usa,x
+retiocb:php
+ txa
+ tay
+ lda fd_table+ft_iocb,x ; get iocb
+ tax
+ plp
+ bne cont
+ php
+ lda #$ff
+ sta fd_table+ft_iocb,y ; clear table entry
+ plp
+cont: rts
+
+ok_notlast:
+ lda #1 ; clears Z
+ jmp retiocb
+
+.endproc
+
+inval: ldx #$ff ; sets N
+ rts
+
+
+; gets fd in ax
+; return iocb index in X
+; return N bit set for invalid fd
+; all registers destroyed
+.proc fdtoiocb
+
+ cpx #0
+ bne inval
+ cmp #MAX_FD_VAL
+ bcs inval
+ asl a ; create index into fd table
+ asl a
+ tax
+ lda #$ff
+ cmp fd_table+ft_iocb,x ; entry in use?
+ beq inval ; no, return error
+ lda fd_table+ft_usa,x ; get usage counter
+ beq inval ; 0? should not happen
+ lda fd_table+ft_iocb,x ; get iocb
+ rts
+
+.endproc
--- /dev/null
+; get arguments from command line (when DOS supports it)
+; and supply function to get default device: char *getdefdev(void);
+
+; Freddy Offenga, 4/21/2000
+
+; SpartaDOS:
+; the ZCRNAME routine is only used to get the default drive because
+; ZCRNAME has two disadvantages:
+; 1. It will convert D: into D1: instead of Dn: (n = default drive)
+; 2. It will give a 'no arguments' status if it detects something
+; like Dn: (without filename).
+
+; OS/A+ DOS:
+; ZCRNAME is slightly different from SpartaDOS. It will convert D:
+; into Dn: where n is the default drive.
+
+MAXARGS = 16 ; max. amount of arguments in arg. table
+CL_SIZE = 64 ; command line buffer size
+SPACE = 32 ; SPACE char.
+
+ .include "atari.inc"
+ .export getargs, argc, argv
+ .export _getdefdev ; get default device (e.g. "D1:")
+ .importzp ptr1
+
+; Get command line
+
+getargs:
+ lda #0
+ sta argc
+ sta argc+1
+ sta argv
+ sta argv+1
+
+ jsr detect
+ bcs argdos ; carry set = DOS supports arguments
+ rts
+
+; Move SpartaDOS command line to our own buffer
+
+argdos: lda DOSVEC
+ clc
+ adc #<LBUF
+ sta ptr1
+ lda DOSVEC+1
+ adc #>LBUF
+ sta ptr1+1
+
+ ldy #0
+cpcl: lda (ptr1),y
+ sta ourcl,y
+ iny
+ cmp #ATEOL
+ beq movdon
+ cpy #CL_SIZE
+ bne cpcl
+
+movdon: lda #0
+ sta ourcl,y ; null terminate behind ATEOL
+
+; Get default device (LBUF will be destroyed!!)
+
+ ldy #BUFOFF
+ lda #0
+ sta (DOSVEC),y ; reset buffer offset
+
+; Store dummy argument
+
+ ldy #LBUF
+ lda dumpar1
+ sta (DOSVEC),y
+ iny
+ lda dumpar2
+ sta (DOSVEC),y
+
+; One extra store to avoid the buggy sequence from OS/A+ DOS:
+; <D><RETURN><:> => drive number = <RETURN>
+
+ iny
+ sta (DOSVEC),y
+
+; Create crunch vector
+
+ ldy #ZCRNAME+1
+ lda (DOSVEC),y
+ sta crvec+1
+ iny
+ lda (DOSVEC),y
+ sta crvec+2
+
+crvec: jsr $FFFF ; will be set to crunch vector
+
+; Get default device
+
+ ldy #COMFNAM ; COMFNAM is always "Dn:"
+ lda (DOSVEC),y
+ sta defdev
+ iny
+ lda (DOSVEC),y
+ sta defdev+1
+
+; Turn command line into argv table
+
+ ldy #0
+eatspc: lda ourcl,y ; eat spaces
+ cmp #ATEOL
+ beq finargs
+ cmp #SPACE
+ bne rpar ; begin of argument found
+ iny
+ cpy #CL_SIZE
+ bne eatspc
+ beq finargs ; only spaces is no argument
+
+; Store argument vector
+
+rpar: lda argc ; low-byte
+ asl
+ tax ; table index
+ tya ; ourcl index
+ clc
+ adc #<ourcl
+ sta argv,x
+ lda #>ourcl
+ adc #0
+ sta argv+1,x
+ ldx argc
+ inx
+ stx argc
+ cpx #MAXARGS
+ beq finargs
+
+; Skip this arg.
+
+skiparg:
+ ldx ourcl,y
+ cpx #ATEOL ; end of line?
+ beq eopar
+ cpx #SPACE
+ beq eopar
+ iny
+ cpy #CL_SIZE
+ bne skiparg
+
+; End of arg. -> place 0
+
+eopar:
+ lda #0
+ sta ourcl,y
+ iny ; y behind arg.
+ cpx #ATEOL ; was it the last arg?
+ bne eatspc
+
+; Finish args
+
+finargs:
+ lda argc
+ asl
+ tax
+ lda #0
+ sta argv,x
+ sta argv+1,x
+ rts
+
+; DOS type detection
+
+detect:
+ lda DOS
+ cmp #$53 ; "S" (SpartaDOS)
+ beq spdos
+
+ ldy #COMTAB
+ lda #$4C
+ cmp (DOSVEC),y
+ bne nordos
+
+ ldy #ZCRNAME
+ cmp (DOSVEC),y
+ bne nordos
+
+ ldy #6 ; OS/A+ has a jmp here
+ cmp (DOSVEC),y
+ beq nordos
+
+spdos: sec ; SpartaDOS, OS/A+ or DOS XL
+ rts
+
+nordos: clc ; normal DOS (no args) detected
+ rts
+
+; Get default device (set by getargs routine)
+
+_getdefdev:
+ lda #<defdev
+ ldx #>defdev
+ rts
+
+ .data
+
+; Dummy argument to get default device
+
+dumpar1:
+ .byte "X"
+dumpar2:
+ .byte ATEOL
+
+; Buffer for command line / argv strings
+
+ourcl: .res CL_SIZE
+ .byte ATEOL
+
+; Default device
+
+defdev:
+ .byte "D1:", 0
+
+ .bss
+
+argc: .res 2
+argv: .res (1 + MAXARGS) * 2
--- /dev/null
+;
+; Christian Groessler, 19-Feb-2000
+;
+; void gotox (unsigned char x);
+;
+
+ .include "atari.inc"
+ .export _gotox
+
+_gotox:
+ sta COLCRS ; Set X
+ lda #0
+ sta COLCRS+1
+ rts
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; void gotoxy (unsigned char x, unsigned char y);
+;
+
+ .include "atari.inc"
+
+ .export _gotoxy
+ .import popa
+
+_gotoxy: ; Set the cursor position
+ sta ROWCRS ; Set Y
+ jsr popa ; Get X
+ sta COLCRS ; Set X
+ lda #0
+ sta COLCRS+1 ;
+ rts
--- /dev/null
+;
+; Christian Groessler, 19-Feb-2000
+;
+; void gotoy (unsigned char y);
+;
+
+ .include "atari.inc"
+ .export _gotoy
+
+_gotoy:
+ sta ROWCRS ; Set Y
+ rts
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; int kbhit (void);
+;
+
+ .export _kbhit
+ .import return0, return1
+
+ .include "atari.inc"
+
+_kbhit:
+ lda CH ; Get number of characters
+ cmp #$FF
+ bne L1
+ jmp return1
+L1: jmp return0
+
+
+
+
--- /dev/null
+;
+; Christian Groessler, May-2000
+;
+; int open(const char *name,int flags,...);
+; returns fd
+;
+
+UCASE_FILENAME = 1 ; comment it out if filename shouldn't be uppercased
+
+ .include "atari.inc"
+ .include "../common/fmode.inc"
+ .include "../common/errno.inc"
+ .export _open
+ .import __do_oserror,__seterrno,incsp4
+ .import ldaxysp,addysp,subysp
+ .import _strupr,__oserror
+ .importzp tmp4,sp
+.ifdef UCASE_FILENAME
+ .importzp tmp3,ptr4
+.endif
+
+.proc _open
+
+ cpy #4 ; correct # of arguments (bytes)?
+ beq parmok ; parameter count ok
+ tya ; parm count < 4 shouldn't be needed to be checked
+ sec ; (it generates a c compiler warning)
+ sbc #4
+ tay
+ jsr addysp ; fix stack, throw away unused parameters
+
+parmok: jsr findfreeiocb
+ beq iocbok ; we found one
+
+ lda #<EMFILE ; "too many open files"
+ ldx #>EMFILE
+seterr: jsr __seterrno
+ jsr incsp4 ; clean up stack
+ lda #$FF
+ tax
+ rts ; return -1
+
+ ; process the mode argument
+ ; @@@TODO: append not handled yet!
+
+iocbok: stx tmp4
+ jsr clriocb ; init with zero
+ ldy #1
+ jsr ldaxysp ; get mode
+ ldx tmp4
+ cmp #O_RDONLY
+ bne l1
+ lda #OPNIN
+set: sta ICAX1,x
+ bne cont
+
+l1: cmp #O_WRONLY
+ bne l2
+ lda #OPNOT
+ bne set
+
+l2: ; O_RDWR
+ lda #OPNOT|OPNIN
+ bne set
+
+ ; process the filename argument
+
+cont: ldy #3
+ jsr ldaxysp
+
+.ifdef UCASE_FILENAME
+ ; we make sure that the filename doesn't contain lowercase letters
+ ; we copy the filename we got onto the stack, uppercase it and use this
+ ; one to open the iocb
+ ; we're using tmp3, ptr4
+
+ ; save the original pointer
+ sta ptr4
+ stx ptr4+1
+
+ ; now we need the length of the name
+ ldy #0
+loop: lda (ptr4),y
+ beq str_end
+ cmp #ATEOL ; we also accept Atari EOF char as end of string
+ beq str_end
+ iny
+ bne loop ; not longer than 255 chars (127 real limit)
+toolong:lda #<EINVAL ; file name is too long
+ ldx #>EINVAL
+ jmp seterr
+
+str_end:iny ; room for terminating zero
+ cpy #128 ; we only can handle lenght < 128
+ bcs toolong
+ sty tmp3 ; save size
+ jsr subysp ; make room on the stack
+
+ ; copy filename to the temp. place on the stack
+ lda #0 ; end-of-string
+ sta (sp),y ; Y still contains length + 1
+ dey
+loop2: lda (ptr4),y
+ sta (sp),y
+ dey
+ bpl loop2 ; bpl: this way we only support a max. length of 127
+
+ ; uppercase the temp. filename
+ ldx sp+1
+ lda sp
+ jsr _strupr
+
+ ; leave X and Y pointing to the modified filename
+ lda sp
+ ldx sp+1
+
+.endif ; defined UCASE_FILENAME
+
+ ldy tmp4
+
+ jsr newfd ; maybe we don't need to open and can reuse an iocb
+ bcc noopen
+
+ sta ICBAL,y
+ txa
+ sta ICBAH,y
+ ldx tmp4
+ lda #OPEN
+ sta ICCOM,x
+ jsr CIOV
+
+ ; clean up the stack
+
+ php
+ txa
+ pha
+ tya
+ pha
+
+.ifdef UCASE_FILENAME
+ ldy tmp3 ; get size
+ jsr addysp ; free used space on the stack
+.endif ; defined UCASE_FILENAME
+
+ jsr incsp4 ; clean up stack
+
+ pla
+ tay
+ pla
+ tax
+ plp
+
+ bpl ok
+ jmp __do_oserror
+
+ok: txa
+ lsr a
+ lsr a
+ lsr a
+ lsr a
+ ldx #0
+ stx __oserror
+ rts
+
+.endproc
+
+
+; find a free iocb
+; no entry parameters
+; return ZF = 0/1 for not found/found
+; index in X if found
+; all registers destroyed
+
+.proc findfreeiocb
+
+ ldx #0
+ ldy #$FF
+loop: tya
+ cmp ICHID,x
+ beq found
+ txa
+ clc
+ adc #$10
+ tax
+ cmp #$80
+ bcc loop
+ inx ; return ZF cleared
+found: rts
+
+.endproc
+
+
+; clear iocb except for ICHID field
+; expects X to be index to IOCB (0,$10,$20,etc.)
+; all registers destroyed
+
+.proc clriocb
+
+ inx ; don't clear ICHID
+ ldy #15
+ lda #0
+loop: sta ICHID,x
+ dey
+ inx
+ bne loop
+ rts
+
+.endproc
--- /dev/null
+;
+; Christian Groessler, May-2000
+;
+; os specific error code mapping
+; int __fastcall__ _osmaperrno (unsigned char oserror);
+;
+
+ .include "../common/errno.inc"
+ .export __osmaperrno
+
+.proc __osmaperrno
+
+ cmp #$80 ; error or success
+ bcs errcode ; error, jump
+
+ lda #0 ; no error, return 0
+ tax
+ rts
+
+errcode:and #$7f ; create index from error number
+ tax
+ cpx #MAX_OSERR_VAL ; valid number?
+ bcs inverr ; no
+
+ lda maptable,x
+ ldx #0
+ rts
+
+inverr: lda #<EUNKNOWN
+ ldx #>EUNKNOWN
+ rts
+
+.endproc
+
+.rodata
+
+maptable:
+ .byte EINTR ;BRKABT = 128 ;($80) BREAK key abort
+ .byte EBUSY ;PRVOPN = 129 ;($81) IOCB already open error
+ .byte ENODEV ;NONDEV = 130 ;($82) nonexistent device error
+ .byte EACCES ;WRONLY = 131 ;($83) IOCB opened for write only error
+ .byte ENOSYS ;NVALID = 132 ;($84) invalid command error
+ .byte EINVAL ;NOTOPN = 133 ;($85) device/file not open error
+ .byte EINVAL ;BADIOC = 134 ;($86) invalid IOCB index error
+ .byte EACCES ;RDONLY = 135 ;($87) IOCB opened for read only error
+ .byte EINVAL ;EOFERR = 136 ;($88) end of file error (should never come,
+ ; specially handled by read.s)
+ .byte EIO ;TRNRCD = 137 ;($89) truncated record error
+ .byte EIO ;TIMOUT = 138 ;($8A) peripheral device timeout error
+ .byte EIO ;DNACK = 139 ;($8B) device does not acknowledge command
+ .byte EIO ;FRMERR = 140 ;($8C) serial bus framing error
+ .byte EINVAL ;CRSROR = 141 ;($8D) cursor overrange error
+ .byte EIO ;OVRRUN = 142 ;($8E) serial bus data overrun error
+ .byte EIO ;CHKERR = 143 ;($8F) serial bus checksum error
+ .byte EIO ;DERROR = 144 ;($90) device done (operation incomplete)
+ .byte EINVAL ;BADMOD = 145 ;($91) bad screen mode number error
+ .byte ENOSYS ;FNCNOT = 146 ;($92) function not implemented in handler
+ .byte ENOMEM ;SCRMEM = 147 ;($93) insufficient memory for screen mode
+; codes below taken from "Mein Atari Computer" (german version of "Your Atari Computer")
+ .byte EUNKNOWN ; 148 - haven't found documentation
+ .byte EUNKNOWN ; 149 - haven't found documentation
+ .byte EBUSY ; 150 - serial port already open
+ .byte EACCES ; 151 - concurrent mode I/O not enabled (serial)
+ .byte EINVAL ; 152 - invalid buffer address for concurrent mode
+ .byte EAGAIN ; 153 - concurrent mode enabled (and another access tried)
+ .byte EACCES ; 154 - concurrent mode I/O not active (serial)
+ .byte EUNKNOWN ; 155 - haven't found documentation
+ .byte EUNKNOWN ; 156 - haven't found documentation
+ .byte EUNKNOWN ; 157 - haven't found documentation
+ .byte EUNKNOWN ; 158 - haven't found documentation
+ .byte EUNKNOWN ; 159 - haven't found documentation
+ .byte ENOENT ; 160 - drive number error (DOS)
+ .byte EMFILE ; 161 - too many open files
+ .byte ENOSPC ; 162 - disk full
+ .byte EIO ; 163 - unrecoverable system data I/O error
+ .byte ESPIPE ; 164 - file number mismatch (inv. seek or disk data strucs damaged)
+ .byte ENOENT ; 165 - invalid file name (e.g. lowercase)
+ .byte ESPIPE ; 166 - point data length error
+ .byte EACCES ; 167 - file locked (read-only)
+ .byte ENOSYS ; 168 - command invalid
+ .byte ENOSPC ; 169 - directory full
+ .byte ENOENT ; 170 - file not found
+ .byte ESPIPE ; 171 - point command invalid
+
+MAX_OSERR_VAL = (* - maptable)
--- /dev/null
+;
+; Christian Groessler, Apr-2000
+;
+; int read(int fd,void *buf,int count)
+;
+
+ .include "atari.inc"
+ .import __rwsetup,__do_oserror,__inviocb,__oserror
+ .export _read
+
+_read: jsr __rwsetup ; do common setup for read and write
+ beq done ; if size 0, it's a no-op
+ cpx #$FF ; invalid iocb?
+ beq _inviocb
+ lda #GETCHR ; iocb command code
+ sta ICCOM,x
+ jsr CIOV ; read it
+ bpl done
+ cpy #EOFERR ; eof is treated specially
+ beq done
+ jmp __do_oserror ; update errno
+
+done: lda ICBLL,x ; buf len lo
+ pha ; save
+ lda ICBLH,x ; get buf len hi
+ tax ; to X
+ lda #0
+ sta __oserror ; clear system dependend error code
+ pla ; get buf len lo
+ rts
+
+_inviocb:
+ jmp __inviocb
--- /dev/null
+;
+; Christian Groessler
+;
+; unsigned readjoy (unsigned char joy);
+;
+
+ .export _readjoy
+
+ .include "atari.inc"
+
+
+.proc _readjoy
+
+ and #3 ; fix joystick number
+ tax ; Joystick number (0-3) into X
+
+; Read joystick
+
+ lda STRIG0,x ; get button
+ asl a
+ asl a
+ asl a
+ asl a
+ ora STICK0,x ; add position information
+ eor #$1F
+ ldx #0 ; fix X
+ rts
+
+.endproc
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 07.08.1998
+;
+; unsigned char revers (unsigned char onoff);
+;
+ .include "atari.inc"
+
+ .export _revers
+
+_revers:
+ ldx #$00 ; Assume revers off
+ tay ; Test onoff
+ beq L1 ; Jump if off
+ ldx #$80 ; Load on value
+L1: ldy #$00 ; Assume old value is zero
+ lda INVFLG ; Load old value
+ stx INVFLG ; Set new value
+ beq L2 ; Jump if old value zero
+ iny ; Make old value = 1
+L2: ldx #$00 ; Load high byte of result
+ tya ; Load low byte, set CC
+ rts
+
--- /dev/null
+;
+; common iocb setup routine for read, write
+; expects parameters (int fd,void *buf,int count)
+;
+ .include "atari.inc"
+ .include "../common/errno.inc"
+ .importzp tmp2,tmp3
+ .import incsp6,ldaxysp
+ .import __errno,__oserror
+ .import fdtoiocb
+
+ .export __rwsetup
+
+__rwsetup:
+
+ ldy #5
+ jsr ldaxysp ; get fd
+ jsr fdtoiocb ; convert to iocb
+ bmi iocberr
+; asl a ; iocb # --> iocb index
+; asl a
+; asl a
+; asl a
+ sta tmp3 ; save it
+ ldy #1
+ jsr ldaxysp ; get size
+ php ; save cond codes, for zero-ness
+ stx tmp2
+ ldx tmp3 ; iocb
+ cpx #$80 ; iocb must be 0...7
+ bcs iocberr
+ sta ICBLL,x
+ lda tmp2 ; size hi
+ sta ICBLH,x
+ ldy #3 ; get buf addr (was 2 in orig. version)
+ jsr ldaxysp
+ stx tmp2
+ ldx tmp3
+ sta ICBAL,x
+ lda tmp2
+ sta ICBAH,x
+ jsr incsp6 ; pop args
+ plp
+ rts
+
+iocberr:jsr incsp6 ; pop args
+ plp ; throw away
+ ldx #$FF ; indicate error + clear ZF
+ rts
+
+
+;
+; this routine updates errno. do a JMP here right after calling
+; CIOV. we expect status in Y.
+;
+ .export __do_oserror,__seterrno,__inviocb
+__do_oserror:
+ sty __oserror ; save os dependent error code
+retminus:
+ lda #$FF
+ tax ; return -1
+ rts
+
+__seterrno:
+ sta __errno
+ stx __errno+1
+ rts
+
+;
+; sets EINVAL error code and returns -1
+;
+
+__inviocb:
+ lda #<EINVAL
+ ldx #>EINVAL
+ jsr __seterrno
+ jmp retminus ; return -1
--- /dev/null
+;
+; save and restore system vectors
+; originally by Mark Keates
+;
+; void save_vecs(void);
+; void rest_vecs(void);
+;
+
+ .export _save_vecs,_rest_vecs
+.include "atari.inc"
+
+ .bss
+
+old_dli: .res 2
+old_dlist: .res 2
+old_vbi: .res 2
+old_vbd: .res 2
+old_gra: .res 1
+old_dma: .res 1
+old_prior: .res 1
+old_cols: .res 8
+old_set: .res 1
+old_rmargin: .res 1 ; lmargin saved in startup code
+
+ .code
+
+.proc _save_vecs
+
+ lda VDSLST
+ sta old_dli
+ lda VDSLST+1
+ sta old_dli+1
+ lda SDLSTL
+ sta old_dlist
+ lda SDLSTL+1
+ sta old_dlist+1
+ lda VVBLKI
+ sta old_vbi
+ lda VVBLKI+1
+ sta old_vbi+1
+ lda VVBLKD
+ sta old_vbd
+ lda VVBLKD+1
+ sta old_vbd+1
+ lda GRACTL
+ sta old_gra
+ lda SDMCTL
+ sta old_dma
+ lda GPRIOR
+ sta old_prior
+ lda CHBAS
+ sta old_set
+ lda RMARGN
+ sta old_rmargin
+
+ ldy #7
+SETUP1:
+ lda PCOLR0,y
+ sta old_cols,y
+ dey
+ bpl SETUP1
+ rts
+
+.endproc
+
+.proc _rest_vecs
+
+ lda #6
+ ldx old_vbi+1
+ ldy old_vbi
+ jsr SETVBV
+ lda #7
+ ldx old_vbd+1
+ ldy old_vbd
+ jsr SETVBV
+ lda old_dli
+ sta VDSLST
+ lda old_dli+1
+ sta VDSLST+1
+ lda old_dlist
+ sta SDLSTL
+ lda old_dlist+1
+ sta SDLSTL+1
+ lda old_gra
+ sta GRACTL
+ lda old_prior
+ sta GPRIOR
+ lda old_dma
+ sta SDMCTL
+ lda old_set
+ sta CHBAS
+ lda old_rmargin
+ sta RMARGN
+ lda #$FF
+ sta CH
+ ldy #7
+SETUP2:
+ lda old_cols,Y
+ sta PCOLR0,Y
+ dey
+ bpl SETUP2
+ rts
+
+.endproc
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; unsigned char wherex (void);
+; unsigned char wherey (void);
+
+ .export _wherex, _wherey
+ .import plot
+
+ .include "atari.inc"
+
+_wherex:
+ sec
+ jsr plot ; Get cursor position
+ tya
+ rts
+
+_wherey:
+ sec
+ jsr plot ; Get cursor position
+ txa
+ rts
+
+
+
+
+
--- /dev/null
+;
+; write(iocb, buf, nbytes)->nbytes written
+;
+ .include "atari.inc"
+ .import __rwsetup,__do_oserror,__inviocb,__oserror
+ .export _write
+_write:
+ jsr __rwsetup ; do common setup
+ beq write9 ; if size 0, it's a no-op
+ cpx #$FF ; invalid iocb?
+ beq _inviocb
+ lda #PUTCHR
+ sta ICCOM,x
+ jsr CIOV
+ bpl write9
+ jmp __do_oserror ; update errno
+
+write9:
+ lda ICBLL,x ; get buf len lo
+ pha
+ lda ICBLH,x ; buf len hi
+ tax
+ lda #0
+ sta __oserror ; clear system dependend error code
+ pla
+ rts
+
+_inviocb:
+ jmp __inviocb
--- /dev/null
+#
+# makefile for CC65 runtime library
+#
+
+.SUFFIXES: .o .s .c
+
+%.o: %.c
+ @echo $<
+ @$(CC) $(CFLAGS) $<
+ @$(AS) -o $@ $(AFLAGS) $(*).s
+
+%.o: %.s
+ @echo $<
+ @$(AS) -g -o $@ $(AFLAGS) $<
+
+C_OBJS =
+
+S_OBJS = crt0.o conio.o kbhit.o clrscr.o cgetc.o readjoy.o\
+ color.o cputc.o break.o
+
+all: $(C_OBJS) $(S_OBJS)
+
+clean:
+ @rm -f $(C_OBJS:.c=.s)
+ @rm -f $(C_OBJS)
+ @rm -f $(S_OBJS)
+ @rm -f crt0.o
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 27.09.1998
+;
+; void set_brk (unsigned Addr);
+; void reset_brk (void);
+;
+
+ .export _set_brk, _reset_brk
+ .export _brk_a, _brk_x, _brk_y, _brk_sr, _brk_pc
+ .import _atexit
+ .importzp ptr1
+
+ .include "c128.inc"
+
+
+.bss
+_brk_a: .res 1
+_brk_x: .res 1
+_brk_y: .res 1
+_brk_sr: .res 1
+_brk_pc: .res 2
+
+oldvec: .res 2 ; Old vector
+
+
+.data
+uservec: jmp $FFFF ; Patched at runtime
+
+.code
+
+; Where will we put the break stub?
+stub_addr = $0E00 ; BASIC sprite area
+
+
+
+; Set the break vector
+.proc _set_brk
+
+ sta uservec+1
+ stx uservec+2 ; Set the user vector
+
+ lda oldvec
+ ora oldvec+1 ; Did we save the vector already?
+ bne L2 ; Jump if we installed the handler already
+
+ lda BRKVec
+ sta oldvec
+ lda BRKVec+1
+ sta oldvec+1 ; Save the old vector
+
+ ldy #stub_size-1 ; Copy our stub into the low mem area
+L1: lda brk_stub,y
+ sta stub_addr,y
+ dey
+ bpl L1
+
+ lda #<_reset_brk
+ ldx #>_reset_brk
+ jsr _atexit ; Install an exit handler
+
+L2: lda #<stub_addr ; Set the break vector to our stub
+ sta BRKVec
+ lda #>stub_addr
+ sta BRKVec+1
+ rts
+
+.endproc
+
+
+; Reset the break vector
+.proc _reset_brk
+
+ lda oldvec
+ sta BRKVec
+ lda oldvec+1
+ sta BRKVec+1
+ rts
+
+.endproc
+
+
+
+; Break handler, called if a break occurs
+
+.proc brk_handler
+
+ pla
+ sta _brk_y
+ pla
+ sta _brk_x
+ pla
+ sta _brk_a
+ pla
+ and #$EF ; Clear break bit
+ sta _brk_sr
+ pla ; PC low
+ sec
+ sbc #2 ; Point to start of brk
+ sta _brk_pc
+ pla ; PC high
+ sbc #0
+ sta _brk_pc+1
+
+ jsr uservec ; Call the user's routine
+
+ lda _brk_pc+1
+ pha
+ lda _brk_pc
+ pha
+ lda _brk_sr
+ pha
+ ldx _brk_x
+ ldy _brk_y
+ lda _brk_a
+ rti ; Jump back...
+
+.endproc
+
+
+brk_stub:
+ .org stub_addr
+ pla ; Get original MMU value
+ sta MMU_CR ; Re-enable our config
+ jmp brk_handler ; Jump to the user handler
+ .reloc
+
+stub_size = * - brk_stub
--- /dev/null
+;
+; C64 generic definitions. Stolen from Elite128
+;
+
+
+; ---------------------------------------------------------------------------
+; Zero page, Commodore stuff
+
+ST = $90 ; IEC status byte
+
+FNAM_LEN = $B7 ; Length of filename
+SECADR = $B9 ; Secondary address
+DEVNUM = $BA ; Device number
+FNAM_BANK = $C7 ; Bank for filename
+FNAM_LO = $BB ; Address of filename
+FNAM_HI = $BC
+KEY_COUNT = $D0 ; Number of keys in input buffer
+MODE = $D7 ; 40/80 column mode flag
+CURS_X = $EC ; Cursor column
+CURS_Y = $EB ; Cursor row
+SCREEN_PTR = $E0 ; Pointer to current char in text screen
+CRAM_PTR = $E2 ; Pointer to current char in color RAM
+
+CHARCOLOR = $F1
+FKEY_COUNT = $D1 ; Characters for function key
+FKEY_LEN = $1000 ; Function key lengths
+FKEY_TEXT = $100A ; Function key texts
+
+; ---------------------------------------------------------------------------
+; Kernal routines
+
+; Direct entries
+CURS_ON = $CD6F
+CURS_OFF = $CD9F
+CLRSCR = $C142
+KBDREAD = $C006
+
+; ---------------------------------------------------------------------------
+; Vectors
+
+IRQVec = $0314
+BRKVec = $0316
+NMIVec = $0318
+KeyStoreVec = $033C
+
+; ---------------------------------------------------------------------------
+; I/O: VIC
+
+VIC = $D000
+VIC_SPR0_X = $D000
+VIC_SPR0_Y = $D001
+VIC_SPR1_X = $D002
+VIC_SPR1_Y = $D003
+VIC_SPR2_X = $D004
+VIC_SPR2_Y = $D005
+VIC_SPR3_X = $D006
+VIC_SPR3_Y = $D007
+VIC_SPR4_X = $D008
+VIC_SPR4_Y = $D009
+VIC_SPR5_X = $D00A
+VIC_SPR5_Y = $D00B
+VIC_SPR6_X = $D00C
+VIC_SPR6_Y = $D00D
+VIC_SPR7_X = $D00E
+VIC_SPR7_Y = $D00F
+VIC_SPR_HI_X = $D010
+VIC_SPR_ENA = $D015
+VIC_SPR_EXP_X = $D017
+VIC_SPR_EXP_Y = $D01D
+VIC_SPR_MCOLOR = $D01C
+VIC_SPR_BG_PRIO = $D01B
+
+VIC_SPR_MCOLOR0 = $D025
+VIC_SPR_MCOLOR1 = $D026
+
+VIC_SPR0_COLOR = $D027
+VIC_SPR1_COLOR = $D028
+VIC_SPR2_COLOR = $D029
+VIC_SPR3_COLOR = $D02A
+VIC_SPR4_COLOR = $D02B
+VIC_SPR5_COLOR = $D02C
+VIC_SPR6_COLOR = $D02D
+VIC_SPR7_COLOR = $D02E
+
+VIC_CTRL1 = $D011
+VIC_CTRL2 = $D016
+
+VIC_HLINE = $D012
+
+VIC_VIDEO_ADR = $D018
+
+VIC_IRR = $D019 ; Interrupt request register
+VIC_IMR = $D01A ; Interrupt mask register
+
+VIC_BORDERCOLOR = $D020
+VIC_BG_COLOR0 = $D021
+VIC_BG_COLOR1 = $D022
+VIC_BG_COLOR2 = $D023
+VIC_BG_COLOR3 = $D024
+
+; 128 stuff:
+VIC_KBD_128 = $D02F ; Extended kbd bits (visible in 64 mode)
+VIC_CLK_128 = $D030 ; Clock rate register (visible in 64 mode)
+
+
+; ---------------------------------------------------------------------------
+; I/O: SID
+
+SID = $D400
+SID_S1Lo = $D400
+SID_S1Hi = $D401
+SID_PB1Lo = $D402
+SID_PB1Hi = $D403
+SID_Ctl1 = $D404
+SID_AD1 = $D405
+SID_SUR1 = $D406
+
+SID_S2Lo = $D407
+SID_S2Hi = $D408
+SID_PB2Lo = $D409
+SID_PB2Hi = $D40A
+SID_Ctl2 = $D40B
+SID_AD2 = $D40C
+SID_SUR2 = $D40D
+
+SID_S3Lo = $D40E
+SID_S3Hi = $D40F
+SID_PB3Lo = $D410
+SID_PB3Hi = $D411
+SID_Ctl3 = $D412
+SID_AD3 = $D413
+SID_SUR3 = $D414
+
+SID_FltLo = $D415
+SID_FltHi = $D416
+SID_FltCtl = $D417
+SID_Amp = $D418
+SID_ADConv1 = $D419
+SID_ADConv2 = $D41A
+SID_Noise = $D41B
+SID_Read3 = $D41C
+
+; ---------------------------------------------------------------------------
+; I/O: VDC (128 only)
+
+VDC_INDEX = $D600
+VDC_DATA = $D601
+
+; ---------------------------------------------------------------------------
+; I/O: CIAs
+
+CIA1 = $DC00
+CIA1_PRA = $DC00
+CIA1_PRB = $DC01
+CIA1_DDRA = $DC02
+CIA1_DDRB = $DC03
+CIA1_ICR = $DC0D
+CIA1_CRA = $DC0E
+CIA1_CRB = $DC0F
+
+CIA2 = $DD00
+CIA2_PRA = $DD00
+CIA2_PRB = $DD01
+CIA2_DDRA = $DD02
+CIA2_DDRB = $DD03
+CIA2_ICR = $DD0D
+CIA2_CRA = $DD0E
+CIA2_CRB = $DD0F
+
+; ---------------------------------------------------------------------------
+; I/O: MMU
+
+MMU_CR = $FF00
+
+; ---------------------------------------------------------------------------
+; Super CPU
+
+SCPU_VIC_Bank1 = $D075
+SCPU_Slow = $D07A
+SCPU_Fast = $D07B
+SCPU_EnableRegs = $D07E
+SCPU_DisableRegs= $D07F
+SCPU_Detect = $D0BC
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; char cgetc (void);
+;
+
+ .export _cgetc
+ .import cursor
+
+ .include "c128.inc"
+
+_cgetc: lda KEY_COUNT ; Get number of characters
+ bne L2 ; Jump if there are already chars waiting
+
+; Switch on the cursor if needed
+
+ lda cursor
+ beq L1
+ jsr CURS_ON
+ jmp L2
+L1: lda #$01
+ jsr CURS_OFF
+L2: lda KEY_COUNT ; Check characters again
+ beq L2
+ jsr CURS_OFF ; Switch cursor off, if characters available
+
+ jsr KBDREAD ; Read char and return in A
+ ldx #0
+ rts
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; void clrscr (void);
+;
+
+ .export _clrscr
+
+ .include "c128.inc"
+
+_clrscr = CLRSCR
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; unsigned char __fastcall__ textcolor (unsigned char color);
+; unsigned char __fastcall__ bgcolor (unsigned char color);
+; unsigned char __fastcall__ bordercolor (unsigned char color);
+;
+
+ .export _textcolor, _bgcolor, _bordercolor
+
+ .include "c128.inc"
+
+
+_textcolor:
+ ldx CHARCOLOR ; get old value
+ sta CHARCOLOR ; set new value
+ txa
+ rts
+
+
+_bgcolor:
+ ldx VIC_BG_COLOR0 ; get old value
+ sta VIC_BG_COLOR0 ; set new value
+ txa
+ rts
+
+
+_bordercolor:
+ ldx VIC_BG_COLOR0 ; get old value
+ sta VIC_BORDERCOLOR ; set new value
+ txa
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; Low level stuff for screen output/console input
+;
+
+ .export initconio, doneconio
+ .exportzp CURS_X, CURS_Y
+ .import xsize, ysize
+
+ .include "c128.inc"
+ .include "../cbm/cbm.inc"
+
+.bss
+keyvec: .res 2
+
+
+.code
+
+initconio:
+ jsr SCREEN
+ inx
+ stx xsize
+ iny
+ sty ysize
+
+; Save the old vector
+
+ lda KeyStoreVec
+ sta keyvec
+ lda KeyStoreVec+1
+ sta keyvec+1
+
+; Set the new vector. I can only hope that this works for other C128
+; versions...
+
+ lda #<$C6B7
+ ldx #>$C6B7
+
+SetVec: sei
+ sta KeyStoreVec
+ stx KeyStoreVec+1
+ cli
+ rts
+
+doneconio:
+ lda keyvec
+ ldx keyvec+1
+ bne SetVec
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; void cputcxy (unsigned char x, unsigned char y, char c);
+; void cputc (char c);
+;
+
+ .export _cputcxy, _cputc, cputdirect, putchar
+ .export advance, newline, plot
+ .import popa, _gotoxy
+ .import xsize, revers
+
+ .include "c128.inc"
+ .include "../cbm/cbm.inc"
+
+_cputcxy:
+ pha ; Save C
+ jsr popa ; Get Y
+ jsr _gotoxy ; Set cursor, drop x
+ pla ; Restore C
+
+; Plot a character - also used as internal function
+
+_cputc: cmp #$0D ; CR?
+ bne L1
+ lda #0
+ sta CURS_X
+ beq plot ; Recalculate pointers
+
+L1: cmp #$0A ; LF?
+ bne L2
+ ldy CURS_Y
+ iny
+ bne newline ; Recalculate pointers
+
+; Printable char of some sort
+
+L2: cmp #' '
+ bcc cputdirect ; Other control char
+ tay
+ bmi L10
+ cmp #$60
+ bcc L3
+ and #$DF
+ bne cputdirect ; Branch always
+L3: and #$3F
+
+cputdirect:
+ jsr putchar ; Write the character to the screen
+
+; Advance cursor position
+
+advance:
+ iny
+ cpy xsize
+ bne L9
+ ldy #0 ; new line
+newline:
+ clc
+ lda xsize
+ adc SCREEN_PTR
+ sta SCREEN_PTR
+ bcc L4
+ inc SCREEN_PTR+1
+L4: clc
+ lda xsize
+ adc CRAM_PTR
+ sta CRAM_PTR
+ bcc L5
+ inc CRAM_PTR+1
+L5: inc CURS_Y
+L9: sty CURS_X
+ rts
+
+; Handle character if high bit set
+
+L10: and #$7F
+ cmp #$7E ; PI?
+ bne L11
+ lda #$5E ; Load screen code for PI
+ bne cputdirect
+L11: ora #$40
+ bne cputdirect
+
+
+
+; Set cursor position, calculate RAM pointers
+
+plot: ldy CURS_X
+ ldx CURS_Y
+ clc
+ jmp PLOT ; Set the new cursor
+
+
+
+; Write one character to the screen without doing anything else, return X
+; position in Y
+
+putchar:
+ ora revers ; Set revers bit
+ ldy CURS_X
+ sta (SCREEN_PTR),y ; Set char
+ lda CHARCOLOR
+ sta (CRAM_PTR),y ; Set color
+ rts
--- /dev/null
+;
+; Startup code for cc65 (C128 version)
+;
+; This must be the *first* file on the linker command line
+;
+
+ .export _exit
+ .import __hinit, initconio, doneconio, zerobss
+ .import push0, doatexit, _main
+
+ .include "c128.inc"
+ .include "../cbm/cbm.inc"
+
+; ------------------------------------------------------------------------
+; Define and export the ZP variables for the C64 runtime
+
+ .exportzp sp, sreg, regsave
+ .exportzp ptr1, ptr2, ptr3, ptr4
+ .exportzp tmp1, tmp2, tmp3, tmp4
+ .exportzp regbank, zpspace
+
+sp = $02 ; stack pointer
+sreg = $04 ; secondary register/high 16 bit for longs
+regsave = $06 ; slot to save/restore (E)AX into
+ptr1 = $0A ;
+ptr2 = $0C
+ptr3 = $0E
+ptr4 = $10
+tmp1 = $12
+tmp2 = $13
+tmp3 = $14
+tmp4 = $15
+regbank = $16 ; 6 byte register bank
+zpspace = $1A ; Zero page space allocated
+
+; ------------------------------------------------------------------------
+; BASIC header with a SYS call
+
+ .org $1BFF
+ .word Head ; Load address
+Head: .word @Next
+ .word 1000 ; Line number
+ .byte $9E,"7181" ; SYS 7181
+ .byte $00 ; End of BASIC line
+@Next: .word 0 ; BASIC end marker
+ .reloc
+
+; ------------------------------------------------------------------------
+; Actual code
+
+ ldy #zpspace-1
+L1: lda sp,y
+ sta zpsave,y ; save the zero page locations we need
+ dey
+ bpl L1
+
+; Close open files
+
+ jsr CLRCH
+
+; Switch to second charset
+
+ lda #14
+ jsr BSOUT
+
+; Get the current MMU setting and save it. Set new memory config.
+
+ lda MMU_CR ; Get current memory configuration...
+ pha ; ...and save it for later
+ lda #$0E ; Bank0 with kernal ROM
+ sta MMU_CR
+
+; Clear the BSS data
+
+ jsr zerobss
+
+; Save system stuff and setup the stack
+
+ pla ; Get MMU setting
+ sta mmusave
+
+ tsx
+ stx spsave ; save system stk ptr
+
+ lda #<$C000
+ sta sp
+ lda #>$C000
+ sta sp+1
+
+; Initialize the heap
+
+ jsr __hinit
+
+; Initialize conio stuff
+
+ jsr initconio
+
+; Pass an empty command line
+
+ jsr push0 ; argc
+ jsr push0 ; argv
+
+ ldy #4 ; Argument size
+ jsr _main ; call the users code
+
+; fall thru to exit...
+
+_exit: jsr doatexit ; call exit functions
+
+; Reset the conio stuff
+
+ jsr doneconio
+
+; Reset stack and the MMU
+
+ ldx spsave ; Patched at runtime
+ txs
+ lda mmusave ; Patched at runtime
+ sta MMU_CR
+
+; Copy back the zero page stuff
+
+ ldy #zpspace-1
+L2: lda zpsave,y
+ sta sp,y
+ dey
+ bpl L2
+
+; Done
+
+ jmp RESTOR
+
+.data
+zpsave: .res zpspace
+
+.bss
+spsave: .res 1
+mmusave:.res 1
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 10.08.1998
+;
+; unsigned DbgSetBreakVec (unsigned Addr);
+;
+
+ .export _DbgSetBreakVec
+ .import popax, utstax
+
+ .include "../cbm/cbm.inc"
+
+_DbgSetBreakVec:
+ jsr popax ; Get the new address
+ ldy BRKVec
+ sta BRKVec
+ lda BRKVec+1
+ stx BRKVec+1
+ tax
+ tya
+ jmp utstax
+
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 18.08.1998
+;
+; int kbhit (void);
+;
+
+ .export _kbhit
+ .import return0, return1
+
+ .include "c128.inc"
+
+_kbhit:
+ lda KEY_COUNT ; Get number of characters
+; ora FKEY_COUNT ; Or with number of chars from function keys
+ bne L1
+ jmp return0
+L1: jmp return1
+
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 23.09.1998
+;
+; unsigned readjoy (unsigned char joy);
+;
+
+ .export _readjoy
+
+ .include "c128.inc"
+
+
+.proc _readjoy
+
+ tax ; Joystick number into X
+ bne joy2
+
+; Read joystick 1
+
+joy1: lda #$7F
+ sei
+ sta CIA1_PRA
+ lda CIA1_PRB
+ cli
+ and #$1F
+ eor #$1F
+ rts
+
+; Read joystick 2
+
+joy2: ldx #0
+ lda #$E0
+ ldy #$FF
+ sta CIA1_DDRA
+ lda CIA1_PRA
+ sty CIA1_DDRA
+ and #$1F
+ eor #$1F
+ rts
+
+.endproc
+
--- /dev/null
+#
+# makefile for CC65 runtime library
+#
+
+.SUFFIXES: .o .s .c
+
+%.o: %.c
+ @echo $<
+ @$(CC) $(CFLAGS) $<
+ @$(AS) -o $@ $(AFLAGS) $(*).s
+
+%.o: %.s
+ @echo $<
+ @$(AS) -g -o $@ $(AFLAGS) $<
+
+C_OBJS =
+
+S_OBJS = crt0.o read.o write.o kbhit.o conio.o clrscr.o mouse.o\
+ cputc.o cgetc.o color.o readjoy.o break.o rs232.o
+
+all: $(C_OBJS) $(S_OBJS)
+
+clean:
+ @rm -f $(C_OBJS:.c=.s)
+ @rm -f $(C_OBJS)
+ @rm -f $(S_OBJS)
+ @rm -f crt0.o
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 27.09.1998
+;
+; void set_brk (unsigned Addr);
+; void reset_brk (void);
+;
+
+ .export _set_brk, _reset_brk
+ .export _brk_a, _brk_x, _brk_y, _brk_sr, _brk_pc
+ .import _atexit
+
+ .include "c64.inc"
+
+
+.bss
+_brk_a: .res 1
+_brk_x: .res 1
+_brk_y: .res 1
+_brk_sr: .res 1
+_brk_pc: .res 2
+
+oldvec: .res 2 ; Old vector
+
+
+.data
+uservec: jmp $FFFF ; Patched at runtime
+
+
+.code
+
+; Set the break vector
+.proc _set_brk
+
+ sta uservec+1
+ stx uservec+2 ; Set the user vector
+
+ lda oldvec
+ ora oldvec+1 ; Did we save the vector already?
+ bne L1 ; Jump if we installed the handler already
+
+ lda BRKVec
+ sta oldvec
+ lda BRKVec+1
+ sta oldvec+1 ; Save the old vector
+
+ lda #<_reset_brk
+ ldx #>_reset_brk
+ jsr _atexit ; Install an exit handler
+
+L1: lda #<brk_handler ; Set the break vector to our routine
+ sta BRKVec
+ lda #>brk_handler
+ sta BRKVec+1
+ rts
+
+.endproc
+
+
+; Reset the break vector
+.proc _reset_brk
+
+ lda oldvec
+ sta BRKVec
+ lda oldvec+1
+ sta BRKVec+1
+ rts
+
+.endproc
+
+
+
+; Break handler, called if a break occurs
+
+.proc brk_handler
+
+ pla
+ sta _brk_y
+ pla
+ sta _brk_x
+ pla
+ sta _brk_a
+ pla
+ and #$EF ; Clear break bit
+ sta _brk_sr
+ pla ; PC low
+ sec
+ sbc #2 ; Point to start of brk
+ sta _brk_pc
+ pla ; PC high
+ sbc #0
+ sta _brk_pc+1
+
+ jsr uservec ; Call the user's routine
+
+ lda _brk_pc+1
+ pha
+ lda _brk_pc
+ pha
+ lda _brk_sr
+ pha
+ ldx _brk_x
+ ldy _brk_y
+ lda _brk_a
+ rti ; Jump back...
+
+.endproc
+
+
--- /dev/null
+;
+; C64 generic definitions. Stolen from Elite128
+;
+
+
+; ---------------------------------------------------------------------------
+; Zero page, Commodore stuff
+
+ST = $90 ; IEC status byte
+
+FNAM_LEN = $B7 ; Length of filename
+SECADR = $B9 ; Secondary address
+DEVNUM = $BA ; Device number
+KEY_COUNT = $C6 ; Number of keys in input buffer
+CURS_FLAG = $CC ; 1 = cursor off
+CURS_BLINK = $CD ; Blink counter
+CURS_CHAR = $CE ; Character under the cursor
+CURS_COLOR = $287 ; Color under the cursor
+CURS_STATE = $CF ; Cursor blink state
+SCREEN_PTR = $D1 ; Pointer to current char in text screen
+CURS_X = $D3 ; Cursor column
+CURS_Y = $D6 ; Cursor row
+CRAM_PTR = $F3 ; Pointer to current char in color RAM
+
+CHARCOLOR = $286
+PALFLAG = $2A6 ; $01 = PAL, $00 = NTSC
+
+
+; ---------------------------------------------------------------------------
+; Kernal routines
+
+; Direct entries
+CLRSCR = $E544
+KBDREAD = $E5B4
+NAMED_OPEN = $F3D5
+NAMED_CLOSE = $F642
+PLOTCHAR = $EA1C ; Char in A, color in X
+
+; ---------------------------------------------------------------------------
+; Vector and other locations
+
+IRQVec = $0314
+BRKVec = $0316
+NMIVec = $0318
+
+; ---------------------------------------------------------------------------
+; I/O: VIC
+
+VIC = $D000
+VIC_SPR0_X = $D000
+VIC_SPR0_Y = $D001
+VIC_SPR1_X = $D002
+VIC_SPR1_Y = $D003
+VIC_SPR2_X = $D004
+VIC_SPR2_Y = $D005
+VIC_SPR3_X = $D006
+VIC_SPR3_Y = $D007
+VIC_SPR4_X = $D008
+VIC_SPR4_Y = $D009
+VIC_SPR5_X = $D00A
+VIC_SPR5_Y = $D00B
+VIC_SPR6_X = $D00C
+VIC_SPR6_Y = $D00D
+VIC_SPR7_X = $D00E
+VIC_SPR7_Y = $D00F
+VIC_SPR_HI_X = $D010
+VIC_SPR_ENA = $D015
+VIC_SPR_EXP_X = $D017
+VIC_SPR_EXP_Y = $D01D
+VIC_SPR_MCOLOR = $D01C
+VIC_SPR_BG_PRIO = $D01B
+
+VIC_SPR_MCOLOR0 = $D025
+VIC_SPR_MCOLOR1 = $D026
+
+VIC_SPR0_COLOR = $D027
+VIC_SPR1_COLOR = $D028
+VIC_SPR2_COLOR = $D029
+VIC_SPR3_COLOR = $D02A
+VIC_SPR4_COLOR = $D02B
+VIC_SPR5_COLOR = $D02C
+VIC_SPR6_COLOR = $D02D
+VIC_SPR7_COLOR = $D02E
+
+VIC_CTRL1 = $D011
+VIC_CTRL2 = $D016
+
+VIC_HLINE = $D012
+
+VIC_VIDEO_ADR = $D018
+
+VIC_IRR = $D019 ; Interrupt request register
+VIC_IMR = $D01A ; Interrupt mask register
+
+VIC_BORDERCOLOR = $D020
+VIC_BG_COLOR0 = $D021
+VIC_BG_COLOR1 = $D022
+VIC_BG_COLOR2 = $D023
+VIC_BG_COLOR3 = $D024
+
+; 128 stuff:
+VIC_KBD_128 = $D02F ; Extended kbd bits (visible in 64 mode)
+VIC_CLK_128 = $D030 ; Clock rate register (visible in 64 mode)
+
+
+; ---------------------------------------------------------------------------
+; I/O: SID
+
+SID = $D400
+SID_S1Lo = $D400
+SID_S1Hi = $D401
+SID_PB1Lo = $D402
+SID_PB1Hi = $D403
+SID_Ctl1 = $D404
+SID_AD1 = $D405
+SID_SUR1 = $D406
+
+SID_S2Lo = $D407
+SID_S2Hi = $D408
+SID_PB2Lo = $D409
+SID_PB2Hi = $D40A
+SID_Ctl2 = $D40B
+SID_AD2 = $D40C
+SID_SUR2 = $D40D
+
+SID_S3Lo = $D40E
+SID_S3Hi = $D40F
+SID_PB3Lo = $D410
+SID_PB3Hi = $D411
+SID_Ctl3 = $D412
+SID_AD3 = $D413
+SID_SUR3 = $D414
+
+SID_FltLo = $D415
+SID_FltHi = $D416
+SID_FltCtl = $D417
+SID_Amp = $D418
+SID_ADConv1 = $D419
+SID_ADConv2 = $D41A
+SID_Noise = $D41B
+SID_Read3 = $D41C
+
+; ---------------------------------------------------------------------------
+; I/O: VDC (128 only)
+
+VDC_INDEX = $D600
+VDC_DATA = $D601
+
+; ---------------------------------------------------------------------------
+; I/O: CIAs
+
+CIA1 = $DC00
+CIA1_PRA = $DC00
+CIA1_PRB = $DC01
+CIA1_DDRA = $DC02
+CIA1_DDRB = $DC03
+CIA1_ICR = $DC0D
+CIA1_CRA = $DC0E
+CIA1_CRB = $DC0F
+
+CIA2 = $DD00
+CIA2_PRA = $DD00
+CIA2_PRB = $DD01
+CIA2_DDRA = $DD02
+CIA2_DDRB = $DD03
+CIA2_ICR = $DD0D
+CIA2_CRA = $DD0E
+CIA2_CRB = $DD0F
+
+; ---------------------------------------------------------------------------
+; Super CPU
+
+SCPU_VIC_Bank1 = $D075
+SCPU_Slow = $D07A
+SCPU_Fast = $D07B
+SCPU_EnableRegs = $D07E
+SCPU_DisableRegs= $D07F
+SCPU_Detect = $D0BC
+
+
+; ---------------------------------------------------------------------------
+; Processor Port at $01
+
+LORAM = $01 ; Enable the basic rom
+HIRAM = $02 ; Enable the kernal rom
+IOEN = $04 ; Enable I/O
+CASSDATA = $08 ; Cassette data
+CASSPLAY = $10 ; Cassette: Play
+CASSMOT = $20 ; Cassette motor on
+TP_FAST = $80 ; Switch Rossmoeller TurboProcess to fast mode
+
+RAMONLY = $F8 ; (~(LORAM | HIRAM | IOEN)) & $FF
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; char cgetc (void);
+;
+
+ .export _cgetc
+ .import cursor
+
+ .include "c64.inc"
+
+_cgetc: lda KEY_COUNT ; Get number of characters
+ bne L3 ; Jump if there are already chars waiting
+
+; Switch on the cursor if needed
+
+ lda CURS_FLAG
+ pha
+ lda cursor
+ jsr setcursor
+L1: lda KEY_COUNT
+ beq L1
+ ldx #0
+ pla
+ bne L2
+ inx
+L2: txa
+ jsr setcursor
+
+L3: jsr KBDREAD ; Read char and return in A
+ ldx #0
+ rts
+
+
+; Switch the cursor on or off
+
+.proc setcursor
+
+ tax ; On or off?
+ bne seton ; Go set it on
+ lda CURS_FLAG ; Is the cursor currently off?
+ bne crs9 ; Jump if yes
+ lda #1
+ sta CURS_FLAG ; Mark it as off
+ lda CURS_STATE ; Cursor currently displayed?
+ beq crs8 ; Jump if no
+ ldy CURS_X ; Get the character column
+ lda (SCREEN_PTR),y ; Get character
+ eor #$80
+ sta (SCREEN_PTR),y ; Store character back
+ lda CURS_COLOR
+ sta (CRAM_PTR),y ; Store color back
+crs8: lda #0
+ sta CURS_STATE ; Cursor not displayed
+crs9: rts
+
+seton: lda #0
+ sta CURS_FLAG
+ rts
+
+.endproc
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; void clrscr (void);
+;
+
+ .export _clrscr
+
+ .include "c64.inc"
+
+_clrscr = CLRSCR
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; unsigned char __fastcall__ textcolor (unsigned char color);
+; unsigned char __fastcall__ bgcolor (unsigned char color);
+; unsigned char __fastcall__ bordercolor (unsigned char color);
+;
+
+
+ .export _textcolor, _bgcolor, _bordercolor
+
+ .include "c64.inc"
+
+_textcolor:
+ ldx CHARCOLOR ; get old value
+ sta CHARCOLOR ; set new value
+ txa
+ rts
+
+
+_bgcolor:
+ ldx VIC_BG_COLOR0 ; get old value
+ sta VIC_BG_COLOR0 ; set new value
+ txa
+ rts
+
+
+_bordercolor:
+ ldx VIC_BG_COLOR0 ; get old value
+ sta VIC_BORDERCOLOR ; set new value
+ txa
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; Low level stuff for screen output/console input
+;
+
+ .export initconio
+ .exportzp CURS_X, CURS_Y
+ .import xsize, ysize
+
+ .include "../cbm/cbm.inc"
+ .include "c64.inc"
+
+.code
+
+initconio:
+ jsr SCREEN
+ stx xsize
+ sty ysize
+ rts
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; void cputcxy (unsigned char x, unsigned char y, char c);
+; void cputc (char c);
+;
+
+ .export _cputcxy, _cputc, cputdirect, putchar
+ .export advance, newline, plot
+ .import popa, _gotoxy
+ .import xsize, revers
+
+ .include "c64.inc"
+ .include "../cbm/cbm.inc"
+
+_cputcxy:
+ pha ; Save C
+ jsr popa ; Get Y
+ jsr _gotoxy ; Set cursor, drop x
+ pla ; Restore C
+
+; Plot a character - also used as internal function
+
+_cputc: cmp #$0D ; CR?
+ bne L1
+ lda #0
+ sta CURS_X
+ beq plot ; Recalculate pointers
+
+L1: cmp #$0A ; LF?
+ bne L2
+ ldy CURS_Y
+ iny
+ bne newline ; Recalculate pointers
+
+; Printable char of some sort
+
+L2: cmp #' '
+ bcc cputdirect ; Other control char
+ tay
+ bmi L10
+ cmp #$60
+ bcc L3
+ and #$DF
+ bne cputdirect ; Branch always
+L3: and #$3F
+
+cputdirect:
+ jsr putchar ; Write the character to the screen
+
+; Advance cursor position
+
+advance:
+ iny
+ cpy xsize
+ bne L9
+ ldy #0 ; new line
+newline:
+ clc
+ lda xsize
+ adc SCREEN_PTR
+ sta SCREEN_PTR
+ bcc L4
+ inc SCREEN_PTR+1
+L4: clc
+ lda xsize
+ adc CRAM_PTR
+ sta CRAM_PTR
+ bcc L5
+ inc CRAM_PTR+1
+L5: inc CURS_Y
+L9: sty CURS_X
+ rts
+
+; Handle character if high bit set
+
+L10: and #$7F
+ cmp #$7E ; PI?
+ bne L11
+ lda #$5E ; Load screen code for PI
+ bne cputdirect
+L11: ora #$40
+ bne cputdirect
+
+
+
+; Set cursor position, calculate RAM pointers
+
+plot: ldy CURS_X
+ ldx CURS_Y
+ clc
+ jmp PLOT ; Set the new cursor
+
+
+
+; Write one character to the screen without doing anything else, return X
+; position in Y
+
+putchar:
+ ora revers ; Set revers bit
+ ldy CURS_X
+ sta (SCREEN_PTR),y ; Set char
+ lda CHARCOLOR
+ sta (CRAM_PTR),y ; Set color
+ rts
--- /dev/null
+;
+; Startup code for cc65 (C64 version)
+;
+; This must be the *first* file on the linker command line
+;
+
+ .export _exit
+ .import __hinit, initconio, zerobss, push0, doatexit
+ .import _main
+
+ .include "c64.inc"
+ .include "../cbm/cbm.inc"
+
+; ------------------------------------------------------------------------
+; Define and export the ZP variables for the C64 runtime
+
+ .exportzp sp, sreg, regsave
+ .exportzp ptr1, ptr2, ptr3, ptr4
+ .exportzp tmp1, tmp2, tmp3, tmp4
+ .exportzp regbank, zpspace
+
+sp = $02 ; stack pointer
+sreg = $04 ; secondary register/high 16 bit for longs
+regsave = $06 ; slot to save/restore (E)AX into
+ptr1 = $0A ;
+ptr2 = $0C
+ptr3 = $0E
+ptr4 = $10
+tmp1 = $12
+tmp2 = $13
+tmp3 = $14
+tmp4 = $15
+regbank = $16 ; 6 byte register bank
+zpspace = $1A ; Zero page space allocated
+
+; ------------------------------------------------------------------------
+; BASIC header with a SYS call
+
+ .org $7FF
+ .word Head ; Load address
+Head: .word @Next
+ .word 1000 ; Line number
+ .byte $9E,"2061" ; SYS 2061
+ .byte $00 ; End of BASIC line
+@Next: .word 0 ; BASIC end marker
+ .reloc
+
+; ------------------------------------------------------------------------
+; Actual code
+
+ ldy #zpspace-1
+L1: lda sp,y
+ sta zpsave,y ; Save the zero page locations we need
+ dey
+ bpl L1
+
+; Close open files
+
+ jsr CLRCH
+
+; Switch to second charset
+
+ lda #14
+ jsr BSOUT
+
+; Clear the BSS data
+
+ jsr zerobss
+
+; Save system stuff and setup the stack
+
+ tsx
+ stx spsave ; Save the system stack ptr
+
+ lda $01
+ sta mmusave ; Save the memory configuration
+ lda $01
+ and #$F8
+ ora #$06 ; Enable kernal+I/O, disable basic
+ sta $01
+
+ lda #<$D000
+ sta sp
+ lda #>$D000
+ sta sp+1 ; Set argument stack ptr
+
+; Initialize the heap
+
+ jsr __hinit
+
+; Initialize conio stuff
+
+ jsr initconio
+
+; Pass an empty command line
+
+ jsr push0 ; argc
+ jsr push0 ; argv
+
+ ldy #4 ; Argument size
+ jsr _main ; call the users code
+
+; fall thru to exit...
+
+_exit: jsr doatexit ; call exit functions
+
+ ldx spsave
+ txs ; Restore stack pointer
+ lda mmusave
+ sta $01 ; Restore memory configuration
+
+; Copy back the zero page stuff
+
+ ldy #zpspace-1
+L2: lda zpsave,y
+ sta sp,y
+ dey
+ bpl L2
+
+; Reset changed vectors, back to basic
+
+ jmp RESTOR
+
+
+.data
+
+zpsave: .res zpspace
+
+.bss
+
+spsave: .res 1
+mmusave:.res 1
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; int kbhit (void);
+;
+
+ .export _kbhit
+ .import return0, return1
+
+ .include "c64.inc"
+
+_kbhit:
+ lda KEY_COUNT ; Get number of characters
+ bne L1
+ jmp return0
+L1: jmp return1
+
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 24.04.1999
+;
+; Routines for the 1351 proportional mouse. Parts of the code are from
+; the Commodore 1351 mouse users guide.
+;
+
+ .export _mouse_init, _mouse_done
+ .export _mouse_hide, _mouse_show
+ .export _mouse_box, _mouse_info
+ .export _mouse_move
+
+ .import popa, popsreg, addysp1
+ .importzp sp, sreg
+
+ .include "c64.inc"
+
+.code
+
+; --------------------------------------------------------------------------
+;
+; void __fastcall__ mouse_init (unsigned char port, unsigned char sprite);
+;
+
+_mouse_init:
+ tax ; Save sprite number
+ jsr popa ; Get the port number
+
+ ldy OldIRQ+1 ; Already initialized?
+ bne Done ; Jump if yes
+
+ stx MouseSprite ; Remember the sprite number
+ sta MousePort ; Remember the port number
+
+; Initialize variables
+
+ ldx #0
+ stx XPos
+ stx XPos+1
+ stx YPos
+ stx YPos+1
+ stx OldPotX
+ stx OldPotY
+ stx XMin
+ stx XMin+1
+ stx YMin
+ stx YMin+1
+ stx YMax+1
+ inx ; X = 1
+ stx Visible ; Mouse *not* visible
+ stx XMax+1 ; >320
+ ldx #<320
+ stx XMax
+ ldx #200
+ stx YMax
+
+; Remember the old IRQ vector
+
+ lda IRQVec
+ sta OldIRQ
+ lda IRQVec+1
+ sta OldIRQ+1
+
+; Set our own IRQ vector
+
+ lda #<MouseIRQ
+ ldx #>MouseIRQ
+ bne SetIRQ
+
+; --------------------------------------------------------------------------
+;
+; void mouse_done (void);
+;
+
+_mouse_done:
+ lda OldIRQ ; Initialized?
+ ldx OldIRQ+1
+ beq Done ; Jump if no
+ ldy #0
+ sty OldIRQ+1 ; Reset the initialized flag
+SetIRQ: sei ; Disable interrupts
+ sta IRQVec ; Set the new/old vector
+ stx IRQVec+1
+ cli ; Enable interrupts
+Done: rts
+
+; --------------------------------------------------------------------------
+;
+; void mouse_hide (void);
+;
+
+_mouse_hide:
+ lda Visible ; Get the flag
+ bne @L1 ; Jump if already invisible
+ ldx MouseSprite ; Sprite defined?
+ beq @L1 ; Jump if no
+
+ lda BitMask-1,x ; Get bit mask
+ eor #$FF ; We must clear the bit
+
+ sei ; Disable interrupts
+ and VIC_SPR_ENA
+ sta VIC_SPR_ENA ; Disable sprite
+ cli ; Enable interrupts
+
+@L1: inc Visible ; Set the flag to invisible
+ rts
+
+; --------------------------------------------------------------------------
+;
+; void mouse_show (void);
+;
+
+_mouse_show:
+ dec Visible ; Get the flag
+ bne @L1 ; Jump if still invisible
+ ldx MouseSprite ; Sprite defined?
+ beq @L1 ; Jump if no
+
+ lda BitMask-1,x ; Get bit mask
+ sei ; Disable interrupts
+ ora VIC_SPR_ENA
+ sta VIC_SPR_ENA ; Enable sprite
+ cli ; Enable interrupts
+
+@L1: rts
+
+; --------------------------------------------------------------------------
+;
+; void __fastcall__ mouse_box (int minx, int miny, int maxx, int maxy);
+;
+
+_mouse_box:
+ sei ; Disable interrupts
+
+ sta YMax
+ stx YMax+1 ; maxy
+
+ ldy #0
+ lda (sp),y
+ sta XMax
+ iny
+ lda (sp),y
+ sta XMax+1 ; maxx
+
+ iny
+ lda (sp),y
+ sta YMin
+ iny
+ lda (sp),y
+ sta YMin+1 ; miny
+
+ iny
+ lda (sp),y
+ sta XMin
+ iny
+ lda (sp),y
+ sta XMin+1 ; minx
+
+ cli ; Enable interrupts
+
+ jmp addysp1 ; Drop params, return
+
+; --------------------------------------------------------------------------
+;
+; void mouse_info (...);
+;
+
+_mouse_info:
+ rts
+
+
+; --------------------------------------------------------------------------
+;
+; void __fastcall__ mouse_move (int x, int y);
+;
+
+_mouse_move:
+ jsr popsreg ; Get X
+ sei ; Disable interrupts
+
+ sta YPos
+ stx YPos+1
+ lda sreg
+ ldx sreg+1
+ sta XPos
+ stx XPos+1 ; Set new position
+
+ lda Visible ; Mouse visible?
+ bne @L9 ; Jump if no
+ lda MouseSprite ; Sprite defined?
+ beq @L9
+
+ jsr MoveSprite ; Move the sprite to the mouse pos
+
+@L9: cli ; Enable interrupts
+ rts
+
+; --------------------------------------------------------------------------
+;
+; Mouse interrupt handler
+;
+
+MouseIRQ:
+ cld
+ lda SID_ADConv1 ; Get mouse X movement
+ ldy OldPotX
+ jsr MoveCheck ; Calculate movement vector
+ sty OldPotX
+
+; Calculate the new X coordinate (--> a/y)
+
+ clc
+ adc XPos
+ tay ; Remember low byte
+ txa
+ adc XPos+1
+
+; Limit the X coordinate to the bounding box
+
+ cpy XMin+1
+ bne @L1
+ cmp XMin
+@L1: bpl @L2
+ ldy XMin
+ lda XMin+1
+ jmp @L4
+
+@L2: cpy XMax+1
+ bne @L3
+ cmp XMax
+ beq @L4
+@L3: bmi @L4
+ ldy XMax
+ lda XMax+1
+@L4: sty XPos
+ sta XPos+1
+
+; Calculate the Y movement vector
+
+ lda SID_ADConv2 ; Get mouse Y movement
+ ldy OldPotY
+ jsr MoveCheck ; Calculate movement
+ sty OldPotY
+
+; Calculate the new Y coordinate (--> a/y)
+
+ clc
+ adc YPos
+ tay ; Remember low byte
+ txa
+ adc YPos+1
+
+; Limit the Y coordinate to the bounding box
+
+ cpy YMin+1
+ bne @L5
+ cmp YMin
+@L5: bpl @L6
+ ldy YMin
+ lda YMin+1
+ jmp @L8
+
+@L6: cpy YMax+1
+ bne @L7
+ cmp YMax
+ beq @L8
+@L7: bmi @L8
+ ldy YMax
+ lda YMax+1
+@L8: sty YPos
+ sta YPos+1
+
+; Jump to the next IRQ handler
+
+ jmp (OldIRQ)
+
+
+; --------------------------------------------------------------------------
+;
+; Move check routine, called for both coordinates.
+;
+; Entry: y = old value of pot register
+; a = current value of pot register
+; Exit: y = value to use for old value
+; x/a = delta value for position
+;
+
+MoveCheck:
+ sty OldValue
+ sta NewValue
+ ldx #$00
+
+ sec ; a = mod64 (new - old)
+ sbc OldValue
+ and #%01111111
+ cmp #%01000000 ; if (a > 0)
+ bcs @L1 ;
+ lsr a ; a /= 2;
+ beq @L2 ; if (a != 0)
+ ldy NewValue ; y = NewValue
+ rts ; return
+
+@L1: ora #%11000000 ; else or in high order bits
+ cmp #$FF ; if (a != -1)
+ beq @L2
+ sec
+ ror a ; a /= 2
+ ldx #$FF ; high byte = -1
+ ldy NewValue
+ rts
+
+@L2: lda #0
+ rts
+
+; --------------------------------------------------------------------------
+;
+; Move the mouse sprite to the current mouse position. Must be called
+; with interrupts off.
+;
+
+MoveSprite:
+ lda Visible ; Mouse pointer visible?
+ bne @L9 ; Jump if no
+ ldx MouseSprite ; Sprite defined?
+ beq @L9 ; Jump if no
+ ldy BitMask-1,x ; Get high bit mask
+ txa
+ asl a ; Index*2
+ tax
+
+; Set the X position
+
+ lda XPos+1 ; Negative?
+ bmi @L2 ; Jump if yes
+ beq @L1
+ tya ; Load high position bit
+@L1: ora VIC_SPR_HI_X ; Set high bit
+ sta VIC_SPR_HI_X
+ lda XPos
+ sta VIC_SPR0_X,x ; Set low byte
+
+; Set the Y position
+
+@L2: ldy YPos+1 ; Negative or too large?
+ bne @L9 ; Jump if yes
+ lda YPos
+ sta VIC_SPR0_Y,x ; Set Y position
+
+; Done
+
+@L9: rts
+
+; --------------------------------------------------------------------------
+; Data
+
+.bss
+
+OldIRQ: .res 2 ; Old IRQ vector
+MousePort: .res 1 ; Port used for the mouse
+MouseSprite: .res 1 ; Number of sprite to control
+OldValue: .res 1 ; Temp for MoveCheck routine
+NewValue: .res 1 ; Temp for MoveCheck routine
+
+Visible: .res 1 ; Is the mouse visible?
+OldPotX: .res 1 ; Old hw counter values
+OldPotY: .res 1
+
+XPos: .res 2 ; Current mouse position, X
+YPos: .res 2 ; Current mouse position, Y
+
+XMin: .res 2 ; X1 value of bounding box
+YMin: .res 2 ; Y1 value of bounding box
+XMax: .res 2 ; X2 value of bounding box
+YMax: .res 2 ; Y2 value of bounding box
+
+.data
+
+BitMask: .byte $01, $02, $04, $08, $10, $20, $40, $80
+
+
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 30.05.1998
+;
+; int read (int fd, void* buf, int count);
+;
+; THIS IS A HACK!
+;
+
+ .export _read
+ .import popax
+ .importzp ptr1, ptr2, ptr3
+
+ .include "../cbm/cbm.inc"
+
+_read: jsr popax ; get count
+ sta ptr2
+ stx ptr2+1 ; save it for later
+ jsr popax ; get buf
+ sta ptr1
+ stx ptr1+1
+ jsr popax ; get fd and discard it
+ lda #0
+ sta ptr3
+ sta ptr3+1 ; set count
+
+L1: lda ptr2
+ ora ptr2+1 ; count zero?
+ beq L9
+ jsr BASIN
+ ldy #0
+ sta (ptr1),y ; save char
+ inc ptr1
+ bne L2
+ inc ptr1+1
+L2: inc ptr3 ; increment count
+ bne L3
+ inc ptr3+1
+L3: cmp #$0D ; CR?
+ bne L1
+
+; Done, return the count
+
+L9: lda ptr3
+ ldx ptr3+1
+ rts
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 23.09.1998
+;
+; unsigned readjoy (unsigned char joy);
+;
+
+ .export _readjoy
+
+ .include "c64.inc"
+
+
+.proc _readjoy
+
+ tax ; Joystick number into X
+ bne joy2
+
+; Read joystick 1
+
+joy1: lda #$7F
+ sei
+ sta CIA1_PRA
+ lda CIA1_PRB
+ cli
+ and #$1F
+ eor #$1F
+ rts
+
+; Read joystick 2
+
+joy2: ldx #0
+ lda #$E0
+ ldy #$FF
+ sta CIA1_DDRA
+ lda CIA1_PRA
+ sty CIA1_DDRA
+ and #$1F
+ eor #$1F
+ rts
+
+.endproc
+
--- /dev/null
+;
+; SwiftLink/Turbo-232 v0.90 device driver, by Craig Bruce, 14-Apr-1998.
+;
+; This software is Public Domain. It is in Buddy assembler format.
+;
+; This device driver uses the SwiftLink RS-232 Serial Cartridge, available from
+; Creative Micro Designs, Inc, and also supports the extensions of the Turbo232
+; Serial Cartridge. Both devices are based on the 6551 ACIA chip. It also
+; supports the "hacked" SwiftLink with a 1.8432 MHz crystal.
+;
+; The code assumes that the kernal + I/O are in context. On the C128, call
+; it from Bank 15. On the C64, don't flip out the Kernal unless a suitable
+; NMI catcher is put into the RAM under then Kernal. For the SuperCPU, the
+; interrupt handling assumes that the 65816 is in 6502-emulation mode.
+;
+;--------------------------------------------------------------------------
+;
+; Adapted for the use with the cc65 runtime library by
+; Ullrich von Bassewitz (uz@musoftware.de) 02-May-1999.
+;
+; All external functions are C callable, the return value is an error code.
+;
+
+
+ .importzp ptr1, ptr2, tmp1, tmp2
+ .import popa, popax
+ .export _rs232_init, _rs232_params, _rs232_done, _rs232_get
+ .export _rs232_put, _rs232_pause, _rs232_unpause, _rs232_status
+
+
+useC64 = 1
+.if useC64
+ NmiExit = $febc ;exit address for nmi
+.else
+ NmiExit = $ff33 ;exit address for nmi
+.endif
+
+ACIA = $DE00
+
+
+
+;----------------------------------------------------------------------------
+;
+; Global variables
+;
+
+.bss
+DropCnt: .res 4 ; Number of bytes lost from rx buffer full
+Initialized: .res 1 ; Flag indicating driver is initialized
+Stopped: .res 1 ; Flow-stopped flag
+RtsOff: .res 1 ;
+Errors: .res 1 ; Number of bytes received in error, low byte
+Turbo232: .res 1 ; Flag indicating turbo-232
+HackedFlag: .res 1 ; Flag indicating hacked-crystal swiftlink
+CpuSpeed: .res 1 ; In MHz
+RecvHead: .res 1 ; Head of receive buffer
+RecvTail: .res 1 ; Tail of receive buffer
+RecvFreeCnt: .res 1 ; Number of bytes in receive buffer
+SendHead: .res 1 ; Head of send buffer
+SendTail: .res 1 ; Tail of send buffer
+SendFreeCnt: .res 1 ; Number of bytes free in send buffer
+BaudCode: .res 1 ; Current baud in effect
+
+; Send and receive buffers: 256 bytes each
+RecvBuf: .res 256
+SendBuf: .res 256
+
+.data
+NmiContinue: .byte $4c ; JMP instruction for NMI save -- continue
+NmiSave: .res 2 ; normal NMI handler
+
+; Switftlink register offsets
+RegData = 0 ; Data register
+RegStatus = 1 ; Status register
+RegCommand = 2 ; Command register
+RegControl = 3 ; Control register
+RegClock = 7 ; Turbo232 external baud-rate generator
+
+; Error codes. Beware: The codes must match the codes in the C header file
+ErrNotInitialized = $01
+ErrBaudTooFast = $02
+ErrBaudNotAvail = $03
+ErrNoData = $04
+ErrOverflow = $05
+
+
+.code
+
+;----------------------------------------------------------------------------
+;
+; unsigned char __fastcall__ rs232_init (char hacked);
+; /* Initialize the serial port, install the interrupt handler. The parameter
+; * must be true (non zero) for a hacked swiftlink and false (zero) otherwise.
+; */
+;
+
+_rs232_init:
+ bit Initialized ;** shut down if started
+ bpl @L1
+ pha
+ jsr _rs232_done
+ pla
+
+;** set hacked-crystal
+
+@L1: sta HackedFlag
+
+;** check for turbo-232
+
+ lda #$00
+ sta ACIA+RegControl
+ tax
+ lda ACIA+RegClock
+ beq @L3
+ dex
+@L3: stx Turbo232
+
+;** get C128/C64 cpu speed
+.if useC64
+ lda #1
+ sta CpuSpeed
+.else
+ lda $d030
+ and #$01
+ clc
+ adc #1
+ sta CpuSpeed
+.endif
+
+;** check for super-cpu at 20 MHz
+
+ bit $d0bc
+ bmi @L4
+ bit $d0b8
+ bvs @L4
+ lda #20
+ sta CpuSpeed
+
+;** initialize buffers & control
+
+@L4: lda #0
+ sta RecvHead
+ sta SendHead
+ sta RecvTail
+ sta SendTail
+ sta Errors
+ sta Stopped
+ lda #255
+ sta RecvFreeCnt
+ sta SendFreeCnt
+
+;** set up nmi's
+
+ lda $318
+ ldy $319
+ sta NmiSave+0
+ sty NmiSave+1
+ lda #<NmiHandler
+ ldy #>NmiHandler
+ sta $318
+ sty $319
+
+;** set default to 2400-8N1, enable interrupts
+
+ lda ACIA+RegData
+ lda ACIA+RegStatus
+ lda #$18
+ bit HackedFlag
+ bpl @L5
+ lda #$1a
+@L5: sta ACIA+RegControl
+
+ lda #$01
+ sta RtsOff
+ ora #$08
+ sta ACIA+RegCommand
+ lda #$06
+ sta BaudCode
+
+;** return
+ lda #$ff
+ sta Initialized
+ lda #$00
+ tax
+ rts
+
+;----------------------------------------------------------------------------
+;
+; unsigned char __fastcall__ rs232_params (unsigned char params, unsigned char parity);
+; /* Set the port parameters. Use a combination of the #defined values above. */
+;
+; Set communication parameters.
+;
+; baud rates stops word | parity
+; --------------------- ----- ----- | ---------
+; $00=50 $08=9600 $00=1 $00=8 | $00=none
+; $01=110 $09=19200 $80=2 $20=7 | $20=odd
+; $02=134.5 $0a=38400 $40=6 | $60=even
+; $03=300 $0b=57600 $60=5 | $A0=mark
+; $04=600 $0c=115200 | $E0=space
+; $05=1200 $0d=230400
+; $06=2400 $0e=future
+; $07=4800 $0f=future
+;
+
+_rs232_params:
+ jsr CheckInitialized ;** check initialized
+ bcc @L1
+ rts
+
+; Save new parity
+
+@L1: and #%11100000
+ ora #%00000001
+ sta tmp2
+
+; Check cpu speed against baud rate
+
+ jsr popa
+ sta tmp1
+ and #$0f
+ cmp #$0c
+ bcc @L3
+ ldx CpuSpeed
+ cpx #1+1
+ bcc @L2
+ cmp #$0c
+ beq @L3
+ cpx #4
+ bcs @L3
+@L2: lda #ErrBaudTooFast
+ bne @L9
+
+; Set baud/parameters
+
+@L3: lda tmp1
+ and #$0f
+ tax
+ lda NormBauds,x
+ bit HackedFlag
+ bpl @L4
+ lda HackBauds,x
+@L4: cmp #$ff
+ bne @L5
+ lda #ErrBaudNotAvail
+ bne @L9
+
+@L5: tax
+ and #$30
+ beq @L6
+ bit Turbo232
+ bmi @L6
+ lda #ErrBaudNotAvail
+ bne @L9
+
+@L6: lda tmp1
+ and #$0f
+ sta BaudCode
+ lda tmp1
+ and #%11100000
+ ora #%00010000
+ sta tmp1
+ txa
+ and #$0f
+ ora tmp1
+ sta ACIA+RegControl
+ txa
+ and #%00110000
+ beq @L7
+ lsr
+ lsr
+ lsr
+ lsr
+ eor #%00000011
+ sta ACIA+RegClock
+
+; Set new parity
+
+@L7: lda tmp2
+ sta RtsOff
+ ora #%00001000
+ sta ACIA+RegCommand
+ lda #0
+@L9: ldx #0
+ rts
+
+.rodata
+
+NormBauds:
+ .byte $ff,$ff,$ff,$05,$06,$07,$08,$0a,$0c,$0e,$0f,$10,$20,$30,$ff,$ff
+HackBauds:
+ .byte $01,$03,$04,$06,$07,$08,$0a,$0c,$0e,$0f,$ff,$ff,$00,$ff,$ff,$ff
+ ;in: 0 1 2 3 4 5 6 7 8 9 a b c d e f
+ ;baud50 110 134 3 6 12 24 48 96 19 38 57 115 230 exp exp
+ ;out masks: $0F=Baud, val$FF=err
+ ; $30=t232ExtBaud: $00=none, $10=57.6, $20=115.2, $30=230.4
+.code
+
+;----------------------------------------------------------------------------
+;
+; unsigned char __fastcall__ rs232_done (void);
+; /* Close the port, deinstall the interrupt hander. You MUST call this function
+; * before terminating the program, otherwise the machine may crash later. If
+; * in doubt, install an exit handler using atexit(). The function will do
+; * nothing, if it was already called.
+; */
+;
+
+
+_rs232_done:
+ bit Initialized ;** check initialized
+ bpl @L9
+
+; Stop interrupts, drop DTR
+
+ lda RtsOff
+ and #%11100010
+ ora #%00000010
+ sta ACIA+RegCommand
+
+; Restore NMI vector
+
+ lda NmiSave+0
+ ldy NmiSave+1
+ sta $318
+ sty $319
+
+; Flag uninitialized
+
+@L9: lda #$00
+ sta Initialized
+ tax
+ rts
+
+;----------------------------------------------------------------------------
+;
+; unsigned char __fastcall__ rs232_get (char* B);
+; /* Get a character from the serial port. If no characters are available, the
+; * function will return RS_ERR_NO_DATA, so this is not a fatal error.
+; */
+;
+
+_rs232_get:
+ jsr CheckInitialized ; Check if initialized
+ bcc @L1
+ rts
+
+; Check for bytes to send
+
+@L1: sta ptr1
+ stx ptr1+1 ; Store pointer to received char
+ ldx SendFreeCnt
+ cpx #$ff
+ beq @L2
+ lda #$00
+ jsr TryToSend
+
+; Check for buffer empty
+
+@L2: lda RecvFreeCnt
+ cmp #$ff
+ bne @L3
+ lda #ErrNoData
+ ldx #0
+ rts
+
+; Check for flow stopped & enough free: release flow control
+
+@L3: ldx Stopped
+ beq @L4
+ cmp #63
+ bcc @L4
+ lda #$00
+ sta Stopped
+ lda RtsOff
+ ora #%00001000
+ sta ACIA+RegCommand
+
+; Get byte from buffer
+
+@L4: ldx RecvHead
+ lda RecvBuf,x
+ inc RecvHead
+ inc RecvFreeCnt
+ ldx #$00
+ sta (ptr1,x)
+ txa ; Return code = 0
+ rts
+
+;----------------------------------------------------------------------------
+;
+; unsigned char __fastcall__ rs232_put (char B);
+; /* Send a character via the serial port. There is a transmit buffer, but
+; * transmitting is not done via interrupt. The function returns
+; * RS_ERR_OVERFLOW if there is no space left in the transmit buffer.
+; */
+;
+
+_rs232_put:
+ jsr CheckInitialized ; Check initialized
+ bcc @L1
+ rts
+
+; Try to send
+
+@L1: ldx SendFreeCnt
+ cpx #$ff
+ beq @L2
+ pha
+ lda #$00
+ jsr TryToSend
+ pla
+
+; Put byte into send buffer & send
+
+@L2: ldx SendFreeCnt
+ bne @L3
+ lda #ErrOverflow
+ ldx #$00
+ rts
+
+@L3: ldx SendTail
+ sta SendBuf,x
+ inc SendTail
+ dec SendFreeCnt
+ lda #$ff
+ jsr TryToSend
+ lda #$00
+ tax
+ rts
+
+;----------------------------------------------------------------------------
+;
+; unsigned char __fastcall__ rs232_pause (void);
+; /* Assert flow control and disable interrupts. */
+;
+
+_rs232_pause:
+; Check initialized
+ jsr CheckInitialized
+ bcc @L1
+ rts
+
+; Assert flow control
+
+@L1: lda RtsOff
+ sta Stopped
+ sta ACIA+RegCommand
+
+; Delay for flow stop to be received
+
+ ldx BaudCode
+ lda PauseTimes,x
+ jsr DelayMs
+
+; Stop rx interrupts
+
+ lda RtsOff
+ ora #$02
+ sta ACIA+RegCommand
+ lda #0
+ tax
+ rts
+
+
+.rodata
+; Delay times: 32 byte-receive times in milliseconds, or 100 max.
+; Formula = 320,000 / baud
+PauseTimes:
+ .byte 100,100,100,100,100,100,100,067,034,017,009,006,003,002,001,001
+ ;in: 0 1 2 3 4 5 6 7 8 9 a b c d e f
+ ;baud50 110 134 3 6 12 24 48 96 19 38 57 115 230 exp exp
+.code
+
+;----------------------------------------------------------------------------
+;
+; unsigned char __fastcall__ rs232_unpause (void);
+; /* Re-enable interrupts and release flow control */
+;
+
+_rs232_unpause:
+; Check initialized
+ jsr CheckInitialized
+ bcc @L1
+ rts
+
+; Re-enable rx interrupts & release flow control
+
+@L1: lda #$00
+ sta Stopped
+ lda RtsOff
+ ora #%00001000
+ sta ACIA+RegCommand
+
+; Poll for stalled char & exit
+
+ jsr PollReceive
+ lda #0
+ tax
+ rts
+
+;----------------------------------------------------------------------------
+;
+; unsigned char __fastcall__ rs232_status (unsigned char* status,
+; unsigned char* errors);
+; /* Return the serial port status. */
+;
+
+_rs232_status:
+ sta ptr2
+ stx ptr2+1
+ jsr popax
+ sta ptr1
+ stx ptr1+1
+ jsr CheckInitialized
+ bcs @L9
+
+; Get status
+
+ lda ACIA+RegStatus
+ ldy #0
+ sta (ptr1),y
+ jsr PollReceive ; bug-recovery hack
+ lda Errors
+ sta (ptr2),y
+ tya
+ tax
+@L9: rts
+
+;----------------------------------------------------------------------------
+;
+; NMI handler
+; C128 NMI overhead=76 cycles: int=7, maxLatency=6, ROMenter=33, ROMexit=30
+; C64 NMI overhead=76 cycles: int=7, maxLatency=6, ROMenter=34, ROMexit=29
+;
+; timing: normal=76+43+9=128 cycles, assertFlow=76+52+9=137 cycles
+;
+; C128 @ 115.2k: 177 cycles avail (fast)
+; C64 @ 57.6k: 177 cycles avail, worstAvail=177-43? = 134
+; SCPU @ 230.4k: 868 cycles avail: for a joke!
+;
+
+NmiHandler:
+.if useC64
+ pha
+ lda ACIA+RegStatus ;(4) ;status ;check for byte received
+ and #$08 ;(2)
+ beq @L9 ;(2*)
+ cld
+ txa
+ pha
+ tya
+ pha
+.else
+ lda ACIA+RegStatus ;(4) ;status ;check for byte received
+ and #$08 ;(2)
+ beq NmiNorm ;(2*)
+.endif
+ lda ACIA+RegStatus ;(4) opt ;status ;check for receive errors
+ and #$07 ;(2) opt
+ beq @L1 ;(3*)opt
+ inc Errors ;(5^)opt
+@L1: lda ACIA+RegData ;(4) ;data ;get byte and put into receive buffer
+ ldy RecvTail ;(4)
+ ldx RecvFreeCnt ;(4)
+ beq @L3 ;(2*)
+ sta RecvBuf,y ;(5)
+ inc RecvTail ;(6)
+ dec RecvFreeCnt ;(6)
+ cpx #33 ;(2) ;check for buffer space low
+ bcc @L2 ;(2*)
+ jmp NmiExit ;(3)
+
+; Assert flow control
+
+@L2: lda RtsOff ;(3) ;assert flow control if buffer space too low
+ sta ACIA+RegCommand ;(4) ;command
+ sta Stopped ;(3)
+ jmp NmiExit ;(3)
+
+; Drop this char
+
+@L3: inc DropCnt+0 ;not time-critical
+ bne @L4
+ inc DropCnt+1
+ bne @L4
+ inc DropCnt+2
+ bne @L4
+ inc DropCnt+3
+@L4: jmp NmiExit
+
+@L9:
+.if useC64
+ pla
+.endif
+ jmp NmiContinue
+
+;----------------------------------------------------------------------------
+;
+; CheckInitialized - internal check if initialized
+; Set carry and an error code if not initialized, clear carry and do not
+; change any registers if initialized.
+;
+
+CheckInitialized:
+ bit Initialized
+ bmi @L1
+ lda #ErrNotInitialized
+ ldx #0
+ sec
+ rts
+
+@L1: clc
+ rts
+
+;----------------------------------------------------------------------------
+; Try to send a byte. Internal routine. A = TryHard
+
+TryToSend:
+ sta tmp1 ; Remember tryHard flag
+@L0: lda SendFreeCnt
+ cmp #$ff
+ beq @L3 ; Bail out
+
+; Check for flow stopped
+
+@L1: lda Stopped
+ bne @L3 ; Bail out
+
+;** check that swiftlink is ready to send
+
+@L2: lda ACIA+RegStatus
+ and #$10
+ bne @L4
+ bit tmp1 ;keep trying if must try hard
+ bmi @L0
+@L3: rts
+
+;** send byte and try again
+
+@L4: ldx SendHead
+ lda SendBuf,x
+ sta ACIA+RegData
+ inc SendHead
+ inc SendFreeCnt
+ jmp @L0
+
+
+;----------------------------------------------------------------------------
+;
+; PollReceive - poll for rx char
+; This function is useful in odd cases where the 6551 has a character in
+; it but it fails to raise an NMI. It might be edge-triggering conditions?
+; Actually, I'm not entirely sure that this condition can still arrise, but
+; calling this function does no harm.
+;
+
+PollReceive:
+ lda #$08
+ and ACIA+RegStatus
+ beq @L9
+ and ACIA+RegStatus
+ beq @L9
+ lda ACIA+RegData
+ ldx RecvFreeCnt
+ beq @L9
+ ldx RecvTail
+ sta RecvBuf,x
+ inc RecvTail
+ dec RecvFreeCnt
+@L9: rts
+
+;----------------------------------------------------------------------------
+;
+; DelayMs : delay for given number of milliseconds
+; This implementation isn't very rigerous; it merely delays for the
+; approximate number of clock cycles for the processor speed.
+; Algorithm:
+; repeat for number of milliseconds:
+; repeat for number of MHz of cpu speed:
+; delay for 1017 clock cycles
+;
+
+DelayMs: ;( .A=milliseconds )
+@L1: ldy CpuSpeed
+@L2: ldx #203 ;(2)
+@L3: dex ;(2)
+ bne @L3 ;(3) // 1017 cycles
+ dey
+ bne @L2
+ sec
+ sbc #1
+ bne @L1
+ rts
+
+.end
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 30.05.1998
+;
+; int write (int fd, const void* buf, int count);
+;
+; THIS IS A HACK!
+;
+
+ .export _write
+ .import popax
+ .importzp ptr1, ptr2, ptr3
+
+ .include "../cbm/cbm.inc"
+
+_write: jsr popax ; get count
+ sta ptr2
+ stx ptr2+1 ; save it for later
+ sta ptr3
+ stx ptr3+1 ; save for function result
+ jsr popax ; get buf
+ sta ptr1
+ stx ptr1+1
+ jsr popax ; get fd and discard it
+
+L1: lda ptr2
+ ora ptr2+1 ; count zero?
+ beq L9
+ ldy #0
+ lda (ptr1),y
+ jsr BSOUT
+ inc ptr1
+ bne L2
+ inc ptr1+1
+L2: lda ptr2
+ bne L3
+ dec ptr2
+ dec ptr2+1
+ jmp L1
+L3: dec ptr2
+ jmp L1
+
+; No error, return count
+
+L9: lda ptr3
+ ldx ptr3+1
+ rts
+
--- /dev/null
+#
+# makefile for CC65 runtime library
+#
+
+.SUFFIXES: .o .s .c
+
+%.o: %.c
+ @echo $<
+ @$(CC) $(CFLAGS) $<
+ @$(AS) -o $@ $(AFLAGS) $(*).s
+
+%.o: %.s
+ @echo $<
+ @$(AS) -g -o $@ $(AFLAGS) $<
+
+C_OBJS =
+
+S_OBJS = ctype.o getenv.o gotoxy.o gotox.o gotoy.o where.o\
+ clock.o chline.o cvline.o cclear.o revers.o\
+ c_readst.o c_close.o c_open.o c_ckout.o c_clrch.o c_bsout.o\
+ c_basin.o c_clall.o c_iobase.o c_setnam.o c_setlfs.o c_acptr.o\
+ c_ciout.o c_untlk.o c_unlsn.o c_listen.o c_talk.o c_load.o\
+ oserror.o
+
+all: $(C_OBJS) $(S_OBJS)
+
+clean:
+ @rm -f *~
+ @rm -f $(C_OBJS:.c=.s)
+ @rm -f $(C_OBJS)
+ @rm -f $(S_OBJS)
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 03.06.1999
+;
+; unsigned char __fastcall__ cbm_acptr (void);
+;
+
+ .include "cbm.inc"
+
+ .export _cbm_acptr
+
+_cbm_acptr:
+ jsr ACPTR
+ ldx #0
+ rts
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 03.06.1999
+;
+; unsigned char __fastcall__ cbm_basin (void);
+;
+
+ .include "cbm.inc"
+
+ .export _cbm_basin
+
+_cbm_basin:
+ jsr BASIN
+ ldx #0
+ rts
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 03.06.1999
+;
+; void __fastcall__ cbm_bsout (unsigned char C);
+;
+
+ .include "cbm.inc"
+
+ .export _cbm_bsout
+
+_cbm_bsout = BSOUT
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 03.06.1999
+;
+; void __fastcall__ cbm_ciout (unsigned char C);
+;
+
+ .include "cbm.inc"
+
+ .export _cbm_ciout
+
+_cbm_ciout = CIOUT
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 03.06.1999
+;
+; unsigned __fastcall__ cbm_ckout (unsigned char FN);
+;
+
+ .include "cbm.inc"
+
+ .export _cbm_ckout
+
+_cbm_ckout:
+ tax
+ jsr CKOUT
+ ldx #0
+ bcc @Ok
+ inx
+ rts
+@Ok: txa
+ rts
+
+
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 03.06.1999
+;
+; void __fastcall__ cbm_clall (void);
+;
+
+ .include "cbm.inc"
+
+ .export _cbm_clall
+
+_cbm_clall = CLALL
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 03.06.1999
+;
+; void __fastcall__ cbm_close (unsigned char FN);
+;
+
+ .include "cbm.inc"
+
+ .export _cbm_close
+
+_cbm_close:
+ clc
+ jmp CLOSE
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 03.06.1999
+;
+; void __fastcall__ cbm_clrch (void);
+;
+
+ .include "cbm.inc"
+
+ .export _cbm_clrch
+
+_cbm_clrch = CLRCH
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 03.06.1999
+;
+; unsigned __fastcall__ cbm_iobase (void);
+;
+
+ .include "cbm.inc"
+
+ .export _cbm_iobase
+
+_cbm_iobase:
+ jsr IOBASE
+ txa
+ pha
+ tya
+ tax
+ pla
+ rts
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 03.06.1999
+;
+; void __fastcall__ cbm_listen (unsigned char dev);
+;
+
+ .include "cbm.inc"
+
+ .export _cbm_listen
+
+_cbm_listen = LISTEN
+
+
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 03.06.1999
+;
+; unsigned __fastcall__ cbm_load (unsigned char flag, unsigned addr);
+;
+
+ .include "cbm.inc"
+
+ .export _cbm_load
+ .import popa
+ .importzp ptr1
+
+_cbm_load:
+ sta ptr1
+ stx ptr1+1
+ jsr popa ; get flag
+ ldx ptr1
+ ldy ptr1+1
+ jsr LOAD
+ ldx #0
+ bcc @Ok
+ inx
+ rts
+@Ok: txa
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 03.06.1999
+;
+; unsigned __fastcall__ cbm_open (void);
+;
+
+ .include "cbm.inc"
+
+ .export _cbm_open
+
+_cbm_open:
+ jsr OPEN
+ ldx #0
+ bcc @Ok
+ inx
+ rts
+@Ok: txa
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 03.06.1999
+;
+; unsigned __fastcall__ cbm_readst (void);
+;
+
+ .include "cbm.inc"
+
+ .export _cbm_readst
+
+_cbm_readst:
+ jsr READST
+ ldx #0
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 03.06.1999
+;
+; void __fastcall__ cbm_setlfs (unsigned char LFN,
+; unsigned char DEV,
+; unsigned char SA);
+;
+
+ .include "cbm.inc"
+
+ .export _cbm_setlfs
+ .import popa
+ .importzp tmp1
+
+_cbm_setlfs:
+ sta tmp1 ; Save SA
+ jsr popa ; Get DEV
+ tax
+ jsr popa ; Get LFN
+ ldy tmp1 ; Get SA
+ jmp SETLFS
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 03.06.1999
+;
+; void __fastcall__ cbm_setnam (const char* Name);
+;
+
+ .include "cbm.inc"
+
+ .export _cbm_setnam
+ .importzp ptr1
+
+_cbm_setnam:
+ sta ptr1 ; Store pointer to file name
+ stx ptr1+1
+ ldy #$FF
+@Loop: iny ; Get length of name
+ lda (ptr1),y
+ bne @Loop
+
+ tya ; Length
+ ldx ptr1
+ ldy ptr1+1
+ jmp SETNAM
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 03.06.1999
+;
+; void __fastcall__ cbm_talk (unsigned char dev);
+;
+
+ .include "cbm.inc"
+
+ .export _cbm_talk
+
+_cbm_talk = TALK
+
+
+
+
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 03.06.1999
+;
+; void __fastcall__ cbm_unlsn (void);
+;
+
+ .include "cbm.inc"
+
+ .export _cbm_unlsn
+
+_cbm_unlsn = UNLSN
+
+
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 03.06.1999
+;
+; void __fastcall__ cbm_untlk (void);
+;
+
+ .include "cbm.inc"
+
+ .export _cbm_untlk
+
+_cbm_untlk = UNTLK
+
+
--- /dev/null
+;
+; Subroutines available in the CBM jump table
+;
+
+
+CINT = $FF81
+IOINIT = $FF84
+RAMTAS = $FF87
+RESTOR = $FF8A
+VECTOR = $FF8D
+SETMSG = $FF90
+SECOND = $FF93
+TKSA = $FF96
+MEMTOP = $FF99
+MEMBOT = $FF9C
+SCNKEY = $FF9F
+SETTMO = $FFA2
+ACPTR = $FFA5
+CIOUT = $FFA8
+UNTLK = $FFAB
+UNLSN = $FFAE
+LISTEN = $FFB1
+TALK = $FFB4
+READST = $FFB7
+SETLFS = $FFBA
+SETNAM = $FFBD
+OPEN = $FFC0
+CLOSE = $FFC3
+CHKIN = $FFC6
+CKOUT = $FFC9
+CLRCH = $FFCC
+BASIN = $FFCF
+BSOUT = $FFD2
+LOAD = $FFD5
+SAVE = $FFD8
+SETTIM = $FFDB
+RDTIM = $FFDE
+STOP = $FFE1
+GETIN = $FFE4
+CLALL = $FFE7
+UDTIM = $FFEA
+SCREEN = $FFED
+PLOT = $FFF0
+IOBASE = $FFF3
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 08.08.1998
+;
+; void cclearxy (unsigned char x, unsigned char y, unsigned char length);
+; void cclear (unsigned char length);
+;
+
+ .export _cclearxy, _cclear
+ .import popa, _gotoxy, cputdirect
+ .importzp tmp1
+
+_cclearxy:
+ pha ; Save the length
+ jsr popa ; Get y
+ jsr _gotoxy ; Call this one, will pop params
+ pla ; Restore the length and run into _cclear
+
+_cclear:
+ cmp #0 ; Is the length zero?
+ beq L9 ; Jump if done
+ sta tmp1
+L1: lda #$20 ; Blank - screen code
+ jsr cputdirect ; Direct output
+ dec tmp1
+ bne L1
+L9: rts
+
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 08.08.1998
+;
+; void chlinexy (unsigned char x, unsigned char y, unsigned char length);
+; void chline (unsigned char length);
+;
+
+ .export _chlinexy, _chline
+ .import popa, _gotoxy, cputdirect
+ .importzp tmp1
+
+_chlinexy:
+ pha ; Save the length
+ jsr popa ; Get y
+ jsr _gotoxy ; Call this one, will pop params
+ pla ; Restore the length
+
+_chline:
+ cmp #0 ; Is the length zero?
+ beq L9 ; Jump if done
+ sta tmp1
+L1: lda #64 ; Horizontal line, screen code
+ jsr cputdirect ; Direct output
+ dec tmp1
+ bne L1
+L9: rts
+
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 21.09.1998
+;
+; clock_t clock (void);
+;
+
+ .export _clock
+ .importzp sreg
+
+ .include "cbm.inc"
+
+
+.proc _clock
+
+ lda #0 ; Byte 3 is always zero
+ sta ::sreg+1
+ jsr RDTIM
+ sty ::sreg
+ rts ; Don't set CC, this has no meaning here
+
+.endproc
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 02.06.1998
+;
+; Character specification table.
+;
+
+; The tables are readonly, put them into the code segment
+
+.code
+
+; Value that must be added to a lower case char to make it an upper case
+; char (example: for ASCII, this must be $E0).
+
+
+ .export __cdiff
+
+__cdiff:
+ .byte $80
+
+
+; The following 256 byte wide table specifies attributes for the isxxx type
+; of functions. Doing it by a table means some overhead in space, but it
+; has major advantages:
+;
+; * It is fast. If it were'nt for the slow parameter passing of cc65, one
+; could even define macros for the isxxx functions (this is usually
+; done on other platforms).
+;
+; * It is highly portable. The only unportable part is the table itself,
+; all real code goes into the common library.
+;
+; * We save some code in the isxxx functions.
+;
+;
+; Bit assignments:
+;
+; 0 - Lower case char
+; 1 - Upper case char
+; 2 - Numeric digit
+; 3 - Hex digit (both, lower and upper)
+; 4 - Control character
+; 5 - The space character itself
+; 6 - Other whitespace (that is: '\f', '\n', '\r', '\t' and '\v')
+; 7 - Space or tab character
+
+
+; The table is taken from Craig S. Bruce technical docs for the ACE os
+
+ .export __ctype
+
+__ctype:
+ .byte $10 ; 0/00 ___rvs_@___
+ .byte $10 ; 1/01 ___rvs_a___
+ .byte $10 ; 2/02 ___rvs_b___
+ .byte $10 ; 3/03 ___rvs_c___
+ .byte $10 ; 4/04 ___rvs_d___
+ .byte $10 ; 5/05 ___rvs_e___
+ .byte $10 ; 6/06 ___rvs_f___
+ .byte $10 ; 7/07 _BEL/rvs_g_
+ .byte $10 ; 8/08 ___rvs_h___
+ .byte $D0 ; 9/09 _TAB/rvs_i_
+ .byte $50 ; 10/0a _BOL/rvs_j_
+ .byte $10 ; 11/0b ___rvs_k___
+ .byte $10 ; 12/0c ___rvs_l___
+ .byte $50 ; 13/0d _CR_/rvs_m_
+ .byte $10 ; 14/0e ___rvs_n___
+ .byte $10 ; 15/0f ___rvs_o___
+ .byte $10 ; 16/10 ___rvs_p___
+ .byte $50 ; 17/11 _VT_/rvs_q_
+ .byte $10 ; 18/12 ___rvs_r___
+ .byte $10 ; 19/13 ___rvs_s___
+ .byte $50 ; 20/14 _BS_/rvs_t_
+ .byte $10 ; 21/15 ___rvs_u___
+ .byte $10 ; 22/16 ___rvs_v___
+ .byte $10 ; 23/17 ___rvs_w___
+ .byte $10 ; 24/18 ___rvs_x___
+ .byte $10 ; 25/19 ___rvs_y___
+ .byte $10 ; 26/1a ___rvs_z___
+ .byte $10 ; 27/1b ___rvs_[___
+ .byte $10 ; 28/1c ___rvs_\___
+ .byte $10 ; 29/1d ___rvs_]___
+ .byte $10 ; 30/1e ___rvs_^___
+ .byte $10 ; 31/1f _rvs_under_
+ .byte $A0 ; 32/20 ___SPACE___
+ .byte $00 ; 33/21 _____!_____
+ .byte $00 ; 34/22 _____"_____
+ .byte $00 ; 35/23 _____#_____
+ .byte $00 ; 36/24 _____$_____
+ .byte $00 ; 37/25 _____%_____
+ .byte $00 ; 38/26 _____&_____
+ .byte $00 ; 39/27 _____'_____
+ .byte $00 ; 40/28 _____(_____
+ .byte $00 ; 41/29 _____)_____
+ .byte $00 ; 42/2a _____*_____
+ .byte $00 ; 43/2b _____+_____
+ .byte $00 ; 44/2c _____,_____
+ .byte $00 ; 45/2d _____-_____
+ .byte $00 ; 46/2e _____._____
+ .byte $00 ; 47/2f _____/_____
+ .byte $0C ; 48/30 _____0_____
+ .byte $0C ; 49/31 _____1_____
+ .byte $0C ; 50/32 _____2_____
+ .byte $0C ; 51/33 _____3_____
+ .byte $0C ; 52/34 _____4_____
+ .byte $0C ; 53/35 _____5_____
+ .byte $0C ; 54/36 _____6_____
+ .byte $0C ; 55/37 _____7_____
+ .byte $0C ; 56/38 _____8_____
+ .byte $0C ; 57/39 _____9_____
+ .byte $00 ; 58/3a _____:_____
+ .byte $00 ; 59/3b _____;_____
+ .byte $00 ; 60/3c _____<_____
+ .byte $00 ; 61/3d _____=_____
+ .byte $00 ; 62/3e _____>_____
+ .byte $00 ; 63/3f _____?_____
+
+ .byte $00 ; 64/40 _____@_____
+ .byte $09 ; 65/41 _____a_____
+ .byte $09 ; 66/42 _____b_____
+ .byte $09 ; 67/43 _____c_____
+ .byte $09 ; 68/44 _____d_____
+ .byte $09 ; 69/45 _____e_____
+ .byte $09 ; 70/46 _____f_____
+ .byte $01 ; 71/47 _____g_____
+ .byte $01 ; 72/48 _____h_____
+ .byte $01 ; 73/49 _____i_____
+ .byte $01 ; 74/4a _____j_____
+ .byte $01 ; 75/4b _____k_____
+ .byte $01 ; 76/4c _____l_____
+ .byte $01 ; 77/4d _____m_____
+ .byte $01 ; 78/4e _____n_____
+ .byte $01 ; 79/4f _____o_____
+ .byte $01 ; 80/50 _____p_____
+ .byte $01 ; 81/51 _____q_____
+ .byte $01 ; 82/52 _____r_____
+ .byte $01 ; 83/53 _____s_____
+ .byte $01 ; 84/54 _____t_____
+ .byte $01 ; 85/55 _____u_____
+ .byte $01 ; 86/56 _____v_____
+ .byte $01 ; 87/57 _____w_____
+ .byte $01 ; 88/58 _____x_____
+ .byte $01 ; 89/59 _____y_____
+ .byte $01 ; 90/5a _____z_____
+ .byte $00 ; 91/5b _____[_____
+ .byte $00 ; 92/5c _____\_____
+ .byte $00 ; 93/5d _____]_____
+ .byte $00 ; 94/5e _____^_____
+ .byte $00 ; 95/5f _UNDERLINE_
+ .byte $00 ; 96/60 _A`_grave__
+ .byte $00 ; 97/61 _A'_acute__
+ .byte $00 ; 98/62 _A^_circum_
+ .byte $00 ; 99/63 _A~_tilde__
+ .byte $00 ; 100/64 _A"_dieres_
+ .byte $00 ; 101/65 _A__ring___
+ .byte $00 ; 102/66 _AE________
+ .byte $00 ; 103/67 _C,cedilla_
+ .byte $00 ; 104/68 _E`_grave__
+ .byte $00 ; 105/69 _E'_acute__
+ .byte $00 ; 106/6a _E^_circum_
+ .byte $00 ; 107/6b _E"_dieres_
+ .byte $00 ; 108/6c _I`_grave__
+ .byte $00 ; 109/6d _I'_acute__
+ .byte $00 ; 110/6e _I^_circum_
+ .byte $00 ; 111/6f _I"_dieres_
+ .byte $00 ; 112/70 _D-_Eth_lr_
+ .byte $00 ; 113/71 _N~_tilde__
+ .byte $00 ; 114/72 _O`_grave__
+ .byte $00 ; 115/73 _O'_acute__
+ .byte $00 ; 116/74 _O^_circum_
+ .byte $00 ; 117/75 _O~_tilde__
+ .byte $00 ; 118/76 _O"_dieres_
+ .byte $00 ; 119/77 __multiply_
+ .byte $00 ; 120/78 _O/_slash__
+ .byte $00 ; 121/79 _U`_grave__
+ .byte $00 ; 122/7a _U'_acute__
+ .byte $00 ; 123/7b _U^_circum_
+ .byte $00 ; 124/7c _U"_dieres_
+ .byte $00 ; 125/7d _Y'_acute__
+ .byte $00 ; 126/7e _cap_thorn_
+ .byte $00 ; 127/7f _Es-sed_B__
+
+ .byte $00 ; 128/80 __bullet___
+ .byte $00 ; 129/81 __v_line___
+ .byte $00 ; 130/82 __h_line___
+ .byte $00 ; 131/83 ___cross___
+ .byte $00 ; 132/84 _tl_corner_
+ .byte $00 ; 133/85 _tr_corner_
+ .byte $00 ; 134/86 _bl_corner_
+ .byte $00 ; 135/87 _br_corner_
+ .byte $00 ; 136/88 ___l_tee___
+ .byte $00 ; 137/89 ___r_tee___
+ .byte $00 ; 138/8a ___t_tee___
+ .byte $00 ; 139/8b ___b_tee___
+ .byte $00 ; 140/8c ___heart___
+ .byte $00 ; 141/8d __diamond__
+ .byte $00 ; 142/8e ___club____
+ .byte $00 ; 143/8f ___spade___
+ .byte $00 ; 144/90 _s_circle__
+ .byte $00 ; 145/91 __circle___
+ .byte $00 ; 146/92 ___pound___
+ .byte $10 ; 147/93 _CLS/check_
+ .byte $00 ; 148/94 ____pi_____
+ .byte $00 ; 149/95 ____+/-____
+ .byte $00 ; 150/96 __divide___
+ .byte $00 ; 151/97 __degree___
+ .byte $00 ; 152/98 _c_checker_
+ .byte $00 ; 153/99 _f_checker_
+ .byte $00 ; 154/9a _solid_sq__
+ .byte $00 ; 155/9b __cr_char__
+ .byte $00 ; 156/9c _up_arrow__
+ .byte $00 ; 157/9d _down_arro_
+ .byte $00 ; 158/9e _left_arro_
+ .byte $00 ; 159/9f _right_arr_
+ .byte $00 ; 160/a0 _req space_
+ .byte $00 ; 161/a1 _!_invertd_
+ .byte $00 ; 162/a2 ___cent____
+ .byte $00 ; 163/a3 ___pound___
+ .byte $00 ; 164/a4 __currency_
+ .byte $00 ; 165/a5 ____yen____
+ .byte $00 ; 166/a6 _|_broken__
+ .byte $00 ; 167/a7 __section__
+ .byte $00 ; 168/a8 __umulaut__
+ .byte $00 ; 169/a9 _copyright_
+ .byte $00 ; 170/aa __fem_ord__
+ .byte $00 ; 171/ab _l_ang_quo_
+ .byte $00 ; 172/ac ____not____
+ .byte $00 ; 173/ad _syl_hyphn_
+ .byte $00 ; 174/ae _registerd_
+ .byte $00 ; 175/af _overline__
+ .byte $00 ; 176/b0 __degrees__
+ .byte $00 ; 177/b1 ____+/-____
+ .byte $00 ; 178/b2 _2_supersc_
+ .byte $00 ; 179/b3 _3_supersc_
+ .byte $00 ; 180/b4 ___acute___
+ .byte $00 ; 181/b5 ____mu_____
+ .byte $00 ; 182/b6 _paragraph_
+ .byte $00 ; 183/b7 __mid_dot__
+ .byte $00 ; 184/b8 __cedilla__
+ .byte $00 ; 185/b9 _1_supersc_
+ .byte $00 ; 186/ba __mas_ord__
+ .byte $00 ; 187/bb _r_ang_quo_
+ .byte $00 ; 188/bc ____1/4____
+ .byte $00 ; 189/bd ____1/2____
+ .byte $00 ; 190/be ____3/4____
+ .byte $00 ; 191/bf _?_invertd_
+
+ .byte $00 ; 192/c0 _____`_____
+ .byte $0A ; 193/c1 _____A_____
+ .byte $0A ; 194/c2 _____B_____
+ .byte $0A ; 195/c3 _____C_____
+ .byte $0A ; 196/c4 _____D_____
+ .byte $0A ; 197/c5 _____E_____
+ .byte $0A ; 198/c6 _____F_____
+ .byte $02 ; 199/c7 _____G_____
+ .byte $02 ; 200/c8 _____H_____
+ .byte $02 ; 201/c9 _____I_____
+ .byte $02 ; 202/ca _____J_____
+ .byte $02 ; 203/cb _____K_____
+ .byte $02 ; 204/cc _____L_____
+ .byte $02 ; 205/cd _____M_____
+ .byte $02 ; 206/ce _____N_____
+ .byte $02 ; 207/cf _____O_____
+ .byte $02 ; 208/d0 _____P_____
+ .byte $02 ; 209/d1 _____Q_____
+ .byte $02 ; 210/d2 _____R_____
+ .byte $02 ; 211/d3 _____S_____
+ .byte $02 ; 212/d4 _____T_____
+ .byte $02 ; 213/d5 _____U_____
+ .byte $02 ; 214/d6 _____V_____
+ .byte $02 ; 215/d7 _____W_____
+ .byte $02 ; 216/d8 _____X_____
+ .byte $02 ; 217/d9 _____Y_____
+ .byte $02 ; 218/da _____Z_____
+ .byte $00 ; 219/db _____{_____
+ .byte $00 ; 220/dc _____|_____
+ .byte $00 ; 221/dd _____}_____
+ .byte $00 ; 222/de _____~_____
+ .byte $00 ; 223/df ___HOUSE___
+ .byte $00 ; 224/e0 _a`_grave__
+ .byte $00 ; 225/e1 _a'_acute__
+ .byte $00 ; 226/e2 _a^_circum_
+ .byte $00 ; 227/e3 _a~_tilde__
+ .byte $00 ; 228/e4 _a"_dieres_
+ .byte $00 ; 229/e5 _a__ring___
+ .byte $00 ; 230/e6 _ae________
+ .byte $00 ; 231/e7 _c,cedilla_
+ .byte $00 ; 232/e8 _e`_grave__
+ .byte $00 ; 233/e9 _e'_acute__
+ .byte $00 ; 234/ea _e^_circum_
+ .byte $00 ; 235/eb _e"_dieres_
+ .byte $00 ; 236/ec _i`_grave__
+ .byte $00 ; 237/ed _i'_acute__
+ .byte $00 ; 238/ee _i^_circum_
+ .byte $00 ; 239/ef _i"_dieres_
+ .byte $00 ; 240/f0 _o^x_Eth_s_
+ .byte $00 ; 241/f1 _n~_tilda__
+ .byte $00 ; 242/f2 _o`_grave__
+ .byte $00 ; 243/f3 _o'_acute__
+ .byte $00 ; 244/f4 _o^_circum_
+ .byte $00 ; 245/f5 _o~_tilde__
+ .byte $00 ; 246/f6 _o"_dieres_
+ .byte $00 ; 247/f7 __divide___
+ .byte $00 ; 248/f8 _o/_slash__
+ .byte $00 ; 249/f9 _u`_grave__
+ .byte $00 ; 250/fa _u'_acute__
+ .byte $00 ; 251/fb _u^_circum_
+ .byte $00 ; 252/fc _u"_dieres_
+ .byte $00 ; 253/fd _y'_acute__
+ .byte $00 ; 254/fe _sm_thorn__
+ .byte $00 ; 255/ff _y"_dieres_
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 08.08.1998
+;
+; void cvlinexy (unsigned char x, unsigned char y, unsigned char length);
+; void cvline (unsigned char length);
+;
+
+ .export _cvlinexy, _cvline
+ .import popa, _gotoxy, putchar, newline
+ .importzp tmp1
+
+_cvlinexy:
+ pha ; Save the length
+ jsr popa ; Get y
+ jsr _gotoxy ; Call this one, will pop params
+ pla ; Restore the length and run into _cvline
+
+_cvline:
+ cmp #0 ; Is the length zero?
+ beq L9 ; Jump if done
+ sta tmp1
+L1: lda #93 ; Vertical bar
+ jsr putchar ; Write, no cursor advance
+ jsr newline ; Advance cursor to next line
+ dec tmp1
+ bne L1
+L9: rts
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 17.06.1998
+;
+; char* getenv (const char* name);
+;
+
+ .export _getenv
+ .import return0
+
+_getenv = return0 ; "not found"
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 07.08.1998
+;
+; void gotox (unsigned char x);
+;
+
+ .export _gotox
+ .import plot
+ .importzp CURS_X
+
+_gotox: sta CURS_X ; Set new position
+ jmp plot ; And activate it
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; void gotoxy (unsigned char x, unsigned char y);
+;
+
+ .export _gotoxy
+ .import popa, plot
+ .importzp CURS_X, CURS_Y
+
+_gotoxy:
+ sta CURS_Y ; Set Y
+ jsr popa ; Get X
+ sta CURS_X ; Set X
+ jmp plot ; Set the cursor position
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 0.08.1998
+;
+; void gotoy (unsigned char y);
+;
+
+ .export _gotoy
+ .import plot
+ .importzp CURS_Y
+
+_gotoy: sta CURS_Y ; Set the new position
+ jmp plot ; And activate it
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 17.05.2000
+;
+; int __fastcall__ _osmaperrno (unsigned char oserror);
+; /* Map a system specific error into a system independent code */
+;
+
+ .export __osmaperrno
+ .include "../common/errno.inc"
+
+.code
+
+__osmaperrno:
+ ldx #ErrTabSize
+@L1: cmp ErrTab-2,x ; Search for the error code
+ beq @L2 ; Jump if found
+ dex
+ dex
+ bne @L1 ; Next entry
+
+; Code not found, return EINVAL
+
+ lda #<EINVAL
+ ldx #>EINVAL
+ rts
+
+; Found the code
+
+@L2: lda ErrTab-1,x
+ ldx #$00 ; High byte always zero
+ rts
+
+.rodata
+
+ErrTab:
+ .byte 1, EMFILE ; Too many open files
+ .byte 2, EINVAL ; File is open
+ .byte 3, EINVAL ; File not open
+ .byte 4, ENOENT ; File not found
+ .byte 5, ENODEV ; Device not present
+ .byte 6, EINVAL ; File not input
+ .byte 7, EINVAL ; File not output
+ .byte 8, EINVAL ; Filename missing
+ .byte 9, ENODEV ; Ilegal device
+; .byte 20, ; Read error
+; .byte 21, ; Read error
+; .byte 22, ; Read error
+; .byte 23, ; Read error
+; .byte 24, ; Read error
+; .byte 25, ; Write error
+ .byte 26, EACCES ; Write protect on
+; .byte 27, ; Read error
+; .byte 28, ; Write error
+; .byte 29, ; Disk ID mismatch
+; .byte 30, ; Syntax error
+; .byte 31, ; Syntax error
+; .byte 32, ; Syntax error
+ .byte 33, EINVAL ; Syntax error (invalid file name)
+ .byte 34, EINVAL ; Syntax error (no file given)
+; .byte 39, ; Syntax error
+; .byte 50, ; Record not present
+; .byte 51, ; Overflow in record
+; .byte 52, ; File too large
+ .byte 60, EINVAL ; Write file open
+ .byte 61, EINVAL ; File not open
+ .byte 62, ENOENT ; File not found
+ .byte 63, EEXIST ; File exists
+ .byte 64, EINVAL ; File type mismatch
+; .byte 65, ; No block
+; .byte 66, ; Illegal track or sector
+; .byte 67, ; Illegal system track or sector
+ .byte 70, EBUSY ; No channel
+; .byte 71, ; Directory error
+; .byte 72, ; Disk full
+; .byte 73, ; DOS version mismatch
+
+ErrTabSize = (* - ErrTab)
--- /dev/null
+;
+; Ullrich von Bassewitz, 07.08.1998
+;
+; unsigned char revers (unsigned char onoff);
+;
+
+ .export _revers
+ .export revers
+
+_revers:
+ ldx #$00 ; Assume revers off
+ tay ; Test onoff
+ beq L1 ; Jump if off
+ ldx #$80 ; Load on value
+L1: ldy #$00 ; Assume old value is zero
+ lda revers ; Load old value
+ stx revers ; Set new value
+ beq L2 ; Jump if old value zero
+ iny ; Make old value = 1
+L2: ldx #$00 ; Load high byte of result
+ tya ; Load low byte, set CC
+ rts
+
+.bss
+
+revers: .res 1
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; unsigned char wherex (void);
+; unsigned char wherey (void);
+
+ .export _wherex, _wherey
+
+ .include "cbm.inc"
+
+_wherex:
+ sec
+ jsr PLOT ; Get cursor position
+ tya
+ rts
+
+_wherey:
+ sec
+ jsr PLOT ; Get cursor position
+ txa
+ rts
+
+
+
+
+
--- /dev/null
+#
+# makefile for CC65 runtime library
+#
+
+.SUFFIXES: .o .s .c
+
+%.o: %.c
+ @echo $<
+ @$(CC) $(CFLAGS) $<
+ @$(AS) -o $@ $(AFLAGS) $(*).s
+
+%.o: %.s
+ @echo $<
+ @$(AS) -g -o $@ $(AFLAGS) $<
+
+C_OBJS =
+
+S_OBJS = crt0.o kbhit.o conio.o clrscr.o cputc.o cgetc.o\
+ color.o break.o banking.o crtc.o pokesys.o\
+ kscnkey.o kplot.o kudtim.o kirq.o rs232.o
+
+all: $(C_OBJS) $(S_OBJS)
+
+clean:
+ @rm -f $(C_OBJS:.c=.s)
+ @rm -f $(C_OBJS)
+ @rm -f $(S_OBJS)
+ @rm -f crt0.o
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 28.09.1998
+;
+; Banking routines for the 610.
+;
+
+ .export set_bank, sys_bank, restore_bank
+ .importzp ptr1
+
+ .include "zeropage.inc"
+
+.code
+
+.proc sys_bank
+ pha
+ lda IndReg
+ sta IndSegSave
+ lda #$0F
+ sta IndReg
+ pla
+ rts
+.endproc
+
+.proc set_bank
+ pha
+ lda IndReg
+ sta IndSegSave
+ pla
+ sta IndReg
+ rts
+.endproc
+
+.proc restore_bank
+ pha
+ lda IndSegSave
+ sta IndReg
+ pla
+ rts
+.endproc
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 27.09.1998
+;
+; void set_brk (unsigned Addr);
+; void reset_brk (void);
+;
+
+ .export _set_brk, _reset_brk
+ .export _brk_a, _brk_x, _brk_y, _brk_sr, _brk_pc
+ .import _atexit
+
+ .include "zeropage.inc"
+ .include "page3.inc"
+
+
+.bss
+_brk_a: .res 1
+_brk_x: .res 1
+_brk_y: .res 1
+_brk_sr: .res 1
+_brk_pc: .res 2
+_brk_01: .res 1
+
+oldvec: .res 2 ; Old vector
+
+
+.data
+uservec: jmp $FFFF ; Patched at runtime
+
+
+.code
+
+; Set the break vector
+.proc _set_brk
+
+ sta uservec+1
+ stx uservec+2 ; Set the user vector
+
+ lda oldvec
+ ora oldvec+1 ; Did we save the vector already?
+ bne L1 ; Jump if we installed the handler already
+
+ lda BRKVec
+ sta oldvec
+ lda BRKVec+1
+ sta oldvec+1 ; Save the old vector
+
+ lda #<_reset_brk
+ ldx #>_reset_brk
+ jsr _atexit ; Install an exit handler
+
+L1: lda #<brk_handler ; Set the break vector to our routine
+ sta BRKVec
+ lda #>brk_handler
+ sta BRKVec+1
+ rts
+
+.endproc
+
+
+; Reset the break vector
+.proc _reset_brk
+
+ lda oldvec
+ sta BRKVec
+ lda oldvec+1
+ sta BRKVec+1
+ rts
+
+.endproc
+
+
+
+; Break handler, called if a break occurs
+
+.proc brk_handler
+
+ pla
+ sta _brk_y
+ pla
+ sta _brk_x
+ pla
+ sta _brk_a
+ pla
+ and #$EF ; Clear break bit
+ sta _brk_sr
+ pla ; PC low
+ sec
+ sbc #2 ; Point to start of brk
+ sta _brk_pc
+ pla ; PC high
+ sbc #0
+ sta _brk_pc+1
+ lda IndReg
+ sta _brk_01
+ lda ExecReg
+ sta IndReg
+
+ jsr uservec ; Call the user's routine
+
+ lda _brk_01
+ sta IndReg
+
+ lda _brk_pc+1
+ pha
+ lda _brk_pc
+ pha
+ lda _brk_sr
+ pha
+ ldx _brk_x
+ ldy _brk_y
+ lda _brk_a
+ rti ; Jump back...
+
+.endproc
+
+
--- /dev/null
+;
+; CBM610 generic definitions.
+;
+
+
+; ---------------------------------------------------------------------------
+; Vector and other locations
+
+FUNKEY_VEC = $03B5
+
+; ---------------------------------------------------------------------------
+; I/O
+
+CRTC = $D800
+CRTC_ADDR = $00
+CRTC_DATA = $01
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; char cgetc (void);
+;
+
+ .export _cgetc
+ .import plot, write_crtc
+ .import cursor
+
+ .include "zeropage.inc"
+ .include "page3.inc"
+
+
+_cgetc: lda KeyIndex ; Get number of characters
+ bne L2 ; Jump if there are already chars waiting
+
+; Switch on the cursor if needed
+
+ lda cursor
+ beq L1 ; Jump if no cursor
+
+ jsr plot ; Set the current cursor position
+ ldy #10
+ lda Config ; Cursor format
+ jsr write_crtc ; Set the cursor formar
+
+L1: lda KeyIndex
+ beq L1
+
+ ldy #10
+ lda #$20 ; Cursor off
+ jsr write_crtc
+
+L2: ldx #$00 ; Get index
+ ldy KeyBuf ; Get first character in the buffer
+ sei
+L3: lda KeyBuf+1,x ; Move up the remaining chars
+ sta KeyBuf,x
+ inx
+ cpx KeyIndex
+ bne L3
+ dec KeyIndex
+ cli
+
+ ldx #$00 ; High byte
+ tya ; First char from buffer
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 22.09.1998
+;
+; void clrscr (void);
+;
+
+ .export _clrscr
+ .import plot
+
+ .include "zeropage.inc"
+
+.proc _clrscr
+
+ lda #0
+ sta CURS_X
+ sta CURS_Y
+ jsr plot ; Set cursor to top left corner
+
+ lda IndReg
+ pha
+ lda #$0F
+ sta IndReg ; Switch to the system bank
+
+ ldx #8
+ ldy #$00
+ lda #$20 ; Screencode for blank
+L1: sta (CharPtr),y
+ iny
+ bne L1
+ inc CharPtr+1
+ dex
+ bne L1
+
+ pla
+ sta IndReg ; Restore old indirect segment
+
+ jmp plot ; Set screen pointer again
+
+.endproc
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; unsigned char __fastcall__ textcolor (unsigned char color);
+; unsigned char __fastcall__ bgcolor (unsigned char color);
+; unsigned char __fastcall__ bordercolor (unsigned char color);
+;
+
+ .export _textcolor, _bgcolor, _bordercolor
+ .import return0, return1
+
+ .include "cbm610.inc"
+
+_textcolor = return1
+
+_bgcolor = return0
+
+_bordercolor = return0
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 22.09.1998
+;
+; Low level stuff for screen output/console input
+;
+
+ .export initconio
+ .import xsize, ysize
+
+ .include "cbm610.inc"
+
+initconio:
+ lda #80
+ sta xsize
+ lda #25
+ sta ysize
+ rts
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; void cputcxy (unsigned char x, unsigned char y, char c);
+; void cputc (char c);
+;
+
+ .export _cputcxy, _cputc, cputdirect, putchar
+ .export advance, newline, plot
+ .exportzp CURS_X, CURS_Y
+ .import _gotoxy
+ .import popa
+ .import xsize, revers
+
+ .include "cbm610.inc"
+ .include "zeropage.inc"
+ .include "../cbm/cbm.inc"
+
+_cputcxy:
+ pha ; Save C
+ jsr popa ; Get Y
+ jsr _gotoxy ; Set cursor, drop x
+ pla ; Restore C
+
+; Plot a character - also used as internal function
+
+_cputc: cmp #$0D ; CR?
+ bne L1
+ lda #0
+ sta CURS_X
+ beq plot ; Recalculate pointers
+
+L1: cmp #$0A ; LF?
+ bne L2
+ ldy CURS_Y
+ iny
+ bne newline ; Recalculate pointers
+
+; Printable char of some sort
+
+L2: cmp #' '
+ bcc cputdirect ; Other control char
+ tay
+ bmi L10
+ cmp #$60
+ bcc L3
+ and #$DF
+ bne cputdirect ; Branch always
+L3: and #$3F
+
+cputdirect:
+ jsr putchar ; Write the character to the screen
+
+; Advance cursor position
+
+advance:
+ iny
+ cpy xsize
+ bne L9
+ ldy #0 ; new line
+newline:
+ clc
+ lda xsize
+ adc CharPtr
+ sta CharPtr
+ bcc L4
+ inc CharPtr+1
+L4: inc CURS_Y
+L9: sty CURS_X
+ rts
+
+; Handle character if high bit set
+
+L10: and #$7F
+ cmp #$7E ; PI?
+ bne L11
+ lda #$5E ; Load screen code for PI
+ bne cputdirect
+L11: ora #$40
+ bne cputdirect ; Branch always
+
+; Set cursor position, calculate RAM pointers
+
+plot: ldy CURS_X
+ ldx CURS_Y
+ clc
+ jmp PLOT
+
+; Write one character to the screen without doing anything else, return X
+; position in Y
+
+putchar:
+ ldx IndReg
+ ldy #$0F
+ sty IndReg
+ ora revers ; Set revers bit
+ ldy CURS_X
+ sta (CharPtr),y ; Set char
+ stx IndReg
+ rts
+
+
--- /dev/null
+;
+; Startup code for cc65 (Plus/4 version)
+;
+; This must be the *first* file on the linker command line
+;
+
+ .export _exit
+ .import __hinit, push0, doatexit, _main
+ .import initconio
+ .import __BSS_RUN__, __BSS_SIZE__
+ .import irq, nmi
+ .import k_irq, k_nmi, k_plot, k_udtim, k_scnkey
+
+ .include "zeropage.inc"
+ .include "io.inc"
+
+
+; ------------------------------------------------------------------------
+; Define and export the ZP variables for the CBM610 runtime
+
+ .exportzp sp, sreg, regsave
+ .exportzp ptr1, ptr2, ptr3, ptr4
+ .exportzp tmp1, tmp2, tmp3, tmp4
+ .exportzp regbank, zpspace
+ .exportzp crtc, sid, IPCcia, cia, acia, tpi1, tpi2
+ .exportzp ktab1, ktab2, ktab3, ktab4, time, RecvBuf, SendBuf
+
+sp = $02 ; stack pointer
+sreg = $04 ; secondary register/high 16 bit for longs
+regsave = $06 ; slot to save/restore (E)AX into
+ptr1 = $0A ;
+ptr2 = $0C
+ptr3 = $0E
+ptr4 = $10
+tmp1 = $12
+tmp2 = $13
+tmp3 = $14
+tmp4 = $15
+regbank = $16 ; 6 byte register bank
+zpspace = $1A ; Zero page space allocated
+
+; ------------------------------------------------------------------------
+; BASIC header and a small BASIC program. Since it is not possible to start
+; programs in other banks using SYS, the BASIC program will write a small
+; machine code program into memory at $100 and start that machine code
+; program. The machine code program will then start the machine language
+; code in bank 1, which will initialize the system by copying stuff from
+; the system bank, and start the application.
+;
+; Here's the basic program that's in the following lines:
+;
+; 10 for i=0 to 4
+; 20 read j
+; 30 poke 256+i,j
+; 40 next i
+; 50 sys 256
+; 60 data 120,169,1,133,0
+;
+; The machine program in the data lines is:
+;
+; sei
+; lda #$01
+; sta $00 <-- Switch to bank 1 after this command
+;
+; Initialization is not only complex because of the jumping from one bank
+; into another. but also because we want to save memory, and because of
+; this, we will use the system memory ($00-$3FF) for initialization stuff
+; that is overwritten later.
+;
+
+; To make things more simple, make the code of this module absolute.
+
+ .org $0001
+Head: .byte $03,$00,$11,$00,$0a,$00,$81,$20,$49,$b2,$30,$20,$a4,$20,$34,$00
+ .byte $19,$00,$14,$00,$87,$20,$4a,$00,$27,$00,$1e,$00,$97,$20,$32,$35
+ .byte $36,$aa,$49,$2c,$4a,$00,$2f,$00,$28,$00,$82,$20,$49,$00,$39,$00
+ .byte $32,$00,$9e,$20,$32,$35,$36,$00,$4f,$00,$3c,$00,$83,$20,$31,$32
+ .byte $30,$2c,$31,$36,$39,$2c,$31,$2c,$31,$33,$33,$2c,$30,$00,$00,$00
+
+; Since we need some vectors to access stuff in the system bank for our own,
+; we will include them here, starting from $60:
+
+ .res $60-*
+
+crtc: .word $d800
+sid: .word $da00
+IPCcia: .word $db00
+cia: .word $dc00
+acia: .word $dd00
+tpi1: .word $de00
+tpi2: .word $df00
+ktab1: .word $ea29
+ktab2: .word $ea89
+ktab3: .word $eae9
+ktab4: .word $eb49
+time: .dword $0000
+RecvBuf: .word $0100 ; RS232 received buffer
+SendBuf: .word $0200 ; RS232 send buffer
+
+
+; The code in the target bank when switching back will be put at the bottom
+; of the stack. We will jump here to switch segments. The range $F2..$FF is
+; not used by any kernal routine.
+
+ .res $F8-*
+Back: ldx spsave
+ txs
+ lda IndReg
+ sta ExecReg
+
+; The following code is a copy of the code that is poked in the system bank
+; memory by the basic header program, it's only for documentation and not
+; actually used here:
+
+ sei
+ lda #$01
+ sta ExecReg
+
+; This is the actual starting point of our code after switching banks for
+; startup. Beware: The following code will get overwritten as soon as we
+; use the stack (since it's in page 1)!
+
+ tsx
+ stx spsave ; Save the system stackpointer
+ ldx #$FF
+ txs ; Set up our own stack
+
+; Set the interrupt, NMI and other vectors
+
+ ldy #vectable_size
+L0: lda vectable-1,y
+ sta $FF80,y
+ dey
+ bne L0
+
+; Switch the indirect segment to the system bank
+
+ lda #$0F
+ sta IndReg
+
+; Copy the kernal zero page ($90-$F2) from the system bank
+
+ lda #$90
+ sta ptr1
+ lda #$00
+ sta ptr1+1
+ ldy #$62-1
+L1: lda (ptr1),y
+ sta $90,y
+ dey
+ bpl L1
+
+; Copy the page 3 vectors in place
+
+ ldy #$00
+L2: lda p3vectable,y
+ sta $300,y
+ iny
+ cpy #p3vectable_size
+ bne L2
+
+; Copy the rest of page 3 from the system bank
+
+ lda #$00
+ sta ptr1
+ lda #$03
+ sta ptr1+1
+L3: lda (ptr1),y
+ sta $300,y
+ iny
+ bne L3
+
+; Set the indirect segment to bank we're executing in
+
+ lda ExecReg
+ sta IndReg
+
+; Zero the BSS segment. We will do that here instead calling the routine
+; in the common library, since we have the memory anyway, and this way,
+; it's reused later.
+
+ lda #<__BSS_RUN__
+ sta ptr1
+ lda #>__BSS_RUN__
+ sta ptr1+1
+ lda #0
+ tay
+
+; Clear full pages
+
+ ldx #>__BSS_SIZE__
+ beq Z2
+Z1: sta (ptr1),y
+ iny
+ bne Z1
+ inc ptr1+1 ; Next page
+ dex
+ bne Z1
+
+; Clear the remaining page
+
+Z2: ldx #<__BSS_SIZE__
+ beq Z4
+Z3: sta (ptr1),y
+ iny
+ dex
+ bne Z3
+Z4:
+
+; Setup the C stack
+
+ lda #<$FF81
+ sta sp
+ lda #>$FF81
+ sta sp+1
+
+; We expect to be in page 2 now
+
+.if (* < $1FD)
+ jmp $200
+ .res $200-*
+.endif
+.if (* < $200)
+ .res $200-*,$EA
+.endif
+.if (* >= $2F0)
+.error "Code range invalid"
+.endif
+
+; This code is in page 2, so we may now start calling subroutines safely,
+; since the code we execute is no longer in the stack page.
+
+ jsr __hinit ; Initialize the heap
+ jsr initconio ; Initialize conio stuff
+
+; Create the (empty) command line for the program
+
+ jsr push0 ; argc
+ jsr push0 ; argv
+
+; Execute the program code
+
+ jmp Start
+
+; ------------------------------------------------------------------------
+; Additional data that we need for initialization and that's overwritten
+; later
+
+vectable:
+ jmp $0000 ; CINT
+ jmp $0000 ; IOINIT
+ jmp $0000 ; RAMTAS
+ jmp $0000 ; RESTOR
+ jmp $0000 ; VECTOR
+ jmp $0000 ; SETMSG
+ jmp $0000 ; SECOND
+ jmp $0000 ; TKSA
+ jmp $0000 ; MEMTOP
+ jmp $0000 ; MEMBOT
+ jmp k_scnkey ; SCNKEY
+ jmp $0000 ; SETTMO
+ jmp $0000 ; ACPTR
+ jmp $0000 ; CIOUT
+ jmp $0000 ; UNTLK
+ jmp $0000 ; UNLSN
+ jmp $0000 ; LISTEN
+ jmp $0000 ; TALK
+ jmp $0000 ; READST
+ jmp k_setlfs ; SETLFS
+ jmp k_setnam ; SETNAM
+ jmp $0000 ; OPEN
+ jmp $0000 ; CLOSE
+ jmp $0000 ; CHKIN
+ jmp $0000 ; CKOUT
+ jmp $0000 ; CLRCH
+ jmp $0000 ; BASIN
+ jmp $0000 ; BSOUT
+ jmp $0000 ; LOAD
+ jmp $0000 ; SAVE
+ jmp k_settim ; SETTIM
+ jmp k_rdtim ; RDTIM
+ jmp $0000 ; STOP
+ jmp $0000 ; GETIN
+ jmp $0000 ; CLALL
+ jmp k_udtim ; UDTIM
+ jmp k_screen ; SCREEN
+ jmp k_plot ; PLOT
+ jmp k_iobase ; IOBASE
+ sta ExecReg
+ rts
+ .byte $01 ; Filler
+ .word nmi
+ .word 0 ; Reset - not used
+ .word irq
+vectable_size = * - vectable
+
+p3vectable:
+ .word k_irq ; IRQ user vector
+ .word k_brk ; BRK user vector
+ .word k_nmi ; NMI user vector
+p3vectable_size = * - p3vectable
+
+
+; ------------------------------------------------------------------------
+; This is the program code after setup. It starts at $400
+
+ .res $400-*
+
+Start:
+
+; Enable interrupts
+
+ cli
+
+; Call the user code
+
+ ldy #4 ; Argument size
+ jsr _main ; call the users code
+
+; Fall thru to exit.
+
+_exit: jsr doatexit ; call exit functions
+
+; Clear the start of the zero page, since it will be interpreted as a
+; (garbage) BASIC program otherwise. This is also the default entry for
+; the break vector.
+
+k_brk: sei
+ lda #$00
+ ldx #$3E
+Clear: sta $02,x
+ dex
+ bne Clear
+
+; Setup the welcome code at the stack bottom in the system bank. Use
+; the F4/F5 vector to access the system bank
+
+ lda #$0F
+ sta IndReg
+ ldy #$00
+ sty $F4
+ iny
+ sty $F5
+ ldy #reset_size-1
+@L1: lda reset,y
+ sta ($F4),y
+ dey
+ bne @L1
+ jmp Back
+
+; ------------------------------------------------------------------------
+; Code that is copied into the system bank at $100 when switching back
+
+reset: cli
+ jmp $8000 ; BASIC cold start
+reset_size = * - reset
+
+; ------------------------------------------------------------------------
+; Code for a few simpler kernal calls goes here
+
+k_iobase:
+ ldx cia
+ ldy cia+1
+ rts
+
+k_screen:
+ ldx #80 ; Columns
+ ldy #25 ; Lines
+ rts
+
+k_setlfs:
+ sta LogicalAdr
+ stx FirstAdr
+ sty SecondAdr
+ rts
+
+k_setnam:
+ sta FileNameLen
+ lda $00,x
+ sta FileNameAdrLo
+ lda $01,x
+ sta FileNameAdrHi
+ lda $02,x
+ sta FileNameAdrSeg
+ rts
+
+k_rdtim:
+ sei
+ lda time+0
+ ldx time+1
+ ldy time+2
+ cli
+ rts
+
+k_settim:
+ sei
+ sta time+0
+ stx time+1
+ sty time+2
+ cli
+ rts
+
+; -------------------------------------------------------------------------
+; Data area - switch back to relocatable mode
+
+ .reloc
+
+.data
+spsave: .res 1
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 28.09.1998
+;
+; Write to the CRTC.
+;
+
+ .export write_crtc, read_crtc
+ .importzp crtc
+
+ .include "cbm610.inc"
+ .include "zeropage.inc"
+
+
+; Write a value to the CRTC. The index is in Y, the value in A
+
+.proc write_crtc
+ sta sedt1
+ lda IndReg
+ pha
+ lda #$0F
+ sta IndReg
+ tya
+ ldy #$00
+ sei
+ sta (crtc),y
+ iny
+ lda sedt1
+ sta (crtc),y
+ cli
+ pla
+ sta IndReg
+ lda sedt1
+ rts
+.endproc
+
+
+.proc read_crtc
+ sty sedt1
+ lda IndReg
+ pha
+ lda #$0F
+ sta IndReg
+ lda sedt1
+ ldy #$00
+ sei
+ sta (crtc),y
+ iny
+ lda (crtc),y
+ cli
+ tay
+ pla
+ sta IndReg
+ tya
+ ldy sedt1
+ rts
+.endproc
+
+
--- /dev/null
+;
+; I/O definitions for the CBM 610
+;
+; Taken from a kernal disassembly done by myself in 1987.
+;
+; Ullrich von Bassewitz, 28.09.1998
+
+
+; I/O $d800: CRTC 6545
+
+; crtc = $d800
+
+ CAdrReg = $00
+ CDataReg = $01
+
+
+
+; I/O $da00: SID 6581
+
+; sid = $da00
+
+ Osc1 = $00
+ Osc2 = $07
+ Osc3 = $0e
+
+ FreqLo = $00
+ FreqHi = $01
+ PulseF = $02
+ PulseC = $03
+ OscCtl = $04
+ AtkDcy = $05
+ SusRel = $06
+
+ FiCtlLo = $15
+ FiCtlHi = $16
+ Resonance = $17
+ Volume = $18
+ PotX = $19
+ PotY = $1A
+ Random = $1B
+ Env3 = $1C
+
+
+
+; I/O $db00: CIA 6526 Inter Process Communication
+
+; IPCcia = $db00
+
+ PortA = $00
+ PortB = $01
+ DDRA = $02
+ DDRB = $03
+ TimALo = $04
+ TimAHi = $05
+ TimBLo = $06
+ TimBHi = $07
+ TOD10 = $08
+ TODsec = $09
+ TODmin = $0A
+ TODhour = $0B
+ SerDataReg = $0C
+ IntCtrReg = $0D
+ CtrlA = $0E
+ CtrlB = $0F
+
+
+
+; I/O $dc00: CIA 6526
+
+; cia = $dc00
+
+
+
+; I/O $dd00: ACIA 6551
+
+; acia = $dd00
+
+ ADataReg = $00
+ AStatusReg = $01
+ ACmdReg = $02
+ ACtrlReg = $03
+
+
+
+; I/O $de00: Triport #1 6525
+
+; tpi1 = $de00
+
+ tpiPortA = $00
+ tpiPortB = $01
+ tpiPortC = $02
+ tpiIntLatch = $02
+ tpiDDRA = $03
+ tpiDDRB = $04
+ tpiDDRC = $05
+ tpiIntMask = $05
+ tpiCtrlReg = $06
+ tpiActIntReg = $07
+
+
+
+; I/O $df00: Triport #2 6525
+
+; tpi2 = $df00
+
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; int kbhit (void);
+;
+
+ .export _kbhit
+ .import return0, return1
+
+ .include "zeropage.inc"
+
+.proc _kbhit
+ lda KeyIndex ; Get number of characters
+ bne L1
+ jmp return0
+L1: jmp return1
+.endproc
+
+
+
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 28.09.1998
+;
+; IRQ routine for the 610.
+;
+
+ .export irq, nmi, k_irq, k_nmi
+ .import k_scnkey, k_udtim, k_rs232
+ .importzp tpi1
+
+ .include "zeropage.inc"
+ .include "io.inc"
+ .include "page3.inc"
+
+
+; -------------------------------------------------------------------------
+; This is the mapping of the active irq register of the 6525 (tpi1):
+;
+; Bit 7 6 5 4 3 2 1 0
+; | | | | ^ 50 Hz
+; | | | ^ SRQ IEEE 488
+; | | ^ cia
+; | ^ IRQB ext. Port
+; ^ acia
+
+
+
+; -------------------------------------------------------------------------
+; IRQ entry point
+
+.proc irq
+
+ pha
+ txa
+ pha
+ tya
+ pha
+ tsx
+ lda $104,x ; Get the flags from the stack
+ and #$10 ; Test break flag
+ bne L1
+ jmp (IRQVec)
+L1: jmp (BRKVec)
+
+.endproc
+
+; -------------------------------------------------------------------------
+; NMI entry point
+
+.proc nmi
+
+ jmp (NMIVec)
+
+.endproc
+
+
+; -------------------------------------------------------------------------
+; Kernal irq entry point. The IRQvec points here (usually).
+
+k_irq:
+ lda IndReg ; Ind. Segment retten
+ pha
+ cld
+ lda #$0F
+ sta IndReg
+ ldy #tpiActIntReg
+ lda (tpi1),y ; Interrupt Register 6525
+ beq noirq
+
+; -------------------------------------------------------------------------
+; 50/60Hz interrupt
+
+ cmp #%00000001 ; ticker irq?
+ bne irq1
+ jsr k_scnkey ; Poll the keyboard
+ jsr k_udtim ; Bump the time
+
+; -------------------------------------------------------------------------
+; UART interrupt
+
+irq1: cmp #%00010000 ; interrupt from uart?
+ bne irqend
+ jsr k_rs232 ; Read character from uart
+
+; -------------------------------------------------------------------------
+; Done
+
+irqend: ldy #tpiActIntReg
+ sta (tpi1),y ; Clear interrupt
+
+noirq: pla
+ sta IndReg
+ pla
+ tay
+ pla
+ tax
+ pla
+k_nmi: rti
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 28.09.1998
+;
+; PLOT routine for the 610.
+;
+
+ .export k_plot
+ .importzp crtc
+
+ .include "zeropage.inc"
+
+
+.proc k_plot
+
+ bcc set
+ ldx CURS_Y
+ ldy CURS_X
+ rts
+
+set: stx CURS_Y
+ sty CURS_X
+ lda LineLSBTab,x
+ sta CharPtr
+ lda LineMSBTab,x
+ sta CharPtr+1
+
+ lda IndReg
+ pha
+ lda #$0F
+ sta IndReg
+
+ ldy #$00
+ clc
+ sei
+ sta (crtc),y
+ lda CharPtr
+ adc CURS_X
+ iny
+ sta (crtc),y
+ dey
+ lda #$0E
+ sta (crtc),y
+ iny
+ lda (crtc),y
+ and #$F8
+ sta sedt1
+ lda CharPtr+1
+ adc #$00
+ and #$07
+ ora sedt1
+ sta (crtc),y
+ cli
+
+ pla
+ sta IndReg
+ rts
+.endproc
+
+; -------------------------------------------------------------------------
+; Low bytes of the start address of the screen lines
+
+.rodata
+
+LineLSBTab:
+ .byte $00,$50,$A0,$F0,$40,$90,$E0,$30
+ .byte $80,$D0,$20,$70,$C0,$10,$60,$B0
+ .byte $00,$50,$A0,$F0,$40,$90,$E0,$30
+ .byte $80
+; -------------------------------------------------------------------------
+; High bytes of the start address of the screen lines
+
+LineMSBTab:
+ .byte $D0,$D0,$D0,$D0,$D1,$D1,$D1,$D2
+ .byte $D2,$D2,$D3,$D3,$D3,$D4,$D4,$D4
+ .byte $D5,$D5,$D5,$D5,$D6,$D6,$D6,$D7
+ .byte $D7
--- /dev/null
+;
+; Ullrich von Bassewitz, 28.09.1998
+;
+; Keyboard polling stuff for the 610.
+;
+
+ .export k_scnkey
+ .importzp tpi2, ktab1, ktab2, ktab3, ktab4
+
+ .include "zeropage.inc"
+ .include "io.inc"
+ .include "page3.inc"
+
+
+.proc k_scnkey
+
+ lda #$FF
+ sta ModKey
+ sta NorKey
+ lda #$00
+ sta KbdScanBuf
+ ldy #tpiPortB
+ sta (tpi2),y
+ ldy #tpiPortA
+ sta (tpi2),y
+ jsr Poll
+ and #$3F
+ eor #$3F
+ bne L1
+ jmp NoKey
+
+L1: lda #$FF
+ ldy #tpiPortA
+ sta (tpi2),y
+ asl a
+ ldy #tpiPortB
+ sta (tpi2),y
+ jsr Poll
+ pha
+ sta ModKey
+ ora #$30
+ bne L3 ; Branch always
+
+L2: jsr Poll
+L3: ldx #$05
+ ldy #$00
+L4: lsr a
+ bcc L5
+ inc KbdScanBuf
+ dex
+ bpl L4
+ sec
+ ldy #tpiPortB
+ lda (tpi2),y
+ rol a
+ sta (tpi2),y
+ ldy #tpiPortA
+ lda (tpi2),y
+ rol a
+ sta (tpi2),y
+ bcs L2
+ pla
+ bcc NoKey ; Branch always
+
+L5: ldy KbdScanBuf
+ sty NorKey
+ pla
+ asl a
+ asl a
+ asl a
+ bcc L6
+ bmi L7
+ lda (ktab2),y ; Shifted normal key
+ ldx GrafMode
+ beq L8
+ lda (ktab3),y ; Shifted key in graph mode
+ bne L8
+
+L6: lda (ktab4),y ; Key with ctrl pressed
+ bne L8
+L7: lda (ktab1),y ; Normal key
+L8: tax
+ cpx #$FF ; Valid key?
+ beq Done
+ cpy LastIndex
+ beq Repeat
+ ldx #$13
+ stx RepeatDelay
+ ldx KeyIndex
+ cpx #$09
+ beq NoKey
+ cpy #$59
+ bne PutKey
+ cpx #$08
+ beq NoKey
+ sta KeyBuf,x
+ inx
+ bne PutKey
+
+NoKey: ldy #$FF
+Done: sty LastIndex
+End: lda #$7F
+ ldy #tpiPortA
+ sta (tpi2),y
+ ldy #tpiPortB
+ lda #$FF
+ sta (tpi2),y
+ rts
+
+Repeat: dec RepeatDelay
+ bpl End
+ inc RepeatDelay
+ dec RepeatCount
+ bpl End
+ inc RepeatCount
+ ldx KeyIndex
+ bne End
+
+PutKey: sta KeyBuf,x
+ inx
+ stx KeyIndex
+ ldx #$03
+ stx RepeatCount
+ bne Done
+
+.endproc
+
+
+; Poll the keyboard port until it's stable
+
+.proc Poll
+ ldy #tpiPortC
+L1: lda (tpi2),y
+ sta KeySave
+ lda (tpi2),y
+ cmp KeySave
+ bne L1
+ rts
+.endproc
+
+
+.bss
+
+KeySave: .res 1
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 28.09.1998
+;
+; udtim routine for the 610. We will not check for the stop key here, since
+; C programs will not use it.
+;
+
+ .export k_udtim
+ .importzp time
+
+
+.proc k_udtim
+
+ inc time
+ bne L9
+ inc time+1
+ bne L9
+ inc time+2
+ bne L9
+ inc time+3
+L9: rts
+
+.endproc
+
+
--- /dev/null
+;
+; Page 3 variables for the CBM 610
+;
+; Taken from a kernal disassembly done by myself in 1987.
+;
+; Ullrich von Bassewitz, 28.09.1998
+
+
+;
+; system ram vectors
+;
+
+IRQVec = $0300
+BRKVec = $0302
+NMIVec = $0304
+openVec = $0306
+closeVec = $0308
+chkinVec = $030A
+ckoutVec = $030C
+clrchVec = $030E
+basinVec = $0310
+bsoutVec = $0312
+stopVec = $0314
+getinVec = $0316
+clallVec = $0318
+loadVec = $031A
+saveVec = $031C
+usrcmd = $031E
+escvec = $0320
+ctrlvec = $0322
+secndVec = $0324
+tksaVec = $0326
+acptrVec = $0328
+cioutVec = $032A
+untlkVec = $032C
+unlsnVec = $032E
+listnVec = $0330
+talkVec = $0332
+
+;
+;
+;
+
+LogicalAdrTable = $0334
+FirstAdrTable = $033E
+SecondAdrTable = $0348
+SysMemBot = $0352
+SysMemTop = $0355
+UsrMemBot = $0358
+UsrMemTop = $035B
+TimOut = $035E
+VerifyFlag = $035F
+DevTabIndex = $0360
+MsgFlag = $0361
+CassBufPtr = $0362
+t1 = $0363
+t2 = $0364
+XSave = $0365
+SaveX = $0366
+SaveXt = $0367
+temp = $0368
+alarm = $0369
+TapeVec = $036A
+LoadStAdr = $036F
+CassMotFlag = $0375
+m6551Ctrl = $0376
+m6551Cmd = $0377
+rs232status = $037A
+dcddsr = $037B
+rs232head = $037C
+rs232tail = $037D
+PgmKeyEnd = $0380
+PgmKeySeg = $0382
+PgmKeySize = $0383
+rvsFlag = $0397
+linetmp = $0398
+LastPrtChar = $0399
+InsertFlag = $039A
+ScrollFlag = $039B
+FktTemp = $039C
+PgmKeyIdx = $039D
+LogScrollFlag = $039E
+BellMode = $039F ; Bell on/off 00 = an
+SegSave = $03A0
+TabStopTable = $03A1 ; 80 bits for tabstops
+KeyBuf = $03AB ; Keyboard buffer
+funvec = $03B5 ; Vector for function key handline
+FunKeyTmp = $03B7
+sedt3 = $03B9
+MoniSegSave = $03f0
+wstvec = $03F8
+WstFlag = $03FA ; Warm start flag
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 29.09.1998
+;
+; void pokebsys (unsigned Addr, unsigned char Val);
+; void pokewsys (unsigned Addr, unsigned Val);
+
+ .export _pokebsys, _pokewsys
+ .import popsreg
+ .importzp sreg, tmp1
+
+ .include "zeropage.inc"
+
+
+_pokebsys:
+ jsr popsreg ; Get the address
+ ldx IndReg
+ ldy #$0F
+ sty IndReg ; Switch to the system bank
+ ldy #$00
+ sta (sreg),y
+ stx IndReg
+ rts
+
+_pokewsys:
+ stx tmp1 ; Save high byte
+ jsr popsreg ; Get the address
+ ldx IndReg
+ ldy #$0F
+ sty IndReg ; Switch to the system bank
+ ldy #$00
+ sta (sreg),y
+ iny
+ lda tmp1
+ sta (sreg),y
+ stx IndReg
+ rts
+
+
--- /dev/null
+;
+; SwiftLink/Turbo-232 v0.90 device driver, by Craig Bruce, 14-Apr-1998.
+;
+; This software is Public Domain. It is in Buddy assembler format.
+;
+; This device driver uses the SwiftLink RS-232 Serial Cartridge, available from
+; Creative Micro Designs, Inc, and also supports the extensions of the Turbo232
+; Serial Cartridge. Both devices are based on the 6551 ACIA chip. It also
+; supports the "hacked" SwiftLink with a 1.8432 MHz crystal.
+;
+; The code assumes that the kernal + I/O are in context. On the C128, call
+; it from Bank 15. On the C64, don't flip out the Kernal unless a suitable
+; NMI catcher is put into the RAM under then Kernal. For the SuperCPU, the
+; interrupt handling assumes that the 65816 is in 6502-emulation mode.
+;
+;--------------------------------------------------------------------------
+;
+; Adapted for the use with the cc65 runtime library by
+; Ullrich von Bassewitz (uz@musoftware.de) 02-May-1999.
+;
+; All external functions are C callable, the return value is an error code.
+;
+
+
+ .importzp ptr1, ptr2, tmp1, tmp2
+ .importzp acia, RecvBuf, SendBuf
+ .import popa, popax
+ .import sys_bank, restore_bank
+ .export _rs232_init, _rs232_params, _rs232_done, _rs232_get
+ .export _rs232_put, _rs232_pause, _rs232_unpause, _rs232_status
+ .export k_rs232
+
+ .include "zeropage.inc"
+
+
+;----------------------------------------------------------------------------
+;
+; Global variables
+;
+
+.bss
+DropCnt: .res 4 ; Number of bytes lost from rx buffer full
+Initialized: .res 1 ; Flag indicating driver is initialized
+Stopped: .res 1 ; Flow-stopped flag
+RtsOff: .res 1 ;
+Errors: .res 1 ; Number of bytes received in error, low byte
+BaudCode: .res 1 ; Current baud in effect
+
+; Segment, the RS232 buffers are in
+BufferSeg = 2
+
+; UART register offsets
+RegData = 0 ; Data register
+RegStatus = 1 ; Status register
+RegCommand = 2 ; Command register
+RegControl = 3 ; Control register
+
+; Error codes. Beware: The codes must match the codes in the C header file
+ErrNotInitialized = $01
+ErrBaudTooFast = $02
+ErrBaudNotAvail = $03
+ErrNoData = $04
+ErrOverflow = $05
+
+
+.code
+
+;----------------------------------------------------------------------------
+;
+; unsigned char __fastcall__ rs232_init (char hacked);
+; /* Initialize the serial port, install the interrupt handler. The parameter
+; * must be true (non zero) for a hacked swiftlink and false (zero) otherwise.
+; */
+;
+
+_rs232_init:
+ bit Initialized ;** shut down if started
+ bpl @L1
+ pha
+ jsr _rs232_done
+ pla
+
+; Initialize buffers & control
+
+@L1: lda #0
+ sta RecvHead
+ sta SendHead
+ sta RecvTail
+ sta SendTail
+ sta Errors
+ sta Stopped
+ lda #255
+ sta RecvFreeCnt
+ sta SendFreeCnt
+
+; Set default to 2400-8N1, enable interrupts
+
+ jsr sys_bank ; Switch indirect to system bank
+
+ ldy #RegData
+ lda (acia),y
+ ldy #RegStatus
+ lda (acia),y
+ lda #$18
+ ldy #RegControl
+ sta (acia),y
+
+ lda #$01
+ sta RtsOff
+ ora #$08
+ ldy #RegCommand
+ sta (acia),y
+ lda #$06
+ sta BaudCode
+
+ jsr restore_bank
+
+ lda #$ff
+ sta Initialized
+ lda #$00
+ tax
+ rts
+
+;----------------------------------------------------------------------------
+;
+; unsigned char __fastcall__ rs232_params (unsigned char params, unsigned char parity);
+; /* Set the port parameters. Use a combination of the #defined values above. */
+;
+; Set communication parameters.
+;
+; baud rates stops word | parity
+; --------------------- ----- ----- | ---------
+; $00=50 $08=9600 $00=1 $00=8 | $00=none
+; $01=110 $09=19200 $80=2 $20=7 | $20=odd
+; $02=134.5 $0a=38400 $40=6 | $60=even
+; $03=300 $0b=57600 $60=5 | $A0=mark
+; $04=600 $0c=115200 | $E0=space
+; $05=1200 $0d=230400
+; $06=2400 $0e=future
+; $07=4800 $0f=future
+;
+
+_rs232_params:
+ jsr CheckInitialized ;** check initialized
+ bcc @L1
+ rts
+
+; Save new parity
+
+@L1: and #%11100000
+ ora #%00000001
+ sta tmp2
+
+; Set baud/parameters
+
+ jsr popa
+ sta tmp1
+ and #$0f
+ tax
+ lda Bauds,x
+ cmp #$ff
+ bne @L5
+ lda #ErrBaudNotAvail
+ bne @L9
+
+@L5: jsr sys_bank ; Indirect segment to system bank
+ tax
+ lda tmp1
+ and #$0f
+ sta BaudCode
+ lda tmp1
+ and #%11100000
+ ora #%00010000
+ sta tmp1
+ txa
+ and #$0f
+ ora tmp1
+ ldy #RegControl
+ sta (acia),y
+
+; Set new parity
+
+@L7: lda tmp2
+ sta RtsOff
+ ora #%00001000
+ ldy #RegCommand
+ sta (acia),y
+ jsr restore_bank ; Restore indirect bank
+ lda #0
+@L9: ldx #0
+ rts
+
+.rodata
+Bauds:
+ .byte $01,$03,$04,$06,$07,$08,$0a,$0c,$0e,$0f,$ff,$ff,$ff,$ff,$ff,$ff
+ ;in: 0 1 2 3 4 5 6 7 8 9 a b c d e f
+ ;baud50 110 134 3 6 12 24 48 96 19 38 57 115 230 exp exp
+ ;out masks: $0F=Baud, val$FF=err
+.code
+
+;----------------------------------------------------------------------------
+;
+; unsigned char __fastcall__ rs232_done (void);
+; /* Close the port, deinstall the interrupt hander. You MUST call this function
+; * before terminating the program, otherwise the machine may crash later. If
+; * in doubt, install an exit handler using atexit(). The function will do
+; * nothing, if it was already called.
+; */
+;
+
+
+_rs232_done:
+ bit Initialized ;** check initialized
+ bpl @L9
+
+; Stop interrupts, drop DTR
+
+ lda RtsOff
+ and #%11100010
+ ora #%00000010
+ ldx IndReg
+ ldy #$0F
+ sty IndReg ; Set indirect to system bank
+ ldy #RegCommand
+ sta (acia),y
+ stx IndReg ; Restore old indirect bank
+
+; Flag uninitialized
+
+@L9: lda #$00
+ sta Initialized
+ tax
+ rts
+
+;----------------------------------------------------------------------------
+;
+; unsigned char __fastcall__ rs232_get (char* B);
+; /* Get a character from the serial port. If no characters are available, the
+; * function will return RS_ERR_NO_DATA, so this is not a fatal error.
+; */
+;
+
+_rs232_get:
+ jsr CheckInitialized ; Check if initialized
+ bcc @L1
+ rts
+
+; Check for bytes to send
+
+@L1: sta ptr1
+ stx ptr1+1 ; Store pointer to received char
+ ldx SendFreeCnt
+ cpx #$ff
+ beq @L2
+ lda #$00
+ jsr TryToSend
+
+; Check for buffer empty
+
+@L2: lda RecvFreeCnt
+ cmp #$ff
+ bne @L3
+ lda #ErrNoData
+ ldx #0
+ rts
+
+; Check for flow stopped & enough free: release flow control
+
+@L3: ldx Stopped
+ beq @L4
+ cmp #63
+ bcc @L4
+ lda #$00
+ sta Stopped
+ lda RtsOff
+ ora #%00001000
+ ldx IndReg
+ ldy #$0F ; Set indirect to system bank
+ sty IndReg
+ ldy #RegCommand
+ sta (acia),y
+ stx IndReg
+
+; Get byte from buffer
+
+@L4: ldx IndReg
+ lda #BufferSeg ; Set indirect to buffer bank
+ sta IndReg
+ ldy RecvHead
+ lda (RecvBuf),y
+ stx IndReg ; Restore indirect bank
+ inc RecvHead
+ inc RecvFreeCnt
+ ldx #$00
+ sta (ptr1,x)
+ txa ; Return code = 0
+ rts
+
+;----------------------------------------------------------------------------
+;
+; unsigned char __fastcall__ rs232_put (char B);
+; /* Send a character via the serial port. There is a transmit buffer, but
+; * transmitting is not done via interrupt. The function returns
+; * RS_ERR_OVERFLOW if there is no space left in the transmit buffer.
+; */
+;
+
+_rs232_put:
+ jsr CheckInitialized ; Check initialized
+ bcc @L1
+ rts
+
+; Try to send
+
+@L1: ldx SendFreeCnt
+ cpx #$ff
+ beq @L2
+ pha
+ lda #$00
+ jsr TryToSend
+ pla
+
+; Put byte into send buffer & send
+
+@L2: ldx SendFreeCnt
+ bne @L3
+ lda #ErrOverflow
+ ldx #$00
+ rts
+
+; There is enough room (character still in A)
+
+@L3: ldx IndReg
+ ldy #BufferSeg ; Set indirect to buffer segment
+ sty IndReg
+ ldy SendTail
+ sta (SendBuf),y
+ stx IndReg ; Restore indirect bank
+ inc SendTail
+ dec SendFreeCnt
+ lda #$ff
+ jsr TryToSend
+ lda #$00
+ tax
+ rts
+
+;----------------------------------------------------------------------------
+;
+; unsigned char __fastcall__ rs232_pause (void);
+; /* Assert flow control and disable interrupts. */
+;
+
+_rs232_pause:
+; Check initialized
+ jsr CheckInitialized
+ bcc @L1
+ rts
+
+; Assert flow control
+
+@L1: lda RtsOff
+ sta Stopped
+ jsr sys_bank ; Set indirect to system bank
+ ldy #RegCommand
+ sta (acia),y
+
+; Delay for flow stop to be received
+
+ ldx BaudCode
+ lda PauseTimes,x
+ jsr DelayMs
+
+; Stop rx interrupts
+
+ lda RtsOff
+ ora #$02
+ ldy #RegCommand
+ sta (acia),y
+ jsr restore_bank ; Restore indirect segment
+ lda #0
+ tax
+ rts
+
+
+.rodata
+; Delay times: 32 byte-receive times in milliseconds, or 100 max.
+; Formula = 320,000 / baud
+PauseTimes:
+ .byte 100,100,100,100,100,100,100,067,034,017,009,006,003,002,001,001
+ ;in: 0 1 2 3 4 5 6 7 8 9 a b c d e f
+ ;baud50 110 134 3 6 12 24 48 96 19 38 57 115 230 exp exp
+.code
+
+;----------------------------------------------------------------------------
+;
+; unsigned char __fastcall__ rs232_unpause (void);
+; /* Re-enable interrupts and release flow control */
+;
+
+_rs232_unpause:
+; Check initialized
+ jsr CheckInitialized
+ bcc @L1
+ rts
+
+; Re-enable rx interrupts & release flow control
+
+@L1: lda #$00
+ sta Stopped
+ lda RtsOff
+ ora #%00001000
+ ldx IndReg
+ ldy #$0F
+ sty IndReg ; Set indirect to system bank
+ ldy #RegCommand
+ sta (acia),y
+ stx IndReg ; Restore indirect bank
+
+; Poll for stalled char & exit
+
+ jsr PollReceive
+ lda #0
+ tax
+ rts
+
+;----------------------------------------------------------------------------
+;
+; unsigned char __fastcall__ rs232_status (unsigned char* status,
+; unsigned char* errors);
+; /* Return the serial port status. */
+;
+
+_rs232_status:
+ sta ptr2
+ stx ptr2+1
+ jsr popax
+ sta ptr1
+ stx ptr1+1
+ jsr CheckInitialized
+ bcs @L9
+
+; Get status
+
+ ldx IndReg ; Save indirect segment
+ lda #$0F
+ sta IndReg ; Set system bank as indirect segment
+ ldy #RegStatus
+ lda (acia),y ; Read status register
+ stx IndReg
+ ldy #0
+ sta (ptr1),y
+ jsr PollReceive ; bug-recovery hack
+ lda Errors
+ ldy #0
+ sta (ptr2),y
+ tya
+ tax
+@L9: rts
+
+;----------------------------------------------------------------------------
+;
+; RS232 interrupt handler.
+; The RS232 handler will be called with the system bank as indirect bank
+; and all registers saved.
+;
+
+k_rs232:
+ ldy #RegStatus
+ lda (acia),y ; check for byte received
+ and #$08
+ beq @L9 ; Nothing to receive
+ lda (acia),y ; check for receive errors
+ and #$07
+ beq @L1
+ inc Errors
+@L1: ldy #RegData
+ lda (acia),y ; get byte and put into receive buffer
+ ldx RecvFreeCnt
+ beq @L3
+ ldy #BufferSeg
+ sty IndReg
+ ldy RecvTail
+ sta (RecvBuf),y ; Store received character
+ lda #$0F
+ sta IndReg ; Restore indirect segment
+ inc RecvTail
+ dec RecvFreeCnt
+ cpx #33 ; check for buffer space low
+ bcs @L9
+
+; Assert flow control
+
+@L2: lda RtsOff ; assert flow control if buffer space too low
+ ldy #RegCommand
+ sta (acia),y
+ sta Stopped
+ rts
+
+; Drop this char
+
+@L3: inc DropCnt+0 ;not time-critical
+ bne @L9
+ inc DropCnt+1
+ bne @L9
+ inc DropCnt+2
+ bne @L9
+ inc DropCnt+3
+@L9: rts
+
+
+;----------------------------------------------------------------------------
+;
+; CheckInitialized - internal check if initialized
+; Set carry and an error code if not initialized, clear carry and do not
+; change any registers if initialized.
+;
+
+CheckInitialized:
+ bit Initialized
+ bmi @L1
+ lda #ErrNotInitialized
+ ldx #0
+ sec
+ rts
+
+@L1: clc
+ rts
+
+;----------------------------------------------------------------------------
+; Try to send a byte. Internal routine. A = TryHard
+
+TryToSend:
+ sta tmp1 ; Remember tryHard flag
+ ldx IndReg ; Save indirect segment
+ lda #$0F
+ sta IndReg ; Set system segment as indirect segment
+@L0: lda SendFreeCnt
+ cmp #$ff
+ beq @L3 ; Bail out
+
+; Check for flow stopped
+
+@L1: lda Stopped
+ bne @L3 ; Bail out
+
+; Check that the UART is ready to send
+
+@L2: ldy #RegStatus
+ lda (acia),y
+ and #$10
+ bne @L4
+ bit tmp1 ; Keep trying if must try hard
+ bmi @L0
+@L3: stx IndReg ; Restore indirect segment
+ rts
+
+; Send byte and try again
+
+@L4: lda #BufferSeg
+ sta IndReg
+ ldy SendHead
+ lda (SendBuf),y
+ ldy #$0F
+ sty IndReg
+ ldy #RegData
+ sta (acia),y
+ inc SendHead
+ inc SendFreeCnt
+ jmp @L0
+
+
+;----------------------------------------------------------------------------
+;
+; PollReceive - poll for rx char
+; This function is useful in odd cases where the 6551 has a character in
+; it but it fails to raise an NMI. It might be edge-triggering conditions?
+; Actually, I'm not entirely sure that this condition can still arrise, but
+; calling this function does no harm.
+;
+
+PollReceive:
+ ldx IndReg ; Save indirect segment
+ lda #$0F
+ sta IndReg ; Set system bank as indirect segment
+ ldy #RegStatus
+ lda (acia),y
+ and #$08
+ beq @L9
+ lda (acia),y ; Read a second time? ###
+ and #$08
+ beq @L9
+ ldy #RegData
+ lda (acia),y
+ ldy RecvFreeCnt
+ beq @L9
+ ldy #BufferSeg
+ sty IndReg
+ ldy RecvTail
+ sta (RecvBuf),y
+ inc RecvTail
+ dec RecvFreeCnt
+@L9: stx IndReg ; Restore indirect segment
+ rts
+
+;----------------------------------------------------------------------------
+;
+; DelayMs : delay for given number of milliseconds
+; This implementation isn't very rigerous; it merely delays for the
+; approximate number of clock cycles for the processor speed.
+; Algorithm:
+; repeat for number of milliseconds:
+; repeat for number of MHz of cpu speed:
+; delay for 1017 clock cycles
+;
+
+DelayMs: ;( .A=milliseconds )
+@L1: ldy #2 ; 2MHz
+@L2: ldx #203 ;(2)
+@L3: dex ;(2)
+ bne @L3 ;(3) // 1017 cycles
+ dey
+ bne @L2
+ sec
+ sbc #1
+ bne @L1
+ rts
+
+.end
+
+
+
--- /dev/null
+;
+; Zero page variables for the CBM 610
+;
+; Taken from a kernal disassembly done by myself in 1987.
+;
+; Ullrich von Bassewitz, 28.09.1998
+
+
+ExecReg = $0000
+IndReg = $0001
+
+; Up to $20 and $60-8F used by runtime and fixed values
+; -----------------------------------
+
+KbdScanBuf = $20 ; Intermediate for keyboard scan
+; RS232 stuff
+RecvHead = $21 ; Head of receive buffer
+RecvTail = $22 ; Tail of receive buffer
+RecvFreeCnt = $23 ; Number of bytes in receive buffer
+SendHead = $24 ; Head of send buffer
+SendTail = $25 ; Tail of send buffer
+SendFreeCnt = $26 ; Number of bytes free in send buffer
+
+FileNameAdrLo = $90
+FileNameAdrHi = $91
+FileNameAdrSeg = $92
+SaveAdrLow = $93
+SaveAdrHi = $94
+SaveAdrSeg = $95
+EndAdrLow = $96
+EndAdrHi = $97
+EndAdrSeg = $98
+StartAdrLow = $99
+StartAdrHi = $9A
+StartAdrSeg = $9B
+Status = $9C
+FileNameLen = $9D
+LogicalAdr = $9E
+FirstAdr = $9F
+SecondAdr = $A0
+DefInpDev = $A1
+DefOutDev = $A2
+TapeBufPtr = $A3
+TapeBufPtrSeg = $A5
+rs232BufPtr = $A6
+rs232BufPtrSeg = $A8
+StopKeyFlag = $A9
+CTemp = $AA
+snsw1 = $AB
+SegChgPtr = $AC
+PChighSave = $AE
+PClowSave = $AF
+SRSave = $B0
+ACSave = $B1
+XRSave = $B2
+YRSave = $B3
+SPSave = $B4
+IndSegSave = $B5
+IRQSaveHi = $B7
+IRQSaveLo = $B8
+Adr1 = $B9
+Adr2 = $BB
+MoniCntr = $BD
+MoniTmp = $BE
+MoniDevNr = $BF
+PgmKeyBuf = $C0
+PgmKeyPtr = $C2
+sedsal = $C4
+sedeal = $C6
+CharPtr = $C8
+CURS_Y = $CA
+CURS_X = $CB
+GrafMode = $CC
+LastIndex = $CD
+LastLine = $CE
+LastCol = $CF
+crsw = $D0
+KeyIndex = $D1
+QuoteSw = $D2
+Insrt = $D3
+Config = $D4
+LastLinePos = $D5
+PgmKeyIndex = $D6
+RepeatCount = $D7
+RepeatDelay = $D8
+sedt1 = $D9 ; Temp
+sedt2 = $DA ; Temp, frequently used
+PrtData = $DB
+ScreenTop = $DC
+ScreenBot = $DD
+ScreenLeft = $DE
+ScreenRight = $DF
+ModKey = $E0
+NorKey = $E1
+BitTable = $E2
+
+
+
+
+
--- /dev/null
+fclose.s
+fgets.s
+fprintf.s
+strdup.s
+calloc.s
+_fopen.s
+fputs.s
+fread.s
+fwrite.s
+gets.s
+realloc.s
+bsearch.s
+printf.s
+_hextab.s
+malloc.s
+free.s
+vfprintf.s
+fdopen.s
+_afailed.s
+fopen.s
+fgetc.s
+fputc.s
+puts.s
+_printf.s
+vprintf.s
+vsprintf.s
+sprintf.s
+abort.s
+errormsg.s
+_hadd.s
+cprintf.s
+vcprintf.s
+freopen.s
+perror.s
+qsort.s
+strxfrm.s
+strtok.s
+locale.s
+putchar.s
+getchar.s
--- /dev/null
+#
+# makefile for CC65 runtime library
+#
+
+.SUFFIXES: .o .s .c
+
+%.o: %.c
+ @echo $<
+ @$(CC) $(CFLAGS) $<
+ @$(AS) -g -o $@ $(AFLAGS) $(*).s
+
+%.o: %.s
+ @echo $<
+ @$(AS) -g -o $@ $(AFLAGS) $<
+
+C_OBJS = fclose.o fgets.o fprintf.o strdup.o calloc.o _fopen.o\
+ fputs.o fread.o fwrite.o gets.o realloc.o bsearch.o strxfrm.o\
+ printf.o _hextab.o malloc.o free.o vfprintf.o fdopen.o strtok.o\
+ _afailed.o fopen.o fgetc.o fputc.o puts.o gets.o perror.o getchar.o\
+ _printf.o vprintf.o vsprintf.o sprintf.o abort.o qsort.o putchar.o\
+ errormsg.o _hadd.o cprintf.o vcprintf.o freopen.o locale.o
+
+S_OBJS = isalpha.o isdigit.o _file.o fmisc.o strlower.o strchr.o tolower.o\
+ toupper.o errno.o strcpy.o strlen.o strcat.o strcmp.o itoa.o\
+ strupper.o isalpha.o isalnum.o isgraph.o islower.o isupper.o\
+ isprint.o ispunct.o isspace.o isxdigit.o isblank.o strrchr.o\
+ _stksize.o _heap.o stricmp.o strncmp.o strncpy.o atoi.o setjmp.o\
+ longjmp.o rand.o atexit.o memset.o memcpy.o memchr.o memcmp.o\
+ ltoa.o strcspn.o strncat.o strpbrk.o strspn.o abs.o labs.o jmpvec.o\
+ _fdesc.o stkcheck.o zerobss.o copydata.o _swap.o strstr.o strcoll.o\
+ _sys.o getcpu.o _oserror.o strerror.o
+
+all: $(C_OBJS) $(S_OBJS)
+
+clean:
+ @rm -f *~
+ @rm -f $(C_OBJS:.o=.s)
+ @rm -f $(C_OBJS)
+ @rm -f $(S_OBJS)
--- /dev/null
+/*
+ * _afailed.c
+ *
+ * Ullrich von Bassewitz, 06.06.1998
+ */
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+
+
+void _afailed (char* file, unsigned line)
+{
+ fprintf (stderr, "ASSERTION FAILED IN %s(%u)\n", file, line);
+ exit (2);
+}
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 17.06.1998
+;
+; int _fdesc (void);
+; /* Find a free descriptor slot */
+
+
+ .export __fdesc
+ .import return0, __filetab
+ .importzp tmp1
+
+__fdesc:
+ ldy #0
+L1: lda __filetab+1,y ; load flags
+ beq L2 ; jump if empty (== CLOSED)
+ iny
+ iny
+ cpy #16 ; Done?
+ bne L1
+
+; File table is full
+
+ jmp return0
+
+; Free slot found
+
+L2: sty tmp1 ; Offset
+ lda #<__filetab
+ ldx #>__filetab
+ clc
+ adc tmp1
+ tay
+ txa
+ adc #0
+ tax
+ tya
+ rts
+
+
--- /dev/null
+/*
+ * _file.h
+ *
+ * Ullrich von Bassewitz, 02.06.1998
+ *
+ */
+
+
+
+#ifndef __FILE_H
+#define __FILE_H
+
+
+
+#include <stdio.h>
+
+
+
+/* Definition of struct _FILE */
+struct _FILE {
+ char f_fd;
+ char f_flags;
+};
+
+/* File table. Beware: FOPEN_MAX is hardcoded in the ASM files! */
+extern FILE _filetab [FOPEN_MAX];
+
+/* Flags field */
+#define _FCLOSED 0x00
+#define _FOPEN 0x01
+#define _FEOF 0x02
+#define _FERROR 0x04
+
+
+
+FILE* _fopen (const char* name, const char* mode, FILE* f);
+/* Open the specified file and fill the descriptor values into f */
+
+FILE* _fdesc (void);
+/* Find a free FILE descriptor */
+
+
+
+/* End of _file.h */
+#endif
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 31.05.1998
+;
+; Data for the stdio file stream.
+;
+
+ .export __filetab, _stdin, _stdout, _stderr
+
+.data
+
+__filetab:
+in: .byte 0, 1 ; stdin
+out: .byte 1, 1 ; stdout
+err: .byte 2, 1 ; stderr
+ .byte 0, 0 ; free slot
+ .byte 0, 0 ; free slot
+ .byte 0, 0 ; free slot
+ .byte 0, 0 ; free slot
+ .byte 0, 0 ; free slot
+
+_stdin:
+ .word in
+
+_stdout:
+ .word out
+
+_stderr:
+ .word err
--- /dev/null
+/*
+ * _fopen.c
+ *
+ * Ullrich von bassewitz, 17.06.1997
+ */
+
+
+
+#include <fcntl.h>
+#include <errno.h>
+#include "_file.h"
+
+
+
+static unsigned char amode_to_bmode (const char* mode)
+/* Convert ASCII mode (like for fopen) to binary mode (for open) */
+{
+ char c;
+ char flag = 0;
+ unsigned char binmode = 0;
+
+ while (c = *mode++) {
+ switch(c) {
+ case 'w':
+ binmode = O_WRONLY;
+ break;
+ case 'r':
+ binmode = O_RDONLY;
+ break;
+ case '+':
+ binmode = O_RDWR;
+ break;
+ /* a,b missing */
+ }
+ }
+ if (binmode == 0) {
+ _errno = EINVAL;
+ }
+ return binmode;
+}
+
+
+
+FILE* _fopen (const char* name, const char* mode, FILE* f)
+/* Open the specified file and fill the descriptor values into f */
+{
+ int fd;
+ unsigned char binmode;
+
+
+ /* Convert ASCII mode to binary mode */
+ if ((binmode = amode_to_bmode (mode)) == 0) {
+ /* Invalid mode, _errno already set */
+ return 0;
+ }
+
+ /* Open the file */
+ fd = open (name, binmode);
+ if (fd == -1) {
+ /* Error - _oserror is set */
+ return 0;
+ }
+
+ /* Remember fd, mark the file as opened */
+ f->f_fd = fd;
+ f->f_flags = _FOPEN;
+
+ /* Return the file descriptor */
+ return f;
+}
+
+
+
--- /dev/null
+/*
+ * _hadd.c
+ *
+ * Ullrich von Bassewitz, 19.06.1998
+ */
+
+
+
+#include <stddef.h>
+#include "_heap.h"
+
+
+
+void _hadd (void* mem, size_t size)
+/* Add an arbitrary memory block to the heap. This function is used by
+ * free(), but it does also allow usage of otherwise unused memory
+ * blocks as heap space. The given block is entered in the free list
+ * without any checks, so beware!
+ */
+{
+ struct freeblock* f;
+ struct freeblock* left;
+ struct freeblock* right;
+
+ if (size >= sizeof (struct freeblock)) {
+
+ /* Set the admin data */
+ f = (struct freeblock*) mem;
+ f->size = size;
+
+ /* Check if the freelist is empty */
+ if (_hfirst == 0) {
+
+ /* The freelist is empty until now, insert the block */
+ f->prev = 0;
+ f->next = 0;
+ _hfirst = f;
+ _hlast = f;
+
+ } else {
+
+ /* We have to search the free list. As we are doing so, we check
+ * if it is possible to combine this block with another already
+ * existing block. Beware: The block may be the "missing link"
+ * between *two* other blocks.
+ */
+ left = 0;
+ right = _hfirst;
+ while (right && f > right) {
+ left = right;
+ right = right->next;
+ }
+
+
+ /* Ok, the current block must be inserted between left and right (but
+ * beware: one of the two may be zero!). Also check for the condition
+ * that we have to merge two or three blocks.
+ */
+ if (right) {
+ /* Check if we must merge the block with the right one */
+ if (((int) f) + size == (int) right) {
+ /* Merge with the right block */
+ f->size += right->size;
+ if (f->next = right->next) {
+ f->next->prev = f;
+ } else {
+ /* This is now the last block */
+ _hlast = f;
+ }
+ } else {
+ /* No merge, just set the link */
+ f->next = right;
+ right->prev = f;
+ }
+ } else {
+ f->next = 0;
+ /* Special case: This is the new freelist end */
+ _hlast = f;
+ }
+ if (left) {
+ /* Check if we must merge the block with the left one */
+ if ((int) f == ((int) left) + left->size) {
+ /* Merge with the left block */
+ left->size += f->size;
+ if (left->next = f->next) {
+ left->next->prev = left;
+ } else {
+ /* This is now the last block */
+ _hlast = left;
+ }
+ } else {
+ /* No merge, just set the link */
+ left->next = f;
+ f->prev = left;
+ }
+ } else {
+ f->prev = 0;
+ /* Special case: This is the new freelist start */
+ _hfirst = f;
+ }
+ }
+ }
+}
+
+
+
--- /dev/null
+/*
+ * _heap.h
+ *
+ * Ullrich von Bassewitz, 03.06.1998
+ *
+ */
+
+
+
+#ifndef __HEAP_H
+#define __HEAP_H
+
+
+
+/* Space needed for administering used blocks */
+#define HEAP_ADMIN_SPACE sizeof (unsigned)
+
+/* The data type used to implement the free list.
+ * Beware: Field order is significant!
+ */
+struct freeblock {
+ unsigned size;
+ struct freeblock* next;
+ struct freeblock* prev;
+};
+
+
+
+/* Variables that describe the heap */
+extern unsigned* _horg; /* Bottom of heap */
+extern unsigned* _hptr; /* Current top */
+extern unsigned* _hend; /* Upper limit */
+extern struct freeblock* _hfirst; /* First free block in list */
+extern struct freeblock* _hlast; /* Last free block in list */
+
+
+
+/* End of _heap.h */
+
+#endif
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 03.06.1998
+;
+; Heap variables and initialization.
+;
+
+ .export __horg, __hptr, __hend, __hfirst, __hlast
+ .export __hinit
+ .import __BSS_RUN__, __BSS_SIZE__, __stksize
+ .importzp sp
+
+.data
+
+__horg:
+ .word __BSS_RUN__+__BSS_SIZE__ ; Linker calculates this symbol
+__hptr:
+ .word __BSS_RUN__+__BSS_SIZE__ ; Dito
+__hend:
+ .word __BSS_RUN__+__BSS_SIZE__
+__hfirst:
+ .word 0
+__hlast:
+ .word 0
+
+
+;
+; Initialization. Must be called from startup!
+;
+
+.code
+
+__hinit:
+ sec
+ lda sp
+ sbc __stksize
+ sta __hend
+ lda sp+1
+ sbc __stksize+1
+ sta __hend+1
+ rts
+
+
+
+
+
--- /dev/null
+/*
+ * Ullrich von Bassewitz, 11.08.1998
+ *
+ * Hex conversion table. Must be in C since the compiler will convert
+ * to the correct character set for the target platform.
+ */
+
+
+
+/* Data in this module is read-only, put it into the RODATA segment */
+#pragma dataseg ("RODATA")
+
+const unsigned char _hextab [16] = {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+};
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 16.05.2000
+;
+; extern unsigned char _oserror;
+; /* Operating system specific errors from the low level functions */
+
+
+ .export __oserror
+
+.bss
+
+__oserror:
+ .res 1
+
--- /dev/null
+/*
+ * Helper function for the printf family.
+ */
+
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include "_printf.h"
+
+
+
+/* Use static variables for locals */
+#pragma staticlocals (1);
+
+
+
+int _printf (struct outdesc* d, char* f, va_list ap)
+{
+ outfunc fout; /* Output function */
+ unsigned char type; /* variable argument type */
+ char str [20]; /* string buffer */
+ char c; /* Current format char */
+ char leftjust; /* left justify string */
+ char addsign; /* always add + or - */
+ char addblank; /* add blank instead of + */
+ char altform; /* alternate form? */
+ char padchar; /* pad with space or zeroes? */
+ char islong; /* l modifier found */
+ unsigned arglen; /* length of argument string */
+ unsigned prec; /* Precision */
+ unsigned width; /* Width of output field */
+ int i; /* Integer value */
+ long l; /* Long value */
+ char* sptr; /* pointer to argument string */
+ register char* s; /* work pointer to argument string */
+
+ /* Remember the format string in a register variable for shorter code */
+ register char* format = f;
+
+ /* Remember the output function in a local variable for speed and size */
+ fout = d->fout;
+
+ /* */
+ d->ccount = 0;
+ while (c = *format++) {
+
+ if (c != '%') {
+ fout (d, &c, 1);
+ continue;
+ }
+
+ /* %%? */
+ if (*format == '%') {
+ fout (d, format, 1);
+ ++format;
+ continue;
+ }
+
+ /* format is: %[flags][width][.precision][mod]type */
+
+ /* flags */
+ leftjust = addsign = addblank = altform = 0;
+ do {
+ switch (c = *format) {
+
+ case '-':
+ leftjust = 1;
+ break;
+
+ case '+':
+ addsign = 1;
+ break;
+
+ case '#':
+ altform = 1;
+ break;
+
+ case ' ':
+ addblank = 1;
+ break;
+
+ default:
+ goto flags_done;
+
+ }
+ ++format;
+ } while (1);
+flags_done:
+
+ /* width */
+ padchar = ' ';
+ if (*format == '0') {
+ padchar = '0';
+ ++format;
+ }
+ if (*format == '*') {
+ width = va_arg (ap, int);
+ ++format;
+ } else {
+ width = 0;
+ while (isdigit (c = *format)) {
+ width = width * 10 + (c - '0');
+ ++format;
+ }
+ }
+
+ /* precision */
+ prec = 0;
+ if (*format == '.') {
+ ++format;
+ if (*format == '*') {
+ prec = va_arg (ap, int);
+ ++format;
+ } else {
+ while (isdigit (c = *format)) {
+ prec = prec * 10 + (c - '0');
+ ++format;
+ }
+ }
+ }
+
+ /* modifiers */
+ islong = 0;
+ while (strchr ("FNhlL", c = *format)) {
+ switch (c) {
+
+ case 'l':
+ islong = 1;
+ break;
+
+ }
+ ++format;
+ }
+
+ /* Check the format specifier */
+ sptr = s = str;
+ type = *format++;
+ switch (type) {
+
+ case 'c':
+ str [0] = va_arg (ap, char);
+ str [1] = 0;
+ break;
+
+ case 'd':
+ case 'i':
+ if (addsign) {
+ *s++ = '+';
+ } else if (addblank) {
+ *s++ = ' ';
+ }
+ if (islong) {
+ ltoa (va_arg (ap, long), s, 10);
+ } else {
+ itoa (va_arg (ap, int), s, 10);
+ }
+ break;
+
+ case 'n':
+ *va_arg (ap, int*) = d->ccount;
+ continue;
+
+ case 'o':
+ if (islong) {
+ l = va_arg (ap, unsigned long);
+ if (altform && (l || prec)) {
+ *s++ = '0';
+ }
+ ultoa (l, s, 8);
+ } else {
+ i = va_arg (ap, unsigned);
+ if (altform && (i || prec)) {
+ *s++ = '0';
+ }
+ utoa (i, s, 8);
+ }
+ break;
+
+ case 's':
+ sptr = va_arg (ap, char*);
+ break;
+
+ case 'u':
+ if (islong) {
+ ultoa (va_arg (ap, unsigned long), str, 10);
+ } else {
+ utoa (va_arg (ap, unsigned), str, 10);
+ }
+ break;
+
+ case 'x':
+ case 'X':
+ if (altform) {
+ *s++ = '0';
+ *s++ = 'X';
+ }
+ if (islong) {
+ ultoa (va_arg (ap, unsigned long), s, 16);
+ } else {
+ utoa (va_arg (ap, unsigned), s, 16);
+ }
+ if (type == 'x') {
+ strlower (str);
+ }
+ break;
+
+ default:
+ /* Unknown type char - skip it */
+ continue;
+
+ }
+
+ /* Do argument string formatting */
+ arglen = strlen (sptr);
+ if (prec && prec < arglen) {
+ arglen = prec;
+ }
+ if (width > arglen) {
+ width -= arglen; /* padcount */
+ } else {
+ width = 0;
+ }
+
+ /* Do padding on the left side if needed */
+ if (!leftjust) {
+ /* argument right justified */
+ while (width) {
+ fout (d, &padchar, 1);
+ --width;
+ }
+ }
+
+ /* Output the argument string */
+ fout (d, sptr, arglen);
+
+ /* Output right padding bytes if needed */
+ if (leftjust) {
+ /* argument left justified */
+ while (width) {
+ fout (d, &padchar, 1);
+ --width;
+ }
+ }
+
+ }
+}
+
+
+
--- /dev/null
+/*
+ * _printf.h
+ *
+ * (C) Copyright 1998 Ullrich von Bassewitz (uz@ibb.schwaben.com)
+ *
+ */
+
+
+
+#ifndef __PRINTF_H
+#define __PRINTF_H
+
+
+
+/* Forward */
+struct outdesc;
+
+/* Type of the function that is called to output data */
+typedef void (*outfunc) (struct outdesc* desc, char* buf, unsigned count);
+
+
+
+struct outdesc {
+ outfunc fout; /* Routine used to output data */
+ int ccount; /* Character counter */
+ void* ptr; /* Data internal to print routine */
+ unsigned uns; /* Data internal to print routine */
+};
+
+
+
+/* Internal formatting routine */
+int _printf (struct outdesc* d, char* format, va_list ap);
+
+
+
+/* End of _printf.h */
+#endif
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 03.06.1998
+;
+; Stack default size definition
+;
+
+ .export __stksize
+
+.data
+
+__stksize:
+ .word $800 ; 2K
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 09.12.1998
+;
+; void __fastcall__ _swap (void* p, void* q, size_t size);
+;
+
+ .export __swap
+ .import popax
+ .importzp ptr1, ptr2, ptr3
+
+
+__swap: sta ptr3 ; Save size
+ stx ptr3+1
+
+ jsr popax ; Get q
+ sta ptr2
+ stx ptr2+1
+
+ jsr popax ; Get p
+ sta ptr1
+ stx ptr1+1
+
+; Prepare for swap
+
+ ldy #$00
+
+; Swap 256 byte blocks
+
+ ldx ptr3+1
+ beq @L2
+
+@L1: lda (ptr1),y
+ tax
+ lda (ptr2),y
+ sta (ptr1),y
+ txa
+ sta (ptr2),y
+ iny
+ bne @L1
+ dec ptr3+1
+ bne @L1
+
+; Swap remaining bytes (Y is zero)
+
+@L2: ldx ptr3
+ beq @L9
+
+@L3: lda (ptr1),y
+ tax
+ lda (ptr2),y
+ sta (ptr1),y
+ txa
+ sta (ptr2),y
+ iny
+ dec ptr3
+ bne @L3
+
+; Done
+
+@L9: rts
+
+
--- /dev/null
+;
+; void __fastcall__ _sys (struct regs* r);
+;
+; Ullrich von Bassewitz, 16.12.1998
+;
+
+ .export __sys
+ .import jmpvec
+ .importzp ptr1
+
+
+__sys: sta ptr1
+ stx ptr1+1 ; Save the pointer to r
+
+; Fetch the PC and store it into the jump vector
+
+ ldy #5
+ lda (ptr1),y
+ sta jmpvec+2
+ dey
+ lda (ptr1),y
+ sta jmpvec+1
+
+; Get the flags, mask unnecessary bits and push them. Push a
+
+ dey
+ lda (ptr1),y
+ and #%11001011
+ pha
+ ldy #0
+ lda (ptr1),y
+ pha
+
+; Get and assign X and Y
+
+ iny
+ lda (ptr1),y
+ tay
+ iny
+ lda (ptr1),y
+ tay
+
+; Set a and the flags, call the machine code routine
+
+ pla
+ plp
+ jsr jmpvec
+
+; Back from the routine. Save the flags and a
+
+ php
+ pha
+
+; Put the register values into the regs structure
+
+ tya
+ ldy #2
+ sta (ptr1),y
+ dey
+ txa
+ sta (ptr1),y
+ dey
+ pla
+ sta (ptr1),y
+ ldy #3
+ pla
+ sta (ptr1),y
+
+; Done
+
+ rts
+
--- /dev/null
+/*
+ * abort.c
+ *
+ * Ullrich von Bassewitz, 02.06.1998
+ */
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+
+
+void abort (void)
+{
+ fputs ("ABNORMAL PROGRAM TERMINATION\n", stderr);
+ exit (3);
+}
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 17.06.1998
+;
+; int abs (int x);
+;
+
+ .export _abs
+ .import negax
+
+_abs: dex
+ inx ; test hi byte
+ bpl L1
+ jmp negax ; Negate if negative
+L1: rts
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.06.1998
+;
+; int atexit (void (*f) (void));
+;
+
+; The exit functions
+
+ .export _atexit, doatexit
+ .import __errno, jmpvec
+
+.bss
+ecount: .byte 0 ; Really an index, inc'ed by 2
+efunc: .word 0,0,0,0,0 ; 5 exit functions
+maxcount = * - efunc
+
+
+.code
+
+_atexit:
+ ldy ecount
+ cpy #maxcount ; slot available?
+ beq E0 ; jump if no
+
+; Enter the function into the table
+
+ sta efunc,y
+ iny
+ txa
+ sta efunc,y
+ iny
+ sty ecount
+
+; Done, return zero
+
+ lda #0
+ tax
+ rts
+
+; Error, no space left
+
+E0: lda #$FF
+ sta __errno ; Use -1 until codes are defined ###
+ sta __errno+1
+ tax
+ rts
+
+; Function called from exit
+
+doatexit:
+ ldy ecount ; get index
+ beq L9 ; jump if done
+ dey
+ lda efunc,y
+ sta jmpvec+2
+ dey
+ lda efunc,y
+ sta jmpvec+1
+ sty ecount
+ ldy #0 ; number of function parms
+ jsr jmpvec
+ jmp doatexit ; next one
+
+L9: rts
+
+
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 05.06.1998
+;
+; int atoi (const char* s);
+; long atol (const char* s);
+;
+
+ .export _atoi, _atol
+ .import __ctype
+ .importzp sreg, ptr1, ptr2, tmp1
+
+;
+; Conversion routine (32 bit)
+;
+
+_atoi:
+_atol: sta ptr1 ; Store s
+ stx ptr1+1
+ ldy #0
+ sty ptr2
+ sty ptr2+1 ; initial value (32 bit)
+ sty sreg
+ sty sreg+1
+
+; Skip whitespace
+
+L1: lda (ptr1),y
+ tax
+ lda __ctype,x ; get character classification
+ and #$80 ; tab or space?
+ beq L2 ; jump if no
+ iny
+ bne L1
+ inc ptr1+1
+ bne L1 ; branch always
+
+; Check for a sign. The character is in X
+
+L2: txa ; get char
+ ldx #0 ; flag: positive
+ cmp #'+' ; ### portable?
+ beq L3
+ cmp #'-' ; ### portable?
+ bne L5
+ dex ; flag: negative
+L3: iny
+ bne L5
+ inc ptr1+1
+
+; Store the sign flag and setup for conversion
+
+L5: stx tmp1 ; remember sign flag
+
+L6: lda (ptr1),y ; get next char
+ tax
+ lda __ctype,x ; get character classification
+ and #$04 ; digit?
+ beq L8 ; done
+
+; Multiply ptr2 (the converted value) by 10
+
+ jsr mul2 ; * 2
+
+ lda sreg+1
+ pha
+ lda sreg
+ pha
+ lda ptr2+1
+ pha
+ lda ptr2
+ pha ; Save value
+
+ jsr mul2 ; * 4
+ jsr mul2 ; * 8
+
+ clc
+ pla
+ adc ptr2
+ sta ptr2
+ pla
+ adc ptr2+1
+ sta ptr2+1
+ pla
+ adc sreg
+ sta sreg
+ pla
+ adc sreg+1
+ sta sreg+1 ; x*2 + x*8 = x*10
+
+; Get the character back and add it
+
+ txa ; get char back
+ sec
+ sbc #'0' ; make numeric value
+ clc
+ adc ptr2
+ sta ptr2
+ bcc L7
+ inc ptr2+1
+ bne L7
+ inc sreg
+ bne L7
+ inc sreg+1
+
+; Next character
+
+L7: iny
+ bne L6
+ inc ptr1+1
+ bne L6
+
+; Conversion done. Be shure to negate the value if needed.
+
+L8: lda ptr2
+ ldx ptr2+1
+ ldy tmp1 ; sign
+ beq L9
+
+; Negate the 32 bit value in ptr2/sreg
+
+ sec
+ lda ptr2
+ eor #$FF
+ adc #0
+ sta ptr2
+ lda ptr2+1
+ eor #$FF
+ adc #0
+ sta ptr2+1
+ lda sreg
+ eor #$FF
+ adc #0
+ sta sreg
+ lda sreg+1
+ eor #$FF
+ adc #0
+ sta sreg+1
+
+; Done, load the low 16 bit into A/X
+
+L9: lda ptr2
+ ldx ptr2+1 ; get value
+ rts
+
+;
+; Helper functions
+;
+
+mul2:
+ asl ptr2
+ rol ptr2+1
+ rol sreg
+ rol sreg+1 ; * 2
+ rts
+
+
--- /dev/null
+/*
+ * bsearch.c
+ *
+ * Ullrich von Bassewitz, 17.06.1998
+ */
+
+
+
+#include <stdlib.h>
+
+
+
+void* bsearch (void* key, void* base, size_t n, size_t size, int (*cmp) (void*, void*))
+{
+ int current;
+ int result;
+ int found = 0;
+ int first = 0;
+ int last = n - 1;
+
+ /* Binary search */
+ while (first <= last) {
+
+ /* Set current to mid of range */
+ current = (last + first) / 2;
+
+ /* Do a compare */
+ result = cmp ((void*) (((int) base) + current*size), key);
+ if (result < 0) {
+ first = current + 1;
+ } else {
+ last = current - 1;
+ if (result == 0) {
+ /* Found one entry that matches the search key. However there may be
+ * more than one entry with the same key value and ANSI guarantees
+ * that we return the first of a row of items with the same key.
+ */
+ found = 1;
+ }
+ }
+ }
+
+ /* Did we find the entry? */
+ return (void*) (found? ((int) base) + first*size : 0);
+}
+
+
+
--- /dev/null
+/*
+ * calloc.c
+ *
+ * Ullrich von Bassewitz, 06.06.1998
+ */
+
+
+
+#include <stdlib.h>
+#include <string.h>
+
+
+
+void* calloc (size_t count, size_t size)
+{
+ void* mem;
+ size *= count;
+ if (mem = malloc (size)) {
+ memset (mem, 0, size);
+ }
+ return mem;
+}
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 07.12.1998
+;
+; Copy the data segment from the LOAD to the RUN location
+;
+
+ .export copydata
+ .import __DATA_LOAD__, __DATA_RUN__, __DATA_SIZE__
+ .importzp ptr1, ptr2
+
+
+copydata:
+ lda #<__DATA_LOAD__ ; Source pointer
+ sta ptr1
+ lda #>__DATA_LOAD__
+ sta ptr1+1
+
+ lda #<__DATA_RUN__ ; Target pointer
+ sta ptr2
+ lda #>__DATA_RUN__
+ sta ptr2+1
+
+ ldy #$00
+ ldx #>__DATA_SIZE__ ; Get page count
+ beq @L2 ; No full pages
+
+; Copy full pages
+
+@L1: lda (ptr1),y
+ sta (ptr2),y
+ iny
+ bne @L1
+ inc ptr1+1
+ inc ptr2+2 ; Bump pointers
+ dex
+ bne @L1
+
+; Copy last page (remember: y contains zero)
+
+@L2: ldx #<__DATA_SIZE__ ; Get remaining bytes
+ beq @L4
+
+@L3: lda (ptr1),y
+ sta (ptr2),y
+ iny
+ dex
+ bne @L3
+
+; Done
+
+@L4: rts
+
+
--- /dev/null
+/*
+ * cprintf.c
+ *
+ * Ullrich von Bassewitz. 11.08.1998
+ */
+
+
+
+#include <stdarg.h>
+#include <conio.h>
+
+
+
+int cprintf (char* format, ...)
+{
+ va_list ap;
+ va_start (ap, format);
+
+ /* Do formatting and output. Since we know, that va_end is empty, we don't
+ * call it here, saving an extra variable and some code.
+ */
+ return vcprintf ((char*) va_fix (ap, 1), ap);
+}
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 16.05.2000
+;
+
+; Error codes, must match the values in the C headers
+
+ENOENT = 1 ; No such file or directory
+ENOMEM = 2 ; Out of memory
+EACCES = 3 ; Permission denied
+ENODEV = 4 ; No such device
+EMFILE = 5 ; Too many open files
+EBUSY = 6 ; Device or resource busy
+EINVAL = 7 ; Invalid argument
+ENOSPC = 8 ; No space left on device
+EEXIST = 9 ; File exists
+EAGAIN = 10 ; Try again
+EIO = 11 ; I/O error
+EINTR = 12 ; Interrupted system call
+ENOSYS = 13 ; Function not implemented
+ESPIPE = 14 ; Illegal seek
+EUNKNOWN = 15 ; Unknown OS specific error - must be last!
+
+EMAX = 15 ; Highest error code
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.06.1998
+;
+; int _errno;
+;
+; void _maperrno(void);
+; /* Map an OS error to a system independent error code */
+;
+
+ .export __maperrno
+ .export __errno
+ .import __oserror
+ .import __osmaperrno
+
+
+.code
+
+__maperrno:
+ lda __oserror ; Get the error code
+ beq @L1 ; Jump if no error
+ ldx #$00 ; Clear error
+ stx __oserror
+ jsr __osmaperrno ; Map the code
+ sta __errno
+ stx __errno+1
+@L1: rts
+
+
+.bss
+
+__errno:
+ .word 0
+
--- /dev/null
+/*
+ * errormsg.c
+ *
+ * Ullrich von Bassewitz, 17.05.2000
+ *
+ * Must be a C function, since we have otherwise problems with the different
+ * character sets.
+ */
+
+
+
+/* Place the following data into the readonly data segment */
+#pragma dataseg ("RODATA")
+
+const char* _sys_errlist[] = {
+ "Unknown error", /* 0 */
+ "No such file or directory", /* 1 */
+ "Out of memory", /* 2 */
+ "Permission denied", /* 3 */
+ "No such device", /* 4 */
+ "Too many open files", /* 5 */
+ "Device or resource busy", /* 6 */
+ "Invalid argument", /* 7 */
+ "No space left on device", /* 8 */
+ "File exists", /* 9 */
+ "Try again", /* 10 */
+ "I/O error", /* 11 */
+ "Interrupted system call", /* 12 */
+ "Function not implemented", /* 13 */
+ "Illegal seek", /* 14 */
+};
+
+
--- /dev/null
+/*
+ * int fclose (FILE* f);
+ */
+
+
+
+#include <fcntl.h>
+#include <errno.h>
+#include "_file.h"
+
+
+
+int fclose (FILE* f)
+{
+ if ((f->f_flags & _FOPEN) == 0) {
+ /* File is not open */
+ _errno = EINVAL; /* File not input */
+ return -1;
+ }
+
+ /* Reset the flags and close the file */
+ f->f_flags = _FCLOSED;
+ return close (f->f_fd);
+}
+
+
+
--- /dev/null
+/*
+ * fopen.c
+ *
+ * Ullrich von Bassewitz, 17.06.1998
+ */
+
+
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include "_file.h"
+
+
+
+FILE* fdopen (int handle, char* /*mode*/)
+{
+ FILE* f;
+
+ /* Find a free file slot */
+ if (!(f = _fdesc ())) {
+ /* No slots */
+ errno = EMFILE; /* Too many files */
+ return 0;
+ }
+
+ /* Insert the handle, and return the descriptor */
+ f->f_fd = handle;
+ f->f_flags = _FOPEN;
+
+ /* Return the file descriptor */
+ return f;
+}
+
+
+
+
--- /dev/null
+/*
+ * Ullrich von Bassewitz, 11.08.1998
+ *
+ * int fgetc (FILE* f);
+ */
+
+
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include "_file.h"
+
+
+
+int fgetc (FILE* f)
+{
+ char c;
+
+ /* Check if the file is open or if there is an error condition */
+ if ((f->f_flags & _FOPEN) == 0 || (f->f_flags & (_FERROR | _FEOF)) != 0) {
+ return -1;
+ }
+
+ /* Read the byte */
+ switch (read (f->f_fd, &c, 1)) {
+
+ case -1:
+ /* Error */
+ f->f_flags |= _FERROR;
+ return -1;
+
+ case 0:
+ /* EOF */
+ f->f_flags |= _FEOF;
+ return -1;
+
+ default:
+ /* Char read */
+ return ((int) c) & 0xFF;
+
+ }
+}
+
+
+
--- /dev/null
+/*
+ * Ullrich von Bassewitz, 11.08.1998
+ *
+ * char* fgets (char* s, int size, FILE* f);
+ */
+
+
+
+#include <stdio.h>
+#include <errno.h>
+#include "_file.h"
+
+
+
+char* fgets (char* s, unsigned size, FILE* f)
+{
+ int i, c;
+
+ /* We do not handle the case "size == 0" here */
+ i = 0; --size;
+ while (i < size) {
+
+ /* Get next character */
+ c = fgetc (f);
+ if (c == -1) {
+ s [i] = 0;
+ /* Error or EOF */
+ if (f->f_flags & _FERROR) {
+ /* ERROR */
+ return 0;
+ } else {
+ /* EOF */
+ if (i) {
+ return s;
+ } else {
+ return 0;
+ }
+ }
+ }
+
+ /* One char more */
+ s [i++] = c;
+
+ /* Stop at end of line */
+ if (c == '\n') {
+ break;
+ }
+ }
+
+ /* Replace newline by NUL */
+ s [i-1] = '\0';
+
+ /* Done */
+ return s;
+}
+
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 31.05.1998
+;
+; Several small file stream functions
+;
+
+ .export _clearerr, _feof, _ferror, _fileno, _fflush
+ .import return0
+ .import __errno
+ .importzp ptr1
+
+;
+; Get the FILE* parameter, check if the file is open
+;
+
+getf: sta ptr1
+ stx ptr1+1
+ ldy #1
+ lda (ptr1),y ; get f->f_flags
+ and #$01 ; file open?
+ beq @L1 ; jump if no
+ clc ; ok
+ rts
+@L1: sec
+ rts
+
+;
+; void clearerr (FILE* f);
+;
+
+_clearerr:
+ jsr getf
+ bcs err
+ lda (ptr1),y
+ and #$F9
+ sta (ptr1),y
+err: rts
+
+;
+; int feof (FILE* f);
+;
+
+_feof:
+ jsr getf
+; bcs err
+ lda (ptr1),y
+ and #$02
+ ldx #0
+ rts
+
+;
+; int ferror (FILE* f);
+;
+
+_ferror:
+ jsr getf
+; bcs err
+ lda (ptr1),y
+ and #$04
+ ldx #0
+ rts
+
+;
+; int fileno (FILE* f);
+;
+
+_fileno:
+ jsr getf
+; bcs err
+ dey
+ lda (ptr1),y
+ ldx #0
+ rts
+
+;
+; int __fastcall__ fflush (FILE* f);
+;
+
+_fflush = return0
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 05.06.1999
+;
+
+; File mode constants, must match the values in the C headers
+
+
+O_RDONLY = $01
+O_WRONLY = $02
+O_RDWR = $03
+O_CREAT = $04
+O_TRUNC = $10
+O_APPEND = $20
+
+
--- /dev/null
+/*
+ * fopen.c
+ *
+ * Ullrich von Bassewitz, 17.06.1998
+ */
+
+
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include "_file.h"
+
+
+
+FILE* fopen (const char* name, const char* mode)
+{
+ FILE* f;
+
+ /* Find a free file slot */
+ if (!(f = _fdesc ())) {
+ /* No slots */
+ _errno = EMFILE; /* Too many files */
+ return 0;
+ }
+
+ /* Open the file and return the descriptor */
+ return _fopen (name, mode, f);
+}
+
+
+
--- /dev/null
+/*
+ * fprintf.c
+ *
+ * Ullrich von Bassewitz, 11.08.1998
+ */
+
+
+
+#include <stdarg.h>
+#include <stdio.h>
+
+
+
+int fprintf (FILE* /*F*/, char* format, ...)
+{
+ va_list ap;
+ va_start (ap, format);
+
+ /* Do formatting and output. Since we know, that va_end is empty, we don't
+ * call it here, saving an extra variable and some code.
+ */
+ return vfprintf ((FILE*) va_fix (ap, 1), (char*) va_fix (ap, 2), ap);
+}
+
+
+
--- /dev/null
+/*
+ * fputc.c
+ *
+ * Ullrich von Bassewitz, 02.06.1998
+ */
+
+
+
+#include <stdio.h>
+#include <fcntl.h>
+#include "_file.h"
+
+
+
+int fputc (int c, FILE* f)
+{
+ /* Check if the file is open or if there is an error condition */
+ if ((f->f_flags & _FOPEN) == 0 || (f->f_flags & (_FERROR | _FEOF)) != 0) {
+ return -1;
+ }
+
+ /* Write the byte (knows about byte order!) */
+ if (write (f->f_fd, &c, 1) <= 0) {
+ /* Error */
+ f->f_flags |= _FERROR;
+ return -1;
+ }
+
+ /* Return the byte written */
+ return c & 0xFF;
+}
+
+
+
--- /dev/null
+/*
+ * int fputs (const char* s, FILE* f);
+ *
+ * Ullrich von Bassewitz, 11.08.1998
+ */
+
+
+
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include "_file.h"
+
+
+
+int fputs (char* s, FILE* f)
+{
+ /* Check if the file is open or if there is an error condition */
+ if ((f->f_flags & _FOPEN) == 0 || (f->f_flags & (_FERROR | _FEOF)) != 0) {
+ return -1;
+ }
+
+ /* Write the string */
+ return write (f->f_fd, s, strlen (s));
+}
+
+
+
--- /dev/null
+/*
+ * fread.c
+ *
+ * Ullrich von Bassewitz, 02.06.1998
+ */
+
+
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include "_file.h"
+
+
+
+size_t fread (void* buf, size_t size, size_t count, FILE* f)
+{
+ int bytes;
+
+ /* Is the file open? */
+ if ((f->f_flags & _FOPEN) == 0) {
+ _errno = EINVAL; /* File not open */
+ return (size_t) -1;
+ }
+
+ /* Did we have an error or EOF? */
+ if ((f->f_flags & (_FERROR | _FEOF)) != 0) {
+ /* Cannot read from stream */
+ return 0;
+ }
+
+ /* How many bytes to read? */
+ bytes = size * count;
+
+ if (bytes) {
+ /* Read the data. */
+ bytes = read (f->f_fd, buf, bytes);
+ if (bytes == -1) {
+ /* Read error */
+ f->f_flags |= _FERROR;
+ return (size_t) -1;
+ }
+ if (bytes == 0) {
+ /* End of file */
+ f->f_flags |= _FEOF;
+ return (size_t) -1;
+ }
+
+ /* Unfortunately, we cannot avoid the divide here... */
+ return bytes / size;
+
+ } else {
+
+ /* 0 bytes read */
+ return count;
+
+ }
+}
+
+
+
--- /dev/null
+/*
+ * free.c
+ *
+ * Ullrich von Bassewitz, 11.08.1998
+ */
+
+
+
+#include <stdlib.h>
+#include "_heap.h"
+
+
+
+void free (void* block)
+/* Release an allocated memory block. The function will accept NULL pointers
+ * (and do nothing in this case).
+ */
+{
+ unsigned* b;
+ unsigned size;
+ struct freeblock* f;
+
+
+ /* Allow NULL arguments */
+ if (block == 0) {
+ return;
+ }
+
+ /* Get a pointer to the real memory block, then get the size */
+ b = (unsigned*) block;
+ size = *--b;
+
+ /* Check if the block is at the top of the heap */
+ if (((int) b) + size == (int) _hptr) {
+
+ /* Decrease _hptr to release the block */
+ _hptr = (unsigned*) (((int) _hptr) - size);
+
+ /* Check if the last block in the freelist is now at heap top. If so,
+ * remove this block from the freelist.
+ */
+ if (f = _hlast) {
+ if (((int) f) + f->size == (int) _hptr) {
+ /* Remove the last block */
+ _hptr = (unsigned*) (((int) _hptr) - f->size);
+ if (_hlast = f->prev) {
+ /* Block before is now last block */
+ f->prev->next = 0;
+ } else {
+ /* The freelist is empty now */
+ _hfirst = 0;
+ }
+ }
+ }
+
+ } else {
+
+ /* Not at heap top, enter the block into the free list */
+ _hadd (b, size);
+
+ }
+}
+
+
+
--- /dev/null
+/*
+ * freopen.c
+ *
+ * Ullrich von Bassewitz, 17.06.1998
+ */
+
+
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include "_file.h"
+
+
+
+FILE* freopen (char* name, char* mode, FILE* f)
+{
+ /* Check if the file is open, if so, close it */
+ if ((f->f_flags & _FOPEN) == 0) {
+ /* File is not open */
+ _errno = EINVAL; /* File not input */
+ return 0;
+ }
+
+ /* Close the file. Don't bother setting the flag, it will get
+ * overwritten by _fopen.
+ */
+ if (close (f->f_fd) < 0) {
+ /* An error occured, _oserror is set */
+ return 0;
+ }
+
+ /* Open the file and return the descriptor */
+ return _fopen (name, mode, f);
+}
+
+
+
--- /dev/null
+/*
+ * fwrite.c
+ *
+ * Ullrich von Bassewitz, 04.06.1998
+ */
+
+
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include "_file.h"
+
+
+
+size_t fwrite (void* buf, size_t size, size_t count, FILE* f)
+{
+ int bytes;
+
+ /* Is the file open? */
+ if ((f->f_flags & _FOPEN) == 0) {
+ _errno = EINVAL; /* File not open */
+ return -1;
+ }
+
+ /* Did we have an error */
+ if ((f->f_flags & _FERROR) != 0) {
+ /* Cannot write to stream */
+ return 0;
+ }
+
+ /* How many bytes to write? */
+ bytes = size * count;
+
+ if (bytes) {
+ /* Write the data. */
+ if (write (f->f_fd, buf, bytes) == -1) {
+ /* Write error */
+ f->f_flags |= _FERROR;
+ return -1;
+ }
+ }
+
+ /* Don't waste time with expensive calculations, assume the write was
+ * complete and return the count of items.
+ */
+ return count;
+}
+
+
+
--- /dev/null
+/*
+ * getchar.c
+ *
+ * Ullrich von Bassewitz, 11.12.1998
+ */
+
+
+
+#include <stdio.h>
+
+/* This is usually declared as a macro */
+#undef getchar
+
+
+
+int getchar (void)
+{
+ return fgetc (stdin);
+}
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 02.04.1999
+;
+; unsigned char getcpu (void);
+;
+
+ .export _getcpu
+
+; ---------------------------------------------------------------------------
+; Subroutine to detect an 816. Returns
+;
+; - carry clear and 0 in A for a NMOS 6502 CPU
+; - carry set and 1 in A for some CMOS 6502 CPU
+; - carry set and 2 in A for a 65816
+;
+; This function uses a $1A opcode which is a INA on the 816 and ignored
+; (interpreted as a NOP) on a NMOS 6502. There are several CMOS versions
+; of the 6502, but all of them interpret unknown opcodes as NOP so this is
+; just what we want.
+
+.p816 ; Enable 65816 instructions
+
+_getcpu:
+ lda #0
+ inc a ; .byte $1A
+ cmp #1
+ bcc @L9
+
+; This is at least a 65C02, check for a 65816
+
+ xba ; .byte $eb, put $01 in B accu
+ dec a ; .byte $3a, A=$00 if 65C02
+ xba ; .byte $eb, get $01 back if 65816
+ inc a ; .byte $1a, make $01/$02
+@L9: ldx #0 ; Load high byte of word
+ rts
+
--- /dev/null
+/*
+ * gets.c
+ *
+ * Ullrich von Bassewitz, 11.08.1998
+ */
+
+
+
+#include <stdio.h>
+#include "_file.h"
+
+
+
+char* gets (char* s)
+{
+ int i, c;
+
+ i = 0;
+ do {
+
+ /* Get next character */
+ c = fgetc (stdin);
+ if (c == -1) {
+ /* Error or EOF */
+ s [i] = 0;
+ if (stdin->f_flags & _FERROR) {
+ /* ERROR */
+ return 0;
+ } else {
+ /* EOF */
+ if (i) {
+ return s;
+ } else {
+ return 0;
+ }
+ }
+ }
+
+ /* One char more */
+ s [i++] = c;
+
+ } while (c != '\n');
+
+ /* Replace newline by NUL */
+ s [i-1] = '\0';
+
+ /* Done */
+ return s;
+}
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 02.06.1998
+;
+; int isalnum (int c);
+;
+
+ .export _isalnum
+ .import __ctype
+
+_isalnum:
+ tay
+ lda __ctype,y ; Get character classification
+ and #$07 ; Mask character/digit bits
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 02.06.1998
+;
+; int isalpha (int c);
+;
+
+ .export _isalpha
+ .import __ctype
+
+_isalpha:
+ tay
+ lda __ctype,y ; Get character classification
+ and #$03 ; Mask character bits
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 02.06.1998
+;
+; int isblank (int c);
+;
+; cc65 (and GNU) extension.
+;
+
+ .export _isblank
+ .import __ctype
+
+_isblank:
+ tay
+ lda __ctype,y ; Get character classification
+ and #$80 ; Mask blank bit
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 02.06.1998
+;
+; int iscntrl (int c);
+;
+
+ .export _iscntrl
+ .import __ctype
+
+_iscntrl:
+ tay
+ lda __ctype,y ; Get character classification
+ and #$10 ; Mask control character bit
+ rts
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 02.06.1998
+;
+; int isdigit (int c);
+;
+
+ .export _isdigit
+ .import __ctype
+
+_isdigit:
+ tay
+ lda __ctype,y ; Get character classification
+ and #$04 ; Mask digit bit
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 02.06.1998
+;
+; int isgraph (int c);
+;
+
+ .export _isgraph
+ .import __ctype
+
+_isgraph:
+ tay
+ lda __ctype,y ; Get character classification
+ eor #$30 ; NOT control and NOT space
+ and #$30 ; Mask character bits
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 02.06.1998
+;
+; int islower (int c);
+;
+
+ .export _islower
+ .import __ctype
+
+_islower:
+ tay
+ lda __ctype,y ; Get character classification
+ and #$01 ; Mask lower char bit
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 02.06.1998
+;
+; int isprint (int c);
+;
+
+ .export _isprint
+ .import __ctype
+
+_isprint:
+ tay
+ lda __ctype,y ; Get character classification
+ eor #$10 ; NOT a control char
+ and #$10 ; Mask control char bit
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 02.06.1998
+;
+; int ispunct (int c);
+;
+
+ .export _ispunct
+ .import __ctype
+
+_ispunct:
+ tay
+ lda __ctype,y ; Get character classification
+ eor #$37 ; NOT (space | control | digit | char)
+ and #$37 ; Mask relevant bits
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 02.06.1998
+;
+; int isspace (int c);
+;
+
+ .export _isspace
+ .import __ctype
+
+_isspace:
+ tay
+ lda __ctype,y ; Get character classification
+ and #$60 ; Mask space bits
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 02.06.1998
+;
+; int isupper (int c);
+;
+
+ .export _isupper
+ .import __ctype
+
+_isupper:
+ tay
+ lda __ctype,y ; Get character classification
+ and #$02 ; Mask upper char bit
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 02.06.1998
+;
+; int isxdigit (int c);
+;
+
+ .export _isxdigit
+ .import __ctype
+
+_isxdigit:
+ tay
+ lda __ctype,y ; Get character classification
+ and #$08 ; Mask xdigit bit
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 31.05.1998
+;
+; char* itoa (int value, char* s, int radix);
+; char* utoa (unsigned value, char* s, int radix);
+;
+
+ .export _itoa, _utoa
+ .import addysp1
+ .import __hextab
+ .importzp sp, sreg, ptr2, ptr3, tmp1
+
+.rodata
+specval:
+ .byte '-', '3', '2', '7', '6', '8', 0
+.code
+
+;
+; Common subroutine to pop the parameters and put them into core
+;
+
+dopop: sta tmp1 ; will loose high byte
+ ldy #0
+ lda (sp),y
+ sta ptr2
+ sta ptr3
+ iny
+ lda (sp),y
+ sta ptr2+1
+ sta ptr3+1
+ iny
+ lda (sp),y
+ sta sreg
+ iny
+ lda (sp),y
+ sta sreg+1
+ jmp addysp1 ; Bump stack pointer
+
+;
+; itoa
+;
+
+_itoa: jsr dopop ; pop the arguments
+
+; We must handle $8000 in a special way, since it is the only negative
+; number that has no positive 16-bit counterpart
+
+ ldy tmp1 ; get radix
+ cpy #10
+ bne utoa
+ cmp #$00
+ bne L2
+ cpx #$80
+ bne L2
+
+ ldy #6
+L1: lda specval,y ; copy -32768
+ sta (ptr2),y
+ dey
+ bpl L1
+ jmp L10
+
+; Check if the value is negative. If so, write a - sign and negate the
+; number.
+
+L2: lda sreg+1 ; get high byte
+ bpl utoa
+ lda #'-'
+ ldy #0
+ sta (ptr2),y ; store sign
+ inc ptr2
+ bne L3
+ inc ptr2+1
+
+L3: lda sreg
+ eor #$FF
+ clc
+ adc #$01
+ sta sreg
+ lda sreg+1
+ eor #$FF
+ adc #$00
+ sta sreg+1
+ jmp utoa
+
+;
+; utoa
+;
+
+_utoa: jsr dopop ; pop the arguments
+
+; Convert to string by dividing and push the result onto the stack
+
+utoa: lda #$00
+ pha ; sentinel
+
+; Divide sreg/tmp1 -> sreg, remainder in a
+
+L5: ldy #16 ; 16 bit
+ lda #0 ; remainder
+L6: asl sreg
+ rol sreg+1
+ rol a
+ cmp tmp1
+ bcc L7
+ sbc tmp1
+ inc sreg
+L7: dey
+ bne L6
+
+ tay ; get remainder into y
+ lda __hextab,y ; get hex character
+ pha ; save char value on stack
+
+ lda sreg
+ ora sreg+1
+ bne L5
+
+; Get the characters from the stack into the string
+
+ ldy #0
+L9: pla
+ sta (ptr2),y
+ beq L10 ; jump if sentinel
+ iny
+ bne L9 ; jump always
+
+; Done! Return the target string
+
+L10: lda ptr3
+ ldx ptr3+1
+ rts
+
+
+
+
+
+
+
+
+
+
+
+
+
+
--- /dev/null
+;
+; General purpose jump vector in the data segment that is patched at
+; runtime and used by several routines.
+;
+; Ullrich von Bassewitz, 16.12.1998
+;
+
+ .export jmpvec
+
+
+.data
+
+jmpvec: jmp $FFFF
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 17.06.1998
+;
+; long labs (long x);
+;
+
+ .export _labs
+ .import negeax, tsteax
+ .importzp sreg
+
+_labs: ldy sreg+1 ; test hi byte
+ bpl L1
+ jmp negeax ; Negate if negative
+L1: rts
+
--- /dev/null
+/*
+ * locale.c
+ *
+ * Ullrich von Bassewitz, 11.12.1998
+ */
+
+
+
+#include <locale.h>
+#include <limits.h>
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Data in this module is read-only, put it into the RODATA segment */
+#pragma dataseg ("RODATA");
+
+/* For memory efficiency use a separate empty string */
+static const char EmptyString [] = "";
+
+static struct lconv lc = {
+ EmptyString, /* currency_symbol */
+ ".", /* decimal_point */
+ EmptyString, /* grouping */
+ EmptyString, /* int_curr_symbol */
+ EmptyString, /* mon_decimal_point */
+ EmptyString, /* mon_grouping */
+ EmptyString, /* mon_thousands_sep */
+ EmptyString, /* negative_sign */
+ EmptyString, /* positive_sign */
+ EmptyString, /* thousands_sep */
+ CHAR_MAX, /* frac_digits */
+ CHAR_MAX, /* int_frac_digits */
+ CHAR_MAX, /* n_cs_precedes */
+ CHAR_MAX, /* n_sep_by_space */
+ CHAR_MAX, /* n_sign_posn */
+ CHAR_MAX, /* p_cs_precedes */
+ CHAR_MAX, /* p_sep_by_space */
+ CHAR_MAX, /* p_sign_posn */
+};
+
+/* Restore the old data segment name */
+#pragma dataseg ("DATA");
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+struct lconv* localeconv (void)
+{
+ return &lc;
+}
+
+
+
+char* setlocale (int, const char* locale)
+{
+ if (locale == 0 || (locale [0] == 'C' && locale [1] == '\0') || locale [0] == '\0') {
+ /* No change, or value already set, our locale is the "C" locale */
+ return "C";
+ } else {
+ /* Cannot set this one */
+ return 0;
+ }
+}
+
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.06.1998
+;
+; void longjmp (jmp_buf buf, int retval);
+;
+
+ .export _longjmp
+ .import popax
+ .importzp sp, ptr1, ptr2
+
+_longjmp:
+ sta ptr2 ; Save retval
+ stx ptr2+1
+ jsr popax ; get buf
+ sta ptr1
+ stx ptr1+1
+ ldy #0
+
+; Get the old parameter stack
+
+ lda (ptr1),y
+ iny
+ sta sp
+ lda (ptr1),y
+ iny
+ sta sp+1
+
+; Get the old stack pointer
+
+ lda (ptr1),y
+ iny
+ tax
+ txs
+
+; Get the return address and push it on the stack
+
+ lda (ptr1),y
+ iny
+ pha
+ lda (ptr1),y
+ pha
+
+; Load the return value and return to the caller
+
+ lda ptr2
+ ldx ptr2+1
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 11.06.1998
+;
+; char* ltoa (long value, char* s, int radix);
+; char* ultoa (unsigned long value, char* s, int radix);
+;
+
+ .export _ltoa, _ultoa
+ .import popax
+ .import __hextab
+ .importzp sreg, ptr1, ptr2, ptr3, tmp1
+
+
+
+.rodata
+specval:
+ .byte '-', '2', '1', '4', '7', '4', '8', '3', '6', '4', '8', 0
+.code
+
+;
+; Common subroutine to pop the parameters and put them into core
+;
+
+dopop: sta tmp1 ; will loose high byte
+ jsr popax ; get s
+ sta ptr1
+ stx ptr1+1
+ sta sreg ; save for return
+ stx sreg+1
+ jsr popax ; get low word of value
+ sta ptr2
+ stx ptr2+1
+ jsr popax ; get high word of value
+ sta ptr3
+ stx ptr3+1
+ rts
+
+;
+; ltoa
+;
+
+_ltoa: jsr dopop ; pop the arguments
+
+; We must handle $80000000 in a special way, since it is the only negative
+; number that has no positive 32-bit counterpart
+
+ ldx ptr3+1 ; get high byte
+ ldy tmp1 ; get radix
+ cpy #10
+ bne ultoa
+ lda ptr3
+ ora ptr2+1
+ ora ptr2
+ bne L2
+ cpx #$80
+ bne L2
+
+ ldy #11
+L1: lda specval,y ; copy -2147483648
+ sta (ptr1),y
+ dey
+ bpl L1
+ jmp L10
+
+; Check if the value is negative. If so, write a - sign and negate the
+; number.
+
+L2: txa ; get high byte
+ bpl ultoa
+ lda #'-'
+ ldy #0
+ sta (ptr1),y ; store sign
+ inc ptr1
+ bne L3
+ inc ptr1+1
+
+L3: lda ptr2 ; negate val
+ eor #$FF
+ clc
+ adc #$01
+ sta ptr2
+ lda ptr2+1
+ eor #$FF
+ adc #$00
+ sta ptr2+1
+ lda ptr3
+ eor #$FF
+ adc #$00
+ sta ptr3
+ lda ptr3+1
+ eor #$FF
+ adc #$00
+ sta ptr3+1
+ jmp ultoa
+
+;
+; utoa
+;
+
+_ultoa: jsr dopop ; pop the arguments
+
+; Convert to string by dividing and push the result onto the stack
+
+ultoa: lda #$00
+ pha ; sentinel
+
+; Divide val/tmp1 -> val, remainder in a
+
+L5: ldy #32 ; 32 bit
+ lda #0 ; remainder
+L6: asl ptr2
+ rol ptr2+1
+ rol ptr3
+ rol ptr3+1
+ rol a
+ cmp tmp1
+ bcc L7
+ sbc tmp1
+ inc ptr2
+L7: dey
+ bne L6
+
+ tay ; get remainder into y
+ lda __hextab,y ; get hex character
+ pha ; save char value on stack
+
+ lda ptr2
+ ora ptr2+1
+ ora ptr3
+ ora ptr3+1
+ bne L5
+
+; Get the characters from the stack into the string
+
+ ldy #0
+L9: pla
+ sta (ptr1),y
+ beq L10 ; jump if sentinel
+ iny
+ bne L9 ; jump always
+
+; Done! Return the target string
+
+L10: lda sreg
+ ldx sreg+1
+ rts
+
+
+
+
+
+
+
+
+
+
+
+
+
+
--- /dev/null
+/*
+ * malloc.c
+ *
+ * Ullrich von Bassewitz, 03.06.1998
+ */
+
+
+
+#include <stddef.h>
+#include "_heap.h"
+
+
+
+void* malloc (size_t size)
+/* Allocate memory from the given heap. The function returns a pointer to the
+ * allocated memory block or a NULL pointer if not enough memory is available.
+ * Allocating a zero size block is not allowed.
+ */
+{
+ struct freeblock* f;
+ unsigned* p;
+
+
+ /* Check for a size of zero, then add the administration space and round
+ * up the size if needed.
+ */
+ if (size == 0) {
+ return 0;
+ }
+ size += HEAP_ADMIN_SPACE;
+ if (size < sizeof (struct freeblock)) {
+ size = sizeof (struct freeblock);
+ }
+
+ /* Search the freelist for a block that is big enough */
+ f = _hfirst;
+ while (f && f->size < size) {
+ f = f->next;
+ }
+
+ /* Did we find one? */
+ if (f) {
+
+ /* We found a block big enough. If the block can hold just the
+ * requested size, use the block in full. Beware: When slicing blocks,
+ * there must be space enough to create a new one! If this is not the
+ * case, then use the complete block.
+ */
+ if (f->size - size < sizeof (struct freeblock)) {
+
+ /* Use the actual size */
+ size = f->size;
+
+ /* Remove the block from the free list */
+ if (f->prev) {
+ /* We have a previous block */
+ f->prev->next = f->next;
+ } else {
+ /* This is the first block, correct the freelist pointer */
+ _hfirst = f->next;
+ }
+ if (f->next) {
+ /* We have a next block */
+ f->next->prev = f->prev;
+ } else {
+ /* This is the last block, correct the freelist pointer */
+ _hlast = f->prev;
+ }
+
+ } else {
+
+ /* We must slice the block found */
+ struct freeblock* newblock;
+ newblock = (struct freeblock*) ((unsigned) f) + size;
+
+ /* Insert the new block (the remaining space) instead of the
+ * old one.
+ */
+ newblock->size = f->size - size; /* Remaining size */
+ newblock->next = f->next;
+ newblock->prev = f->prev;
+ if (f->prev) {
+ /* We have a previous block */
+ f->prev->next = newblock;
+ } else {
+ /* This is the first block, correct the freelist pointer */
+ _hfirst = newblock;
+ }
+ if (f->next) {
+ /* We have a next block */
+ f->next->prev = newblock;
+ } else {
+ /* This is the last block, correct the freelist pointer */
+ _hlast = newblock;
+ }
+
+ }
+
+ /* Setup the pointer for the bock */
+ p = (unsigned*) f;
+
+ } else {
+
+ /* We did not find a block big enough. Try to use new space from the
+ * heap top.
+ */
+ if (((unsigned) _hend) - ((unsigned) _hptr) < size) {
+ /* Out of heap space */
+ return 0;
+ }
+
+
+ /* There is enough space left, take it from the heap top */
+ p = _hptr;
+ _hptr = (unsigned*) (((unsigned) _hptr) + size);
+
+ }
+
+ /* New block is now in p. Fill in the size and return the user pointer */
+ *p++ = size;
+ return p;
+}
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 09.06.1998
+;
+; void* memchr (const void* p, int c, size_t n);
+;
+
+ .export _memchr
+ .import popax, return0
+ .importzp ptr1, ptr2, tmp1
+
+
+_memchr:
+ sta ptr2 ; Save n
+ stx ptr2+1
+ jsr popax ; get c
+ sta tmp1
+ jsr popax ; get p
+ sta ptr1
+ stx ptr1+1
+
+ ldy #0
+ lda tmp1 ; get c
+ ldx ptr2 ; use X as low counter byte
+ beq L3 ; check high byte
+
+; Search for the char
+
+L1: cmp (ptr1),y
+ beq L5 ; jump if found
+ iny
+ bne L2
+ inc ptr1+1
+L2: cpx #0
+ beq L3
+ dex
+ jmp L1
+L3: ldx ptr2+1 ; Check high byte
+ beq L4 ; Jump if counter off
+ dec ptr2+1
+ ldx #$FF
+ bne L1 ; branch always
+
+; Character not found, return zero
+
+L4: jmp return0
+
+; Character found, calculate pointer
+
+L5: ldx ptr1+1 ; get high byte of pointer
+ tya ; low byte offset
+ clc
+ adc ptr1
+ bcc L6
+ inx
+L6: rts
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 09.06.1998
+;
+; int memcmp (const void* p1, const void* p2, size_t count);
+;
+
+ .export _memcmp
+ .import popax, return0
+ .importzp ptr1, ptr2, ptr3
+
+_memcmp:
+ sta ptr3 ; Save count
+ sta ptr3+1
+ jsr popax ; get p2
+ sta ptr2
+ stx ptr2+1
+ jsr popax ; get p1
+ sta ptr1
+ stx ptr1+1
+
+ ldy #0
+ ldx ptr3 ; use X as low counter byte
+ beq L3
+
+L1: lda (ptr1),y
+ cmp (ptr2),y
+ bne L5
+ iny
+ bne L2
+ inc ptr1+1
+ inc ptr2+1
+L2: txa
+ beq L3
+ dex
+ jmp L1
+L3: lda ptr3+1 ; check high byte
+ beq L4
+ dec ptr3+1
+ dex ; X = $FF
+ bne L1 ; branch always
+
+; Memory areas are equal
+
+L4: jmp return0
+
+; Not equal, check which one is greater
+
+L5: bcs L6
+ ldx #$FF
+ rts
+
+L6: ldx #$01
+ rts
+
--- /dev/null
+;
+; void* memcpy (void* dest, const void* src, size_t n);
+; void* memmove (void* dest, const void* src, size_t n);
+;
+; Ullrich von Bassewitz, 10.12.1998
+;
+
+ .export _memcpy, _memmove
+ .import popax
+ .importzp ptr1, ptr2, ptr3, tmp1, tmp2
+
+; ----------------------------------------------------------------------
+_memcpy:
+ jsr getparms ; Get the parameters from stack
+
+; Copy upwards
+
+copyup: ldy #0 ; set up to move 256
+ ldx tmp2 ; hi byte of n
+ beq @L2
+
+@L1: lda (ptr1),y ; get a byte
+ sta (ptr2),y ; store it
+ iny
+ bne @L1
+ inc ptr1+1 ; bump ptrs
+ inc ptr2+1
+ dex
+ bne @L1 ; do another block
+
+@L2: ldx tmp1 ; get low byte of n
+ beq done ; jump if done
+
+@L3: lda (ptr1),y ; get a byte
+ sta (ptr2),y ; store it
+ iny
+ dex
+ bne @L3
+
+done: lda ptr3
+ ldx ptr3+1 ; get function result (dest)
+ rts
+
+
+; ----------------------------------------------------------------------
+_memmove:
+ jsr getparms ; Get the parameters from stack
+
+ cpx ptr1+1 ; dest > src?
+ bne @L1
+ cmp ptr1
+@L1: beq done ; Both pointers are equal - nothing to copy
+ bcc copyup ; Copy upwards
+
+; Copy downwards
+
+ clc
+ lda ptr1+1
+ adc tmp2
+ sta ptr1+1
+
+ clc
+ lda ptr2+1
+ adc tmp2
+ sta ptr2+1
+
+; Copy the incomplete page
+
+ ldy tmp1 ; Get low byte of count
+ beq @L3
+
+@L2: dey
+ lda (ptr1),y
+ sta (ptr2),y
+ tya ; Test Y
+ bne @L2 ; Jump if not zero
+
+; Copy complete pages
+
+@L3: ldx tmp2 ; Get hi byte of count
+ beq done
+
+@L4: dec ptr1+1
+ dec ptr2+1
+@L5: dey
+ lda (ptr1),y
+ sta (ptr2),y
+ tya
+ bne @L5
+ dex
+ bne @L4
+
+; Done
+
+ beq done
+
+; ----------------------------------------------------------------------
+; Get the parameters from stack
+
+getparms:
+ sta tmp1 ; Save n
+ stx tmp2
+ jsr popax ; src
+ sta ptr1
+ stx ptr1+1
+ jsr popax ; dest
+ sta ptr2
+ stx ptr2+1 ; save work copy
+ sta ptr3
+ stx ptr3+1 ; save function result
+ rts
+
+
--- /dev/null
+;
+; void* memset (void* ptr, int c, size_t n);
+;
+; Ullrich von Bassewitz, 29.05.1998
+;
+
+ .export _memset
+ .import popax
+ .importzp ptr1, ptr2, tmp1, tmp2, tmp3
+
+_memset:
+ sta tmp1 ; Save n
+ stx tmp2
+ jsr popax ; Get c
+ sta tmp3 ; Save c
+ jsr popax ; Get ptr
+ sta ptr1
+ stx ptr1+1 ; Save work copy
+ sta ptr2
+ stx ptr2+1 ; Save a copy for the function result
+ lda tmp3
+
+ ldy #0
+ ldx tmp2 ; Get high byte of n
+ beq L2 ; Jump if zero
+
+; Set 256 byte blocks
+
+L1: sta (ptr1),y ; Set one byte
+ iny
+ sta (ptr1),y ; Unroll this a bit to make it faster
+ iny
+ bne L1
+ inc ptr1+1
+ dex ; Next 256 byte block
+ bne L1 ; Repeat if any
+
+; Set the remaining bytes if any
+
+L2: ldx tmp1 ; Get the low byte of n
+ beq L9 ; Low byte is zero
+
+L3: sta (ptr1),y ; Set one byte
+ iny
+ dex ; Done?
+ bne L3
+
+L9: lda ptr2 ; Load function result
+ ldx ptr2+1
+ rts
+
+
--- /dev/null
+/*
+ * perror.c
+ *
+ * Ullrich von Bassewitz, 01.10.1998
+ */
+
+
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+
+
+void perror (const char* msg)
+{
+ if (msg) {
+ fprintf (stderr, "%s: ", msg);
+ }
+ fprintf (stderr, "%s\n", strerror (errno));
+}
+
+
+
--- /dev/null
+/*
+ * printf.c
+ *
+ * Ullrich von Bassewitz, 11.08.1998
+ */
+
+
+
+#include <stdarg.h>
+#include <stdio.h>
+
+
+
+int printf (char* format, ...)
+{
+ va_list ap;
+ va_start (ap, format);
+
+ /* Do formatting and output. Since we know, that va_end is empty, we don't
+ * call it here, saving an extra variable and some code.
+ */
+ return vfprintf (stdout, (char*) va_fix (ap, 1), ap);
+}
+
+
+
--- /dev/null
+/*
+ * putchar.c
+ *
+ * Ullrich von Bassewitz, 11.12.1998
+ */
+
+
+
+#include <stdio.h>
+
+/* This is usually declared as a macro */
+#undef putchar
+
+
+
+int putchar (int c)
+{
+ return fputc (c, stdout);
+}
+
+
+
--- /dev/null
+/*
+ * puts.c
+ *
+ * Ullrich von Bassewitz, 11.08.1998
+ */
+
+
+
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include "_file.h"
+
+
+
+int puts (const char* s)
+{
+ static char nl = '\n';
+
+ /* Assume stdout is always open */
+ if (write (stdout->f_fd, s, strlen (s)) < 0 ||
+ write (stdout->f_fd, &nl, 1) < 0) {
+ stdout->f_flags |= _FERROR;
+ return -1;
+ }
+
+ /* Done */
+ return 0;
+}
+
+
+
--- /dev/null
+/*
+ * qsort.c
+ *
+ * Ullrich von Bassewitz, 09.12.1998
+ */
+
+
+
+#include <stdlib.h>
+
+
+
+static void QuickSort (void* Base, int Lo, int Hi, size_t Size,
+ int (*Compare)(const void*, const void*))
+/* Internal recursive function. Works with ints, but this shouldn't be
+ * a problem.
+ */
+{
+ int I, J;
+
+ /* Get a char pointer */
+ unsigned char* B = Base;
+
+ /* Quicksort */
+ while (Hi > Lo) {
+ I = Lo + Size;
+ J = Hi;
+ while (I <= J) {
+ while (I <= J && Compare (B + Lo, B + I) >= 0) {
+ I += Size;
+ }
+ while (I <= J && Compare (B + Lo, B + J) < 0) {
+ J -= Size;
+ }
+ if (I <= J) {
+ _swap (B + I, B + J, Size);
+ I += Size;
+ J -= Size;
+ }
+ }
+ if (J != Lo) {
+ _swap (B + J, B + Lo, Size);
+ }
+ if (((unsigned) J) * 2 > (Hi + Lo)) {
+ QuickSort (Base, J + Size, Hi, Size, Compare);
+ Hi = J - Size;
+ } else {
+ QuickSort (Base, Lo, J - Size, Size, Compare);
+ Lo = J + Size;
+ }
+ }
+}
+
+
+
+void qsort (void* base, size_t nmemb, size_t size,
+ int (*compare)(const void*, const void*))
+/* Quicksort implementation */
+{
+ if (nmemb > 1) {
+ QuickSort (base, 0, (nmemb-1) * size, size, compare);
+ }
+}
+
+
+
+
+
--- /dev/null
+;
+; Randum number generator
+;
+; Written and donated by Sidney Cadot - sidney@ch.twi.tudelft.nl
+;
+; May be distributed with the cc65 runtime using the same license.
+;
+;
+; int rand (void);
+; void srand (unsigned seed);
+;
+; Uses 4-byte state.
+; Multiplier must be 1 (mod 4)
+; Added value must be 1 (mod 2)
+; This guarantees max. period (2**32)
+; Bits 8-22 are returned (positive 2-byte int)
+; where 0 is LSB, 31 is MSB.
+; This is better as lower bits exhibit easily
+; detectable patterns.
+;
+
+ .export _rand, _srand
+
+.bss
+
+rand: .res 4 ; Seed
+
+.code
+
+_rand: clc
+ lda rand+0 ; SEED *= $01010101
+ adc rand+1
+ sta rand+1
+ adc rand+2
+ sta rand+2
+ adc rand+3
+ sta rand+3
+ clc
+ lda rand+0 ; SEED += $31415927
+ adc #$27
+ sta rand+0
+ lda rand+1
+ adc #$59
+ sta rand+1
+ pha
+ lda rand+2
+ adc #$41
+ sta rand+2
+ and #$7f ; Suppress sign bit (make it positive)
+ tax
+ lda rand+3
+ adc #$31
+ sta rand+3
+ pla ; return bit 8-22 in (X,A)
+ rts
+
+_srand: sta rand+0 ; Store the seed
+ stx rand+1
+ lda #0
+ sta rand+2 ; Set MSW to zero
+ sta rand+3
+ rts
+
--- /dev/null
+/*
+ * realloc.c
+ *
+ * Ullrich von Bassewitz, 06.06.1998
+ */
+
+
+
+#include <stdlib.h>
+#include <string.h>
+#include "_heap.h"
+
+
+
+void* realloc (void* block, size_t size)
+{
+ unsigned* b;
+ unsigned* newblock;
+ unsigned oldsize;
+ int diff;
+
+ /* Check the block parameter */
+ if (!block) {
+ /* Block is NULL, same as malloc */
+ return malloc (size);
+ }
+
+ /* Check the size parameter */
+ if (size == 0) {
+ /* Block is not NULL, but size is: free the block */
+ free (block);
+ return 0;
+ }
+
+ /* Make the internal used size from the given size */
+ size += HEAP_ADMIN_SPACE;
+ if (size < sizeof (struct freeblock)) {
+ size = sizeof (struct freeblock);
+ }
+
+ /* Get a pointer to the real block, get the old block size */
+ b = (unsigned*) (((int) block) - 2);
+ oldsize = *b;
+
+ /* Get the size difference as a signed quantity */
+ diff = size - oldsize;
+
+ /* Is the block at the current heap top? */
+ if (((int) b) + oldsize == ((int) _hptr)) {
+ /* Check if we've enough memory at the heap top */
+ int newhptr;
+ newhptr = ((int) _hptr) + diff;
+ if (newhptr <= ((int) _hend)) {
+ /* Ok, there's space enough */
+ _hptr = (unsigned*) newhptr;
+ *b = size;
+ return block;
+ }
+ }
+
+ /* The given block was not located on top of the heap, or there's no
+ * room left. Try to allocate a new block and copy the data.
+ */
+ if (newblock = malloc (size)) {
+ memcpy (newblock, block, oldsize - 2);
+ free (block);
+ }
+ return newblock;
+}
+
+
+
+
+
+
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.06.1998
+;
+; int setjmp (jmp_buf buf);
+;
+
+ .export __setjmp
+ .importzp sp, ptr1
+
+__setjmp:
+ sta ptr1 ; Save buf
+ stx ptr1+1
+ ldy #0
+
+; The parameter stack is now empty, put it into buf
+
+ lda sp
+ sta (ptr1),y
+ iny
+ lda sp+1
+ sta (ptr1),y
+ iny
+
+; Put the return stack pointer next
+
+ tsx
+ inx
+ inx ; drop return address
+ txa
+ sta (ptr1),y
+ iny
+
+; Last thing is the return address.
+
+ pla
+ tax
+ pla
+ sta (ptr1),y ; high byte first
+ iny
+ pha
+ txa
+ sta (ptr1),y
+ pha
+
+; Return zero
+
+ lda #0
+ tax
+ rts
+
+
+
--- /dev/null
+/*
+ * sprintf.c
+ *
+ * Ullrich von Bassewitz, 11.08.1998
+ */
+
+
+
+#include <stdarg.h>
+#include <stdio.h>
+
+
+
+int sprintf (char* /*buf*/, char* format, ...)
+{
+ va_list ap;
+ va_start (ap, format);
+
+ /* Do formatting and output. Since we know, that va_end is empty, we don't
+ * call it here, saving an extra variable and some code.
+ */
+ return vsprintf ((char*) va_fix (ap, 1), (char*) va_fix (ap, 2), ap);
+}
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 18.08.1998
+;
+; Stack checker
+;
+
+
+ .export _stkcheck, __stksafety
+ .import pushax, exit
+ .import __hend
+ .importzp sp
+
+.data
+__stksafety:
+ .word 64 ;
+
+.code
+_stkcheck:
+ clc
+ lda __hend
+ adc __stksafety
+ tax ; Remember low byte
+ lda __hend+1
+ adc __stksafety+1
+
+ cmp sp+1
+ bcc Ok
+ bne L1
+ cpx sp
+ bcc Ok
+
+; Stack overflow
+
+L1: inc sp+1 ; Create 256 bytes of space
+ ldx #0
+ lda #4
+ jsr pushax
+ jmp exit
+
+; All is well
+
+Ok: rts
+
+
+
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 31.05.1998
+;
+; char* strcat (char* dest, const char* src);
+;
+
+ .export _strcat
+ .import popax
+ .importzp ptr1, ptr2, ptr3
+
+_strcat:
+ sta ptr1 ; Save src
+ stx ptr1+1
+ jsr popax ; Get dest
+ sta ptr2
+ stx ptr2+1
+ sta ptr3 ; Remember for function return
+ stx ptr3+1
+ ldy #0
+
+; find end of dest
+
+sc1: lda (ptr2),y
+ beq sc2
+ iny
+ bne sc1
+ inc ptr2+1
+ bne sc1
+
+; end found, get offset in y into pointer
+
+sc2: tya
+ clc
+ adc ptr2
+ sta ptr2
+ bcc sc3
+ inc ptr2+1
+
+; copy src
+
+sc3: ldy #0
+sc4: lda (ptr1),y
+ sta (ptr2),y
+ beq sc5
+ iny
+ bne sc4
+ inc ptr1+1
+ inc ptr2+1
+ bne sc4
+
+; done, return pointer to dest
+
+sc5: lda ptr3
+ ldx ptr3+1
+ rts
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 31.05.1998
+;
+; const char* strchr (const char* s, int c);
+;
+
+ .export _strchr
+ .import popax
+ .importzp ptr1, tmp1
+
+_strchr:
+ sta tmp1 ; Save c
+ jsr popax ; get s
+ sta ptr1
+ stx ptr1+1
+ ldy #0
+
+scloop: lda (ptr1),y ; get next char
+ beq strz ; jump if end of string
+ cmp tmp1 ; found?
+ beq strf ; jump if yes
+ iny
+ bne scloop
+ inc ptr1+1
+ bne scloop ; jump always
+
+; found, calculate pointer to c
+
+strf: ldx ptr1+1 ; get high byte of pointer
+ tya ; low byte offset
+ clc
+ adc ptr1
+ bcc str1
+ inx
+str1: rts
+
+; not found, return zero
+
+strz: tax ; return 0
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 31.05.1998
+;
+; int strcmp (const char* s1, const char* s2);
+;
+
+ .export _strcmp
+ .import popax
+ .importzp ptr1, ptr2
+
+_strcmp:
+ sta ptr2 ; Save s2
+ stx ptr2+1
+ jsr popax ; Get s1
+ sta ptr1
+ stx ptr1+1
+ ldy #0
+
+loop: lda (ptr1),y
+ cmp (ptr2),y
+ bne L1
+ tax ; end of strings?
+ beq L3
+ iny
+ bne loop
+ inc ptr1+1
+ inc ptr2+1
+ bne loop
+
+L1: bcs L2
+ ldx #$FF
+ rts
+
+L2: ldx #$01
+L3: rts
--- /dev/null
+;
+; Ullrich von Bassewitz, 11.12.1998
+;
+; int strcoll (const char* s1, const char* s2);
+;
+; Since we don't have locales, this function is equivalent to strcmp.
+;
+
+ .export _strcoll
+ .import _strcmp
+
+_strcoll = _strcmp
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 31.05.1998
+;
+; char* strcpy (char* dest, const char* src);
+;
+
+ .export _strcpy
+ .import popax
+ .importzp ptr1, ptr2, ptr3
+
+_strcpy:
+ sta ptr1 ; Save src
+ stx ptr1+1
+ jsr popax ; Get dest
+ sta ptr2
+ stx ptr2+1
+ sta ptr3 ; remember for function return
+ stx ptr3+1
+ ldy #$00
+
+L1: lda (ptr1),y
+ sta (ptr2),y
+ beq L9
+ iny
+ bne L1
+ inc ptr1+1
+ inc ptr2+1
+ bne L1
+
+L9: lda ptr3
+ ldx ptr3+1
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 11.06.1998
+;
+; size_t strcspn (const char* s1, const char* s2);
+;
+
+ .export _strcspn
+ .import popax
+ .importzp ptr1, ptr2, tmp1, tmp2, tmp3
+
+_strcspn:
+ sta ptr2 ; Save s2
+ stx ptr2+1
+ jsr popax ; Get s1
+ sta ptr1
+ stx ptr1+1
+ ldx #0 ; low counter byte
+ stx tmp1 ; high counter byte
+ ldy #$00
+
+L1: lda (ptr1),y ; get next char from s1
+ beq L6 ; jump if done
+ sta tmp2 ; save char
+ iny
+ bne L2
+ inc ptr1+1
+L2: sty tmp3 ; save index into s1
+
+ ldy #0 ; get index into s2
+L3: lda (ptr2),y ;
+ beq L4 ; jump if done
+ cmp tmp2
+ beq L6
+ iny
+ bne L3
+
+; The character was not found in s2. Increment the counter and start over
+
+L4: ldy tmp3 ; reload index
+ inx
+ bne L1
+ inc tmp1
+ bne L1
+
+; The character was found, or we reached the end of s1. Return count of
+; characters
+
+L6: txa ; get low counter byte
+ ldx tmp1 ; get high counter byte
+ rts
+
+
+
+
--- /dev/null
+/*
+ * strdup.c
+ *
+ * Ullrich von Bassewitz, 11.08.1998
+ */
+
+
+
+#include <string.h>
+#include <stdlib.h>
+
+
+
+char* strdup (char* s)
+{
+ char* p;
+ p = malloc (strlen (s) + 1);
+ if (p) {
+ strcpy (p, s);
+ }
+ return p;
+}
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 17.05.2000
+;
+; char* __fastcall__ strerror (int errcode);
+; /* Map an error number to an error message */
+;
+
+ .export _strerror
+ .import __sys_errlist
+
+ .include "errno.inc"
+
+_strerror:
+ cpx #$00 ; High byte must be zero
+ bne @L1 ; Jump if invalid error
+ cmp #EMAX ; Valid error code (map EUNKNOWN to 0)?
+ bcc @L2 ; Jump if ok
+@L1: lda #$00 ; "Unknown error"
+@L2: asl a ; * 2
+ tay
+
+; Load the pointer to the error message and return
+
+ lda __sys_errlist+1,y
+ tax
+ lda __sys_errlist,y
+ rts
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 03.06.1998
+;
+; int stricmp (const char* s1, const char* s2); /* DOS way */
+; int strcasecmp (const char* s1, const char* s2); /* UNIX way */
+;
+
+ .export _stricmp, _strcasecmp
+ .import popax
+ .import __ctype, __cdiff
+ .importzp ptr1, ptr2, tmp1
+
+
+_stricmp:
+_strcasecmp:
+ sta ptr2 ; Save s2
+ stx ptr2+1
+ jsr popax ; get s1
+ sta ptr1
+ stx ptr1+1
+ ldy #0
+
+loop: lda (ptr2),y ; get char from second string
+ tax
+ lda __ctype,x ; get character classification
+ and #$01 ; lower case char?
+ beq L1 ; jump if no
+ txa ; get character back
+ clc
+ adc __cdiff ; make upper case char
+ tax ;
+L1: stx tmp1 ; remember upper case equivalent
+
+ lda (ptr1),y ; get character from first string
+ tax
+ lda __ctype,x ; get character classification
+ and #$01 ; lower case char?
+ beq L2 ; jump if no
+ txa ; get character back
+ clc
+ adc __cdiff ; make upper case char
+ tax
+
+L2: cpx tmp1 ; compare characters
+ bne L3
+ txa ; end of strings?
+ beq L5 ; a/x both zero
+ iny
+ bne loop
+ inc ptr1+1
+ inc ptr2+1
+ bne loop
+
+L3: bcs L4
+ ldx #$FF
+ rts
+
+L4: ldx #$01
+L5: rts
--- /dev/null
+;
+; Ullrich von Bassewitz, 31.05.1998
+;
+; int strlen (const char* s);
+;
+
+ .export _strlen
+ .importzp ptr1
+
+_strlen:
+ sta ptr1 ; Save s
+ stx ptr1+1
+ ldx #0 ; YX used as counter
+ ldy #0
+
+L1: lda (ptr1),y
+ beq L9
+ iny
+ bne L1
+ inc ptr1+1
+ inx
+ bne L1
+
+L9: tya ; get low byte of counter, hi's all set
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 02.06.1998
+;
+; char* strlower (char* s);
+; char* strlwr (char* s);
+;
+; Non-ANSI
+;
+
+ .export _strlower, _strlwr
+ .import popax
+ .import __ctype, __cdiff
+ .importzp ptr1, ptr2
+
+_strlower:
+_strlwr:
+ sta ptr1 ; Save s (working copy)
+ stx ptr1+1
+ sta ptr2
+ sta ptr2+2 ; save function result
+ ldy #0
+
+loop: lda (ptr1),y ; get character
+ beq L9 ; jump if done
+ tax
+ lda __ctype,x ; get character classification
+ and #$02 ; upper case char?
+ beq L1 ; jump if no
+ txa ; get character back into accu
+ sec
+ sbc __cdiff ; make lower case char
+ sta (ptr1),y ; store back
+L1: iny ; next char
+ bne loop
+ inc ptr1+1 ; handle offset overflow
+ bne loop ; branch always
+
+; Done, return the argument string
+
+L9: lda ptr2
+ ldx ptr2+1
+ rts
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 31.05.1998
+;
+; char* strncat (char* dest, const char* src, size_t n);
+;
+
+ .export _strncat
+ .import popax
+ .importzp ptr1, ptr2, ptr3, tmp1, tmp2
+
+_strncat:
+ eor #$FF ; one's complement to count upwards
+ sta tmp1
+ txa
+ eor #$FF
+ sta tmp2
+ jsr popax ; get src
+ sta ptr1
+ stx ptr1+1
+ jsr popax ; get dest
+ sta ptr2
+ stx ptr2+1
+ sta ptr3 ; remember for function return
+ stx ptr3+1
+ ldy #0
+
+; find end of dest
+
+L1: lda (ptr2),y
+ beq L2
+ iny
+ bne L1
+ inc ptr2+1
+ bne L1
+
+; end found, get offset in y into pointer
+
+L2: tya
+ clc
+ adc ptr2
+ sta ptr2
+ bcc L3
+ inc ptr2+1
+
+; copy src. We've put the ones complement of the count into the counter, so
+; we'll increment the counter on top of the loop
+
+L3: ldy #0
+ ldx tmp1 ; low counter byte
+
+L4: inx
+ bne L5
+ inc tmp2
+ beq L6 ; jump if done
+L5: lda (ptr1),y
+ sta (ptr2),y
+ beq L7
+ iny
+ bne L4
+ inc ptr1+1
+ inc ptr2+1
+ bne L4
+
+; done, set the trailing zero and return pointer to dest
+
+L6: lda #0
+ sta (ptr2),y
+L7: lda ptr3
+ ldx ptr3+1
+ rts
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 25.05.2000
+;
+; int strncmp (const char* s1, const char* s2, unsigned n);
+;
+
+ .export _strncmp
+ .import popax
+ .importzp ptr1, ptr2, ptr3
+
+
+_strncmp:
+
+; Convert the given counter value in a/x from a downward counter into an
+; upward counter, so we can increment the counter in the loop below instead
+; of decrementing it. This adds some overhead now, but is cheaper than
+; executing a more complex test in each iteration of the loop. We do also
+; correct the value by one, so we can do the test on top of the loop.
+
+ eor #$FF
+ sta ptr3
+ txa
+ eor #$FF
+ sta ptr3+1
+
+; Get the remaining arguments
+
+ jsr popax ; get s2
+ sta ptr2
+ stx ptr2+1
+ jsr popax ; get s1
+ sta ptr1
+ stx ptr1+1
+
+; Loop setup
+
+ ldy #0
+
+; Start of compare loop. Check the counter.
+
+Loop: inc ptr3
+ beq IncHi ; Increment high byte
+
+; Compare a byte from the strings
+
+Comp: lda (ptr1),y
+ cmp (ptr2),y
+ bne NotEqual ; Jump if strings different
+ tax ; End of strings?
+ beq Equal1 ; Jump if EOS reached, a/x == 0
+
+; Increment the pointers
+
+ iny
+ bne Loop
+ inc ptr1+1
+ inc ptr2+1
+ bne Loop ; Branch always
+
+; Increment hi byte
+
+IncHi: inc ptr3+1
+ bne Comp ; Jump if counter not zero
+
+; Exit code if strings are equal. a/x not set
+
+Equal: lda #$00
+ tax
+Equal1: rts
+
+; Exit code if strings not equal
+
+NotEqual:
+ bcs L1
+ ldx #$FF ; Make result negative
+ rts
+
+L1: ldx #$01 ; Make result positive
+ rts
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 31.05.1998
+;
+; char* strncpy (char* dest, const char* src, unsigned size);
+;
+
+ .export _strncpy
+ .import popax
+ .importzp ptr1, ptr2, ptr3, tmp1, tmp2
+
+_strncpy:
+ sta tmp1 ; Save size
+ stx tmp2
+ jsr popax ; get src
+ sta ptr1
+ stx ptr1+1
+ jsr popax ; get dest
+ sta ptr2
+ stx ptr2+1
+ sta ptr3 ; remember for function return
+ stx ptr3+1
+
+ ldy #$00
+ ldx tmp1 ; Low byte of size
+ beq L1
+
+; Copy the first chunk < 256
+
+ jsr CopyChunk
+ bcs L3 ; Jump if end of string found
+
+; Copy full 256 byte chunks
+
+L1: lda tmp2 ; High byte of size
+ beq L3
+ ldx #$00 ; Copy 256 bytes
+L2: jsr CopyChunk
+ bcs L3
+ dec tmp2
+ bne L2
+ beq L9
+
+; Fill the remaining space with zeroes. If we come here, the value in X
+; is the low byte of the fill count, tmp2 holds the high byte. Y is the index
+; into the target string.
+
+L3: tax ; Test low byte
+ beq L4
+ jsr FillChunk
+
+L4: lda tmp2 ; Test high byte
+ beq L9
+L5: jsr FillChunk
+ dec tmp2
+ bne L5
+
+; Done - return a pointer to the string
+
+L9: lda ptr3
+ ldx ptr3+1
+ rts
+
+
+; -------------------------------------------------------------------
+; Copy byte count in X from ptr1 to ptr2
+
+.proc CopyChunk
+L1: lda (ptr1),y
+ sta (ptr2),y
+ beq L3
+ iny
+ bne L2
+ inc ptr1+1
+ inc ptr2+1
+L2: dex
+ bne L1
+ clc
+ rts
+L3: sec
+ rts
+.endproc
+
+
+; -------------------------------------------------------------------
+; Fill byte count in X with zeroes
+
+.proc FillChunk
+ lda #$00
+L1: sta (ptr1),y
+ iny
+ bne L2
+ inc ptr1+1
+L2: dex
+ bne L1
+ rts
+.endproc
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 11.06.1998
+;
+; char* strpbrk (const char* s1, const char* s2);
+;
+
+ .export _strpbrk
+ .import popax, return0
+ .importzp ptr1, ptr2, tmp1, tmp2, tmp3
+
+_strpbrk:
+ jsr popax ; get s2
+ sta ptr2
+ stx ptr2+1
+ jsr popax ; get s1
+ sta ptr1
+ stx ptr1+1
+ ldy #$00
+
+L1: lda (ptr1),y ; get next char from s1
+ beq L9 ; jump if done
+ sta tmp2 ; save char
+ iny
+ bne L2
+ inc ptr1+1
+L2: sty tmp3 ; save index into s1
+
+ ldy #0 ; get index into s2
+L3: lda (ptr2),y ;
+ beq L4 ; jump if done
+ cmp tmp2
+ beq L6
+ iny
+ bne L3
+
+; The character was not found in s2. Increment the counter and start over
+
+L4: ldy tmp3 ; reload index
+ inx
+ bne L1
+ inc tmp1
+ bne L1
+
+; A character was found. Calculate a pointer to this char in s1 and return it.
+
+L6: ldx ptr1+1
+ lda tmp3 ; get y offset
+ clc
+ adc ptr1
+ bcc L7
+ inx
+L7: rts
+
+; None of the characters in s2 was found - return NULL
+
+L9: jmp return0
+
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 31.05.1998
+;
+; char* strrchr (const char* s, int c);
+;
+
+ .export _strrchr
+ .import popax
+ .importzp ptr1, ptr2, tmp1
+
+_strrchr:
+ sta tmp1 ; Save c
+ jsr popax ; get s
+ sta ptr1
+ stx ptr1+1
+ lda #0 ; function result = NULL
+ sta ptr2
+ sta ptr2+1
+ tay
+
+L1: lda (ptr1),y ; get next char
+ beq L3 ; jump if end of string
+ cmp tmp1 ; found?
+ bne L2 ; jump if no
+
+; Remember a pointer to the character
+
+ tya
+ clc
+ adc ptr1
+ sta ptr2
+ lda ptr1+1
+ adc #$00
+ sta ptr2+1
+
+; Next char
+
+L2: iny
+ bne L1
+ inc ptr1+1
+ bne L1 ; jump always
+
+; Return the pointer to the last occurrence
+
+L3: lda ptr2
+ ldx ptr2+1
+ rts
--- /dev/null
+;
+; Ullrich von Bassewitz, 11.06.1998
+;
+; size_t strspn (const char* s1, const char* s2);
+;
+
+ .export _strspn
+ .import popax
+ .importzp ptr1, ptr2, tmp1, tmp2, tmp3
+
+_strspn:
+ sta ptr2 ; Save s2
+ stx ptr2+1
+ jsr popax ; get s1
+ sta ptr1
+ stx ptr1+1
+ ldx #0 ; low counter byte
+ stx tmp1 ; high counter byte
+ ldy #$00
+
+L1: lda (ptr1),y ; get next char from s1
+ beq L6 ; jump if done
+ sta tmp2 ; save char
+ iny
+ bne L2
+ inc ptr1+1
+L2: sty tmp3 ; save index into s1
+
+ ldy #0 ; get index into s2
+L3: lda (ptr2),y ;
+ beq L6 ; jump if done
+ cmp tmp2
+ beq L4
+ iny
+ bne L3
+
+; The character was found in s2. Increment the counter and start over
+
+L4: ldy tmp3 ; reload index
+ inx
+ bne L1
+ inc tmp1
+ bne L1
+
+; The character was not found, or we reached the end of s1. Return count of
+; characters
+
+L6: txa ; get low counter byte
+ ldx tmp1 ; get high counter byte
+ rts
+
+
+
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 11.12.1998
+;
+; char* strstr (const char* haystack, const char* needle);
+;
+
+ .export _strstr
+ .import popax
+ .importzp ptr1, ptr2, ptr3, ptr4, tmp1
+
+_strstr:
+ sta ptr2 ; Save needle
+ stx ptr2+1
+ sta ptr4 ; Setup temp copy for later
+
+ jsr popax ; Get haystack
+ sta ptr1
+ stx ptr1+1 ; Save haystack
+
+; If needle is empty, return haystack
+
+ ldy #$00
+ lda (ptr2),y ; Get first byte of needle
+ beq @Found ; Needle is empty --> we're done
+
+; Search for the beginning of the string (this is not an optimal search
+; strategy [in fact, it's pretty dumb], but it's simple to implement).
+
+ sta tmp1 ; Save start of needle
+@L1: lda (ptr1),y ; Get next char from haystack
+ beq @NotFound ; Jump if end
+ cmp tmp1 ; Start of needle found?
+ beq @L2 ; Jump if so
+ iny ; Next char
+ bne @L1
+ inc ptr1+1 ; Bump high byte
+ bne @L1 ; Branch always
+
+; We found the start of needle in haystack
+
+@L2: tya ; Get offset
+ clc
+ adc ptr1
+ sta ptr1 ; Make ptr1 point to start
+ bcc @L3
+ inc ptr1+1
+
+; ptr1 points to the start of needle now. Setup temporary pointers for the
+; search. The low byte of ptr4 is already set.
+
+@L3: sta ptr3
+ lda ptr1+1
+ sta ptr3+1
+ lda ptr2+1
+ sta ptr4+1
+ ldy #1 ; First char is identical, so start on second
+
+; Do the compare
+
+@L4: lda (ptr4),y ; Get char from needle
+ beq @Found ; Jump if end of needle (-> found)
+ cmp (ptr3),y ; Compare with haystack
+ bne @L5 ; Jump if not equal
+ iny ; Next char
+ bne @L4
+ inc ptr3+1
+ inc ptr4+1 ; Bump hi byte of pointers
+ bne @L4 ; Next char (branch always)
+
+; The strings did not compare equal, search next start of needle
+
+@L5: ldy #1 ; Start after this char
+ bne @L1 ; Branch always
+
+; We found the start of needle
+
+@Found: lda ptr1
+ ldx ptr1+1
+ rts
+
+; We reached end of haystack without finding needle
+
+@NotFound:
+ lda #$00 ; return NULL
+ tax
+ rts
+
+
+
+
+
+
+
+
+
+
+
--- /dev/null
+/*
+ * strtok.c
+ *
+ * Ullrich von Bassewitz, 11.12.1998
+ */
+
+
+
+#include <string.h>
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Memory location that holds the last input */
+static char* Last = 0;
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+char* strtok (char* s1, const char* s2)
+{
+ char c;
+ char* start;
+
+ /* Use the stored location if called with a NULL pointer */
+ if (s1 == 0) {
+ s1 = Last;
+ }
+
+ /* If s1 is empty, there are no more tokens. Return 0 in this case. */
+ if (*s1 == '\0') {
+ return 0;
+ }
+
+ /* Search the address of the first element in s1 that equals none
+ * of the characters in s2.
+ */
+ while ((c = *s1) && strchr (s2, c) != 0) {
+ ++s1;
+ }
+ if (c == '\0') {
+ /* No more tokens found */
+ Last = s1;
+ return 0;
+ }
+
+ /* Remember the start of the token */
+ start = s1;
+
+ /* Search for the end of the token */
+ while ((c = *s1) && strchr (s2, c) == 0) {
+ ++s1;
+ }
+ if (c == '\0') {
+ /* Last element */
+ Last = s1;
+ } else {
+ *s1 = '\0';
+ Last = s1 + 1;
+ }
+
+ /* Return the start of the token */
+ return start;
+}
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 02.06.1998
+;
+; char* strupper (char* s);
+; char* strupr (char* s);
+;
+; Non-ANSI
+;
+
+ .export _strupper, _strupr
+ .import popax
+ .import __ctype, __cdiff
+ .importzp ptr1, ptr2
+
+_strupper:
+_strupr:
+ sta ptr1 ; Save s (working copy)
+ stx ptr1+1
+ sta ptr2
+ sta ptr2+2 ; save function result
+ ldy #0
+
+loop: lda (ptr1),y ; get character
+ beq L9 ; jump if done
+ tax
+ lda __ctype,x ; get character classification
+ and #$01 ; lower case char?
+ beq L1 ; jump if no
+ txa ; get character back into accu
+ clc
+ adc __cdiff ; make upper case char
+ sta (ptr1),y ; store back
+L1: iny ; next char
+ bne loop
+ inc ptr1+1 ; handle offset overflow
+ bne loop ; branch always
+
+; Done, return the argument string
+
+L9: lda ptr2
+ ldx ptr2+1
+ rts
+
+
+
--- /dev/null
+/*
+ * strxfrm.c
+ *
+ * Ullrich von Bassewitz, 11.12.1998
+ */
+
+
+
+#include <string.h>
+
+
+
+size_t strxfrm (char* dest, const char* src, size_t count)
+{
+ strncpy (dest, src, count);
+ return strlen (src);
+}
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 02.06.1998
+;
+; int tolower (int c);
+;
+
+ .export _tolower
+ .import __ctype, __cdiff
+
+_tolower:
+ tay ; Get C into Y
+ lda __ctype,y ; Get character classification
+ and #$02 ; Is this an upper case char?
+ beq L1 ; Jump if no
+ tya ; Get char back into A
+ sec
+ sbc __cdiff ; make lower case char
+ rts ; CC are set
+
+L1: tya ; Get char back into A
+ rts ; CC are set
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 02.06.1998
+;
+; int toupper (int c);
+;
+
+ .export _toupper
+ .import __ctype, __cdiff
+
+_toupper:
+ tay ; Get c into Y
+ lda __ctype,y ; Get character classification
+ and #$01 ; Mask lower char bit
+ beq L1 ; Jump if not lower char
+ tya ; Get C back into A
+ clc
+ adc __cdiff ; make upper case char
+ rts ; CC are set
+
+L1: tya ; Get C back
+ rts ; CC are set
+
--- /dev/null
+/*
+ * vcprintf.c
+ *
+ * Ullrich von Bassewitz, 11.08.1998
+ */
+
+
+
+#include <stdarg.h>
+#include <conio.h>
+#include "_printf.h"
+
+
+
+static void out (struct outdesc* d, char* buf, unsigned count)
+/* Routine used for writing */
+{
+ /* Fast screen output */
+ d->ccount += count;
+ while (count) {
+ cputc (*buf);
+ ++buf;
+ --count;
+ }
+}
+
+
+
+int vcprintf (char* format, va_list ap)
+{
+ struct outdesc d;
+
+ /* Setup descriptor */
+ d.fout = out;
+
+ /* Do formatting and output */
+ _printf (&d, format, ap);
+
+ /* Return bytes written */
+ return d.ccount;
+}
+
+
+
--- /dev/null
+/*
+ * vfprintf.c
+ *
+ * Ullrich von Bassewitz, 11.08.1998
+ */
+
+
+
+#include <stdarg.h>
+#include <stdio.h>
+#include "_printf.h"
+
+
+
+static void out (struct outdesc* d, char* buf, unsigned count)
+/* Routine used for writing */
+{
+ /* Write to the file */
+ if (fwrite (buf, count, 1, (FILE*) d->ptr) == -1) {
+ d->ccount = -1;
+ } else {
+ d->ccount += count;
+ }
+}
+
+
+
+int vfprintf (FILE* f, char* format, va_list ap)
+{
+ struct outdesc d;
+
+ /* Setup descriptor */
+ d.fout = out;
+ d.ptr = f;
+
+ /* Do formatting and output */
+ _printf (&d, format, ap);
+
+ /* Return bytes written */
+ return d.ccount;
+}
+
+
+
--- /dev/null
+/*
+ * vprintf.c
+ *
+ * Ullrich von Bassewitz, 11.08.1998
+ */
+
+
+
+#include <stdarg.h>
+#include <stdio.h>
+#include "_printf.h"
+
+
+
+int vprintf (char* format, va_list ap)
+{
+ return vfprintf (stdout, format, ap);
+}
+
+
+
--- /dev/null
+/*
+ * vsprintf.c
+ *
+ * Ullrich von Bassewitz, 11.08.1998
+ */
+
+
+
+#include <stdarg.h>
+#include <stdio.h>
+#include "_printf.h"
+
+
+
+static void out (struct outdesc* d, char* buf, unsigned count)
+/* Routine used for writing */
+{
+ /* String - be shure to check the size */
+ while (count-- && d->ccount < d->uns) {
+ ((char*) d->ptr) [d->ccount] = *buf;
+ ++buf;
+ ++d->ccount;
+ }
+}
+
+
+
+int vsprintf (char* buf, char* format, va_list ap)
+{
+ struct outdesc d;
+
+ /* Setup descriptor */
+ d.fout = out;
+ d.ptr = buf;
+ d.uns = 0x7FFF;
+
+ /* Do formatting and output */
+ _printf (&d, format, ap);
+
+ /* Return bytes written */
+ return d.ccount;
+}
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 17.09.1998
+;
+; Zero the bss segment.
+;
+
+ .export zerobss
+ .import __BSS_RUN__, __BSS_SIZE__
+ .importzp ptr1
+
+
+.code
+
+zerobss:
+ lda #<__BSS_RUN__
+ sta ptr1
+ lda #>__BSS_RUN__
+ sta ptr1+1
+ lda #0
+ tay
+
+; Clear full pages
+
+L1: ldx #>__BSS_SIZE__
+ beq L3
+L2: sta (ptr1),y
+ iny
+ bne L2
+ inc ptr1+1
+ dex
+ bne L2
+
+; Clear remaining page (y is zero on entry)
+
+L3: ldx #<__BSS_SIZE__
+ beq L5
+L4: sta (ptr1),y
+ iny
+ dex
+ bne L4
+
+; Done
+
+L5: rts
+
+
+
--- /dev/null
+#
+# makefile for CC65 runtime library
+#
+
+.SUFFIXES: .o .s .c
+
+%.o: %.c
+ @echo $<
+ @$(CC) $(CFLAGS) $<
+ @$(AS) -o $@ $(AFLAGS) $(*).s
+
+%.o: %.s
+ @echo $<
+ @$(AS) -g -o $@ $(AFLAGS) $<
+
+C_OBJS =
+
+S_OBJS = cputs.o cursor.o cputhex.o scrsize.o
+
+all: $(C_OBJS) $(S_OBJS)
+
+clean:
+ @rm -f *~
+ @rm -f $(C_OBJS:.o=.s)
+ @rm -f $(C_OBJS)
+ @rm -f $(S_OBJS)
--- /dev/null
+;
+; Ullrich von Bassewitz, 08.08.1998
+;
+; void cputhex8 (unsigned char val);
+; void cputhex16 (unsigned val);
+;
+
+ .export _cputhex8, _cputhex16
+ .import _cputc
+ .import __hextab
+
+
+_cputhex16:
+ pha ; Save low byte
+ txa ; Get high byte into A
+ jsr _cputhex8 ; Output high byte
+ pla ; Restore low byte and run into _cputhex8
+
+_cputhex8:
+ pha ; Save the value
+ lsr a
+ lsr a
+ lsr a
+ lsr a
+ tay
+ lda __hextab,y
+ jsr _cputc
+ pla
+ and #$0F
+ tay
+ lda __hextab,y
+ jmp _cputc
+
+
+
+
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; void cputsxy (unsigned char x, unsigned char y, char* s);
+; void cputs (char* s);
+;
+
+ .export _cputsxy, _cputs
+ .import popa, _gotoxy, _cputc
+ .importzp ptr1, tmp1
+
+_cputsxy:
+ sta ptr1 ; Save s for later
+ stx ptr1+1
+ jsr popa ; Get Y
+ jsr _gotoxy ; Set cursor, pop x
+ jmp L0 ; Same as cputs...
+
+_cputs: sta ptr1 ; Save s
+ stx ptr1+1
+L0: ldy #0
+L1: lda (ptr1),y
+ beq L9 ; Jump if done
+ iny
+ sty tmp1 ; Save offset
+ jsr _cputc ; Output char, advance cursor
+ ldy tmp1 ; Get offset
+ bne L1 ; Next char
+ inc ptr1+1 ; Bump high byte
+ bne L1
+
+; Done
+
+L9: rts
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 17.06.1998
+;
+; unsigned char cursor (unsigned char onoff);
+;
+
+ .export _cursor
+ .export cursor
+
+
+.proc _cursor
+
+ tay ; onoff into Y
+ ldx #0 ; High byte of result
+ lda cursor ; Get old value
+ sty cursor ; Set new value
+ rts
+
+.endproc
+
+
+.bss
+
+cursor: .res 1
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 08.08.1998
+;
+; void screensize (unsigned char* x, unsigned char* y);
+;
+
+ .export _screensize
+ .export xsize, ysize
+
+ .import popax
+ .importzp ptr1, ptr2
+
+.proc _screensize
+
+ sta ptr1 ; Store the y pointer
+ stx ptr1+1
+
+ jsr popax ; get the x pointer
+ sta ptr2
+ stx ptr2+1
+
+ ldy #0
+ lda xsize
+ sta (ptr2),y
+ lda ysize
+ sta (ptr1),y
+ rts
+
+.endproc
+
+
+.bss
+
+xsize: .res 1
+ysize: .res 1
+
+
+
--- /dev/null
+#
+# makefile for CC65 runtime library
+#
+
+.SUFFIXES: .o .s .c
+
+%.o: %.c
+ @echo $<
+ @$(CC) $(CFLAGS) $<
+ @$(AS) -g -o $@ $(AFLAGS) $(*).s
+
+%.o: %.s
+ @echo $<
+ @$(AS) -g -o $@ $(AFLAGS) $<
+
+C_OBJS = dbg.o
+
+S_OBJS = asmtab.o dbgdasm.o dbgdump.o dbgisram.o dbgsupp.o
+
+all: $(C_OBJS) $(S_OBJS)
+
+clean:
+ @rm -f *~
+ @rm -f $(C_OBJS:.o=.s)
+ @rm -f $(C_OBJS)
+ @rm -f $(S_OBJS)
--- /dev/null
+;
+; Ullrich von Bassewitz, 07.08.1998
+;
+; Tables needed for the line assembler/disassembler.
+;
+
+ .export OffsetTab
+ .export AdrFlagTab
+ .export SymbolTab1, SymbolTab2
+ .export MnemoTab1, MnemoTab2
+
+; -------------------------------------------------------------------------
+; Assembler tables
+
+.rodata
+
+
+OffsetTab:
+ .byte $40,$02,$45,$03,$D0,$08,$40,$09
+ .byte $30,$22,$45,$33,$D0,$08,$40,$09
+ .byte $40,$02,$45,$33,$D0,$08,$40,$09
+ .byte $40,$02,$45,$B3,$D0,$08,$40,$09
+ .byte $00,$22,$44,$33,$D0,$8C,$44,$00
+ .byte $11,$22,$44,$33,$D0,$8C,$44,$9A
+ .byte $10,$22,$44,$33,$D0,$08,$40,$09
+ .byte $10,$22,$44,$33,$D0,$08,$40,$09
+ .byte $62,$13,$78,$A9
+
+AdrFlagTab:
+ .byte $00,$21,$81,$82,$00,$00,$59,$4D
+ .byte $91,$92,$86,$4A,$85,$9D
+
+SymbolTab1:
+ .byte $2C,$29,$2C,$23,$28,$24
+
+SymbolTab2:
+ .byte $59,$00,$58,$24,$24,$00
+
+MnemoTab1:
+ .byte $1C,$8A,$1C,$23,$5D,$8B,$1B,$A1
+ .byte $9D,$8A,$1D,$23,$9D,$8B,$1D,$A1
+ .byte $00,$29,$19,$AE,$69,$A8,$19,$23
+ .byte $24,$53,$1B,$23,$24,$53,$19,$A1
+ .byte $00,$1A,$5B,$5B,$A5,$69,$24,$24
+ .byte $AE,$AE,$A8,$AD,$29,$00,$7C,$00
+ .byte $15,$9C,$6D,$9C,$A5,$69,$29,$53
+ .byte $84,$13,$34,$11,$A5,$69,$23,$A0
+
+MnemoTab2:
+ .byte $D8,$62,$5A,$48,$26,$62,$94,$88
+ .byte $54,$44,$C8,$54,$68,$44,$E8,$94
+ .byte $00,$B4,$08,$84,$74,$B4,$28,$6E
+ .byte $74,$F4,$CC,$4A,$72,$F2,$A4,$8A
+ .byte $00,$AA,$A2,$A2,$74,$74,$74,$72
+ .byte $44,$68,$B2,$32,$B2,$00,$22,$00
+ .byte $1A,$1A,$26,$26,$72,$72,$88,$C8
+ .byte $C4,$CA,$26,$48,$44,$44,$A2,$C8
+
+
+
+
--- /dev/null
+/*
+ * dbg.c
+ *
+ * Ullrich von Bassewitz, 08.08.1998
+ *
+ */
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <conio.h>
+#include <ctype.h>
+#include <6502.h>
+#include <dbg.h>
+
+
+
+/*****************************************************************************/
+/* Function forwards */
+/*****************************************************************************/
+
+
+
+/* Forwards for handler functions */
+static char AsmHandler (void);
+static char RegHandler (void);
+static char StackHandler (void);
+static char CStackHandler (void);
+static char DumpHandler (void);
+static char HelpHandler (void);
+
+/* Forwards for other functions */
+static void DisplayPrompt (char* s);
+static void SingleStep (char StepInto);
+static void RedrawStatic (char Frame);
+static void Redraw (char Frame);
+static char GetKeyUpdate (void);
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+/* Color definitions */
+#ifdef __PLUS4__
+# define COLOR_BORDER (BCOLOR_DARKBLUE | CATTR_LUMA6)
+# define COLOR_BACKGROUND COLOR_WHITE
+# define COLOR_TEXTHIGH COLOR_BLACK
+# define COLOR_TEXTLOW COLOR_GRAY1
+# define COLOR_FRAMEHIGH COLOR_BLACK
+# define COLOR_FRAMELOW COLOR_GRAY2
+#else
+# ifdef COLOR_GRAY3
+# define COLOR_BORDER COLOR_BLACK
+# define COLOR_BACKGROUND COLOR_BLACK
+# define COLOR_TEXTHIGH COLOR_WHITE
+# define COLOR_TEXTLOW COLOR_GRAY3
+# define COLOR_FRAMEHIGH COLOR_WHITE
+# define COLOR_FRAMELOW COLOR_GRAY3
+# else
+# ifdef __APPLE2__
+# define COLOR_BORDER COLOR_BLACK
+# define COLOR_BACKGROUND COLOR_BLACK
+# define COLOR_TEXTHIGH COLOR_BLACK
+# define COLOR_TEXTLOW COLOR_BLACK
+# define COLOR_FRAMEHIGH COLOR_BLACK
+# define COLOR_FRAMELOW COLOR_BLACK
+# else
+# define COLOR_BORDER COLOR_BLACK
+# define COLOR_BACKGROUND COLOR_BLACK
+# define COLOR_TEXTHIGH COLOR_WHITE
+# define COLOR_TEXTLOW COLOR_WHITE
+# define COLOR_FRAMEHIGH COLOR_WHITE
+# define COLOR_FRAMELOW COLOR_WHITE
+# endif
+# endif
+#endif
+
+/* Screen definitions */
+#ifdef __CBM610__
+# define BIGSCREEN
+# define MAX_X 80
+# define MAX_Y 25
+# define DUMP_BYTES 16
+#else
+# ifdef __APPLE2__
+# define MAX_X 40
+# define MAX_Y 24
+# define DUMP_BYTES 8
+# else
+# ifdef __ATARI__
+# define MAX_X 40
+# define MAX_Y 24
+# define DUMP_BYTES 8
+# else
+# define MAX_X 40
+# define MAX_Y 25
+# define DUMP_BYTES 8
+# endif
+# endif
+#endif
+
+
+
+/* Key definitions */
+#ifndef CH_F1
+# define CH_F1 '?'
+#endif
+#ifndef CH_F2
+# define CH_F2 0
+#endif
+#ifndef CH_F3
+# define CH_F3 0
+#endif
+#ifndef CH_F4
+# define CH_F4 0
+#endif
+#ifndef CH_F5
+# define CH_F5 0
+#endif
+#ifndef CH_F6
+# define CH_F6 0
+#endif
+#ifndef CH_F7
+# define CH_F7 0
+#endif
+#ifndef CH_F8
+# define CH_F8 0
+#endif
+
+
+
+/* Defines for opcodes */
+#define OPC_BRK 0x00
+#define OPC_BPL 0x10
+#define OPC_JSR 0x20
+#define OPC_BMI 0x30
+#define OPC_RTI 0x40
+#define OPC_JMP 0x4C
+#define OPC_BVC 0x50
+#define OPC_RTS 0x60
+#define OPC_JMPIND 0x6C
+#define OPC_BVS 0x70
+#define OPC_BCC 0x90
+#define OPC_BCS 0xB0
+#define OPC_BNE 0xD0
+#define OPC_BEQ 0xF0
+
+
+
+/* Register values that are used also in the assembler stuff */
+extern unsigned char DbgSP; /* Stack pointer */
+extern unsigned DbgCS; /* C stack pointer */
+extern unsigned DbgHI; /* High 16 bit of primary reg */
+
+
+
+/* Descriptor for one text line */
+typedef struct {
+ unsigned char x;
+ unsigned char y;
+ char* text;
+} TextDesc;
+
+/* Window descriptor */
+typedef struct {
+ unsigned char fd_tl; /* Top left char */
+ unsigned char fd_tr; /* Top right char */
+ unsigned char fd_bl; /* Bottom left char */
+ unsigned char fd_br; /* Bottom right char */
+ unsigned char fd_x1, fd_y1; /* Upper left corner */
+ unsigned char fd_x2, fd_y2; /* Lower right corner */
+ unsigned char fd_width, fd_height; /* Redundant but faster */
+ unsigned char fd_visible; /* Is the window currently visible? */
+ char (*fd_func) (void); /* Handler function */
+ unsigned char fd_textcount; /* Number of text lines to print */
+ TextDesc* fd_text; /* Static text in the window */
+} FrameDesc;
+
+
+
+/* Texts for the windows */
+static TextDesc RegText [] = {
+ { 1, 0, "PC" },
+ { 1, 1, "SR" },
+ { 1, 2, "A" },
+ { 1, 3, "X" },
+ { 1, 4, "Y" },
+ { 1, 5, "SP" },
+ { 1, 6, "CS" },
+ { 1, 7, "HI" }
+};
+static TextDesc HelpText [] = {
+ { 1, 0, "F1 Help" },
+ { 1, 1, "F2 Toggle breakpoint" },
+ { 1, 2, "F3 Run until subroutine returns" },
+ { 1, 3, "F4 Run to cursor" },
+ { 1, 4, "F7 Step into" },
+ { 1, 5, "F8 Step over" },
+ { 1, 6, "1-5 Select active window" },
+ { 1, 7, "+ Page down" },
+ { 1, 8, "- Page up" },
+ { 1, 9, "Cursor Move up/down" },
+ { 1, 10, "c Continue" },
+ { 1, 11, "f Follow instruction" },
+ { 1, 12, "o Goto origin" },
+ { 1, 13, "p Use as new PC value" },
+ { 1, 14, "r Redraw screen" },
+ { 1, 15, "q Quit" },
+ { 1, 16, "s Skip next instruction" },
+};
+
+
+/* Window data */
+static FrameDesc AsmFrame = {
+ CH_ULCORNER, CH_TTEE, CH_LTEE, CH_CROSS,
+ 0, 0, MAX_X - 10, 15,
+ MAX_X - 11, 14,
+ 1,
+ AsmHandler,
+ 0, 0
+};
+static FrameDesc RegFrame = {
+ CH_TTEE, CH_URCORNER, CH_LTEE, CH_RTEE,
+ MAX_X - 10, 0, MAX_X - 1, 9,
+ 8, 8,
+ 1,
+ RegHandler,
+ sizeof (RegText) / sizeof (RegText [0]), RegText
+};
+static FrameDesc StackFrame = {
+ CH_LTEE, CH_RTEE, CH_CROSS, CH_RTEE,
+ MAX_X - 10, 9, MAX_X - 1, 15,
+ 8, 5,
+ 1,
+ StackHandler,
+ 0, 0
+};
+static FrameDesc CStackFrame = {
+ CH_CROSS, CH_RTEE, CH_BTEE, CH_LRCORNER,
+ MAX_X - 10, 15, MAX_X - 1, MAX_Y - 1,
+ 8, MAX_Y - 17,
+ 1,
+ CStackHandler,
+ 0, 0
+};
+static FrameDesc DumpFrame = {
+ CH_LTEE, CH_CROSS, CH_LLCORNER, CH_BTEE,
+ 0, 15, MAX_X - 10, MAX_Y-1,
+ MAX_X - 11, MAX_Y - 17,
+ 1,
+ DumpHandler,
+ 0, 0
+};
+static FrameDesc HelpFrame = {
+ CH_ULCORNER, CH_URCORNER, CH_LLCORNER, CH_LRCORNER,
+ 0, 0, MAX_X - 1, MAX_Y-1,
+ MAX_X - 2, MAX_Y - 2,
+ 0,
+ HelpHandler,
+ sizeof (HelpText) / sizeof (HelpText [0]), HelpText
+};
+static FrameDesc* Frames [] = {
+ &AsmFrame,
+ &RegFrame,
+ &StackFrame,
+ &CStackFrame,
+ &DumpFrame,
+ &HelpFrame
+};
+
+/* Number of active frame, -1 = none */
+static int ActiveFrame = -1;
+
+/* Window names */
+#define WIN_ASM 0
+#define WIN_REG 1
+#define WIN_STACK 2
+#define WIN_CSTACK 3
+#define WIN_DUMP 4
+#define WIN_HELP 5
+
+/* Other window data */
+static unsigned AsmAddr; /* Start address of output */
+static unsigned DumpAddr; /* Start address of output */
+static unsigned CStackAddr; /* Start address of output */
+static unsigned char StackAddr; /* Start address of output */
+
+
+
+/* Prompt line data */
+static char* ActivePrompt = 0; /* Last prompt line displayed */
+static char PromptColor; /* Color behind prompt */
+static char PromptLength; /* Length of current prompt string */
+
+
+
+/* Values for the bk_use field of struct BreakPoint */
+#define BRK_EMPTY 0x00
+#define BRK_USER 0x01
+#define BRK_TMP 0x80
+
+/* Structure describing a breakpoint */
+typedef struct {
+ unsigned bk_addr; /* Address, 0 if unused */
+ unsigned char bk_opc; /* Opcode */
+ unsigned char bk_use; /* 1 if in use, 0 otherwise */
+} BreakPoint;
+
+
+
+/* Temporary breakpoints - also accessed from the assembler source */
+#define MAX_USERBREAKS 10
+unsigned char DbgBreakCount = 0;
+BreakPoint DbgBreaks [MAX_USERBREAKS+2];
+
+
+
+/*****************************************************************************/
+/* Forwards for functions in the assembler source */
+/*****************************************************************************/
+
+
+
+BreakPoint* DbgGetBreakSlot (void);
+/* Search for a free breakpoint slot. Return a pointer to the slot or 0 */
+
+BreakPoint* DbgIsBreak (unsigned Addr);
+/* Check if there is a user breakpoint at the given address, if so, return
+ * a pointer to the slot, else return 0.
+ */
+
+
+
+/*****************************************************************************/
+/* Frame/window drawing code */
+/*****************************************************************************/
+
+
+
+static void DrawFrame (FrameDesc* F, char Active)
+/* Draw one window frame */
+{
+ TextDesc* T;
+ unsigned char Count;
+ unsigned char tl, tr, bl, br;
+ unsigned char x1, y1, width;
+ unsigned char OldColor;
+
+ /* Determine the characters for the corners, set frame color */
+ if (Active) {
+ OldColor = textcolor (COLOR_FRAMEHIGH);
+ tl = CH_ULCORNER;
+ tr = CH_URCORNER;
+ bl = CH_LLCORNER;
+ br = CH_LRCORNER;
+ } else {
+ OldColor = textcolor (COLOR_FRAMELOW);
+ tl = F->fd_tl;
+ tr = F->fd_tr;
+ bl = F->fd_bl;
+ br = F->fd_br;
+ }
+
+ /* Get the coordinates into locals for faster access */
+ x1 = F->fd_x1;
+ y1 = F->fd_y1;
+ width = F->fd_width;
+
+ /* Top line */
+ cputcxy (x1, y1, tl);
+ chline (width);
+ cputc (tr);
+
+ /* Left line */
+ cvlinexy (x1, ++y1, F->fd_height);
+
+ /* Bottom line */
+ cputc (bl);
+ chline (width);
+ cputc (br);
+
+ /* Right line */
+ cvlinexy (F->fd_x2, y1, F->fd_height);
+
+ /* If the window has static text associated, print the text */
+ textcolor (COLOR_TEXTLOW);
+ Count = F->fd_textcount;
+ T = F->fd_text;
+ while (Count--) {
+ cputsxy (x1 + T->x, y1 + T->y, T->text);
+ ++T;
+ }
+
+ /* Set the old color */
+ textcolor (OldColor);
+}
+
+
+
+static void DrawFrames (void)
+/* Draw all frames */
+{
+ unsigned char I;
+ FrameDesc* F;
+
+ /* Build the frame layout of the screen */
+ for (I = 0; I < sizeof (Frames) / sizeof (Frames [0]); ++I) {
+ F = Frames [I];
+ if (F->fd_visible) {
+ DrawFrame (F, 0);
+ }
+ }
+}
+
+
+
+static void ActivateFrame (int Num, unsigned char Clear)
+/* Activate a new frame, deactivate the old one */
+{
+ unsigned char y;
+ FrameDesc* F;
+
+ if (ActiveFrame != Num) {
+
+ /* Deactivate the old one */
+ if (ActiveFrame >= 0) {
+ DrawFrame (Frames [ActiveFrame], 0);
+ }
+
+ /* Activate the new one */
+ if ((ActiveFrame = Num) >= 0) {
+ F = Frames [ActiveFrame];
+ /* Clear the frame if requested */
+ if (Clear) {
+ for (y = F->fd_y1+1; y < F->fd_y2; ++y) {
+ cclearxy (F->fd_x1+1, y, F->fd_width);
+ }
+ }
+ DrawFrame (F, 1);
+ }
+
+ /* Redraw the current prompt line */
+ DisplayPrompt (ActivePrompt);
+
+ }
+}
+
+
+
+/*****************************************************************************/
+/* Prompt line */
+/*****************************************************************************/
+
+
+
+static void DisplayPrompt (char* s)
+/* Display a prompt */
+{
+ unsigned char OldColor;
+
+ /* Remember the current color */
+ OldColor = textcolor (COLOR_TEXTHIGH);
+
+ /* Clear the old prompt if there is one */
+ if (ActivePrompt) {
+ textcolor (PromptColor);
+ chlinexy ((MAX_X - PromptLength) / 2, MAX_Y-1, PromptLength);
+ }
+
+ /* Get the new prompt data */
+ ActivePrompt = s;
+ PromptColor = OldColor;
+ PromptLength = strlen (ActivePrompt);
+
+ /* Display the new prompt */
+ textcolor (COLOR_TEXTHIGH);
+ cputsxy ((MAX_X - PromptLength) / 2, MAX_Y-1, ActivePrompt);
+
+ /* Restore the old color */
+ textcolor (PromptColor);
+}
+
+
+
+static void HelpPrompt (void)
+/* Display a prompt line mentioning the help key */
+{
+ DisplayPrompt ("Press F1 for help");
+}
+
+
+
+static void AnyKeyPrompt (void)
+{
+ DisplayPrompt ("Press any key to continue");
+}
+
+
+
+static char Input (char* Prompt, char* Buf, unsigned char Count)
+/* Read input from the user, return 1 on success, 0 if aborted */
+{
+ int Frame;
+ unsigned char OldColor;
+ unsigned char OldCursor;
+ unsigned char x1;
+ unsigned char i;
+ unsigned char done;
+ char c;
+
+ /* Clear the current prompt line */
+ cclearxy (0, MAX_Y-1, MAX_X);
+
+ /* Display the new prompt */
+ OldColor = textcolor (COLOR_TEXTHIGH);
+ cputsxy (0, MAX_Y-1, Prompt);
+ textcolor (COLOR_TEXTLOW);
+
+ /* Remember where we are, enable the cursor */
+ x1 = wherex ();
+ OldCursor = cursor (1);
+
+ /* Get input and handle it */
+ i = done = 0;
+ do {
+ c = cgetc ();
+ if (isalnum (c) && i < Count) {
+ Buf [i] = c;
+ cputcxy (x1 + i, MAX_Y-1, c);
+ ++i;
+ } else if (i > 0 && c == CH_DEL) {
+ --i;
+ cputcxy (x1 + i, MAX_Y-1, ' ');
+ gotoxy (x1 + i, MAX_Y-1);
+ } else if (c == '\n') {
+ Buf [i] = '\0';
+ done = 1;
+ } else if (c == CH_ESC) {
+ /* Abort */
+ done = 2;
+ }
+ } while (!done);
+
+ /* Reset settings, display old prompt line */
+ cursor (OldCursor);
+ textcolor (OldColor);
+ DrawFrames ();
+ Frame = ActiveFrame;
+ ActiveFrame = -1;
+ ActivateFrame (Frame, 0);
+
+ return (done == 1);
+}
+
+
+
+static int InputHex (char* Prompt, unsigned* Val)
+/* Prompt for a hexadecimal value */
+{
+ char Buf [5];
+ char* P;
+ char C;
+ unsigned V;
+
+ /* Read input from the user (4 digits max), check input */
+ if (Input (Prompt, Buf, sizeof (Buf)-1) && isxdigit (Buf [0])) {
+
+ /* Check the characters and convert to hex */
+ P = Buf;
+ V = 0;
+ while ((C = *P) && isxdigit (C)) {
+ V <<= 4;
+ if (isdigit (C)) {
+ C -= '0';
+ } else {
+ C = toupper (C) - ('A' - 10);
+ }
+ V += C;
+ ++P;
+ }
+
+ /* Assign the value */
+ *Val = V;
+
+ /* Success */
+ return 1;
+
+ } else {
+
+ /* Failure */
+ return 0;
+
+ }
+}
+
+
+
+static int InputGoto (unsigned* Addr)
+/* Prompt "Goto" and read an address */
+{
+ return InputHex ("Goto: ", Addr);
+}
+
+
+
+static void ErrorPrompt (char* Msg)
+/* Display an error message and wait for a key */
+{
+ /* Save the current prompt */
+ char* OldPrompt = ActivePrompt;
+
+ /* Display the new one */
+ DisplayPrompt (Msg);
+
+ /* Wait for a key and discard it */
+ cgetc ();
+
+ /* Restore the old prompt */
+ DisplayPrompt (OldPrompt);
+}
+
+
+
+static void BreakInRomError (void)
+/* Print an error message if we cannot set a breakpoint */
+{
+ ErrorPrompt ("Cannot set breakpoint - press a key");
+}
+
+
+
+/*****************************************************************************/
+/* Breakpoint handling */
+/*****************************************************************************/
+
+
+
+static void DbgSetTmpBreak (unsigned Addr)
+/* Set a breakpoint */
+{
+ BreakPoint* B = DbgGetBreakSlot ();
+ B->bk_addr = Addr;
+ B->bk_use = BRK_TMP;
+}
+
+
+
+static void DbgToggleUserBreak (unsigned Addr)
+/* Set a breakpoint */
+{
+ BreakPoint* B = DbgIsBreak (Addr);
+
+ if (B) {
+ /* We have a breakpoint, remove it */
+ B->bk_use = BRK_EMPTY;
+ --DbgBreakCount;
+ } else {
+ /* We don't have a breakpoint, set one */
+ if (DbgBreakCount >= MAX_USERBREAKS) {
+ ErrorPrompt ("Too many breakpoints - press a key");
+ } else {
+ /* Test if we can set a breakpoint at that address */
+ if (!DbgIsRAM (Addr)) {
+ BreakInRomError ();
+ } else {
+ /* Set the breakpoint */
+ B = DbgGetBreakSlot ();
+ B->bk_addr = Addr;
+ B->bk_use = BRK_USER;
+ ++DbgBreakCount;
+ }
+ }
+ }
+}
+
+
+
+static void DbgResetTmpBreaks (void)
+/* Reset all temporary breakpoints */
+{
+ unsigned char i;
+ BreakPoint* B = DbgBreaks;
+
+ for (i = 0; i < MAX_USERBREAKS; ++i) {
+ if (B->bk_use == BRK_TMP) {
+ B->bk_use = BRK_EMPTY;
+ }
+ ++B;
+ }
+}
+
+
+
+static int DbgTmpBreaksOk (void)
+/* Check if the temporary breakpoints can be set, if so, return 1, if not,
+ * reset them all and return 0.
+ */
+{
+ unsigned char i;
+ BreakPoint* B = DbgBreaks;
+ for (i = 0; i < MAX_USERBREAKS; ++i) {
+ if (B->bk_use == BRK_TMP && !DbgIsRAM (B->bk_addr)) {
+ BreakInRomError ();
+ DbgResetTmpBreaks ();
+ return 0;
+ }
+ ++B;
+ }
+ return 1;
+}
+
+
+
+/*****************************************************************************/
+/* Assembler window stuff */
+/*****************************************************************************/
+
+
+
+static unsigned AsmBack (unsigned mem, unsigned char lines)
+/* Go back in the assembler window the given number of lines (calculate
+ * new start address).
+ */
+{
+ unsigned cur;
+ unsigned adr [32];
+ unsigned char in;
+
+ unsigned offs = 6;
+ while (1) {
+ in = 0;
+ cur = mem - (lines * 3) - offs;
+ while (1) {
+ cur += DbgDisAsmLen (cur);
+ adr [in] = cur;
+ in = (in + 1) & 0x1F;
+ if (cur >= mem) {
+ if (cur == mem || offs == 12) {
+ /* Found */
+ return adr [(in - lines - 1) & 0x1F];
+ } else {
+ /* The requested address is inside an instruction, go back
+ * one more byte and try again.
+ */
+ ++offs;
+ break;
+ }
+ }
+ }
+ }
+}
+
+
+
+static unsigned UpdateAsm (void)
+/* Update the assembler window starting at the given address */
+{
+ char buf [MAX_X];
+ unsigned char len;
+ unsigned char y;
+ unsigned char width = AsmFrame.fd_width;
+ unsigned char x = AsmFrame.fd_x1 + 1;
+ unsigned m = AsmBack (AsmAddr, 2);
+
+ for (y = AsmFrame.fd_y1+1; y < AsmFrame.fd_y2; ++y) {
+ len = DbgDisAsm (m, buf, width);
+ if (m == brk_pc) {
+ buf [4] = '-';
+ buf [5] = '>';
+ }
+ if (DbgIsBreak (m)) {
+ buf [5] = '*';
+ }
+ if (m == AsmAddr) {
+ revers (1);
+ cputsxy (1, y, buf);
+ revers (0);
+ } else {
+ cputsxy (1, y, buf);
+ }
+ m += len;
+ }
+ return m;
+}
+
+
+
+static unsigned AsmArg16 (void)
+/* Return a 16 bit argument */
+{
+ return *(unsigned*)(AsmAddr+1);
+}
+
+
+
+static void AsmFollow (void)
+/* Follow the current instruction */
+{
+ switch (*(unsigned char*) AsmAddr) {
+
+ case OPC_JMP:
+ case OPC_JSR:
+ AsmAddr = AsmArg16 ();
+ break;
+
+ case OPC_JMPIND:
+ AsmAddr = *(unsigned*)AsmArg16 ();
+ break;
+
+ case OPC_BPL:
+ case OPC_BMI:
+ case OPC_BVC:
+ case OPC_BVS:
+ case OPC_BCC:
+ case OPC_BCS:
+ case OPC_BNE:
+ case OPC_BEQ:
+ AsmAddr = AsmAddr + 2 + *(signed char*)(AsmAddr+1);
+ break;
+
+ case OPC_RTS:
+ AsmAddr = (*(unsigned*) (DbgSP + 0x101) + 1);
+ break;
+
+ case OPC_RTI:
+ AsmAddr = *(unsigned*) (DbgSP + 0x102);
+ break;
+
+ }
+}
+
+
+
+static void AsmHome (void)
+/* Set the cursor to home position */
+{
+ AsmAddr = brk_pc;
+}
+
+
+
+static void InitAsm (void)
+/* Initialize the asm window */
+{
+ AsmHome ();
+ UpdateAsm ();
+}
+
+
+
+static char AsmHandler (void)
+/* Get characters and handle them */
+{
+ char c;
+ unsigned Last;
+
+ while (1) {
+
+ /* Update the window contents */
+ Last = UpdateAsm ();
+
+ /* Read and handle input */
+ switch (c = GetKeyUpdate ()) {
+
+ case '+':
+ AsmAddr = Last;
+ break;
+
+ case '-':
+ AsmAddr = AsmBack (AsmAddr, AsmFrame.fd_height);
+ break;
+
+ case CH_F2:
+ DbgToggleUserBreak (AsmAddr);
+ break;
+
+ case 'f':
+ AsmFollow ();
+ break;
+
+ case 'g':
+ InputGoto (&AsmAddr);
+ break;
+
+ case 'o':
+ AsmHome ();
+ break;
+
+ case 'p':
+ brk_pc = AsmAddr;
+ break;
+
+ case CH_CURS_UP:
+ AsmAddr = AsmBack (AsmAddr, 1);
+ break;
+
+ case CH_CURS_DOWN:
+ AsmAddr += DbgDisAsmLen (AsmAddr);
+ break;
+
+ default:
+ return c;
+
+ }
+ }
+}
+
+
+
+/*****************************************************************************/
+/* Register window stuff */
+/*****************************************************************************/
+
+
+
+static unsigned UpdateReg (void)
+/* Update the register window */
+{
+ unsigned char x1 = RegFrame.fd_x1 + 5;
+ unsigned char x2 = x1 + 2;
+ unsigned char y = RegFrame.fd_y1;
+
+ /* Print the register contents */
+ gotoxy (x1, ++y); cputhex16 (brk_pc);
+ gotoxy (x2, ++y); cputhex8 (brk_sr);
+ gotoxy (x2, ++y); cputhex8 (brk_a);
+ gotoxy (x2, ++y); cputhex8 (brk_x);
+ gotoxy (x2, ++y); cputhex8 (brk_y);
+ gotoxy (x2, ++y); cputhex8 (DbgSP);
+ gotoxy (x1, ++y); cputhex16 (DbgCS);
+ gotoxy (x1, ++y); cputhex16 (DbgHI);
+
+ /* Not needed */
+ return 0;
+}
+
+
+
+static void InitReg (void)
+/* Initialize the register window */
+{
+ UpdateReg ();
+}
+
+
+
+static char RegHandler (void)
+/* Get characters and handle them */
+{
+ return GetKeyUpdate ();
+}
+
+
+
+/*****************************************************************************/
+/* Stack window stuff */
+/*****************************************************************************/
+
+
+
+static unsigned UpdateStack (void)
+/* Update the stack window */
+{
+ unsigned char mem = StackAddr;
+ unsigned char x1 = StackFrame.fd_x1 + 1;
+ unsigned char x2 = x1 + 6;
+ unsigned char y;
+
+ for (y = StackFrame.fd_y2-1; y > StackFrame.fd_y1; --y) {
+ gotoxy (x1, y);
+ cputhex8 (mem);
+ gotoxy (x2, y);
+ cputhex8 (* (unsigned char*) (mem + 0x100));
+ ++mem;
+ }
+ return mem;
+}
+
+
+
+static void StackHome (void)
+/* Set the cursor to home position */
+{
+ StackAddr = DbgSP + 1;
+}
+
+
+
+static void InitStack (void)
+/* Initialize the stack window */
+{
+ StackHome ();
+ UpdateStack ();
+}
+
+
+
+static char StackHandler (void)
+/* Get characters and handle them */
+{
+ char c;
+ unsigned char BytesPerPage = StackFrame.fd_height;
+
+ while (1) {
+
+ /* Read and handle input */
+ switch (c = GetKeyUpdate ()) {
+
+ case '+':
+ StackAddr += BytesPerPage;
+ break;
+
+ case '-':
+ StackAddr -= BytesPerPage;
+ break;
+
+ case 'o':
+ StackHome ();
+ break;
+
+ case CH_CURS_UP:
+ --StackAddr;
+ break;
+
+ case CH_CURS_DOWN:
+ ++StackAddr;
+ break;
+
+ default:
+ return c;
+
+ }
+
+ /* Update the window contents */
+ UpdateStack ();
+ }
+}
+
+
+
+/*****************************************************************************/
+/* C Stack window stuff */
+/*****************************************************************************/
+
+
+
+static unsigned UpdateCStack (void)
+/* Update the C stack window */
+{
+ unsigned mem = CStackAddr;
+ unsigned char x = CStackFrame.fd_x1 + 5;
+ unsigned char y;
+
+ for (y = CStackFrame.fd_y2-1; y > CStackFrame.fd_y1; --y) {
+ gotoxy (x, y);
+ cputhex16 (* (unsigned*)mem);
+ mem += 2;
+ }
+ cputsxy (CStackFrame.fd_x1+1, CStackFrame.fd_y2-1, "->");
+ return mem;
+}
+
+
+
+static void CStackHome (void)
+/* Set the cursor to home position */
+{
+ CStackAddr = DbgCS;
+}
+
+
+
+static void InitCStack (void)
+/* Initialize the C stack window */
+{
+ CStackHome ();
+ UpdateCStack ();
+}
+
+
+
+static char CStackHandler (void)
+/* Get characters and handle them */
+{
+ char c;
+ unsigned char BytesPerPage = CStackFrame.fd_height * 2;
+
+ while (1) {
+
+ /* Read and handle input */
+ switch (c = GetKeyUpdate ()) {
+
+ case '+':
+ CStackAddr += BytesPerPage;
+ break;
+
+ case '-':
+ CStackAddr -= BytesPerPage;
+ break;
+
+ case 'o':
+ CStackHome ();
+ break;
+
+ case CH_CURS_UP:
+ CStackAddr -= 2;
+ break;
+
+ case CH_CURS_DOWN:
+ CStackAddr += 2;
+ break;
+
+ default:
+ return c;
+
+ }
+
+ /* Update the window contents */
+ UpdateCStack ();
+ }
+}
+
+
+
+/*****************************************************************************/
+/* Dump window stuff */
+/*****************************************************************************/
+
+
+
+static unsigned UpdateDump (void)
+/* Update the dump window */
+{
+ char Buf [MAX_X];
+ unsigned char y;
+ unsigned mem = DumpAddr;
+ unsigned char x = DumpFrame.fd_x1 + 1;
+ unsigned char* p = (unsigned char*) mem;
+
+ for (y = DumpFrame.fd_y1+1; y < DumpFrame.fd_y2; ++y) {
+ cputsxy (x, y, DbgMemDump (mem, Buf, DUMP_BYTES));
+ mem += DUMP_BYTES;
+ }
+ return mem;
+}
+
+
+
+static void DumpHome (void)
+/* Set the cursor to home position */
+{
+ DumpAddr = 0;
+}
+
+
+
+static char DumpHandler (void)
+/* Get characters and handle them */
+{
+ char c;
+ unsigned BytesPerPage = DumpFrame.fd_height * 8;
+
+ while (1) {
+
+ /* Read and handle input */
+ switch (c = GetKeyUpdate ()) {
+
+ case '+':
+ DumpAddr += BytesPerPage;
+ break;
+
+ case '-':
+ DumpAddr -= BytesPerPage;
+ break;
+
+ case 'g':
+ InputGoto (&DumpAddr);
+ break;
+
+ case 'o':
+ DumpHome ();
+ break;
+
+ case CH_CURS_UP:
+ DumpAddr -= 8;
+ break;
+
+ case CH_CURS_DOWN:
+ DumpAddr += 8;
+ break;
+
+ default:
+ return c;
+
+ }
+
+ /* Update the window contents */
+ UpdateDump ();
+ }
+}
+
+
+
+/*****************************************************************************/
+/* Help window stuff */
+/*****************************************************************************/
+
+
+
+static char HelpHandler (void)
+/* Get characters and handle them */
+{
+ /* Activate the frame */
+ int OldActive = ActiveFrame;
+ ActivateFrame (WIN_HELP, 1);
+
+ /* Say that we're waiting for a key */
+ AnyKeyPrompt ();
+
+ /* Get a character and discard it */
+ cgetc ();
+
+ /* Redraw the old stuff */
+ Redraw (OldActive);
+
+ /* Done, return no char */
+ return 0;
+}
+
+
+
+/*****************************************************************************/
+/* Singlestep */
+/*****************************************************************************/
+
+
+
+static unsigned GetArg16 (void)
+/* Read an argument */
+{
+ return *(unsigned*)(brk_pc+1);
+}
+
+
+
+static unsigned GetStack16 (unsigned char Offs)
+/* Fetch a 16 bit value from stack top */
+{
+ return *(unsigned*)(DbgSP+Offs+0x101);
+}
+
+
+
+static void SetRTSBreak (void)
+/* Set a breakpoint at the return target */
+{
+ DbgSetTmpBreak (GetStack16 (0) + 1);
+}
+
+
+
+static void SingleStep (char StepInto)
+{
+ signed char Offs;
+
+ switch (*(unsigned char*) brk_pc) {
+
+ case OPC_JMP:
+ /* Set breakpoint at target */
+ DbgSetTmpBreak (GetArg16 ());
+ return;
+
+ case OPC_JMPIND:
+ /* Indirect jump, ignore CPU error when crossing page */
+ DbgSetTmpBreak (*(unsigned*)GetArg16 ());
+ return;
+
+ case OPC_BPL:
+ case OPC_BMI:
+ case OPC_BVC:
+ case OPC_BVS:
+ case OPC_BCC:
+ case OPC_BCS:
+ case OPC_BNE:
+ case OPC_BEQ:
+ /* Be sure not to set the breakpoint twice if this is a jump to
+ * the following instruction.
+ */
+ Offs = *(signed char*)(brk_pc+1);
+ if (Offs) {
+ DbgSetTmpBreak (brk_pc + Offs + 2);
+ }
+ break;
+
+ case OPC_RTS:
+ /* Set a breakpoint at the return target */
+ SetRTSBreak ();
+ return;
+
+ case OPC_RTI:
+ /* Set a breakpoint at the return target */
+ DbgSetTmpBreak (GetStack16 (1));
+ return;
+
+ case OPC_JSR:
+ if (StepInto) {
+ /* Set breakpoint at target */
+ DbgSetTmpBreak (GetArg16 ());
+ return;
+ }
+ break;
+ }
+
+ /* Place a breakpoint behind the instruction */
+ DbgSetTmpBreak (brk_pc + DbgDisAsmLen (brk_pc));
+}
+
+
+
+/*****************************************************************************/
+/* High level window handling */
+/*****************************************************************************/
+
+
+
+static void RedrawStatic (char Frame)
+/* Redraw static display stuff */
+{
+ /* Reset the active frame */
+ ActiveFrame = -1;
+
+ /* Clear the screen hide the cursor */
+ bordercolor (COLOR_BORDER);
+ bgcolor (COLOR_BACKGROUND);
+ clrscr ();
+ cursor (0);
+
+ /* Build the frame layout of the screen */
+ textcolor (COLOR_FRAMELOW);
+ DrawFrames ();
+
+ /* Draw the prompt line */
+ HelpPrompt ();
+
+ /* Activate the active frame */
+ ActivateFrame (Frame, 0);
+}
+
+
+
+static void Redraw (char Frame)
+/* Redraw the display in case it's garbled */
+{
+ /* Redraw the static stuff */
+ RedrawStatic (Frame);
+
+ /* Init the window contents */
+ UpdateAsm ();
+ UpdateReg ();
+ UpdateStack ();
+ UpdateCStack ();
+ UpdateDump ();
+}
+
+
+
+static char GetKeyUpdate (void)
+/* Wait for a key updating the windows in the background */
+{
+ static unsigned char Win;
+
+ /* While there are no keys... */
+ while (!kbhit ()) {
+
+ switch (Win) {
+
+ case 0:
+ UpdateAsm ();
+ break;
+
+ case 1:
+ UpdateStack ();
+ break;
+
+ case 2:
+ UpdateCStack ();
+ break;
+
+ case 3:
+ UpdateDump ();
+ break;
+ }
+
+ Win = (Win + 1) & 0x03;
+
+ }
+
+ /* We have a key - return it */
+ return cgetc ();
+}
+
+
+
+/*****************************************************************************/
+/* Externally visible functions */
+/*****************************************************************************/
+
+
+
+void DbgEntry (void)
+/* Start up the debugger */
+{
+ static unsigned char FirstTime = 1;
+ char c;
+ char done;
+
+ /* If this is the first call, setup the display */
+ if (FirstTime) {
+ FirstTime = 0;
+
+ /* Draw the window, default active frame is ASM frame */
+ RedrawStatic (WIN_ASM);
+ InitAsm ();
+ InitReg ();
+ InitStack ();
+ InitCStack ();
+ UpdateDump ();
+ }
+
+ /* Only initialize variables here, don't do a display update. The actual
+ * display update will be done while waiting for user input.
+ */
+ AsmHome ();
+ UpdateReg (); /* Must update this (static later) */
+ StackHome ();
+ CStackHome ();
+ DumpHome ();
+
+ /* Wait for user input */
+ done = 0;
+ while (!done) {
+ c = Frames [ActiveFrame]->fd_func ();
+ switch (c) {
+
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ ActivateFrame (c - '1', 0);
+ break;
+
+ case CH_F1:
+ HelpHandler ();
+ break;
+
+ case CH_F3:
+ /* Go until return */
+ SetRTSBreak ();
+ done = 1;
+ break;
+
+ case CH_F4:
+ /* Go to cursor, only possible if cursor not at current PC */
+ if (AsmAddr != brk_pc) {
+ DbgSetTmpBreak (AsmAddr);
+ done = 1;
+ }
+ break;
+
+ case ' ':
+ case '\n':
+ case CH_F7:
+ case CH_F8:
+ SingleStep (c == CH_F7 || c == ' ');
+ if (DbgTmpBreaksOk ()) {
+ /* Could set breakpoints */
+ done = 1;
+ }
+ break;
+
+ case 'c':
+ case 0:
+ done = 1;
+ break;
+
+ case 's':
+ /* Skip instruction */
+ brk_pc += DbgDisAsmLen (brk_pc);
+ InitAsm ();
+ break;
+
+ case 'r':
+ /* Redraw screen */
+ Redraw (ActiveFrame);
+ break;
+
+ case 'q':
+ /* Quit program */
+ clrscr ();
+ exit (1);
+
+ }
+ }
+}
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 07.08.1998
+;
+; unsigned DbgDisAsm (char* buf, unsigned addr);
+; unsigned DbgDisAsm (unsigned addr);
+;
+;
+; Part of this code is taken from the Plus/4 machine language monitor
+; (TEDMon).
+;
+
+ .import utsta0, popax
+ .import __hextab, OffsetTab, AdrFlagTab
+ .import SymbolTab1, SymbolTab2, MnemoTab1, MnemoTab2
+
+
+
+; -------------------------------------------------------------------------
+; Equates for better readability
+
+ .importzp sreg, tmp1, tmp2, tmp3, tmp4, ptr1, ptr2, ptr3
+
+BufIndex = tmp1 ; Index into output buffer
+OperandLen = tmp2 ; Length of operand
+BufLen = tmp3 ; Length of output buffer
+AdrFlagBuf = tmp4 ; Flag for addressing mode
+YSave = sreg ; Temp storage
+XSave = sreg+1 ; Dito
+BufPtr = ptr1 ; Pointer to output buffer
+MemPtr = ptr2 ; Pointer to memory to disassemble
+MnemoBuf = ptr3 ; Buffer for decoding mnemonic
+
+
+; -------------------------------------------------------------------------
+; Main entries
+
+ .export _DbgDisAsm, _DbgDisAsmLen
+
+.proc _DbgDisAsm
+ sta BufLen ; Save the buffer length
+ jsr popax ; Get the buffer pointer
+ sta BufPtr
+ stx BufPtr+1
+ jsr popax ; Get the address
+ sta MemPtr
+ stx MemPtr+1
+ lda #0
+ sta BufIndex ; Initialize index into buffer
+ jsr DisAssLine ; Disassemble one line into the buffer
+
+ lda BufLen ; Get requested length
+ sec
+ sbc BufIndex
+ beq L2
+ tax ; Count into X
+ ldy BufIndex
+ lda #$20 ; Get a space
+L1: sta (BufPtr),y
+ iny
+ dex
+ bne L1
+L2: lda #0 ; Add C string terminator
+ sta (BufPtr),y
+ beq disassret
+
+.endproc
+
+
+_DbgDisAsmLen:
+ sta MemPtr ; Save address
+ stx MemPtr+1
+ ldy #$00
+ lda (MemPtr),y ; Get the opcode from memory...
+ jsr AnalyzeOPCode ; ...and analyze it
+disassret:
+ ldx OperandLen ; Get length of operand
+ inx ; Adjust for opcode byte
+ txa
+ jmp utsta0 ; Set condition codes
+
+; -------------------------------------------------------------------------
+; Helper functions
+
+
+Put3Spaces:
+ jsr PutSpace
+Put2Spaces:
+ jsr PutSpace
+PutSpace:
+ lda #$20
+PutChar:
+ sty YSave ; Save Y
+ ldy BufIndex ; Get current line pointer
+ cpy BufLen ; Be sure not to overflow the buffer
+ bcs PC9
+ sta (BufPtr),y ; store character
+ iny ; bump index
+ sty BufIndex
+PC9: ldy YSave ; get old value
+ rts
+
+; Print the 16 bit hex value in X/Y
+
+PutHex16:
+ txa
+ jsr PutHex8
+ tya
+
+; Print 8 bit value in A, save X and Y
+
+PutHex8:
+ stx XSave
+ sty YSave
+ ldy BufIndex
+ pha
+ lsr a
+ lsr a
+ lsr a
+ lsr a
+ tax
+ lda __hextab,x
+ sta (BufPtr),y
+ iny
+ pla
+ and #$0F
+ tax
+ lda __hextab,x
+ sta (BufPtr),y
+ iny
+ sty BufIndex
+ ldy YSave
+ ldx XSave
+ rts
+
+; -------------------------------------------------------------------------
+; Eine Zeile disassemblieren
+
+DisAssLine:
+ ldy MemPtr
+ ldx MemPtr+1
+ jsr PutHex16 ; Print the address
+ jsr Put2Spaces ; Add some space
+ ldy #$00
+ lda (MemPtr),y ; Get the opcode from memory...
+ jsr AnalyzeOPCode ; ...and analyze it
+ pha ; Save mnemonic
+ ldx OperandLen ; Number of bytes
+
+; Print the bytes that make up the instruction
+
+ inx
+L2083: dex
+ bpl L208C ; Print the instruction bytes
+ jsr Put3Spaces ; If none left, print spaces instead
+ jmp L2094
+L208C: lda (MemPtr),y ; Get a byte from memory
+ jsr PutHex8 ; ...and print it
+ jsr PutSpace ; Add some space
+
+L2094: iny ; Next one...
+ cpy #$03 ; Maximum is three
+ bcc L2083 ;
+
+ jsr Put2Spaces ; Add some space after bytes
+
+; Print the assembler mnemonic
+
+ pla ; Get mnemonic code
+ ldx #$03
+ jsr PutMnemo ; Print the mnemonic
+ ldx #$06
+
+; Print the operand
+
+L20A4: cpx #$03
+ bne L20BA
+ ldy OperandLen
+ beq L20BA
+
+L20AC: lda AdrFlagBuf
+ cmp #$E8 ; Branch?
+ lda (MemPtr),y ; Get branch offset
+ bcs GetBranchAdr ; If branch: Calculate address
+ jsr PutHex8 ; Otherwise print 8bit value
+ dey
+ bne L20AC
+
+L20BA: asl AdrFlagBuf
+ bcc L20CC
+ lda SymbolTab1-1,x
+ jsr PutChar
+ lda SymbolTab2-1,x
+ beq L20CC
+ jsr PutChar
+
+L20CC: dex
+ bne L20A4
+ rts
+
+; If the instruction is a branch, calculate the absolute address of the
+; branch target and print it.
+
+GetBranchAdr:
+ jsr L20DD
+ clc
+ adc #$01
+ bne L20D9
+ inx ; Bump high byte
+L20D9: tay
+ jmp PutHex16 ; Output address
+
+L20DD: ldx MemPtr+1
+ tay
+ bpl L20E3
+ dex
+L20E3: adc MemPtr
+ bcc L20E8
+ inx ; Bump high byte
+L20E8: rts
+
+; -------------------------------------------------------------------------
+; Subroutine to analyze an opcode byte in A. Will return a byte that
+; encodes the mnemonic, and will set the number of bytes needed for this
+; instruction in OperandLen
+
+AnalyzeOPCode:
+ tay
+ lsr a
+ bcc L20F8
+ lsr a
+ bcs L2107
+ cmp #$22
+ beq L2107
+ and #$07
+ ora #$80
+L20F8: lsr a
+ tax
+ lda OffsetTab,x
+ bcs L2103
+ lsr a
+ lsr a
+ lsr a
+ lsr a
+L2103: and #$0F
+ bne L210B
+L2107: ldy #$80
+ lda #$00
+L210B: tax
+ lda AdrFlagTab,x
+ sta AdrFlagBuf
+ and #$03
+ sta OperandLen
+ tya
+ and #$8F
+ tax
+ tya
+ ldy #$03
+ cpx #$8A
+ beq L212B
+
+L2120: lsr a
+ bcc L212B
+ lsr a
+L2124: lsr a
+ ora #$20
+ dey
+ bne L2124
+ iny
+L212B: dey
+ bne L2120
+ rts
+
+; -------------------------------------------------------------------------
+; Print the mnemonic with code in A (that code was returned by
+; AnalyzeOpcode).
+
+PutMnemo:
+ tay
+ lda MnemoTab1,y
+ sta MnemoBuf
+ lda MnemoTab2,y
+ sta MnemoBuf+1
+L213A: lda #$00
+ ldy #$05 ; 3*5 bits in two bytes
+L213E: asl MnemoBuf+1
+ rol MnemoBuf
+ rol a
+ dey
+ bne L213E
+ adc #$3F
+ jsr PutChar
+ dex
+ bne L213A
+ jmp PutSpace
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 11.08.1998
+;
+; char* DbgMemDump (unsigend Addr, char* Buf, unsigned char Length);
+;
+
+ .export _DbgMemDump
+ .import addysp1
+ .import __hextab
+ .importzp sp, tmp2, tmp3, tmp4, ptr3, ptr4
+
+_DbgMemDump:
+ ldy #0
+ lda (sp),y ; Get length
+ sta tmp4
+ iny
+ lda (sp),y ; Get the string buffer
+ sta ptr3
+ iny
+ lda (sp),y
+ sta ptr3+1
+ iny
+ lda (sp),y ; Get the address
+ sta ptr4
+ iny
+ lda (sp),y
+ sta ptr4+1
+ jsr addysp1 ; Drop the parameters
+
+ lda #0
+ sta tmp2 ; String index
+ sta tmp3 ; Byte index
+
+; Print the address
+
+ lda ptr4+1 ; Hi address byte
+ jsr dump ; Print address
+ lda ptr4 ; Lo address byte
+ jsr dump
+ jsr putspace ; Add a space
+
+dump1: dec tmp4 ; Bytes left?
+ bmi dump9 ; Jump if no
+ jsr putspace ; Add a space
+ ldy tmp3
+ inc tmp3
+ lda (ptr4),y
+ jsr dump
+ jmp dump1
+
+dump9: lda #0
+ ldy tmp2
+ sta (ptr3),y ; Add string terminator
+ lda ptr3
+ ldx ptr3+1 ; We assume this is not zero
+ rts
+
+; Dump one hex byte
+
+dump: pha
+ lsr a
+ lsr a
+ lsr a
+ lsr a
+ tax
+ lda __hextab,x
+ jsr putc
+ pla
+ and #$0F
+ tax
+ lda __hextab,x
+putc: ldy tmp2
+ inc tmp2
+ sta (ptr3),y
+ rts
+
+putspace:
+ lda #$20
+ bne putc
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 10.08.1998
+;
+; int DbgIsRAM (unsigned Addr);
+;
+
+ .export _DbgIsRAM
+ .import popax, return0, return1
+ .importzp ptr1
+
+_DbgIsRAM:
+ sta ptr1 ; Store the address
+ stx ptr1+1
+
+ ldy #0
+ php ; Save I flag
+ sei ; Disable interrupts
+
+ lda (ptr1),y ; Get old value
+ pha ; ...and save it
+
+ ldx #3
+L1: lda TestVal,x
+ jsr CheckCell
+ bne L2
+ dex
+ bpl L1
+
+; This seems to be RAM
+
+ pla
+ sta (ptr1),y ; Restore old value
+ plp ; Restore old I flag
+ jmp return1
+
+; No RAM at this address
+
+L2: pla
+ sta (ptr1),y ; Restore old value
+ plp ; Restore old I flag
+ jmp return0
+
+; Check one memory cell
+
+CheckCell:
+ sta (ptr1),y
+ cmp (ptr1),y ; Could we write it?
+ rts
+
+
+.rodata
+TestVal:
+ .byte $55, $AA, $33, $CC
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 08.08.1998
+;
+; Support routines for the debugger
+;
+
+ .export _DbgInit
+ .export _DbgSP, _DbgCS, _DbgHI
+ .import popax, return0, _DbgEntry, _set_brk, _end_brk
+ .import _DbgBreaks
+ .import _brk_pc
+ .importzp sp, sreg, ptr1, tmp1, zpspace
+
+; C callable function, will install the debugger
+
+_DbgInit:
+ lda #<DbgBreak
+ ldx #>DbgBreak
+ jmp _set_brk
+
+
+; Entry for the break vector.
+
+DbgBreak:
+ pla
+ sta retsav
+ pla
+ sta retsav+1
+
+ cli
+ tsx ; Stack pointer
+ stx _DbgSP
+
+ jsr DbgSwapZP ; Swap stuff
+ lda #<DbgStack ; Set new stack
+ sta sp
+ lda #>DbgStack
+ sta sp+1
+ jsr ResetDbgBreaks ; Reset temporary breakpoints
+ jsr _DbgEntry ; Call C code
+ jsr SetDbgBreaks ; Set temporary breakpoints
+ jsr DbgSwapZP ; Swap stuff back
+
+ lda retsav+1
+ pha
+ lda retsav
+ pha
+ rts
+
+
+
+; Stack used when in debugger mode
+
+.bss
+ .res 256
+DbgStack:
+
+; Swap space for the the C temporaries
+
+CTemp:
+_DbgCS: .res 2 ; sp
+_DbgHI: .res 2 ; sreg
+ .res 22 ; Other stuff
+_DbgSP: .res 1
+retsav: .res 2 ; Save buffer for return address
+
+.code
+
+; Swap the C temporaries
+
+DbgSwapZP:
+ ldy #zpspace-1
+Swap1: ldx CTemp,y
+ lda sp,y ; ######
+ sta CTemp,y
+ txa
+ sta sp,y
+ dey
+ bpl Swap1
+ rts
+
+; ----------------------------------------------------------------------------
+; Utility functions
+
+
+; Set/reset the breakpoints. We must do that here since the breakpoints
+; may be in the runtime stuff, causing the C part to fail before it has
+; reset the breakpoints. See declaration of struct breakpoint in the C
+; source
+
+MaxBreaks = 48 ; 4*12
+
+ResetDbgBreaks:
+ ldy #0
+ ldx #0
+L4: lda _DbgBreaks+3,x ; Get bk_use
+ beq L6 ; Jump if not set
+ bpl L5 ; Jump if user breakpoint
+ lda #0
+ sta _DbgBreaks+3,x ; Clear if temp breakpoint
+L5: lda _DbgBreaks+1,x ; PC hi
+ sta ptr1+1
+ lda _DbgBreaks,x ; PC lo
+ sta ptr1
+ lda _DbgBreaks+2,x ; Old OPC
+ sta (ptr1),y ; Reset the breakpoint
+L6: inx
+ inx
+ inx
+ inx
+ cpx #MaxBreaks ; Done?
+ bne L4
+ rts
+
+SetDbgBreaks:
+ ldx #0
+ ldy #0
+L7: lda _DbgBreaks+3,x ; Get bk_use
+ beq L8 ; Jump if not set
+ lda _DbgBreaks+1,x ; PC hi
+ sta ptr1+1
+ lda _DbgBreaks,x ; PC lo
+ sta ptr1
+ lda (ptr1),y ; Get the breakpoint OPC...
+ sta _DbgBreaks+2,x ; ...and save it
+ lda #$00 ; Load BRK opcode
+ sta (ptr1),y
+L8: inx
+ inx
+ inx
+ inx
+ cpx #MaxBreaks ; Done?
+ bne L7
+ rts
+
+; Get a free breakpoint slot or return 0
+
+ .export _DbgGetBreakSlot
+
+_DbgGetBreakSlot:
+ ldx #0
+L10: lda _DbgBreaks+3,x ; Get bk_use
+ beq L11 ; Jump if not set
+ inx
+ inx
+ inx
+ inx
+ cpx #MaxBreaks ; Done?
+ bne L10
+ jmp return0 ; No free slot
+
+L11: stx tmp1
+ lda #<_DbgBreaks
+ ldx #>_DbgBreaks
+ clc
+ adc tmp1
+ bcc L12
+ inx
+L12: ldy #1 ; Force != 0
+ rts
+
+
+; Check if a given address has a user breakpoint set, if found, return the
+; slot, otherwise return 0.
+
+ .export _DbgIsBreak
+
+_DbgIsBreak:
+ jsr popax ; Get address
+ sta ptr1
+ stx ptr1+1
+ ldx #0
+L20: lda _DbgBreaks+3,x ; Get bk_use
+ beq L21 ; Jump if not set
+ bmi L21 ; Jump if temp breakpoint
+ lda _DbgBreaks,x ; Low byte of address
+ cmp ptr1
+ bne L21
+ lda _DbgBreaks+1,x ; High byte of address
+ cmp ptr1+1
+ beq L22
+L21: inx
+ inx
+ inx
+ inx
+ cpx #MaxBreaks ; Done?
+ bne L20
+ jmp return0 ; Not found
+
+L22: stx tmp1
+ lda #<_DbgBreaks
+ ldx #>_DbgBreaks
+ clc
+ adc tmp1
+ bcc L23
+ inx
+L23: ldy #1 ; Force != 0
+ rts
+
+
+
--- /dev/null
+#
+# Makefile for GEOS lib
+# for cc65
+#
+# Maciej 'YTM/Alliance' Witkowiak
+
+export CC = ../../../src/cc65
+export CFLAGS = -O
+export AS = ../../../src/ca65/ca65
+export ASFLAGS =
+AR = ../../src/ar65/ar65
+
+
+OBJ_DIRS=disk dlgbox file graph menuicon memory mousesprite process system
+
+all:
+ @for i in devel $(OBJ_DIRS); do $(MAKE) -C $$i; done
+ @mv devel/crt0.o ../geos.o
+ @for i in $(OBJ_DIRS); do $(AR) a ../geos.lib $$i/*.o; done
+
+rebuild: zap all clean
+
+
+.PHONY: clean
+clean:
+ @for i in $(OBJ_DIRS); do \
+ cd $$i; \
+ $(MAKE) clean; \
+ cd ..; \
+ done
+
+.PHONY: zap
+zap: clean
+ @rm -f ../geos.lib ../geos.o
+
--- /dev/null
+#
+# Makefile for GEOS lib
+# for cc65
+#
+#
+
+%.o: %.s
+ @echo $<
+ @$(AS) -o $@ $(AFLAGS) $<
+
+
+S_OBJS = crt0.o
+
+all: $(S_OBJS)
+
+clean:
+ @rm -f *.~ $(S_OBJS) core
\ No newline at end of file
--- /dev/null
+;
+; This must be the *second* file on the linker command line
+; (.cvt header must be the *first* one)
+
+; Maciej 'YTM/Alliance' Witkowiak
+; 26.10.99, 10.3.2000
+
+; no __hinit
+
+ .export _exit
+ .import pushax
+ .import _main
+ .import zerobss, doatexit
+
+; ------------------------------------------------------------------------
+; Define and export the ZP variables for the C64 runtime
+
+ .exportzp sp, sreg, regsave, regbank
+ .exportzp ptr1, ptr2, ptr3, ptr4
+ .exportzp tmp1, tmp2, tmp3, tmp4
+
+sp = $72 ; stack pointer
+sreg = $74 ; secondary register/high 16 bit for longs
+regsave = $76 ; slot to save/restore (E)AX into
+ptr1 = $7A ;
+ptr2 = $7C
+ptr3 = $7E
+ptr4 = $70
+tmp1 = $fb
+tmp2 = $fc
+tmp3 = $fd
+tmp4 = $fe
+
+regbank = $a3 ; 6 bytes hopefully not used by Kernal
+
+; ------------------------------------------------------------------------
+
+; .org $0400-508 ; $0400 - length of .cvt header
+; .include "cvthead.s"
+
+ .reloc
+
+; ------------------------------------------------------------------------
+; Actual code
+
+; Clear the BSS data
+
+ jsr zerobss
+
+; Setup stack
+
+ lda #<$7900
+ sta sp
+ lda #>$7900
+ sta sp+1 ; Set argument stack ptr
+
+; Initialize the heap
+
+;;! jsr __hinit
+
+; Pass an empty command line
+
+ lda #0
+ tax
+ jsr pushax ; argc
+ jsr pushax ; argv
+
+ ldy #4 ; Argument size
+ jsr _main ; call the users code
+ jmp $c1c3 ; jump to GEOS MainLoop
+
+; exit must be called from the code!
+
+_exit:
+ jsr doatexit ; call exit functions
+
+ jmp $c22c ; EnterDeskTop
--- /dev/null
+
+; NOTE THAT EASIER AND SAFER WAY OF GETTING HEADER IS TO GENERATE IT !!!
+
+; Maciej 'YTM/Alliance' Witkowiak
+; 28.02.2000
+
+; This is .cvt header for GEOS files, it is recognized by Convert v2.5 for GEOS
+; and Star Commander (when copying GEOS files to/from .d64 images)
+; This is only an example, and you should customize file header values (such as
+; Author, Class, Date, filename) either here for all GEOS apps or manually later
+; in GEOS environment using specialized apps or disk editor
+
+; currently only SEQUENTIAL structure is supported, no overlays
+
+; defineable values are marked with ';**' in comment line, please be careful with
+; string lengths
+
+
+; .org $0400-508 ; $0400 - length of .cvt header
+
+ .segment "HEADER"
+
+ .include "../inc/const.inc"
+
+ProgType = APPLICATION ;** may be one of:
+ ; APPLICATION
+ ; ASSEMBLY
+ ; DESK_ACC (unusable, unless you will fix end address in header before run)
+ ; PRINTER (unusable, unless you change $0400 to $7900 here and in crt0.s)
+ ; INPUT_DEVICE (like above but change $0400 to $fe80, you have $017a bytes)
+ ; AUTO_EXEC (you need to fit in $0400-$4fff area)
+ ; INPUT_128 (like INPUT_DEVICE but change $0400 to $fd80, you have $017a bytes)
+
+ .byte USR | $80 ; DOS filetype
+ .word 0 ; T&S, will be fixed by converter
+
+ .byte "filename" ;** DOS filename (16 chars with $a0 padding)
+ .byte $a0,$a0,$a0,$a0,$a0,$a0,$a0,$a0
+
+ .word 0 ; header T&S
+
+ .byte SEQUENTIAL ; GEOS structure
+ .byte ProgType ; GEOS filetype
+ .byte 00 ;** year 2000=00 or 100?
+ .byte 02 ;** month
+ .byte 28 ;** day
+ .byte 18 ;** hour
+ .byte 58 ;** minute
+
+ .word 0 ; size in blocks, will be fixed by converter
+
+ .byte "PRG formatted GEOS file V1.0"
+ ; converter stamp
+ .res $c4 ; some bytes are left
+
+ .byte 3, 21, 63 | $80 ; icon picture header, 63 bytes follow
+
+ ;** hey, uberhacker! edit icon here!!! ;-))
+ .byte %11111111, %11111111, %11111111
+ .byte %10000000, %00000000, %00000001
+ .byte %10000000, %00000000, %00000001
+ .byte %10000000, %00000000, %00000001
+ .byte %10000000, %00000000, %00000001
+ .byte %10000000, %00000000, %00000001
+ .byte %10000000, %00000000, %00000001
+ .byte %10000000, %00000000, %00000001
+ .byte %10000000, %00000000, %00000001
+ .byte %10000000, %00000000, %00000001
+ .byte %10000000, %00000000, %00000001
+ .byte %10000000, %00000000, %00000001
+ .byte %10000000, %00000000, %00000001
+ .byte %10000000, %00000000, %00000001
+ .byte %10000000, %00000000, %00000001
+ .byte %10000000, %00000000, %00000001
+ .byte %10000000, %00000000, %00000001
+ .byte %10000000, %00000000, %00000001
+ .byte %10000000, %00000000, %00000001
+ .byte %10000000, %00000000, %00000001
+ .byte %11111111, %11111111, %11111111
+
+ .byte USR | $80 ;again DOS type
+ .byte ProgType ;again GEOS type
+ .byte SEQUENTIAL ;structure
+ .word $0400 ;ProgStart
+ .word $0400-1 ;ProgEnd (needs proper value for DESK_ACC)
+ .word $0400 ;ProgExec
+
+ .byte "Filename" ;**GEOS class (12 chars)
+ .byte $20,$20,$20,$20 ; padding with spaces to 12
+
+ .byte "V1.0",0 ;**version
+ .word 0
+
+ .byte %01000000 ;**40/80 columns capability
+; B7 B6
+; 0 0 - runs under GEOS128 but only in 40 column mode
+; 0 1 - runs under GEOS128 in both 40/80 column modes
+; 1 0 - does not run under GEOS128
+; 1 1 - runs under GEOS128 but only in 80 column mode
+
+
+ .byte "Author" ;**author's name (63 chars)
+ .byte 0 ; +terminator
+ .res (63-7) ; padding to 63
+
+ .byte "Compiled with cc65" ;**note (95 chars)
+ .byte 0 ; +terminator
+ .res (95-18) ; padding to 95
+
+ ; end of header, code follows
--- /dev/null
+#
+# Makefile for GEOS lib
+# for cc65
+#
+
+%.o: %.s
+ @echo $<
+ @$(AS) -o $@ $(AFLAGS) $<
+
+
+S_OBJS = blkalloc.o calcblksfree.o changediskdevice.o chkdkgeos.o enterturbo.o exitturbo.o\
+ findbambit.o freeblock.o getblock.o getdirhead.o getptrcurdknm.o newdisk.o\
+ nxtblkalloc.o opendisk.o purgeturbo.o putblock.o putdirhead.o readblock.o\
+ readbuff.o setnextfree.o setgeosdisk.o writeblock.o writebuff.o verwriteblock.o\
+ gettrse.o
+
+all: $(S_OBJS)
+
+clean:
+ @rm -f *.~ $(S_OBJS) core
\ No newline at end of file
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; char BlkAlloc (struct tr_se output[], int length);
+
+ .import popax
+ .export _BlkAlloc
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_BlkAlloc:
+ sta r2L
+ stx r2H
+ jsr popax
+ sta r4L
+ stx r4H
+ jsr BlkAlloc
+ stx errno
+ txa
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; int CalcBlksFree (void);
+
+ .export _CalcBlksFree
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_CalcBlksFree:
+ jsr CalcBlksFree
+ stx errno
+ lda r4L
+ ldx r4H
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; char ChangeDiskDevice (char newDriveNumber);
+
+ .export _ChangeDiskDevice
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_ChangeDiskDevice:
+ jsr ChangeDiskDevice
+ stx errno
+ txa
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; char ChkDkGEOS (void);
+
+ .export _ChkDkGEOS
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_ChkDkGEOS:
+ jsr ChkDkGEOS
+ stx errno
+ lda isGEOS
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; void EnterTurbo (void);
+
+ .export _EnterTurbo
+
+ .include "../inc/jumptab.inc"
+
+_EnterTurbo = EnterTurbo
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; void ExitTurbo (void);
+
+ .export _ExitTurbo
+
+ .include "../inc/jumptab.inc"
+
+_ExitTurbo = ExitTurbo
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; char FindBAMBit (struct tr_se *TS);
+; (might be called inUSE (if (!inUSE(block))))
+
+ .import gettrse
+ .export _FindBAMBit
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_FindBAMBit:
+ jsr gettrse
+ sta r6L
+ stx r6H
+ jsr FindBAMBit
+ bne inUse
+ lda #0
+ rts
+inUse: lda #$ff
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; char FreeBlock (struct tr_se *TS);
+
+ .import gettrse
+ .export _FreeBlock
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_FreeBlock:
+ jsr gettrse
+ sta r6L
+ stx r6H
+ jsr FreeBlock
+ stx errno
+ txa
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; char GetBlock (struct tr_se *myTS, char *buffer);
+
+ .import popax
+ .import gettrse
+ .export _GetBlock
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_GetBlock:
+ sta r4L
+ stx r4H
+ jsr popax
+ jsr gettrse
+ sta r1L
+ stx r1H
+ jsr GetBlock
+ stx errno
+ txa
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; char GetDirHead (void);
+
+ .export _GetDirHead
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_GetDirHead:
+ jsr GetDirHead
+ stx errno
+ txa
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; void GetPtrCurDkNm (char *curName);
+; (fills curName[17] with current disk's name)
+
+ .importzp ptr4, ptr3
+ .export _GetPtrCurDkNm
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_GetPtrCurDkNm:
+ sta ptr3
+ stx ptr3+1
+ ldx #ptr4
+ jsr GetPtrCurDkNm
+ ldy #0
+ txa
+ bne fin
+namelp: lda (ptr4),y
+ cmp #$a0
+ beq fin
+ sta (ptr3),y
+ iny
+ cpy #16
+ bne namelp
+fin: lda #0
+ sta (ptr3),y
+ stx errno
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 29.1.00
+
+ .export gettrse
+ .importzp ptr4
+gettrse:
+ sta ptr4
+ stx ptr4+1
+ ldy #1
+ lda (ptr4),y
+ tax
+ dey
+ lda (ptr4),y
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; char NewDisk (void);
+
+ .export _NewDisk
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_NewDisk:
+ jsr NewDisk
+ stx errno
+ txa
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; char NxtBlkAlloc (struct tr_se *startTS, struct tr_se output[], int length );
+
+ .import popax
+ .import gettrse
+ .importzp ptr4
+ .export _NxtBlkAlloc
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_NxtBlkAlloc:
+ sta r2L
+ stx r2H
+ jsr popax
+ sta r4L
+ stx r4H
+ jsr popax
+ jsr gettrse
+ sta r3L
+ stx r3H
+ jsr NxtBlkAlloc
+ stx errno
+ txa
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; char OpenDisk (void);
+
+ .export _OpenDisk
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_OpenDisk:
+ jsr OpenDisk
+ stx errno
+ txa
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; void PurgeTurbo (void);
+
+ .export _PurgeTurbo
+
+ .include "../inc/jumptab.inc"
+
+_PurgeTurbo = PurgeTurbo
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; char PutBlock (struct tr_se *myTS, char *buffer);
+
+ .import popax
+ .import gettrse
+ .export _PutBlock
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_PutBlock:
+ sta r4L
+ stx r4H
+ jsr popax
+ jsr gettrse
+ sta r1L
+ stx r1H
+ jsr PutBlock
+ stx errno
+ txa
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; char PutDirHead (void);
+
+ .export _PutDirHead
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_PutDirHead:
+ jsr PutDirHead
+ stx errno
+ txa
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; char ReadBlock (struct tr_se myTS, char *buffer);
+
+ .import popax
+ .import gettrse
+ .export _ReadBlock
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_ReadBlock:
+ sta r4L
+ stx r4H
+ jsr popax
+ jsr gettrse
+ sta r1L
+ stx r1H
+ jsr ReadBlock
+ stx errno
+ txa
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 26.10.99
+
+; char ReadBuff (struct tr_se);
+
+ .import gettrse
+ .export _ReadBuff
+
+ .include "../inc/diskdrv.inc"
+ .include "../inc/geossym.inc"
+
+_ReadBuff:
+ jsr gettrse
+ sta r1L
+ stx r1H
+ jsr ReadBuff
+ stx errno
+ txa
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; char SetGEOSDisk (void);
+
+ .export _SetGEOSDisk
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_SetGEOSDisk:
+ jsr SetGEOSDisk
+ stx errno
+ txa
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; struct tr_se SetNextFree (struct tr_se *startTS);
+
+ .import gettrse
+ .export _SetNextFree
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_SetNextFree:
+ jsr gettrse
+ sta r3L
+ stx r3H
+ jsr SetNextFree
+ stx errno
+ lda r3L
+ ldx r3H
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; char VerWriteBlock (struct tr_se *myTS, char *buffer);
+
+ .import popax
+ .import gettrse
+ .export _VerWriteBlock
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_VerWriteBlock:
+ sta r4L
+ stx r4H
+ jsr popax
+ jsr gettrse
+ sta r1L
+ stx r1H
+ jsr VerWriteBlock
+ stx errno
+ txa
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; char WriteBlock (struct tr_se *myTS, char *buffer);
+
+ .import popax
+ .import gettrse
+ .export _WriteBlock
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_WriteBlock:
+ sta r4L
+ stx r4H
+ jsr popax
+ jsr gettrse
+ sta r1L
+ stx r1H
+ jsr WriteBlock
+ stx errno
+ txa
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 26.10.99
+
+; char WriteBuff (struct tr_se*);
+
+ .import gettrse
+ .export _WriteBuff
+
+ .include "../inc/diskdrv.inc"
+ .include "../inc/geossym.inc"
+
+_WriteBuff:
+ jsr gettrse
+ sta r1L
+ stx r1H
+ jsr WriteBuff
+ stx errno
+ txa
+ rts
--- /dev/null
+#
+# Makefile for GEOS lib
+# for cc65
+#
+#
+
+%.o: %.s
+ @echo $<
+ @$(AS) -o $@ $(AFLAGS) $<
+
+
+S_OBJS = dodlgbox.o rstrfrmdialogue.o\
+ dbget2lines.o dlgboxyesno.o dlgboxokcancel.o dlgboxok.o dlgboxgetstring.o\
+ dlgboxfileselect.o
+
+all: $(S_OBJS)
+
+clean:
+ @rm -f *.~ $(S_OBJS) core
\ No newline at end of file
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+ .export DB_get2lines
+ .importzp ptr3,ptr4
+ .import popax
+
+DB_get2lines:
+ sta ptr4
+ stx ptr4+1
+ jsr popax
+ sta ptr3
+ stx ptr3+1
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char DlgBoxFileSelect (char *class, char ftype, char *fname);
+
+ .export _DlgBoxFileSelect
+ .import popa, popax
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+ .include "../inc/const.inc"
+ .include "../inc/geosmac.ca65.inc"
+
+_DlgBoxFileSelect:
+; sta r5L
+; stx r5H
+; jsr popa
+; sta r7L
+; jsr popax
+; sta r10L
+; stx r10H
+
+ sta tmp_r5
+ stx tmp_r5+1
+ jsr popa
+ sta tmp_r7L
+ jsr popax
+ sta tmp_r10
+ stx tmp_r10+1
+
+DB_FS_reload:
+ MoveW tmp_r5, r5
+ MoveW tmp_r10, r10
+ MoveB tmp_r7L, r7L
+
+ lda #<paramStrFileSelect
+ ldx #>paramStrFileSelect
+ sta r0L
+ stx r0H
+ jsr DoDlgBox
+ lda r0L
+ cmp #DISK
+ bne DB_FS_Fin
+ jsr OpenDisk
+ txa
+ beq DB_FS_reload
+DB_FS_Fin: rts
+
+paramStrFileSelect:
+ .byte DEF_DB_POS | 1
+ .byte DBGETFILES, 4, 4
+ .byte OPEN, DBI_X_2, DBI_Y_0+16
+ .byte DISK, DBI_X_2, DBI_Y_0+32+1
+ .byte CANCEL, DBI_X_2, DBI_Y_0+64+3
+ .byte NULL
+
+tmp_r5: .word 0
+tmp_r7L: .byte 0
+tmp_r10: .word 0
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char DlgBoxGetString (char *string, char strlen, char *line1,char *line2);
+
+ .export _DlgBoxGetString
+ .import DB_get2lines
+ .importzp ptr2, ptr3, ptr4
+ .import popa, popax
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+ .include "../inc/const.inc"
+
+_DlgBoxGetString:
+ jsr DB_get2lines
+ jsr popa
+ sta DB_strlen
+ jsr popax
+ sta ptr2
+ stx ptr2+1
+ lda #<paramStrGetString
+ ldx #>paramStrGetString
+ sta r0L
+ stx r0H
+ jsr DoDlgBox
+ lda r0L
+ rts
+
+paramStrGetString:
+ .byte DEF_DB_POS | 1
+ .byte DBVARSTR, TXT_LN_X, TXT_LN_1_Y, ptr3
+ .byte DBVARSTR, TXT_LN_X, TXT_LN_2_Y, ptr4
+ .byte DBGETSTRING, TXT_LN_X, TXT_LN_3_Y, ptr2
+DB_strlen: .byte 17
+ .byte CANCEL, DBI_X_2, DBI_Y_2
+ .byte NULL
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char DlgBoxOk (char *line1,char *line2);
+
+ .export _DlgBoxOk
+ .import DB_get2lines
+ .importzp ptr3, ptr4
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+ .include "../inc/const.inc"
+
+_DlgBoxOk:
+ jsr DB_get2lines
+ lda #<paramStrOk
+ ldx #>paramStrOk
+ sta r0L
+ stx r0H
+ jsr DoDlgBox
+ lda r0L
+ rts
+
+paramStrOk:
+ .byte DEF_DB_POS | 1
+ .byte DBVARSTR, TXT_LN_X, TXT_LN_2_Y, ptr3
+ .byte DBVARSTR, TXT_LN_X, TXT_LN_3_Y, ptr4
+ .byte OK, DBI_X_0, DBI_Y_2
+ .byte NULL
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char DlgBoxOkCancel (char *line1,char *line2);
+
+ .export _DlgBoxOkCancel
+ .import DB_get2lines
+ .importzp ptr3, ptr4
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+ .include "../inc/const.inc"
+
+_DlgBoxOkCancel:
+ jsr DB_get2lines
+ lda #<paramStrOkCancel
+ ldx #>paramStrOkCancel
+ sta r0L
+ stx r0H
+ jsr DoDlgBox
+ lda r0L
+ rts
+
+paramStrOkCancel:
+ .byte DEF_DB_POS | 1
+ .byte DBVARSTR, TXT_LN_X, TXT_LN_2_Y, ptr3
+ .byte DBVARSTR, TXT_LN_X, TXT_LN_3_Y, ptr4
+ .byte OK, DBI_X_0, DBI_Y_2
+ .byte CANCEL, DBI_X_2, DBI_Y_2
+ .byte NULL
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char DlgBoxYesNo (char *line1,char *line2);
+
+ .export _DlgBoxYesNo
+ .import DB_get2lines
+ .importzp ptr3, ptr4
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+ .include "../inc/const.inc"
+
+_DlgBoxYesNo:
+ jsr DB_get2lines
+ lda #<paramStrYesNo
+ ldx #>paramStrYesNo
+ sta r0L
+ stx r0H
+ jsr DoDlgBox
+ lda r0L
+ rts
+
+paramStrYesNo:
+ .byte DEF_DB_POS | 1
+ .byte DBVARSTR, TXT_LN_X, TXT_LN_2_Y, ptr3
+ .byte DBVARSTR, TXT_LN_X, TXT_LN_3_Y, ptr4
+ .byte YES, DBI_X_0, DBI_Y_2
+ .byte NO, DBI_X_2, DBI_Y_2
+ .byte NULL
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char DoDlgBox (char *myParamString);
+
+ .export _DoDlgBox
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_DoDlgBox:
+ sta r0L
+ stx r0H
+ jsr DoDlgBox
+ lda r0L
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char RstrFrmDialogue (void);
+
+ .export _RstrFrmDialogue
+
+ .include "../inc/jumptab.inc"
+
+_RstrFrmDialogue = RstrFrmDialogue
--- /dev/null
+#
+# Makefile for GEOS lib
+# for cc65
+#
+
+%.o: %.s
+ @echo $<
+ @$(AS) -o $@ $(AFLAGS) $<
+
+
+S_OBJS = get1stdirentry.o getnxtdirentry.o\
+ openrecordfile.o closerecordfile.o nextrecord.o previousrecord.o pointrecord.o\
+ deleterecord.o insertrecord.o appendrecord.o readrecord.o writerecord.o\
+ updaterecordfile.o\
+ findfile.o followchain.o getfhdrinfo.o readfile.o savefile.o freefile.o\
+ deletefile.o renamefile.o findftypes.o readbyte.o
+
+all: $(S_OBJS)
+
+clean:
+ @rm -f *.~ $(S_OBJS) core
\ No newline at end of file
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char AppendRecord (void);
+
+ .export _AppendRecord
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_AppendRecord:
+
+ jsr AppendRecord
+ stx errno
+ txa
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char CloseRecordFile (void);
+
+ .export _CloseRecordFile
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_CloseRecordFile:
+ jsr CloseRecordFile
+ stx errno
+ txa
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char DeleteFile (char *myName);
+
+ .export _DeleteFile
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_DeleteFile:
+ sta r0L
+ stx r0H
+ jsr DeleteFile
+ stx errno
+ txa
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char DeleteRecord (void);
+
+ .export _DeleteRecord
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_DeleteRecord:
+ jsr DeleteRecord
+ stx errno
+ txa
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char FindFile (char *myName);
+
+ .export _FindFile
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_FindFile:
+ sta r6L
+ stx r6H
+ jsr FindFile
+ stx errno
+ txa
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char FindFTypes (char *buffer, char fileType, char fileMax, char *Class);
+
+ .export _FindFTypes
+ .import popax, popa
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_FindFTypes:
+ sta r10L
+ stx r10H
+ jsr popa
+ sta r7H
+ jsr popa
+ sta r7L
+ jsr popax
+ sta r6L
+ stx r6H
+ jsr FindFTypes
+ stx errno
+ txa
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char FollowChain (struct tr_se *myTrSe, char *buffer);
+
+ .export _FollowChain
+ .import popax
+ .import gettrse
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_FollowChain:
+ sta r3L
+ stx r3H
+ jsr popax
+ jsr gettrse
+ sta r1L
+ stx r1H
+ jsr FollowChain
+ stx errno
+ txa
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char FreeFile (struct trse myTrSe[]);
+
+ .export _FreeFile
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_FreeFile:
+ sta r9L
+ stx r9H
+ jsr FreeFile
+ stx errno
+ txa
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 26.10.99
+
+; struct filehandle* Get1stDirEntry (void);
+
+ .export _Get1stDirEntry
+
+ .include "../inc/diskdrv.inc"
+ .include "../inc/geossym.inc"
+
+_Get1stDirEntry:
+ jsr Get1stDirEntry
+ stx errno
+ lda r5L
+ ldx r5H
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char GetFHdrInfo (struct filehandle *myFile);
+
+ .export _GetFHdrInfo
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_GetFHdrInfo:
+ sta r9L
+ stx r9H
+ jsr GetFHdrInfo
+ stx errno
+ txa
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 26.10.99
+
+; struct filehandle* GetNxtDirEntry (void);
+
+ .export _GetNxtDirEntry
+
+ .include "../inc/diskdrv.inc"
+ .include "../inc/geossym.inc"
+
+_GetNxtDirEntry:
+ jsr GetNxtDirEntry
+ stx errno
+ lda r5L
+ ldx r5H
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char InsertRecord (void);
+
+ .export _InsertRecord
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_InsertRecord:
+ jsr InsertRecord
+ stx errno
+ txa
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char NextRecord (void);
+
+ .export _NextRecord
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_NextRecord:
+ jsr NextRecord
+ stx errno
+ txa
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char OpenRecordFile (char *myName);
+
+ .export _OpenRecordFile
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_OpenRecordFile:
+ sta r0L
+ stx r0H
+ jsr OpenRecordFile
+ stx errno
+ txa
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char PointRecord (char recordNum);
+
+ .export _PointRecord
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_PointRecord:
+ jsr PointRecord
+ stx errno
+ txa
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char PreviousRecord (void);
+
+ .export _PreviousRecord
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_PreviousRecord:
+ jsr PreviousRecord
+ stx errno
+ txa
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char ReadByte (void);
+
+ .export _ReadByte
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_ReadByte:
+ jsr ReadByte
+ stx errno
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char ReadFile (struct tr_se *myTS, char *buffer, int length);
+
+ .export _ReadFile
+ .import popax
+ .import gettrse
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_ReadFile:
+ sta r2L
+ stx r2H
+ jsr popax
+ sta r7L
+ stx r7H
+ jsr popax
+ jsr gettrse
+ sta r1L
+ stx r1H
+ jsr ReadFile
+ stx errno
+ txa
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char ReadRecord (char *buffer, int length);
+
+ .export _ReadRecord
+ .import popax
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_ReadRecord:
+ sta r2L
+ stx r2H
+ jsr popax
+ sta r7L
+ stx r7H
+ jsr ReadRecord
+ stx errno
+ txa
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char RenameFile (char *source, char *target);
+
+ .export _RenameFile
+ .import popax
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_RenameFile:
+ sta r0L
+ stx r0H
+ jsr popax
+ sta r6L
+ stx r6H
+ jsr RenameFile
+ stx errno
+ txa
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char SaveFile (struct fileheader *myHeader);
+
+ .export _SaveFile
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_SaveFile:
+ sta r9L
+ stx r9H
+ jsr SaveFile
+ stx errno
+ txa
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char UpdateRecordFile (void);
+
+ .export _UpdateRecordFile
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_UpdateRecordFile:
+ jsr UpdateRecordFile
+ stx errno
+ txa
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; char WriteRecord (char *buffer, int length);
+
+ .export _WriteRecord
+ .import popax
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_WriteRecord:
+ sta r2L
+ stx r2H
+ jsr popax
+ sta r7L
+ stx r7H
+ jsr WriteRecord
+ stx errno
+ txa
+ rts
--- /dev/null
+#
+# Makefile for GEOS lib
+# for cc65
+#
+#
+
+%.o: %.s
+ @echo $<
+ @$(AS) -o $@ $(AFLAGS) $<
+
+
+S_OBJS = drawline.o drawpoint.o framerectangle.o hlineregs.o horizontalline.o\
+ imprintrectangle.o invertline.o invertrectangle.o pointregs.o recoverline.o\
+ recoverrectangle.o rectangle.o initdrawwindow.o setpattern.o testpoint.o verticalline.o\
+ putchar.o putdecimal.o putstring.o usesystemfont.o\
+ getcharwidth.o loadcharset.o bitmapup.o bitmapregs.o bitmapclip.o bitotherclip.o\
+ graphicsstring.o getintcharint.o
+
+all: $(S_OBJS)
+
+clean:
+ @rm -f *.~ $(S_OBJS) core
\ No newline at end of file
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; void BitmapClip (char skipl, char skipr, int skipy, struct iconpic *myGfx);
+
+ .import popa, popax
+ .import BitmapRegs
+ .export _BitmapClip
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_BitmapClip:
+ jsr BitmapRegs
+ jsr popax
+ sta r12L
+ stx r12H
+ jsr popa
+ sta r11H
+ jsr popa
+ sta r11L
+ jmp BitmapClip
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+ .importzp ptr4
+
+ .export BitmapRegs
+
+ .include "../inc/geossym.inc"
+
+BitmapRegs: ;a/x is a struct iconpic*
+ sta ptr4
+ stx ptr4+1
+ ldy #0
+bmpLp: lda (ptr4),y
+ sta r0L,y
+ iny
+ cpy #6
+ bne bmpLp
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; void BitmapUp (struct iconpic *myGfx);
+
+
+ .import BitmapRegs
+ .export _BitmapUp
+
+ .include "../inc/jumptab.inc"
+
+_BitmapUp:
+ jsr BitmapRegs
+ jmp BitmapUp
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; void BitOtherClip (void *proc1, void* proc2, char skipl, char skipr, int skipy,
+; struct iconpic *myGfx);
+
+; both proc1, proc2 should be: char __fastcall something (void);
+; proc1 is called before reading a byte (.A returns next data)
+; proc2 is called before reading each byte which is not pattern (code >219)
+
+
+ .import popa, popax
+ .import BitOtherRegs
+ .export _BitOtherClip
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_BitOtherClip:
+ jsr BitOtherRegs
+ jsr popax
+ sta r12L
+ stx r12H
+ jsr popa
+ sta r11H
+ jsr popa
+ sta r11L
+ jsr popax
+ sta r14L
+ stx r14H
+ jsr popax
+ sta r13L
+ stx r13H
+ jmp BitOtherClip
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 29.10.99
+
+; void DrawLine (struct window *mywindow);
+
+ .import _InitDrawWindow
+ .export _DrawLine
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+ .include "../inc/geosmac.ca65.inc"
+
+_DrawLine:
+ tay
+ PushW r2
+ tya
+ jsr _InitDrawWindow
+ MoveW r2, r11
+ PopW r2
+ jmp DrawLine
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 29.10.99
+
+; void DrawPoint (struct pixel *mypixel);
+
+
+ .import PointRegs
+ .export _DrawPoint
+
+ .include "../inc/jumptab.inc"
+
+_DrawPoint:
+ jsr PointRegs
+ jmp DrawPoint
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 29.10.99
+
+; void FrameRectangle (char pattern);
+
+ .export _FrameRectangle
+
+ .include "../inc/jumptab.inc"
+
+_FrameRectangle = FrameRectangle
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; char GetCharWidth (char character);
+
+ .export _GetCharWidth
+
+ .include "../inc/jumptab.inc"
+
+_GetCharWidth = GetCharWidth
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 11.03.2000
+
+ .import popa, popax
+ .export getintcharint
+
+ .include "../inc/geossym.inc"
+
+getintcharint:
+ sta r11L
+ stx r11H
+ jsr popa
+ sta r1H
+ jsr popax
+ sta r0L
+ stx r0H
+ rts
+
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 25.12.99
+
+; void GraphicsString (char *myString);
+
+ .export _GraphicsString
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_GraphicsString:
+ sta r0L
+ stx r0H
+ jmp GraphicsString
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 29.10.99
+
+
+ .import popax, popa
+
+ .export HLineRegs
+
+ .include "../inc/geossym.inc"
+
+HLineRegs:
+ stx r4H
+ sta r4L
+ jsr popax
+ stx r3H
+ sta r3L
+ jsr popa
+ sta r11L
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 29.10.99
+
+; void HorizontalLine (char pattern, char y, int xstart, int xend);
+
+ .import popa
+ .import HLineRegs
+
+ .export _HorizontalLine
+
+ .include "../inc/jumptab.inc"
+
+_HorizontalLine:
+ jsr HLineRegs
+ jsr popa
+ jmp HorizontalLine
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; void ImprintRectangle (void);
+
+ .export _ImprintRectangle
+
+ .include "../inc/jumptab.inc"
+
+_ImprintRectangle = ImprintRectangle
+
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 29.10.99
+; 11.03.2000
+
+; void InitDrawWindow (struct window *myWindow);
+
+ .importzp ptr4
+
+ .export _InitDrawWindow
+
+ .include "../inc/geossym.inc"
+
+_InitDrawWindow: ;a/x is a struct window*
+ sta ptr4
+ stx ptr4+1
+ ldy #0
+copyWin: lda (ptr4),y
+ sta r2L,y
+ iny
+ cpy #6
+ bne copyWin
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 29.10.99
+
+; void InvertLine (char y, int xstart, int xend);
+
+ .import HLineRegs
+ .export _InvertLine
+
+ .include "../inc/jumptab.inc"
+
+_InvertLine:
+ jsr HLineRegs
+ jmp InvertLine
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 29.10.99
+
+; void InvertRectangle (void);
+
+ .export _InvertRectangle
+
+ .include "../inc/jumptab.inc"
+
+_InvertRectangle = InvertRectangle
+
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; void LoadCharSet (struct fontdesc *myFont);
+
+ .export _LoadCharSet
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_LoadCharSet:
+ sta r0L
+ stx r0H
+ jmp LoadCharSet
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 29.10.99
+
+ .importzp ptr4
+
+ .export PointRegs
+
+ .include "../inc/geossym.inc"
+
+PointRegs: ;a/x is a struct pixel*
+ sta ptr4
+ stx ptr4+1
+ ldy #0
+ lda (ptr4),y
+ sta r3L
+ iny
+ lda (ptr4),y
+ sta r3H
+ iny
+ lda (ptr4),y
+ sta r11L
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void PutChar (char character, char y, int x);
+
+ .import popa
+ .export _PutChar
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_PutChar:
+ sta r11L
+ stx r11H
+ jsr popa
+ sta r1H
+ jsr popa
+ jmp PutChar
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void PutDecimal (char style, int value, char y, int x);
+
+ .import popa, popax
+ .import getintcharint
+ .export _PutDecimal
+
+ .include "../inc/jumptab.inc"
+
+_PutDecimal:
+ jsr getintcharint
+ jsr popa
+ jmp PutDecimal
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void PutString (char *mytxt, char y, int x);
+
+ .import popax, popa
+ .import getintcharint
+ .export _PutString
+
+ .include "../inc/jumptab.inc"
+
+_PutString:
+ jsr getintcharint
+ jmp PutString
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 29.10.99
+
+; void RecoverLine (char y, int xstart, int xend);
+
+ .import HLineRegs
+
+ .export _RecoverLine
+
+ .include "../inc/jumptab.inc"
+
+_RecoverLine:
+ jsr HLineRegs
+ jmp RecoverLine
+
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 29.10.99
+
+; void RecoverRectangle (void);
+
+ .export _RecoverRectangle
+
+ .include "../inc/jumptab.inc"
+
+_RecoverRectangle = RecoverRectangle
+
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 29.10.99
+
+; void Rectangle (void);
+
+ .export _Rectangle
+
+ .include "../inc/jumptab.inc"
+
+_Rectangle = Rectangle
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 29.10.99
+
+; void SetPattern (char pattern);
+
+ .export _SetPattern
+
+ .include "../inc/jumptab.inc"
+
+_SetPattern = SetPattern
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 29.10.99
+
+; char TestPoint (struct pixel *mypixel);
+
+ .import PointRegs
+ .export _TestPoint
+
+ .include "../inc/jumptab.inc"
+
+_TestPoint:
+ jsr PointRegs
+ jsr TestPoint
+ bcc goFalse
+ lda #$ff
+ rts
+goFalse: lda #0
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void UseSystemFont (void);
+
+ .export _UseSystemFont
+
+ .include "../inc/jumptab.inc"
+
+_UseSystemFont = UseSystemFont
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 29.10.99
+
+; void VerticalLine (char pattern, char ystart, char yend, int x);
+
+ .import popa
+
+ .export _VerticalLine
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_VerticalLine:
+ stx r4H
+ sta r4L
+ jsr popa
+ sta r3H
+ jsr popa
+ sta r3L
+ jsr popa
+ jmp VerticalLine
--- /dev/null
+
+;GeosConst - various system constans sorted by function
+;reassembled by Maciej 'YTM/Alliance' Witkowiak
+;4-2-99, 18-3-99
+
+NULL = 0
+FALSE = NULL
+TRUE = $ff
+
+MOUSE_SPRNUM = 0
+
+DISK_DRV_LGH = $0d80
+
+;
+;filetypes
+; GEOS
+NOT_GEOS = 0
+BASIC = 1
+ASSEMBLY = 2
+DATA = 3
+SYSTEM = 4
+DESK_ACC = 5
+APPLICATION = 6
+APPL_DATA = 7
+FONT = 8
+PRINTER = 9
+INPUT_DEVICE = 10
+DISK_DEVICE = 11
+SYSTEM_BOOT = 12
+TEMPORARY = 13
+AUTO_EXEC = 14
+INPUT_128 = 15
+NUMFILETYPES = 16
+; structure
+SEQUENTIAL = 0
+VLIR = 1
+; DOS
+DEL = 0
+SEQ = 1
+PRG = 2
+USR = 3
+REL = 4
+CBM = 5
+
+;drivetypes
+DRV_NULL = 0
+DRV_1541 = 1
+DRV_1571 = 2
+DRV_1581 = 3
+DRV_NETWORK = 15
+
+;various disk
+REL_FILE_NUM = 9
+CMND_FILE_NUM = 15
+MAX_CMND_STR = 32
+DIR_1581_TRACK = 40
+DIR_ACC_CHAN = 13
+DIR_TRACK = 18
+N_TRACKS = 35
+DK_NM_ID_LEN = 18
+TRACK = 9
+SECTOR = 12
+TOTAL_BLOCKS = 664
+
+;colours
+BLACK = 0
+WHITE = 1
+RED = 2
+CYAN = 3
+PURPLE = 4
+GREEN = 5
+BLUE = 6
+YELLOW = 7
+ORANGE = 8
+BROWN = 9
+LTRED = 10
+DKGREY = 11
+GREY = 12
+MEDGREY = 12
+LTGREEN = 13
+LTBLUE = 14
+LTGREY = 15
+
+;vic memory banks
+GRBANK0 = %11
+GRBANK1 = %10
+GRBANK2 = %01
+GRBANK3 = %00
+
+;screen
+VIC_X_POS_OFF = 24
+VIC_Y_POS_OFF = 50
+SC_BYTE_WIDTH = 40
+SC_PIX_HEIGHT = 200
+SC_PIX_WIDTH = 320
+SC_SIZE = 8000
+;128 screen size constants
+SCREENBYTEWIDTH = 80
+SCREENPIXELWIDTH = 640
+
+
+;control characters
+EOF = 0
+BACKSPACE = 8
+FORWARDSPACE = 9
+TAB = 9
+LF = 10
+HOME = 11
+PAGE_BREAK = 12
+UPLINE = 12
+CR = 13
+ULINEON = 14
+ULINEOFF = 15
+ESC_GRAPHICS = 16
+ESC_RULER = 17
+REV_ON = 18
+REV_OFF = 19
+GOTOX = 20
+GOTOY = 21
+GOTOXY = 22
+NEWCARDSET = 23
+BOLDON = 24
+ITALICON = 25
+OUTLINEON = 26
+PLAINTEXT = 27
+
+;keyboard
+KEY_F1 = 1
+KEY_F2 = 2
+KEY_F3 = 3
+KEY_F4 = 4
+KEY_F5 = 5
+KEY_F6 = 6
+KEY_NOSCRL = 7
+KEY_ENTER = 11
+KEY_F7 = 14
+KEY_F8 = 15
+KEY_UP = 16
+KEY_DOWN = 17
+KEY_HOME = 18
+KEY_CLEAR = 19
+KEY_LARROW = 20
+KEY_UPARROR = 21
+KEY_STOP = 22
+KEY_RUN = 23
+KEY_BPS = 24
+KEY_HELP = 25
+KEY_ALT = 26
+KEY_ESC = 27
+KEY_INSERT = 28
+KEY_DELETE = 29
+KEY_RIGHT = 30
+KEY_INVALID = 31
+KEY_LEFT = BACKSPACE
+
+;DialogBox
+; icons
+OK = 1
+CANCEL = 2
+YES = 3
+NO = 4
+OPEN = 5
+DISK = 6
+; commands
+DBTXTSTR = 11
+DBVARSTR = 12
+DBGETSTRING = 13
+DBSYSOPV = 14
+DBGRPHSTR = 15
+DBGETFILES = 16
+DBOPVEC = 17
+DBUSRICON = 18
+DB_USR_ROUT = 19
+; tabulation in standard window
+DBI_X_0 = 1
+DBI_X_1 = 9
+DBI_X_2 = 17
+DBI_Y_0 = 8
+DBI_Y_1 = 40
+DBI_Y_2 = 72
+; standard window
+SET_DB_POS = 0
+DEF_DB_POS = $80
+DEF_DB_TOP = 32
+DEF_DB_BOT = 127
+DEF_DB_LEFT = 64
+DEF_DB_RIGHT = 255
+; text tabulation
+TXT_LN_1_Y = 16
+TXT_LN_2_Y = 32
+TXT_LN_3_Y = 48
+TXT_LN_4_Y = 64
+TXT_LN_5_Y = 80
+TXT_LN_X = 16
+; ???
+SYSDBI_HEIGHT = 16
+SYSDBI_WIDTH = 6
+
+;GraphicsString - commands
+MOVEPENTO = 1
+LINETO = 2
+RECTANGLETO = 3
+NEWPATTERN = 5
+ESC_PUTSTRING = 6
+FRAME_RECTO = 7
+PEN_X_DELTA = 8
+PEN_Y_DELTA = 9
+PEN_XY_DELTA = 10
+
+
+;DoMenu - menutypes
+MENU_ACTION = $00
+DYN_SUB_MENU = $40
+SUB_MENU = $80
+HORIZONTAL = %00000000
+VERTICAL = %10000000
+
+;Errors
+ANY_FAULT = %11110000
+NO_BLOCKS = 1
+INV_TRACK = 2
+INSUFF_SPACE = 3
+FULL_DIRECTORY = 4
+FILE_NOT_FOUND = 5
+BAD_BAM = 6
+UNOPENED_VLIR = 7
+INV_RECORD = 8
+OUT_OF_RECORDS = 9
+STRUCT_MISMAT = 10
+BFR_OVERFLOW = 11
+CANCEL_ERR = 12
+DEV_NOT_FOUND = 13
+INCOMPATIBLE = 14
+HDR_NOT_THERE = $20
+NO_SYNC = $21
+DBLK_NOT_THERE = $22
+DAT_CHKSUM_ERR = $23
+WR_VER_ERR = $25
+WR_PR_ON = $26
+HDR_CHKSUM_ERR = $27
+DSK_ID_MISMAT = $29
+BYTE_DEC_ERR = $2e
+DOS_MISMATCH = $73
+
+;Offsets
+; ???
+OFF_INDEX_PTR = 1
+; icons
+OFF_NM_ICNS = 0
+OFF_IC_XMOUSE = 1
+OFF_IC_YMOUSE = 3
+OFF_PIC_ICON = 0
+OFF_X_ICON_POS = 2
+OFF_Y_ICON_POS = 3
+OFF_WDTH_ICON = 4
+OFF_HEIGHT_ICON = 5
+OFF_SRV_RT_ICON = 6
+OFF_NX_ICON = 8
+; menu
+OFF_MY_TOP = 0
+OFF_MY_BOT = 1
+OFF_MX_LEFT = 2
+OFF_MX_RIGHT = 4
+OFF_NUM_M_ITEMS = 6
+OFF_1ST_M_ITEM = 7
+; dialog box
+OFF_DB_FORM = 0
+OFF_DB_TOP = 1
+OFF_DB_BOT = 2
+OFF_DB_LEFT = 3
+OFF_DB_RIGHT = 5
+OFF_DB_1STCMD = 7
+; directory
+; disk header
+OFF_TO_BAM = 4
+OFF_DISK_NAME = 144
+OFF_GS_DTYPE = 189
+OFF_OP_TR_SC = 171
+OFF_GS_ID = 173
+; dir entry
+FRST_FILE_ENTRY = 2
+OFF_CFILE_TYPE = 0
+OFF_DE_TR_SC = 1
+OFF_FNAME = 3
+OFF_GHDR_PTR = 19
+OFF_GSTRUC_TYPE = 21
+OFF_GFILE_TYPE = 22
+OFF_YEAR = 23
+OFF_SIZE = 28
+OFF_NXT_FILE = 32
+; file header
+O_GHIC_WIDTH = 2
+O_GHIC_HEIGHT = 3
+O_GHIC_PIC = 4
+O_GHCMDR_TYPE = 68
+O_GHGEOS_TYPE = 69
+O_GHSTR_TYPE = 70
+O_GHST_ADDR = 71
+O_GHEND_ADDR = 73
+O_GHST_VEC = 75
+O_GHFNAME = 77
+O_128_FLAGS = 96
+O_GH_AUTHOR = 97
+O_GHP_DISK = 97
+O_GHP_FNAME = 117
+O_GHINFO_TXT = $a0
+
+;values for config - C128 mmu
+CIOIN = $7E ;60K RAM, 4K I/O space in
+CRAM64K = $7F ;64K RAM
+CKRNLBASIOIN = $40 ;kernal, I/O and basic ROM's mapped into memory
+CKRNLIOIN = $4E ;Kernal ROM and I/O space mapped in
+
+;values of faultData - pointer position vs. mouseTop/Bottom/Left/Right
+; bit numbers
+OFFTOP_BIT = 7
+OFFBOTTOM_BIT = 6
+OFFLEFT_BIT = 5
+OFFRIGHT_BIT = 4
+OFFMENU_BIT = 3
+; masks
+SET_OFFTOP = %10000000
+SET_OFFBOTTOM = %01000000
+SET_OFFLEFT = %00100000
+SET_OFFRIGHT = %00010000
+SET_OFFMENU = %00001000
+
+;values of currentMode
+; bit numbers
+UNDERLINE_BIT = 7
+BOLD_BIT = 6
+REVERSE_BIT = 5
+ITALIC_BIT = 4
+OUTLINE_BIT = 3
+SUPERSCRIPT_BIT = 2
+SUBSCRIPT_BIT = 1
+; masks
+SET_UNDERLINE = %10000000
+SET_BOLD = %01000000
+SET_REVERSE = %00100000
+SET_ITALIC = %00010000
+SET_OUTLINE = %00001000
+SET_SUPERSCRIPT = %00000100
+SET_SUBSCRIPT = %00000010
+SET_PLAINTEXT = %00000000
+
+;Process control variable
+; bit numbers
+RUNABLE_BIT = 7
+BLOCKED_BIT = 6
+FROZEN_BIT = 5
+NOTIMER_BIT = 4
+; masks
+SET_RUNABLE = %10000000
+SET_BLOCKED = %01000000
+SET_FROZEN = %00100000
+SET_NOTIMER = %00010000
+
+;mouseOn
+; bit numbers
+MOUSEON_BIT = 7
+MENUON_BIT = 6
+ICONSON_BIT = 5
+; masks
+SET_MSE_ON = %10000000
+SET_MENUON = %01000000
+SET_ICONSON = %00100000
+
+;pressFlag
+; bit numbers
+KEYPRESS_BIT = 7
+INPUT_BIT = 6
+MOUSE_BIT = 5
+; masks
+SET_KEYPRESS = %10000000
+SET_INPUTCHG = %01000000
+SET_MOUSE = %00100000
+
+;dispBufferOn
+ST_WRGS_FORE = $20
+ST_WR_BACK = $40
+ST_WR_FORE = $80
+
+;alarmSetFlag
+ALARMMASK = %00000100
+
+;PutDecimal
+ ;leading zeroes
+SET_NOSURPRESS = %00000000
+SET_SURPRESS = %01000000
+ ;justification
+SET_RIGHTJUST = %00000000
+SET_LEFTJUST = %10000000
+
+;icons, menus status flags
+ST_FLASH = $80
+ST_INVERT = $40
+ST_LD_AT_ADDR = $01
+ST_LD_DATA = $80
+ST_PR_DATA = $40
+ST_WR_PR = $40
+
+;???
+ADD1_W = $2000
+DOUBLE_B = $80
+DOUBLE_W = $8000
+
+CLR_SAVE = %01000000
+CONSTRAINED = %01000000
+UN_CONSTRAINED = %00000000
+FG_SAVE = %10000000
+
+FUTURE1 = 7
+FUTURE2 = 8
+FUTURE3 = 9
+FUTURE4 = 10
+USELAST = 127
+SHORTCUT = 128
--- /dev/null
+
+;GEOS Disk Driver JumpTab
+;reassembled by Maciej 'YTM/Alliance' Witkowiak
+;4-2-99
+
+;pointers
+_InitForIO = $9000
+_DoneWithIO = $9002
+_ExitTurbo = $9004
+_PurgeTurbo = $9006
+_EnterTurbo = $9008
+_ChangeDiskDevice = $900a
+_NewDisk = $900c
+_ReadBlock = $900e
+_WriteBlock = $9010
+_VerWriteBlock = $9012
+_OpenDisk = $9014
+_GetBlock = $9016
+_PutBlock = $9018
+_GetDirHead = $901a
+_PutDirHead = $901c
+_GetFreeDirBlk = $901e
+_CalcBlksFree = $9020
+_FreeBlock = $9022
+_SetNextFree = $9024
+_FindBAMBit = $9026
+_NxtBlkAlloc = $9028
+_BlkAlloc = $902a
+_ChkDkGEOS = $902c
+_SetGEOSDisk = $902e
+
+;jump table
+Get1stDirEntry = $9030
+GetNxtDirEntry = $9033
+GetBorder = $9036
+AddDirBlock = $9039
+ReadBuff = $903c
+WriteBuff = $903f
+;??? = $9042
+;??? = $9045
+AllocateBlock = $9048
+ReadLink = $904b
--- /dev/null
+
+;GEOS macros
+;reassembled for 6502TASM/MMS by Maciej 'YTM/Alliance' Witkowiak
+;4-2-99
+
+;28-6-99 - ca65 port
+;macro 'sub' renamed to 'ssub' due to 65816 mnemonics
+
+
+ .macro LoadB dest, value
+ lda #value
+ sta dest
+ .endmacro
+
+ .macro LoadW dest, value
+ lda #>value
+ sta dest+1
+ .if (>value)<>(<value)
+ lda #<value
+ .endif
+ sta dest+0
+ .endmacro
+
+ .macro MoveB source, dest
+ lda source
+ sta dest
+ .endmacro
+
+ .macro MoveW source, dest
+ MoveB source+1, dest+1
+ MoveB source+0, dest+0
+ .endmacro
+
+ .macro add source
+ clc
+ adc source
+ .endmacro
+
+ .macro AddB source, dest
+ lda source
+ add dest
+ sta dest
+ .endmacro
+
+ .macro AddW source, dest
+ AddB source+0, dest+0
+ lda source+1
+ adc dest+1
+ sta dest+1
+ .endmacro
+
+ .macro AddVB value, dest
+ lda dest
+ clc
+ adc #value
+ sta dest
+ .endmacro
+
+ .macro AddVW value, dest
+.local Skip
+ clc
+ lda #<value
+ adc dest+0
+ sta dest+0
+ .if (>value)=0
+ bcc Skip
+ inc dest+1
+ .else
+ lda #>value
+ adc dest+1
+ sta dest+1
+ .endif
+Skip:
+ .endmacro
+
+ .macro ssub source
+ sec
+ sbc source
+ .endmacro
+
+ .macro SubB source, dest
+ lda dest
+ ssub source
+ sta dest
+ .endmacro
+
+ .macro SubW source, dest
+ SubB source+0, dest+0
+ lda dest+1
+ sbc source+1
+ sta dest+1
+ .endmacro
+
+ .macro SubVW value, dest
+ sec
+ lda dest+0
+ sbc #<value
+ sta dest+0
+ lda dest+1
+ sbc #>value
+ sta dest+1
+ .endmacro
+
+ .macro CmpB source, dest
+ lda source
+ cmp dest
+ .endmacro
+
+ .macro CmpBI source, immed
+ lda source
+ cmp #immed
+ .endmacro
+
+ .macro CmpW source, dest
+.local Skip
+ CmpB source+1, dest+1
+ bne Skip
+ CmpB source+0, dest+0
+Skip:
+ .endmacro
+
+ .macro CmpWI source, immed
+.local Skip
+ CmpBI source+1, >immed
+ bne Skip
+ CmpBI source+0, <immed
+Skip:
+ .endmacro
+
+ .macro PushB source
+ lda source
+ pha
+ .endmacro
+
+ .macro PushW source
+ PushB source+1
+ PushB source+0
+ .endmacro
+
+ .macro PopB dest
+ pla
+ sta dest
+ .endmacro
+
+ .macro PopW dest
+ PopB dest+0
+ PopB dest+1
+ .endmacro
+
+ .macro bra addr
+ clv
+ bvc addr
+ .endmacro
+
+ .macro smb bitNumber, dest
+ pha
+ lda #(1 << bitNumber)
+ ora dest
+ sta dest
+ pla
+ .endmacro
+
+ .macro smbf bitNumber, dest
+ lda #(1 << bitNumber)
+ ora dest
+ sta dest
+ .endmacro
+
+ .macro rmb bitNumber, dest
+ pha
+ lda #(1 << bitNumber) ^ $ff
+ ora dest
+ sta dest
+ pla
+ .endmacro
+
+ .macro rmbf bitNumber, dest
+ lda #(1 << bitNumber) ^ $ff
+ ora dest
+ sta dest
+ .endmacro
+
+ .macro bbs bitNumber, source, addr
+.local Skip
+ php
+ pha
+ lda source
+ and #(1 << bitNumber)
+ beq Skip
+ pla
+ plp
+ bra addr
+Skip: pla
+ plp
+ .endmacro
+
+ .macro bbsf bitNumber, source, addr
+ .if bitNumber=7
+ bit source
+ bmi addr
+ .else
+ .if bitNumber=6
+ bit source
+ bvs addr
+ .else
+ lda source
+ and #(1 << bitNumber)
+ bne addr
+ .endif
+ .endif
+ .endmacro
+
+ .macro bbr bitNumber, source, addr
+.local Skip
+ php
+ pha
+ lda source
+ and #(1 << bitNumber)
+ bne Skip
+ pla
+ plp
+ bra addr
+Skip: pla
+ plp
+ .endmacro
+
+ .macro bbrf bitNumber, source, addr
+ .if bitNumber=7
+ bit source
+ bpl addr
+ .else
+ .if bitNumber=6
+ bit source
+ bvc addr
+ .else
+ lda source
+ and #(1 << bitNumber)
+ beq addr
+ .endif
+ .endif
+ .endmacro
+
+;03.03.99 by Maciej Witkowiak
+
+ .macro addv value
+ clc
+ adc #value
+ .endmacro
+
+ .macro subv value
+ sec
+ sbc #value
+ .endmacro
+
+ .macro bnex addr
+ txa
+ bne addr
+ .endmacro
+
+ .macro beqx addr
+ txa
+ beq addr
+ .endmacro
\ No newline at end of file
--- /dev/null
+
+;GEOS variable memory locations sorted by address
+;reassembled by Maciej 'YTM/Alliance' Witkowiak
+;4-2-99
+
+zpage = $0000
+;
+
+CPU_DDR = $00
+CPU_DATA = $01
+;
+r0 = $02
+r0L = $02
+r0H = $03
+r1 = $04
+r1L = $04
+r1H = $05
+r2 = $06
+r2L = $06
+r2H = $07
+r3 = $08
+r3L = $08
+r3H = $09
+r4 = $0a
+r4L = $0a
+r4H = $0b
+r5 = $0c
+r5L = $0c
+r5H = $0d
+r6 = $0e
+r6L = $0e
+r6H = $0f
+r7 = $10
+r7L = $10
+r7H = $11
+r8 = $12
+r8L = $12
+r8H = $13
+r9 = $14
+r9L = $14
+r9H = $15
+r10 = $16
+r10L = $16
+r10H = $17
+r11 = $18
+r11L = $18
+r11H = $19
+r12 = $1a
+r12L = $1a
+r12H = $1b
+r13 = $1c
+r13L = $1c
+r13H = $1d
+r14 = $1e
+r14L = $1e
+r14H = $1f
+r15 = $20
+r15L = $20
+r15H = $21
+;
+a0 = $fb
+a0L = $fb
+a0H = $fc
+a1 = $fd
+a1L = $fd
+a1H = $fe
+a2 = $70
+a2L = $70
+a2H = $71
+a3 = $72
+a3L = $72
+a3H = $73
+a4 = $74
+a4L = $74
+a4H = $75
+a5 = $76
+a5L = $76
+a5H = $77
+a6 = $78
+a6L = $78
+a6H = $79
+a7 = $7a
+a7L = $7a
+a7H = $7b
+a8 = $7c
+a8L = $7c
+a8H = $7d
+a9 = $7e
+a9L = $7e
+a9H = $7f
+
+;
+
+curPattern = $22
+string = $24
+baselineOffset = $26
+curSetWidth = $27
+curHeight = $29
+curIndexTable = $2a
+cardDataPntr = $2c
+currentMode = $2e
+dispBufferOn = $2f
+mouseOn = $30
+RAM_64K = $30
+msePicPtr = $31
+windowTop = $33
+windowBottom = $34
+leftMargin = $35
+IO_IN = $35
+KRNL_IO_IN = $36
+rightMargin = $37
+KRNL_BAS_IO_IN = $37
+pressFlag = $39
+mouseXPos = $3a
+mouseYPos = $3c
+returnAddress = $3d
+graphMode = $3f
+TURBO_DD00 = $8e ; from 1541 turbo
+TURBO_DD00_CPY = $8f ; from 1541 turbo
+STATUS = $90
+curDevice = $ba
+;
+errno = $91 ; custom error return code
+;
+irqvec = $0314
+bkvec = $0316
+nmivec = $0318
+;
+APP_RAM = $0400
+BACK_SCR_BASE = $6000
+PRINTBASE = $7900
+OS_VARS = $8000
+;
+diskBlkBuf = $8000
+fileHeader = $8100
+curDirHead = $8200
+fileTrScTab = $8300
+dirEntryBuf = $8400
+DrACurDkNm = $841e
+DrBCurDkNm = $8430
+dataFileName = $8442
+dataDiskName = $8453
+PrntFilename = $8465
+PrntDiskName = $8476
+curDrive = $8489
+diskOpenFlg = $848a
+isGEOS = $848b
+interleave = $848c
+NUMDRV = $848d
+driveType = $848e
+_driveType = driveType-8
+turboFlags = $8492
+_turboFlags = turboFlags-8
+curRecord = $8496
+usedRecords = $8497
+fileWritten = $8498
+fileSize = $8499
+appMain = $849b
+intTopVector = $849d
+intBotVector = $849f
+mouseVector = $84a1
+keyVector = $84a3
+inputVector = $84a5
+mouseFaultVec = $84a7
+otherPressVec = $84a9
+StringFaultVec = $84ab
+alarmTmtVector = $84ad
+BRKVector = $84af
+RecoverVector = $84b1
+selectionFlash = $84b3
+alphaFlag = $84b4
+iconSelFlg = $84b5
+faultData = $84b6
+menuNumber = $84b7
+mouseTop = $84b8
+mouseBottom = $84b9
+mouseLeft = $84ba
+mouseRight = $84bc
+stringX = $84be
+stringY = $84c0
+mousePicData = $84c1
+maxMouseSpeed = $8501
+minMouseSpeed = $8502
+mouseAccel = $8503
+keyData = $8504
+mouseData = $8505
+inputData = $8506
+mouseSpeed = $8507
+random = $850a
+saveFontTab = $850c
+dblClickCount = $8515
+year = $8516
+month = $8517
+day = $8518
+hour = $8519
+minutes = $851a
+seconds = $851b
+alarmSetFlag = $851c
+sysDBData = $851d
+screencolors = $851e
+dlgBoxRamBuf = $851f ; to $8697
+;
+;$8698 - $8877 - various system data (keyboard queue, VLIR t&s, DBox, Menu, timers)
+;
+savedmoby2 = $88bb
+scr80polar = $88bc
+scr80colors = $88bd
+vdcClrMode = $88be
+driveData = $88bf
+ramExpSize = $88c3
+sysRAMFlg = $88c4
+firstBoot = $88c5
+curType = $88c6
+ramBase = $88c7
+inputDevName = $88cb
+memBase = $88cf ;???
+DrCCurDkNm = $88dc
+DrDCurDkNm = $88ee
+dir2Head = $8900
+;
+SPRITE_PICS = $8a00
+spr0pic = $8a00
+spr1pic = $8a40
+spr2pic = $8a80
+spr3pic = $8ac0
+spr4pic = $8b00
+spr5pic = $8b40
+spr6pic = $8b80
+spr7pic = $8bc0
+COLOR_MATRIX = $8c00
+;
+obj0Pointer = $8ff8
+obj1Pointer = $8ff9
+obj2Pointer = $8ffa
+obj3Pointer = $8ffb
+obj4Pointer = $8ffc
+obj5Pointer = $8ffd
+obj6Pointer = $8ffe
+obj7Pointer = $8fff
+;
+DISK_BASE = $9000
+SCREEN_BASE = $a000
+OS_ROM = $c000
+OS_JUMPTAB = $c100
+RAMC_BASE = $de00
+RAMC_WINDOW = $df00
+EXP_BASE = $df00
+MOUSE_BASE_128 = $fd00
+MOUSE_JMP_128 = $fd00
+END_MOUSE_128 = $fe80
+MOUSE_BASE = $fe80
+MOUSE_JMP = $fe80
+config = $ff00
+END_MOUSE = $fffa
+NMI_VECTOR = $fffa
+RESET_VECTOR = $fffc
+IRQ_VECTOR = $fffe
+;
+vicbase = $d000
+sidbase = $d400
+mmu = $d500
+VDC = $d600
+ctab = $d800
+cia1base = $dc00
+cia2base = $dd00
+;
+mob0xpos = $d000
+mob0ypos = $d001
+mob1xpos = $d002
+mob1ypos = $d003
+mob2xpos = $d004
+mob2ypos = $d005
+mob3xpos = $d006
+mob3ypos = $d007
+mob4xpos = $d008
+mob4ypos = $d009
+mob5xpos = $d00a
+mob5ypos = $d00b
+mob6xpos = $d00c
+mob6ypos = $d00d
+mob7xpos = $d00e
+mob7ypos = $d00f
+msbxpos = $d010
+grcntrl1 = $d011
+rasreg = $d012
+lpxpos = $d013
+lpypos = $d014
+mobenble = $d015
+grcntrl2 = $d016
+grmemptr = $d018
+grirq = $d019
+grirqen = $d01a
+moby2 = $d017
+mobprior = $d01b
+mobmcm = $d01c
+mobx2 = $d01d
+mobmobcol = $d01e
+mobbakcol = $d01f
+extclr = $d020
+bakclr0 = $d021
+bakclr1 = $d022
+bakclr2 = $d023
+bakclr3 = $d024
+mcmclr0 = $d025
+mcmclr1 = $d026
+mob0clr = $d027
+mob1clr = $d028
+mob2clr = $d029
+mob3clr = $d02a
+mob4clr = $d02b
+mob5clr = $d02c
+mob6clr = $d02d
+mob7clr = $d02e
+keyreg = $d02f
+clkreg = $d030
+
+;
+vdcreg = $d600
+vdcdata = $d601
+;
--- /dev/null
+
+;GEOS various variables in OS_ROM area
+;reassembled by Maciej 'YTM/Alliance' Witkowiak
+;4-2-99
+
+bootName = $c006
+version = $c00f
+nationality = $c010
+sysFlgCopy = $c012
+c128Flag = $c013
+dateCopy = $c018
\ No newline at end of file
--- /dev/null
+
+;GEOS Input Driver Jump Tab
+;reassembled by Maciej 'YTM/Alliance' Witkowiak
+;4-2-99
+
+;for C64
+;MOUSE_JMP = $fe80
+SlowMouse = $fe83
+UpdateMouse = $fe86
+SetMouse = $fe89
+
+;for C128
+;MOUSE_JMP_128 = $fd00
+SlowMouse_128 = $fd03
+UpdateMouse_128 = $fd06
+SetMouse_128 = $fd09
--- /dev/null
+
+;GEOS System Jump Table
+;reassembled by Maciej 'YTM/Alliance' Witkowiak
+;4-2-99
+
+;jump table
+InterruptMain = $c100
+InitProcesses = $c103
+RestartProcess = $c106
+EnableProcess = $c109
+BlockProcess = $c10c
+UnBlockProcess = $c10f
+FreezeProcess = $c112
+UnFreezeProcess = $c115
+HorizontalLine = $c118
+InvertLine = $c11b
+RecoverLine = $c11e
+VerticalLine = $c121
+Rectangle = $c124
+FrameRectangle = $c127
+InvertRectangle = $c12a
+RecoverRectangle = $c12d
+DrawLine = $c130
+DrawPoint = $c133
+GraphicsString = $c136
+SetPattern = $c139
+GetScanLine = $c13c
+TestPoint = $c13f
+BitmapUp = $c142
+PutChar = $c145
+PutString = $c148
+UseSystemFont = $c14b
+StartMouseMode = $c14e
+DoMenu = $c151
+RecoverMenu = $c154
+RecoverAllMenus = $c157
+DoIcons = $c15a
+DShiftLeft = $c15d
+BBMult = $c160
+BMult = $c163
+DMult = $c166
+Ddiv = $c169
+DSdiv = $c16c
+Dabs = $c16f
+Dnegate = $c172
+Ddec = $c175
+ClearRam = $c178
+FillRam = $c17b
+MoveData = $c17e
+InitRam = $c181
+PutDecimal = $c184
+GetRandom = $c187
+MouseUp = $c18a
+MouseOff = $c18d
+DoPreviousMenu = $c190
+ReDoMenu = $c193
+GetSerialNumber = $c196
+Sleep = $c199
+ClearMouseMode = $c19c
+i_Rectangle = $c19f
+i_FrameRectangle = $c1a2
+i_RecoverRectangle = $c1a5
+i_GraphicsString = $c1a8
+i_BitmapUp = $c1ab
+i_PutString = $c1ae
+GetRealSize = $c1b1
+i_FillRam = $c1b4
+i_MoveData = $c1b7
+GetString = $c1ba
+GotoFirstMenu = $c1bd
+InitTextPrompt = $c1c0
+MainLoop = $c1c3
+DrawSprite = $c1c6
+GetCharWidth = $c1c9
+LoadCharSet = $c1cc
+PosSprite = $c1cf
+EnablSprite = $c1d2
+DisablSprite = $c1d5
+CallRoutine = $c1d8
+CalcBlksFree = $c1db
+ChkDkGEOS = $c1de
+NewDisk = $c1e1
+GetBlock = $c1e4
+PutBlock = $c1e7
+SetGEOSDisk = $c1ea
+SaveFile = $c1ed
+SetGDirEntry = $c1f0
+BldGDirEntry = $c1f3
+GetFreeDirBlk = $c1f6
+WriteFile = $c1f9
+BlkAlloc = $c1fc
+ReadFile = $c1ff
+SmallPutChar = $c202
+FollowChain = $c205
+GetFile = $c208
+FindFile = $c20b
+CRC = $c20e
+LdFile = $c211
+EnterTurbo = $c214
+LdDeskAcc = $c217
+ReadBlock = $c21a
+LdApplic = $c21d
+WriteBlock = $c220
+VerWriteBlock = $c223
+FreeFile = $c226
+GetFHdrInfo = $c229
+EnterDeskTop = $c22c
+StartAppl = $c22f
+ExitTurbo = $c232
+PurgeTurbo = $c235
+DeleteFile = $c238
+FindFTypes = $c23b
+RstrAppl = $c23e
+ToBASIC = $c241
+FastDelFile = $c244
+GetDirHead = $c247
+PutDirHead = $c24a
+NxtBlkAlloc = $c24d
+ImprintRectangle = $c250
+i_ImprintRectangle = $c253
+DoDlgBox = $c256
+RenameFile = $c259
+InitForIO = $c25c
+DoneWithIO = $c25f
+DShiftRight = $c262
+CopyString = $c265
+CopyFString = $c268
+CmpString = $c26b
+CmpFString = $c26e
+FirstInit = $c271
+OpenRecordFile = $c274
+CloseRecordFile = $c277
+NextRecord = $c27a
+PreviousRecord = $c27d
+PointRecord = $c280
+DeleteRecord = $c283
+InsertRecord = $c286
+AppendRecord = $c289
+ReadRecord = $c28c
+WriteRecord = $c28f
+SetNextFree = $c292
+UpdateRecordFile = $c295
+GetPtrCurDkNm = $c298
+PromptOn = $c29b
+PromptOff = $c29e
+OpenDisk = $c2a1
+DoInlineReturn = $c2a4
+GetNextChar = $c2a7
+BitmapClip = $c2aa
+FindBAMBit = $c2ad
+SetDevice = $c2b0
+IsMseInRegion = $c2b3
+ReadByte = $c2b6
+FreeBlock = $c2b9
+ChangeDiskDevice = $c2bc
+RstrFrmDialogue = $c2bf
+Panic = $c2c2
+BitOtherClip = $c2c5
+StashRAM = $c2c8
+FetchRAM = $c2cb
+SwapRAM = $c2ce
+VerifyRAM = $c2d1
+DoRAMOp = $c2d4
+
+;only in GEOS 128
+TempHideMouse = $c2d7
+SetMousePicture = $c2da
+SetNewMode = $c2dd
+NormalizeX = $c2e0
+MoveBData = $c2e3
+SwapBData = $c2e6
+VerifyBData = $c2e9
+DoBOp = $c2ec
+AccessCache = $c2ef
+HideOnlyMouse = $c2f2
+SetColorMode = $c2f5
+ColorCard = $c2f8
+ColorRectangle = $c2fb
--- /dev/null
+
+;GEOS Printer Driver Jump Table
+;reassembled by Maciej 'YTM/Alliance' Witkowiak
+;4-2-99
+
+;jump table
+InitForPrint = $7900
+StartPrint = $7903
+PrintBuffer = $7906
+StopPrint = $7909
+GetDimensions = $790c
+PrinsASCII = $790f
+StartASCII = $7912
+SetNLQ = $7915
--- /dev/null
+#
+# Makefile for GEOS lib
+# for cc65
+#
+#
+
+%.o: %.s
+ @echo $<
+ @$(AS) -o $@ $(AFLAGS) $<
+
+
+S_OBJS = crc.o doublepop.o reuregs.o clearram.o fillram.o initram.o movedata.o\
+ stashram.o fetchram.o swapram.o verifyram.o\
+ doublespop.o copystring.o cmpstring.o copyfstring.o cmpfstring.o
+
+all: $(S_OBJS)
+
+clean:
+ @rm -f *.~ $(S_OBJS) core
\ No newline at end of file
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void ClearRam (char *dest, int length);
+
+ .import DoublePop
+ .export _ClearRam
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_ClearRam:
+ jsr DoublePop
+ jmp ClearRam
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 22.12.99
+
+; void CmpFString (char length, char *dest, char* source);
+
+ .import DoubleSPop
+ .import popa
+ .export _CmpFString
+
+ .include "../inc/jumptab.inc"
+
+_CmpFString:
+ jsr DoubleSPop
+ jsr popa
+ jmp CmpFString
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 22.12.99
+
+; char CmpString (char *dest, char* source);
+
+ .import DoubleSPop
+ .export _CmpString
+
+ .include "../inc/jumptab.inc"
+
+_CmpString:
+ jsr DoubleSPop
+ jmp CmpString
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 22.12.99
+
+; void CopyFString (char length, char *dest, char* source);
+
+ .import DoubleSPop
+ .import popa
+ .export _CopyFString
+
+ .include "../inc/jumptab.inc"
+
+_CopyFString:
+ jsr DoubleSPop
+ jsr popa
+ jmp CopyFString
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 22.12.99
+
+; void CopyString (char *dest, char* source);
+
+ .import DoubleSPop
+ .export _CopyString
+
+ .include "../inc/jumptab.inc"
+
+_CopyString:
+ jsr DoubleSPop
+ jmp CopyString
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 22.12.99
+
+; int CRC (char *memory, int length);
+
+ .import DoublePop
+ .export _CRC
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_CRC:
+ jsr DoublePop
+ jsr CRC
+ lda r2L
+ ldx r2H
+ rts
+
\ No newline at end of file
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 31.12.99
+
+ .import popax
+ .export DoublePop
+
+ .include "../inc/geossym.inc"
+
+DoublePop:
+ sta r0L
+ stx r0H
+ jsr popax
+ sta r1L
+ stx r1H
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 22.12.99
+
+ .import popax
+ .importzp ptr3, ptr4
+ .export DoubleSPop
+
+ .include "../inc/geossym.inc"
+
+DoubleSPop:
+ sta ptr4
+ stx ptr4+1
+ jsr popax
+ sta ptr3
+ stx ptr3+1
+ lda #ptr4
+ ldx #ptr3
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; void FetchRAM (char REUBank, int length, char *from, char *dest);
+
+ .import REURegs
+ .export _FetchRAM
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_FetchRAM:
+ jsr REURegs
+ jmp FetchRAM
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void FillRam (char what, char *dest, int length);
+
+ .import DoublePop, popa
+ .export _FillRam
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_FillRam:
+ jsr DoublePop
+ jsr popa
+ sta r2L
+ jmp FillRam
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void InitRam (struct inittab*);
+
+ .export _InitRam
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_InitRam:
+ sta r0L
+ stx r0H
+ jmp InitRam
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void MoveData (char* source, char *dest, int length);
+
+ .import popax
+ .export _MoveData
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_MoveData:
+ sta r2L
+ stx r2H
+ jsr popax
+ sta r1L
+ stx r1H
+ jsr popax
+ sta r0L
+ stx r0H
+ jmp MoveData
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 31.12.99
+
+ .import popax, popa
+ .import DoublePop
+ .export REURegs
+
+ .include "../inc/geossym.inc"
+
+REURegs:
+ jsr DoublePop
+ jsr popax
+ sta r2L
+ stx r2H
+ jsr popa
+ sta r3L
+ rts
+
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; void StashRAM (char REUBank, int length, char *dest, char *from);
+
+ .import REURegs
+ .export _StashRAM
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_StashRAM:
+ jsr REURegs
+ jmp StashRAM
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; void SwapRAM (char REUBank, int length, char *reuaddy, char *cpuaddy);
+; note that in all REU procs last two pointers are identified like here
+
+ .import REURegs
+ .export _SwapRAM
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_SwapRAM:
+ jsr REURegs
+ jmp SwapRAM
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; char VerifyRAM (char REUBank, int length, char *reuaddy, char *cpuaddy);
+
+ .import REURegs
+ .export _VerifyRAM
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_VerifyRAM:
+ jsr REURegs
+ jsr VerifyRAM
+ txa
+ rts
--- /dev/null
+#
+# Makefile for GEOS lib
+# for cc65
+#
+#
+
+%.o: %.s
+ @echo $<
+ @$(AS) -o $@ $(AFLAGS) $<
+
+
+S_OBJS = domenu.o dopreviousmenu.o redomenu.o recovermenu.o recoverallmenus.o\
+ gotofirstmenu.o doicons.o
+
+all: $(S_OBJS)
+
+clean:
+ @rm -f *.~ $(S_OBJS) core
\ No newline at end of file
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void DoIcons (struct icontab *myicons);
+
+ .export _DoIcons
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_DoIcons:
+ sta r0L
+ stx r0H
+ jmp DoIcons
\ No newline at end of file
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void DoMenu (struct menu *mymenu);
+
+ .export _DoMenu
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_DoMenu:
+ sta r0L
+ stx r0H
+ lda #0
+ jmp DoMenu
\ No newline at end of file
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void DoPreviousMenu (void);
+
+ .export _DoPreviousMenu
+
+ .include "../inc/jumptab.inc"
+
+_DoPreviousMenu = DoPreviousMenu
\ No newline at end of file
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void GotoFirstMenu (void);
+
+ .export _GotoFirstMenu
+
+ .include "../inc/jumptab.inc"
+
+_GotoFirstMenu = GotoFirstMenu
\ No newline at end of file
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void RecoverAllMenus (void);
+
+ .export _RecoverAllMenus
+
+ .include "../inc/jumptab.inc"
+
+_RecoverAllMenus = RecoverAllMenus
\ No newline at end of file
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void RecoverMenu (void);
+
+ .export _RecoverMenu
+
+ .include "../inc/jumptab.inc"
+
+_RecoverMenu = RecoverMenu
\ No newline at end of file
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void ReDoMenu (void);
+
+ .export _ReDoMenu
+
+ .include "../inc/jumptab.inc"
+
+_ReDoMenu = ReDoMenu
\ No newline at end of file
--- /dev/null
+#
+# Makefile for GEOS lib
+# for cc65
+#
+#
+
+%.o: %.s
+ @echo $<
+ @$(AS) -o $@ $(AFLAGS) $<
+
+
+S_OBJS = startmousemode.o clearmousemode.o mouseup.o mouseoff.o\
+ drawsprite.o possprite.o enablsprite.o disablsprite.o\
+ ismseinregion.o inittextprompt.o promptoff.o prompton.o\
+ getnextchar.o
+
+all: $(S_OBJS)
+
+clean:
+ @rm -f *.~ $(S_OBJS) core
\ No newline at end of file
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void ClearMouseMode (void);
+
+ .export _ClearMouseMode
+
+ .include "../inc/jumptab.inc"
+
+_ClearMouseMode = ClearMouseMode
\ No newline at end of file
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void DisablSprite (char spritenum);
+
+ .export _DisablSprite
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_DisablSprite:
+ sta r3L
+ jmp DisablSprite
\ No newline at end of file
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+;
+; void DrawSprite (char spritenum, char *tab63 );
+;
+
+ .import popa
+ .export _DrawSprite
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_DrawSprite:
+
+ sta r4L
+ stx r4H
+ jsr popa
+ sta r3L
+ jmp DrawSprite
\ No newline at end of file
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void EnablSprite (char spritenum);
+
+ .export _EnablSprite
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_EnablSprite:
+ sta r3L
+ jmp EnablSprite
\ No newline at end of file
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; char GetNextChar (void);
+; note that if it returns 0 (FALSE) then no characters are available
+
+ .export _GetNextChar
+
+ .include "../inc/jumptab.inc"
+
+_GetNextChar = GetNextChar
\ No newline at end of file
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; void InitTextPrompt (char height);
+
+ .export _InitTextPrompt
+
+ .include "../inc/jumptab.inc"
+
+_InitTextPrompt = InitTextPrompt
\ No newline at end of file
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; char IsMseInRegion (struct window *mywindow);
+
+ .import RectRegs
+
+ .export _IsMseInRegion
+
+ .include "../inc/jumptab.inc"
+
+_IsMseInRegion:
+ jsr RectRegs
+ jmp IsMseInRegion
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void MouseOff (void);
+
+ .export _MouseOff
+
+ .include "../inc/jumptab.inc"
+
+_MouseOff = MouseOff
\ No newline at end of file
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void MouseUp (void);
+
+ .export _MouseUp
+
+ .include "../inc/jumptab.inc"
+
+_MouseUp = MouseUp
\ No newline at end of file
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+;
+; void PosSprite (char spritenum, struct pixel *position );
+;
+
+ .importzp ptr4
+ .import popa
+ .export _PosSprite
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_PosSprite:
+ sta ptr4
+ stx ptr4+1
+ ldy #0
+ lda (ptr4),y
+ sta r4L
+ iny
+ lda (ptr4),y
+ sta r4H
+ iny
+ lda (ptr4),y
+ sta r5L
+ jsr popa
+ sta r3L
+ jmp PosSprite
\ No newline at end of file
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; void PromptOff (void);
+
+ .export _PromptOff
+
+ .include "../inc/jumptab.inc"
+
+_PromptOff = PromptOff
\ No newline at end of file
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; void PromptOn (struct pixel *);
+
+ .importzp ptr4
+ .export _PromptOn
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_PromptOn:
+ sta ptr4
+ stx ptr4+1
+ ldy #0
+promptLp: lda (ptr4),y
+ sta stringX,y
+ iny
+ cpy #3
+ bne promptLp
+ jmp PromptOn
\ No newline at end of file
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void StartMouseMode (void);
+
+ .export _StartMouseMode
+
+ .include "../inc/jumptab.inc"
+
+_StartMouseMode:
+ clc
+ jmp StartMouseMode
\ No newline at end of file
--- /dev/null
+#
+# Makefile for GEOS lib
+# for cc65
+#
+#
+
+%.o: %.s
+ @echo $<
+ @$(AS) -o $@ $(AFLAGS) $<
+
+
+S_OBJS = processinitrestartenable.o processblock.o processfreeze.o sleep.o
+
+all: $(S_OBJS)
+
+clean:
+ @rm -f *.~ $(S_OBJS) core
\ No newline at end of file
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 27.10.99
+
+;
+; void InitProcesses (char number, struct process* proctab);
+; (rest)
+; void BlockProcess (char number);
+; void UnBlockProcess (char number);
+;
+
+ .export _BlockProcess
+ .export _UnBlockProcess
+
+ .include "../inc/jumptab.inc"
+
+_BlockProcess:
+ tax
+ jmp BlockProcess
+
+_UnBlockProcess:
+ tax
+ jmp UnBlockProcess
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 27.10.99
+
+;
+; void FreezeProcess (char number);
+; void UnFreezeProcess (char number);
+;
+
+ .export _FreezeProcess
+ .export _UnFreezeProcess
+
+ .include "../inc/jumptab.inc"
+
+_FreezeProcess:
+ tax
+ jmp FreezeProcess
+
+_UnFreezeProcess:
+ tax
+ jmp UnFreezeProcess
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 27.10.99
+
+;
+; void InitProcesses (char number, struct process* proctab);
+; void RestartProcess (char number);
+; void EnableProcess (char number);
+;
+
+ .import popa
+ .export _InitProcesses
+ .export _RestartProcess
+ .export _EnableProcess
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_InitProcesses:
+
+ sta r0L
+ stx r0H
+ jsr popa
+ jmp InitProcesses
+
+_RestartProcess:
+ tax
+ jmp RestartProcess
+
+_EnableProcess:
+ tax
+ jmp EnableProcess
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+;
+; void Sleep (int jiffies);
+;
+
+ .export _Sleep
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_Sleep:
+
+ sta r0L
+ stx r0H
+ jmp Sleep
\ No newline at end of file
--- /dev/null
+#
+# Makefile for GEOS lib
+# for cc65
+#
+#
+
+%.o: %.s
+ @echo $<
+ @$(AS) -o $@ $(AFLAGS) $<
+
+
+S_OBJS = callroutine.o enterdesktop.o firstinit.o getrandom.o getserialnumber.o\
+ initdoneio.o mainloop.o panic.o tobasic.o setdevice.o
+
+all: $(S_OBJS)
+
+clean:
+ @rm -f *.~ $(S_OBJS) core
\ No newline at end of file
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; void CallRoutine (myRoutine);
+
+ .export _CallRoutine
+
+ .include "../inc/jumptab.inc"
+
+_CallRoutine = CallRoutine
\ No newline at end of file
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void EnterDeskTop (void);
+
+ .export _EnterDeskTop
+
+ .include "../inc/jumptab.inc"
+
+_EnterDeskTop = EnterDeskTop
\ No newline at end of file
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void FirstInit (void);
+
+ .export _FirstInit
+
+ .include "../inc/jumptab.inc"
+
+_FirstInit = FirstInit
\ No newline at end of file
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; int GetRandom (void);
+
+ .export _GetRandom
+
+ .include "../inc/jumptab.inc"
+
+_GetRandom = GetRandom
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; int GetSerialNumber (void);
+
+ .export _GetSerialNumber
+
+ .include "../inc/jumptab.inc"
+ .include "../inc/geossym.inc"
+
+_GetSerialNumber:
+
+ jsr GetSerialNumber
+ lda r0L
+ ldx r0H
+ rts
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void InitForIO (void);
+; void DoneWithIO (void);
+
+ .export _InitForIO, _DoneWithIO
+
+ .include "../inc/jumptab.inc"
+
+_InitForIO = InitForIO
+
+_DoneWithIO = DoneWithIO
\ No newline at end of file
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void MainLoop (void);
+
+ .export _MainLoop
+
+ .include "../inc/jumptab.inc"
+
+_MainLoop = MainLoop
\ No newline at end of file
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void Panic (void);
+
+ .export _Panic
+
+ .include "../inc/jumptab.inc"
+
+_Panic = Panic
\ No newline at end of file
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 21.12.99
+
+; void SetDevice (char newDeviceNumber);
+
+ .export _SetDevice
+
+ .include "../inc/jumptab.inc"
+
+_SetDevice = SetDevice
--- /dev/null
+
+;
+; Maciej 'YTM/Alliance' Witkowiak
+;
+; 30.10.99
+
+; void ToBASIC (void);
+
+ .export _ToBASIC
+
+ .include "../inc/jumptab.inc"
+
+_ToBASIC = ToBASIC
\ No newline at end of file
--- /dev/null
+#
+# makefile for CC65 runtime library
+#
+
+.SUFFIXES: .o .s .c
+
+%.o: %.c
+ @echo $<
+ @$(CC) $(CFLAGS) $<
+ @$(AS) -o $@ $(AFLAGS) $(*).s
+
+%.o: %.s
+ @echo $<
+ @$(AS) -g -o $@ $(AFLAGS) $<
+
+C_OBJS =
+
+S_OBJS = crt0.o kbhit.o conio.o clrscr.o cputc.o cgetc.o break.o color.o
+
+all: $(C_OBJS) $(S_OBJS)
+
+clean:
+ @rm -f $(C_OBJS:.c=.s)
+ @rm -f $(C_OBJS)
+ @rm -f $(S_OBJS)
+ @rm -f crt0.o
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 26.11.1998
+;
+; void set_brk (unsigned Addr);
+; void reset_brk (void);
+;
+
+ .export _set_brk, _reset_brk
+ .export _brk_a, _brk_x, _brk_y, _brk_sr, _brk_pc
+ .import _atexit
+
+ .include "pet.inc"
+
+
+.bss
+_brk_a: .res 1
+_brk_x: .res 1
+_brk_y: .res 1
+_brk_sr: .res 1
+_brk_pc: .res 2
+
+oldvec: .res 2 ; Old vector
+
+
+.data
+uservec: jmp $FFFF ; Patched at runtime
+
+
+.code
+
+; Set the break vector
+.proc _set_brk
+
+ sta uservec+1
+ stx uservec+2 ; Set the user vector
+
+ lda oldvec
+ ora oldvec+1 ; Did we save the vector already?
+ bne L1 ; Jump if we installed the handler already
+
+ lda BRKVec
+ sta oldvec
+ lda BRKVec+1
+ sta oldvec+1 ; Save the old vector
+
+ lda #<_reset_brk
+ ldx #>_reset_brk
+ jsr _atexit ; Install an exit handler
+
+L1: lda #<brk_handler ; Set the break vector to our routine
+ sta BRKVec
+ lda #>brk_handler
+ sta BRKVec+1
+ rts
+
+.endproc
+
+
+; Reset the break vector
+.proc _reset_brk
+
+ lda oldvec
+ sta BRKVec
+ lda oldvec+1
+ sta BRKVec+1
+ rts
+
+.endproc
+
+
+
+; Break handler, called if a break occurs
+
+.proc brk_handler
+
+ pla
+ sta _brk_y
+ pla
+ sta _brk_x
+ pla
+ sta _brk_a
+ pla
+ and #$EF ; Clear break bit
+ sta _brk_sr
+ pla ; PC low
+ sec
+ sbc #2 ; Point to start of brk
+ sta _brk_pc
+ pla ; PC high
+ sbc #0
+ sta _brk_pc+1
+
+ jsr uservec ; Call the user's routine
+
+ lda _brk_pc+1
+ pha
+ lda _brk_pc
+ pha
+ lda _brk_sr
+ pha
+ ldx _brk_x
+ ldy _brk_y
+ lda _brk_a
+ rti ; Jump back...
+
+.endproc
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; char cgetc (void);
+;
+
+ .export _cgetc
+ .import cursor
+
+ .include "pet.inc"
+
+_cgetc: lda KEY_COUNT ; Get number of characters
+ bne L3 ; Jump if there are already chars waiting
+
+; Switch on the cursor if needed
+
+ lda CURS_FLAG
+ pha
+ lda cursor
+ jsr setcursor
+L1: lda KEY_COUNT
+ beq L1
+ ldx #0
+ pla
+ bne L2
+ inx
+L2: txa
+ jsr setcursor
+
+; Fetch the character from the keyboard buffer
+
+L3: sei
+ ldy KEY_BUF
+ ldx #$00
+L4: lda KEY_BUF+1,x
+ sta KEY_BUF,x
+ inx
+ cpx KEY_COUNT
+ bne L4
+ dec KEY_COUNT
+ cli
+ ldx #$00 ; Clear high byte
+ tya
+ rts
+
+; Switch the cursor on or off
+
+setcursor:
+ tax ; On or off?
+ bne seton ; Go set it on
+ lda CURS_FLAG ; Is the cursor currently off?
+ bne crs9 ; Jump if yes
+ lda #1
+ sta CURS_FLAG ; Mark it as off
+ lda CURS_STATE ; Cursor currently displayed?
+ beq crs8 ; Jump if no
+ ldy CURS_X ; Get the character column
+ lda (SCREEN_PTR),y ; Get character
+ eor #$80
+ sta (SCREEN_PTR),y ; Store character back
+crs8: lda #0
+ sta CURS_STATE ; Cursor not displayed
+crs9: rts
+
+seton: lda #0
+ sta CURS_FLAG
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 26.11.1998
+;
+; void clrscr (void);
+;
+
+ .export _clrscr
+ .import plot
+ .importzp ptr1
+ .import xsize
+
+ .include "pet.inc"
+
+_clrscr:
+
+; Set the screen base address
+
+ lda #$00
+ sta ptr1
+ lda #$80
+ sta ptr1+1
+
+; Determine, how many pages to fill
+
+ ldx #4
+ lda xsize
+ cmp #40
+ beq L1
+ ldx #8
+
+; Clear the screen
+
+L1: lda #$20 ; Screen code for blank
+ ldy #$00
+L2: sta (ptr1),y
+ iny
+ bne L2
+ inc ptr1+1
+ dex
+ bne L2
+
+; Set the cursor to 0/0
+
+ lda #0
+ sta CURS_X
+ sta CURS_Y
+ jmp plot
+
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; unsigned char __fastcall__ textcolor (unsigned char color);
+; unsigned char __fastcall__ bgcolor (unsigned char color);
+; unsigned char __fastcall__ bordercolor (unsigned char color);
+;
+
+ .export _textcolor, _bgcolor, _bordercolor
+ .import return0, return1
+
+_textcolor = return1
+
+_bgcolor = return0
+
+_bordercolor = return0
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 26.11.1998
+;
+; Low level stuff for screen output/console input
+;
+
+ .export initconio
+ .import xsize, ysize
+ .exportzp CURS_X, CURS_Y
+
+ .include "pet.inc"
+
+.code
+
+initconio:
+ ldx SCR_LINELEN
+ inx ; Variable is one less
+ stx xsize
+ lda #25
+ sta ysize
+ rts
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; void cputcxy (unsigned char x, unsigned char y, char c);
+; void cputc (char c);
+;
+
+ .export _cputcxy, _cputc, cputdirect, putchar
+ .export advance, newline, plot
+ .import popa, _gotoxy
+ .import xsize, revers
+
+ .include "pet.inc"
+ .include "../cbm/cbm.inc"
+
+_cputcxy:
+ pha ; Save C
+ jsr popa ; Get Y
+ jsr _gotoxy ; Set cursor, drop x
+ pla ; Restore C
+
+; Plot a character - also used as internal function
+
+_cputc: cmp #$0D ; CR?
+ bne L1
+ lda #0
+ sta CURS_X
+ beq plot ; Recalculate pointers
+
+L1: cmp #$0A ; LF?
+ bne L2
+ ldy CURS_Y
+ iny
+ bne newline ; Recalculate pointers
+
+; Printable char of some sort
+
+L2: cmp #' '
+ bcc cputdirect ; Other control char
+ tay
+ bmi L10
+ cmp #$60
+ bcc L3
+ and #$DF
+ bne cputdirect ; Branch always
+L3: and #$3F
+
+cputdirect:
+ jsr putchar ; Write the character to the screen
+
+; Advance cursor position
+
+advance:
+ iny
+ cpy xsize
+ bne L9
+ ldy #0 ; new line
+newline:
+ clc
+ lda xsize
+ adc SCREEN_PTR
+ sta SCREEN_PTR
+ bcc L4
+ inc SCREEN_PTR+1
+L4: inc CURS_Y
+L9: sty CURS_X
+ rts
+
+; Handle character if high bit set
+
+L10: and #$7F
+ cmp #$7E ; PI?
+ bne L11
+ lda #$5E ; Load screen code for PI
+ bne cputdirect
+L11: ora #$40
+ bne cputdirect
+
+
+
+; Set cursor position, calculate RAM pointers
+
+plot: ldy CURS_Y
+ lda ScrLo,y
+ sta SCREEN_PTR
+ lda ScrHi,y
+ ldy xsize
+ cpy #40
+ beq @L1
+ asl SCREEN_PTR ; 80 column mode
+ rol a
+@L1: ora #$80 ; Screen at $8000
+ sta SCREEN_PTR+1
+ rts
+
+
+; Write one character to the screen without doing anything else, return X
+; position in Y
+
+putchar:
+ ora revers ; Set revers bit
+ ldy CURS_X
+ sta (SCREEN_PTR),y ; Set char
+ rts
+
+; Screen address tables - offset to real screen
+
+.rodata
+
+ScrLo: .byte $00, $28, $50, $78, $A0, $C8, $F0, $18
+ .byte $40, $68, $90, $B8, $E0, $08, $30, $58
+ .byte $80, $A8, $D0, $F8, $20, $48, $70, $98
+ .byte $C0
+
+ScrHi: .byte $00, $00, $00, $00, $00, $00, $00, $01
+ .byte $01, $01, $01, $01, $01, $02, $02, $02
+ .byte $02, $02, $02, $02, $03, $03, $03, $03
+ .byte $03
+
+
--- /dev/null
+;
+; Startup code for cc65 (PET version)
+;
+; This must be the *first* file on the linker command line
+;
+
+ .export _exit
+ .import __hinit, initconio, zerobss, push0, doatexit
+ .import _main
+
+ .include "pet.inc"
+ .include "../cbm/cbm.inc"
+
+; ------------------------------------------------------------------------
+; Define and export the ZP variables for the C64 runtime
+
+ .exportzp sp, sreg, regsave
+ .exportzp ptr1, ptr2, ptr3, ptr4
+ .exportzp tmp1, tmp2, tmp3, tmp4
+ .exportzp regbank, zpspace
+
+sp = $02 ; stack pointer
+sreg = $04 ; secondary register/high 16 bit for longs
+regsave = $06 ; slot to save/restore (E)AX into
+ptr1 = $0A ;
+ptr2 = $0C
+ptr3 = $0E
+ptr4 = $10
+tmp1 = $12
+tmp2 = $13
+tmp3 = $14
+tmp4 = $15
+regbank = $16 ; 6 byte register bank
+zpspace = $1A ; Zero page space allocated
+
+; ------------------------------------------------------------------------
+; BASIC header with a SYS call
+
+ .org $3FF
+ .word Head ; Load address
+Head: .word @Next
+ .word 1000 ; Line number
+ .byte $9E,"1037" ; SYS 1037
+ .byte $00 ; End of BASIC line
+@Next: .word 0 ; BASIC end marker
+ .reloc
+
+; ------------------------------------------------------------------------
+; Actual code
+
+ ldy #zpspace-1
+L1: lda sp,y
+ sta zpsave,y ; Save the zero page locations we need
+ dey
+ bpl L1
+
+; Close open files
+
+ jsr CLRCH
+
+; Switch to second charset
+
+ lda #14
+; sta $E84C ; See PET FAQ
+ jsr BSOUT
+
+; Clear the BSS data
+
+ jsr zerobss
+
+; Save system stuff and setup the stack
+
+ tsx
+ stx spsave ; Save the system stack ptr
+
+ lda MEMSIZE
+ sta sp
+ lda MEMSIZE+1
+ sta sp+1 ; Set argument stack ptr
+
+; Initialize the heap
+
+ jsr __hinit
+
+; Initialize conio stuff
+
+ jsr initconio
+
+; Pass an empty command line
+
+ jsr push0 ; argc
+ jsr push0 ; argv
+
+ ldy #4 ; Argument size
+ jsr _main ; call the users code
+
+; fall thru to exit...
+
+_exit: jsr doatexit ; call exit functions
+
+ ldx spsave
+ txs ; Restore stack pointer
+
+; Copy back the zero page stuff
+
+ ldy #zpspace-1
+L2: lda zpsave,y
+ sta sp,y
+ dey
+ bpl L2
+
+; Back to basic
+
+ rts
+
+
+.data
+
+zpsave: .res zpspace
+
+.bss
+
+spsave: .res 1
+mmusave:.res 1
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 26.11.1998
+;
+; int kbhit (void);
+;
+
+ .export _kbhit
+ .import return0, return1
+
+ .include "pet.inc"
+
+_kbhit:
+ lda KEY_COUNT ; Get number of characters
+ bne L1
+ jmp return0
+L1: jmp return1
+
+
+
+
--- /dev/null
+;
+; C64 generic definitions. Stolen from Elite128
+;
+
+
+; ---------------------------------------------------------------------------
+; Zero page, Commodore stuff
+
+MEMSIZE = $34 ; Size of memory installed
+ST = $96 ; IEC status byte
+SECADR = $D3 ; Secondary address
+DEVNUM = $D4 ; Device number
+KEY_COUNT = $9E ; Number of keys in input buffer
+CURS_FLAG = $A7 ; 1 = cursor off
+CURS_BLINK = $A8 ; Blink counter
+CURS_CHAR = $A9 ; Character under the cursor
+CURS_STATE = $AA ; Cursor blink state
+SCREEN_PTR = $C4 ; Pointer to current char in text screen
+CURS_X = $C6 ; Cursor column
+CURS_Y = $D8 ; Cursor row
+SCR_LINELEN = $D5 ; Screen line length
+
+KEY_BUF = $26F ; Keyboard buffer
+
+
+; ---------------------------------------------------------------------------
+; Vector and other locations
+
+IRQVec = $0090
+BRKVec = $0092
+NMIVec = $0094
+
--- /dev/null
+#
+# makefile for CC65 runtime library
+#
+
+.SUFFIXES: .o .s .c
+
+%.o: %.c
+ @echo $<
+ @$(CC) $(CFLAGS) $<
+ @$(AS) -o $@ $(AFLAGS) $(*).s
+
+%.o: %.s
+ @echo $<
+ @$(AS) -g -o $@ $(AFLAGS) $<
+
+C_OBJS =
+
+S_OBJS = crt0.o kbhit.o conio.o clrscr.o cputc.o cgetc.o\
+ color.o readjoy.o break.o
+
+all: $(C_OBJS) $(S_OBJS)
+
+clean:
+ @rm -f $(C_OBJS:.c=.s)
+ @rm -f $(C_OBJS)
+ @rm -f $(S_OBJS)
+ @rm -f crt0.o
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 27.09.1998
+;
+; void set_brk (unsigned Addr);
+; void reset_brk (void);
+;
+
+ .export _set_brk, _reset_brk
+ .export _brk_a, _brk_x, _brk_y, _brk_sr, _brk_pc
+ .import _atexit
+
+ .include "plus4.inc"
+
+
+.bss
+_brk_a: .res 1
+_brk_x: .res 1
+_brk_y: .res 1
+_brk_sr: .res 1
+_brk_pc: .res 2
+
+oldvec: .res 2 ; Old vector
+
+
+.data
+uservec: jmp $FFFF ; Patched at runtime
+
+
+.code
+
+; Set the break vector
+.proc _set_brk
+
+ sta uservec+1
+ stx uservec+2 ; Set the user vector
+
+ lda oldvec
+ ora oldvec+1 ; Did we save the vector already?
+ bne L1 ; Jump if we installed the handler already
+
+ lda BRKVec
+ sta oldvec
+ lda BRKVec+1
+ sta oldvec+1 ; Save the old vector
+
+ lda #<_reset_brk
+ ldx #>_reset_brk
+ jsr _atexit ; Install an exit handler
+
+L1: lda #<brk_handler ; Set the break vector to our routine
+ sta BRKVec
+ lda #>brk_handler
+ sta BRKVec+1
+ rts
+
+.endproc
+
+
+; Reset the break vector
+.proc _reset_brk
+
+ lda oldvec
+ sta BRKVec
+ lda oldvec+1
+ sta BRKVec+1
+ rts
+
+.endproc
+
+
+
+; Break handler, called if a break occurs
+
+.proc brk_handler
+
+ pla
+ sta _brk_y
+ pla
+ sta _brk_x
+ pla
+ sta _brk_a
+ pla
+ and #$EF ; Clear break bit
+ sta _brk_sr
+ pla ; PC low
+ sec
+ sbc #2 ; Point to start of brk
+ sta _brk_pc
+ pla ; PC high
+ sbc #0
+ sta _brk_pc+1
+
+ jsr uservec ; Call the user's routine
+
+ lda _brk_pc+1
+ pha
+ lda _brk_pc
+ pha
+ lda _brk_sr
+ pha
+ ldx _brk_x
+ ldy _brk_y
+ lda _brk_a
+ rti ; Jump back...
+
+.endproc
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; char cgetc (void);
+;
+
+ .export _cgetc
+ .import cursor
+
+ .include "plus4.inc"
+
+
+_cgetc: lda KEY_COUNT ; Get number of characters
+ ora FKEY_COUNT ; Or with number of function key chars
+ bne L2 ; Jump if there are already chars waiting
+
+; Switch on the cursor if needed
+
+ ldy CURS_X
+ lda (CRAM_PTR),y ; Get current char
+ pha ; And save it
+ lda CHARCOLOR
+ sta (CRAM_PTR),y
+
+ lda cursor
+ beq L1 ; Jump if no cursor
+ tya
+ clc
+ adc SCREEN_PTR
+ sta TED_CURSLO
+ lda SCREEN_PTR+1
+ adc #$00
+ sbc #$0B ; + carry = $C00 (screen address)
+ sta TED_CURSHI
+
+L1: lda KEY_COUNT
+ ora FKEY_COUNT
+ beq L1
+ pla
+ sta (CRAM_PTR),y
+ lda #$ff
+ sta TED_CURSLO ; Cursor off
+ sta TED_CURSHI
+
+L2: jsr KBDREAD ; Read char and return in A
+ ldx #0
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; void clrscr (void);
+;
+
+ .export _clrscr
+
+ .include "plus4.inc"
+
+_clrscr = CLRSCR
+
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; unsigned char __fastcall__ textcolor (unsigned char color);
+; unsigned char __fastcall__ bgcolor (unsigned char color);
+; unsigned char __fastcall__ bordercolor (unsigned char color);
+;
+
+ .export _textcolor, _bgcolor, _bordercolor
+
+ .include "plus4.inc"
+
+_textcolor:
+ ldx CHARCOLOR ; get old value
+ sta CHARCOLOR ; set new value
+ txa
+ rts
+
+
+_bgcolor:
+ ldx TED_BGCOLOR ; get old value
+ sta TED_BGCOLOR ; set new value
+ txa
+ rts
+
+
+_bordercolor:
+ ldx TED_BORDERCOLOR ; get old value
+ sta TED_BORDERCOLOR ; set new value
+ txa
+ rts
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; Low level stuff for screen output/console input
+;
+
+ .export initconio, doneconio
+ .exportzp CURS_X, CURS_Y
+ .import xsize, ysize
+
+ .include "plus4.inc"
+ .include "../cbm/cbm.inc"
+
+.code
+
+initconio:
+ jsr SCREEN
+ stx xsize
+ sty ysize
+ ldy #15
+L1: lda fnkeys,y
+ sta FKEY_SPACE,y
+ dey
+ bpl L1
+ rts
+
+
+doneconio:
+ ldx #$39 ; Copy the original function keys
+L2: lda FKEY_ORIG,x
+ sta FKEY_SPACE,x
+ dex
+ bpl L2
+ rts
+
+; Function key table, readonly
+
+.rodata
+fnkeys: .byte $01, $01, $01, $01, $01, $01, $01, $01
+ .byte 133, 137, 134, 138, 135, 139, 136, 140
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; void cputcxy (unsigned char x, unsigned char y, char c);
+; void cputc (char c);
+;
+
+ .export _cputcxy, _cputc, cputdirect, putchar
+ .export advance, newline, plot
+ .import popa, _gotoxy
+ .import xsize, revers
+
+ .include "plus4.inc"
+ .include "../cbm/cbm.inc"
+
+_cputcxy:
+ pha ; Save C
+ jsr popa ; Get Y
+ jsr _gotoxy ; Set cursor, drop x
+ pla ; Restore C
+
+; Plot a character - also used as internal function
+
+_cputc: cmp #$0D ; CR?
+ bne L1
+ lda #0
+ sta CURS_X
+ beq plot ; Recalculate pointers
+
+L1: cmp #$0A ; LF?
+ bne L2
+ ldy CURS_Y
+ iny
+ bne newline ; Recalculate pointers
+
+; Printable char of some sort
+
+L2: cmp #' '
+ bcc cputdirect ; Other control char
+ tay
+ bmi L10
+ cmp #$60
+ bcc L3
+ and #$DF
+ bne cputdirect ; Branch always
+L3: and #$3F
+
+cputdirect:
+ jsr putchar ; Write the character to the screen
+
+; Advance cursor position
+
+advance:
+ iny
+ cpy xsize
+ bne L9
+ ldy #0 ; new line
+newline:
+ clc
+ lda xsize
+ adc SCREEN_PTR
+ sta SCREEN_PTR
+ bcc L4
+ inc SCREEN_PTR+1
+L4: clc
+ lda xsize
+ adc CRAM_PTR
+ sta CRAM_PTR
+ bcc L5
+ inc CRAM_PTR+1
+L5: inc CURS_Y
+L9: sty CURS_X
+ rts
+
+; Handle character if high bit set
+
+L10: and #$7F
+ cmp #$7E ; PI?
+ bne L11
+ lda #$5E ; Load screen code for PI
+ bne cputdirect
+L11: ora #$40
+ bne cputdirect
+
+
+
+; Set cursor position, calculate RAM pointers
+
+plot: ldy CURS_X
+ ldx CURS_Y
+ clc
+ jmp PLOT ; Set the new cursor
+
+
+
+; Write one character to the screen without doing anything else, return X
+; position in Y
+
+putchar:
+ ora revers ; Set revers bit
+ ldy CURS_X
+ sta (SCREEN_PTR),y ; Set char
+ lda CHARCOLOR
+ sta (CRAM_PTR),y ; Set color
+ rts
--- /dev/null
+;
+; Startup code for cc65 (Plus/4 version)
+;
+; This must be the *first* file on the linker command line
+;
+
+ .export _exit
+ .import __hinit, push0, doatexit, _main
+ .import initconio, doneconio, zerobss
+
+ .include "plus4.inc"
+ .include "../cbm/cbm.inc"
+
+; ------------------------------------------------------------------------
+; Define and export the ZP variables for the C64 runtime
+
+ .exportzp sp, sreg, regsave
+ .exportzp ptr1, ptr2, ptr3, ptr4
+ .exportzp tmp1, tmp2, tmp3, tmp4
+ .exportzp regbank, zpspace
+
+sp = $02 ; stack pointer
+sreg = $04 ; secondary register/high 16 bit for longs
+regsave = $06 ; slot to save/restore (E)AX into
+ptr1 = $0A ;
+ptr2 = $0C
+ptr3 = $0E
+ptr4 = $10
+tmp1 = $12
+tmp2 = $13
+tmp3 = $14
+tmp4 = $15
+regbank = $16 ; 6 byte register bank
+zpspace = $1A ; Zero page space allocated
+
+; ------------------------------------------------------------------------
+; BASIC header with a SYS call
+
+ .org $0FFF
+ .word Head ; Load address
+Head: .word @Next
+ .word 1000 ; Line number
+ .byte $9E,"4109" ; SYS 4109
+ .byte $00 ; End of BASIC line
+@Next: .word 0 ; BASIC end marker
+ .reloc
+
+; ------------------------------------------------------------------------
+; Actual code
+
+ ldy #zpspace-1
+L1: lda sp,y
+ sta zpsave,y ; save the zero page locations we need
+ dey
+ bpl L1
+
+; Close open files
+
+ jsr CLRCH
+
+; Switch to second charset
+
+ lda #14
+ jsr BSOUT
+
+; Clear the BSS data
+
+ jsr zerobss
+
+; Save system stuff and setup the stack
+
+ tsx
+ stx spsave ; save system stk ptr
+
+ sec
+ jsr MEMTOP ; Get top memory
+ cpy #$80 ; We can only use the low 32K :-(
+ bcc MemOk
+ ldy #$80
+ ldx #$00
+MemOk: stx sp
+ sty sp+1 ; set argument stack ptr
+
+; Initialize the heap
+
+ jsr __hinit
+
+; Initialize conio stuff
+
+ jsr initconio
+
+; Pass an empty command line
+
+ jsr push0 ; argc
+ jsr push0 ; argv
+
+ ldy #4 ; Argument size
+ jsr _main ; call the users code
+
+; fall thru to exit...
+
+_exit: jsr doatexit ; call exit functions
+ ldx spsave
+ txs
+
+; Reset the conio stuff
+
+ jsr doneconio
+
+; Copy back the zero page stuff
+
+ ldy #zpspace-1
+L2: lda zpsave,y
+ sta sp,y
+ dey
+ bpl L2
+
+; Reset changed vectors
+
+ jmp RESTOR
+
+
+.data
+zpsave: .res zpspace
+
+.bss
+spsave: .res 1
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; int kbhit (void);
+;
+
+ .export _kbhit
+ .import return0, return1
+
+ .include "plus4.inc"
+
+_kbhit:
+ lda KEY_COUNT ; Get number of characters
+ ora FKEY_COUNT ; Or with number of chars from function keys
+ bne L1
+ jmp return0
+L1: jmp return1
+
+
+
+
--- /dev/null
+;
+; Plus/4 generic definitions.
+;
+
+
+; ---------------------------------------------------------------------------
+; Zero page, Commodore stuff
+
+ST = $90 ; IEC status byte
+
+FNAM_LEN = $AB ; Length of filename
+SECADR = $AD ; Secondary address
+DEVNUM = $AE ; Device number
+KEY_COUNT = $EF ; Number of keys in input buffer
+CURS_X = $CA ; Cursor column
+CURS_Y = $CD ; Cursor row
+SCREEN_PTR = $C8 ; Pointer to current char in text screen
+CRAM_PTR = $EA ; Pointer to current char in color RAM
+
+CHARCOLOR = $53B
+FKEY_COUNT = $55D ; Characters for function key
+FKEY_SPACE = $55F ; Function key definitions
+FKEY_ORIG = $F3D2 ; Original definitions
+
+; ---------------------------------------------------------------------------
+; Kernal routines
+
+; Direct entries
+CLRSCR = $D88B
+KBDREAD = $D8C1
+
+; ---------------------------------------------------------------------------
+; Vector and other locations
+
+IRQVec = $0314
+BRKVec = $0316
+NMIVec = $0318
+
+; ---------------------------------------------------------------------------
+; I/O
+
+TED_T1LO = $FF00
+TED_T1HI = $FF01
+TED_T2LO = $FF02
+TED_T2HI = $FF03
+TED_T3LO = $FF04
+TED_T4HI = $FF05
+TED_KBD = $FF08
+TED_CURSHI = $FF0C
+TED_CURSLO = $FF0D
+TED_V1FRQLO = $FF0E
+TED_V2FRQLO = $FF0F
+TED_V2FRQHI = $FF10
+TED_BGCOLOR = $FF15
+TED_COLOR1 = $FF16
+TED_COLOR2 = $FF17
+TED_COLOR3 = $FF18
+TED_BORDERCOLOR = $FF19
+TED_VLINEHI = $FF1C
+TED_VLINELO = $FF1D
+TED_HPOS = $FF1E
+TED_ROMSEL = $FF3E
+TED_RAMSEL = $FF3F
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 23.09.1998
+;
+; unsigned readjoy (unsigned char joy);
+;
+
+ .export _readjoy
+
+ .include "plus4.inc"
+
+
+.proc _readjoy
+
+ ldy #$FA ; Load index for joystick #1
+ tax ; Test joystick number
+ beq L1
+ ldy #$FB ; Load index for joystick #2
+L1: sei
+ sty TED_KBD
+ lda TED_KBD
+ cli
+ ldx #$00 ; Clear high byte
+ and #$1F
+ eor #$1F
+ rts
+
+.endproc
+
+
--- /dev/null
+#
+# makefile for CC65 runtime library
+#
+
+.SUFFIXES: .o .s .c
+
+.c.s:
+ @echo $<
+ @$(CC) $(CFLAGS) $<
+
+.s.o:
+ @echo $<
+ @$(AS) -g -o $@ $(AFLAGS) $<
+
+OBJS = runtime.o mul.o div.o push.o inc.o dec.o shl.o shr.o add.o\
+ sub.o rsub.o or.o xor.o and.o neg.o bneg.o compl.o icmp.o\
+ call.o swap.o switch.o gt.o ugt.o ge.o makebool.o ldau0sp.o\
+ uge.o lt.o ult.o le.o ule.o eq.o ne.o test.o subeqsp.o\
+ udiv.o umod.o mod.o shelp.o aslax1.o asrax1.o shrax1.o\
+ aslax2.o asrax2.o shrax2.o aslax3.o asrax3.o shrax3.o\
+ enter.o leave.o leaysp.o popsreg.o ldai.o ldaxi.o ldauisp.o\
+ ldaui.o pushw.o pushb.o staxsp.o ldaxsp.o addeqsp.o\
+ ldasp.o ldausp.o bpushbsp.o pushwsp.o pushbsp.o
+
+LOBJS = lruntime.o lconvert.o ladd.o lsub.o lrsub.o leq.o lne.o\
+ lneg.o lbneg.o lcompl.o lpush.o land.o lor.o lxor.o ldeaxi.o\
+ ltest.o llt.o lle.o lge.o lgt.o lsave.o asleax1.o laddeqsp.o\
+ asreax1.o shreax1.o asleax2.o asreax2.o shreax2.o lsubeqsp.o\
+ asleax3.o asreax3.o shreax3.o lmul.o lshelp.o ludiv.o lumod.o\
+ ldiv.o lmod.o lswitch.o steaxsp.o lshr.o lshl.o lcmp.o lugt.o\
+ luge.o lult.o lule.o linc.o ldec.o lswap.o lpop.o ldeax.o\
+ lsubeq.o laddeq.o
+
+all: $(OBJS) $(LOBJS)
+
+clean:
+ @rm -f *~
+ @rm -f $(COBJS:.o=.s)
+ @rm -f $(OBJS)
+ @rm -f $(LOBJS)
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 05.08.1998
+;
+; CC65 runtime: add ints
+;
+
+; Make this as fast as possible, even if it needs more space since it's
+; called a lot!
+
+ .export tosadda0, tosaddax
+ .importzp sp, tmp1
+
+tosadda0:
+ ldx #0
+tosaddax:
+ ldy #0
+ clc
+ adc (sp),y ; lo byte
+ sta tmp1 ; save it
+ txa
+ iny
+ adc (sp),y ; hi byte
+ tax
+ clc
+ lda sp
+ adc #2
+ sta sp
+ bcc L1
+ inc sp+1
+L1: txa ; Test high byte
+ bmi L2
+ bne L3
+ lda tmp1 ; Get low byte
+ rts
+
+; Value is negative
+
+L2: lda tmp1 ; Get low byte
+ ldy #$FF ; Force negative
+ rts
+
+; Value is positive != 0
+
+L3: lda tmp1 ; Get low byte
+ ldy #1
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 08.10.1998
+;
+; CC65 runtime: += operator for ints on the stack
+;
+
+ .export addeq0sp, addeqysp
+ .importzp sp
+
+addeq0sp:
+ ldy #0
+addeqysp:
+ clc
+ adc (sp),y
+ sta (sp),y
+ pha
+ iny
+ txa
+ adc (sp),y
+ sta (sp),y
+ tax
+ pla
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 05.08.1998
+;
+; CC65 runtime: and on ints
+;
+
+ .export tosanda0, tosandax
+ .import addysp1
+ .importzp sp, ptr4
+
+tosanda0:
+ ldx #$00
+tosandax:
+ ldy #0
+ and (sp),y
+ sta ptr4
+ iny
+ txa
+ and (sp),y
+ tax
+ lda ptr4
+ jmp addysp1 ; drop TOS, set condition codes
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Scale the primary register
+;
+
+ .export aslax1, shlax1
+ .importzp tmp1
+
+aslax1:
+shlax1: stx tmp1
+ asl A
+ rol tmp1
+ ldx tmp1
+ rts
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Scale the primary register by 4
+;
+
+ .export aslax2, shlax2
+ .importzp tmp1
+
+aslax2:
+shlax2: stx tmp1
+ asl a
+ rol tmp1
+ asl a
+ rol tmp1
+ ldx tmp1
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Scale the primary register by 8
+;
+
+ .export aslax3, shlax3
+ .importzp tmp1
+
+aslax3:
+shlax3: stx tmp1
+ asl a
+ rol tmp1
+ asl a
+ rol tmp1
+ asl a
+ rol tmp1
+ ldx tmp1
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Scale the 32 bit primary register by 2
+;
+
+ .export asleax1, shleax1
+ .importzp sreg, tmp1
+
+asleax1:
+shleax1:
+ stx tmp1
+ asl a
+ rol tmp1
+ rol sreg
+ rol sreg+1
+ ldx tmp1
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Scale the 32 bit primary register by 4
+;
+
+ .export asleax2, shleax2
+ .importzp sreg, tmp1
+
+asleax2:
+shleax2:
+ stx tmp1
+ asl a
+ rol tmp1
+ rol sreg
+ rol sreg+1
+ asl a
+ rol tmp1
+ rol sreg
+ rol sreg+1
+ ldx tmp1
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Scale the 32 bit primary register by 8
+;
+
+ .export asleax3, shleax3
+ .importzp sreg, tmp1
+
+asleax3:
+shleax3:
+ stx tmp1
+ asl a
+ rol tmp1
+ rol sreg
+ rol sreg+1
+ asl a
+ rol tmp1
+ rol sreg
+ rol sreg+1
+ asl a
+ rol tmp1
+ rol sreg
+ rol sreg+1
+ ldx tmp1
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Scale the primary register
+;
+
+ .export asrax1
+ .importzp tmp1
+
+asrax1: stx tmp1
+ cpx #$80 ; Put bit 7 into carry
+ ror tmp1
+ ror a
+ ldx tmp1
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Scale the primary register by 4
+;
+
+ .export asrax2
+ .importzp tmp1
+
+asrax2: stx tmp1
+ cpx #$80 ; Put bit 7 into carry
+ ror tmp1
+ ror a
+ cpx #$80
+ ror tmp1
+ ror a
+ ldx tmp1
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Scale the primary register by 8
+;
+
+ .export asrax3
+ .importzp tmp1
+
+asrax3: stx tmp1
+ cpx #$80 ; Put bit 7 into carry
+ ror tmp1
+ ror a
+ ldx tmp1
+ cpx #$80
+ ror tmp1
+ ror a
+ ldx tmp1
+ cpx #$80
+ ror tmp1
+ ror a
+ ldx tmp1
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Scale the primary register
+;
+
+ .export asreax1
+ .importzp sreg, tmp1
+
+asreax1:
+ stx tmp1
+ ldx sreg+1
+ cpx #$80 ; Get bit 7 into carry
+ ror sreg+1
+ ror sreg
+ ror tmp1
+ ror a
+ ldx tmp1
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Scale the 32 bit primary register by 4
+;
+
+ .export asreax2
+ .importzp sreg, tmp1
+
+asreax2:
+ stx tmp1
+ ldx sreg+1
+ cpx #$80 ; Get bit 7 into carry
+ ror sreg+1
+ ror sreg
+ ror tmp1
+ ror a
+ ldx sreg+1
+ cpx #$80 ; Get bit 7 into carry
+ ror sreg+1
+ ror sreg
+ ror tmp1
+ ror a
+ ldx tmp1
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Scale the 32 bit primary register by 8
+;
+
+ .export asreax3
+ .importzp sreg, tmp1
+
+asreax3:
+ stx tmp1
+ ldx sreg+1
+ cpx #$80 ; Get bit 7 into carry
+ ror sreg+1
+ ror sreg
+ ror tmp1
+ ror a
+ ldx sreg+1
+ cpx #$80 ; Get bit 7 into carry
+ ror sreg+1
+ ror sreg
+ ror tmp1
+ ror a
+ ldx sreg+1
+ cpx #$80 ; Get bit 7 into carry
+ ror sreg+1
+ ror sreg
+ ror tmp1
+ ror a
+ ldx tmp1
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 05.08.1998
+;
+; CC65 runtime: boolean negation
+;
+
+ .export bnega, bnegax
+ .import return0, return1
+
+bnegax: cpx #0
+ bne L0
+bnega: cmp #0
+ bne L0
+L1: ldx #0
+ lda #1
+ rts
+
+L0: ldx #0
+ txa
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 31.08.1998
+;
+; CC65 runtime: Load a from stack slot and push as byte
+;
+
+ .export bpushbsp, bpushbysp
+ .import pusha
+ .importzp sp
+
+bpushbsp:
+ ldy #0
+bpushbysp:
+ lda (sp),y
+ jmp pusha
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: call function via pointer in ax
+;
+
+ .export callax
+ .importzp ptr1
+
+callax: sta ptr1
+ stx ptr1+1
+ jmp (ptr1) ; jump there
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: integer complement
+;
+
+ .export complax
+
+complax:
+ eor #$FF ; Not A
+ pha
+ txa
+ eor #$FF ; Not X
+ tax
+ pla
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 29.12.1999
+;
+; CC65 runtime: Decrement ax by constant or value in Y
+;
+
+ .export decaxy
+ .export decax2, decax1
+ .importzp tmp1
+
+
+decaxy: sty tmp1
+ sec
+ sbc tmp1
+ bcs *+3
+ dex
+ rts
+
+decax2: sec
+ sbc #2
+ bcs *+3
+ dex
+ rts
+
+decax1: sec
+ sbc #1
+ bcs *+3
+ dex
+ rts
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 07.08.1998
+;
+; CC65 runtime: division for signed ints
+;
+
+; When negating values, we will ignore the possibility here, that one of the
+; values if $8000, in which case the negate will fail.
+
+ .export tosdiva0, tosdivax
+ .import popsargs, udiv16, adjsres
+ .importzp sreg
+
+tosdiva0:
+ ldx #0
+tosdivax:
+ jsr popsargs ; Get arguments from stack, adjust sign
+ jsr udiv16 ; Do the division
+ lda sreg ; Result is in sreg, remainder in ptr1
+ ldx sreg+1
+ jmp adjsres ; Adjust the sign of the result if needed
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: function prologue
+;
+
+ .export enter
+ .importzp sp
+
+enter: tya ; get arg size
+ ldy sp
+ bne L1
+ dec sp+1
+L1: dec sp
+ ldy #0
+ sta (sp),y ; Store the arg count
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Compare == for ints
+;
+
+ .export toseq00, toseqa0, toseqax
+ .import tosicmp, booleq
+ .importzp sp, tmp1
+
+toseq00:
+ lda #$00
+toseqa0:
+ ldx #$00
+toseqax:
+ jsr tosicmp ; Set flags
+ jmp booleq ; Convert to boolean
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Compare >= for signed ints
+;
+
+ .export tosge00, tosgea0, tosgeax
+ .import tosicmp, boolge
+
+
+tosge00:
+ lda #$00
+tosgea0:
+ ldx #$00
+tosgeax:
+ jsr tosicmp ; Set flags
+ jmp boolge ; Convert to boolean
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Compare > for signed ints
+;
+
+ .export tosgt00, tosgta0, tosgtax
+ .import tosicmp, boolgt
+
+
+tosgt00:
+ lda #$00
+tosgta0:
+ ldx #$00
+tosgtax:
+ jsr tosicmp ; Set the flags
+ jmp boolgt ; Convert to boolean
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 10.12.1998
+;
+; Integer compare function - used by the compare operators
+;
+
+ .export tosicmp
+ .import incsp2
+ .importzp sp, sreg
+
+
+tosicmp:
+ sta sreg
+ stx sreg+1 ; Save ax
+
+ ldy #$01
+ lda (sp),y ; Get high byte
+ tax
+ dey
+ lda (sp),y ; Get low byte
+
+; Inline incsp2 for better performance
+
+ inc sp ; 5
+ bne @L1 ; 3
+ inc sp+1 ; (5)
+@L1: inc sp ; 5
+ bne @L2 ; 3
+ inc sp+1 ; (5)
+
+; Do the compare.
+
+@L2: cpx sreg+1 ; Compare high byte
+ bne @L3
+ cmp sreg ; Compare low byte
+ beq @L3
+ bcs @L4
+ lda #$FF ; Set the N flag
+@L3: rts
+
+@L4: lda #$01 ; Clear the N flag
+ rts
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 05.08.1998
+;
+; CC65 runtime: Increment ax by constant or value in Y
+;
+
+ .export incaxy
+ .export incax8, incax7, incax6, incax5
+ .export incax4, incax3, incax2, incax1
+ .importzp tmp1
+
+
+incax8: ldy #8
+ bne incaxy
+
+incax7: ldy #7
+ bne incaxy
+
+incax6: ldy #6
+ bne incaxy
+
+incax5: ldy #5
+ bne incaxy
+
+incax4: ldy #4
+ bne incaxy
+
+incax3: ldy #3
+; bne incaxy
+incaxy: sty tmp1
+ clc
+ adc tmp1
+ bcc *+3
+ inx
+ rts
+
+incax2: clc
+ adc #2
+ bcc *+3
+ inx
+ rts
+
+incax1: clc
+ adc #1
+ bcc *+3
+ inx
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 05.08.1998
+;
+; CC65 runtime: long add
+;
+
+ .export tosaddeax
+ .import addysp1
+ .importzp sp, sreg, tmp1
+
+; EAX = TOS + EAX
+
+tosaddeax:
+ ldy #0
+ clc
+ adc (sp),y ; byte 0
+ sta tmp1 ; use as temp storage
+ iny
+ txa
+ adc (sp),y ; byte 1
+ tax
+ iny
+ lda sreg
+ adc (sp),y ; byte 2
+ sta sreg
+ iny
+ lda sreg+1
+ adc (sp),y ; byte 3
+ sta sreg+1
+ lda tmp1 ; load byte 0
+ jmp addysp1 ; drop TOS
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 07.04.2000
+;
+; CC65 runtime: += operator
+;
+; On entry, the low byte of the address of the variable to increment is
+; in ptr1, the high byte is in Y, and the increment is in eax.
+;
+
+ .export laddeq1, laddeqa, laddeq
+ .importzp sreg, ptr1, tmp1
+
+
+laddeq1:
+ lda #$01
+
+laddeqa:
+ ldx #$00
+ stx sreg
+ stx sreg+1
+
+laddeq: sty ptr1+1 ; Store high byte of address
+ ldy #$00 ; Address low byte
+ clc
+
+ adc (ptr1),y
+ sta (ptr1),y
+ pha ; Save byte 0 of result for later
+
+ iny ; Address byte 1
+ txa
+ adc (ptr1),y ; Load byte 1
+ sta (ptr1),y
+ tax
+
+ iny ; Address byte 2
+ lda sreg
+ adc (ptr1),y
+ sta (ptr1),y
+ sta sreg
+
+ iny ; Address byte 3
+ lda sreg+1
+ adc (ptr1),y
+ sta (ptr1),y
+ sta sreg+1
+
+ pla ; Retrieve byte 0 of result
+
+ rts ; Done
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 08.10.1998
+;
+; CC65 runtime: += operator for longs on the stack
+;
+
+ .export laddeq0sp, laddeqysp
+ .importzp sp, sreg
+
+laddeq0sp:
+ ldy #0
+laddeqysp:
+ clc
+ adc (sp),y
+ sta (sp),y
+ pha
+ iny
+ txa
+ adc (sp),y
+ sta (sp),y
+ tax
+ iny
+ lda sreg
+ adc (sp),y
+ sta (sp),y
+ sta sreg
+ iny
+ lda sreg+1
+ adc (sp),y
+ sta (sp),y
+ sta sreg+1
+ pla
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: and on longs
+;
+
+ .export tosandeax
+ .import addysp1
+ .importzp sp, sreg, tmp1
+
+tosandeax:
+ ldy #0
+ and (sp),y ; byte 0
+ sta tmp1
+ iny
+ txa
+ and (sp),y ; byte 1
+ tax
+ iny
+ lda sreg
+ and (sp),y ; byte 2
+ sta sreg
+ iny
+ lda sreg+1
+ and (sp),y ; byte 3
+ sta sreg+1
+
+ lda tmp1
+ jmp addysp1
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: boolean negation for longs
+;
+
+ .export bnegeax
+ .import return0, return1
+ .importzp sreg
+
+bnegeax:
+ cmp #0
+ bne L1
+ cpx #0
+ bne L1
+ lda sreg
+ bne L1
+ lda sreg+1
+ bne L1
+ jmp return1
+L1: jmp return0
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 10.12.1998
+;
+; Long int compare function - used by the compare operators
+;
+
+ .export lcmp
+ .import incsp4
+ .importzp sp, sreg, ptr1
+
+
+lcmp: sta ptr1
+ stx ptr1+1 ; EAX now in sreg:ptr1
+
+ ldy #$03
+ lda (sp),y
+ cmp sreg+1
+ bne L4
+
+ dey
+ lda (sp),y
+ cmp sreg
+ bne L1
+
+ dey
+ lda (sp),y
+ cmp ptr1+1
+ bne L1
+
+ dey
+ lda (sp),y
+ cmp ptr1
+
+L1: php ; Save flags
+ jsr incsp4 ; Drop TOS
+ plp ; Restore the flags
+ beq L2
+ bcs L3
+ lda #$FF ; Set the N flag
+L2: rts
+
+L3: lda #$01 ; Clear the N flag
+ rts
+
+L4: php ; Save flags
+ jsr incsp4 ; Drop TOS
+ plp ; Restore flags
+ rts
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: long complement
+;
+
+ .export compleax
+ .importzp sreg
+
+; eax = ~eax
+
+compleax:
+ eor #$FF
+ pha
+ txa
+ eor #$FF
+ tax
+ lda sreg
+ eor #$FF
+ sta sreg
+ lda sreg+1
+ eor #$FF
+ sta sreg+1
+ pla
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 05.08.1998
+;
+; CC65 runtime: long conversion routines
+;
+
+;
+; Convert TOS from long to int by cutting of the high 16bit
+;
+ .export tosint, tosulong, toslong, axulong, axlong
+ .import incsp2, decsp2
+ .importzp sp, sreg
+
+tosint: pha
+ ldy #0
+ lda (sp),y ; sp+1
+ ldy #2
+ sta (sp),y
+ ldy #1
+ lda (sp),y
+ ldy #3
+ sta (sp),y
+ pla
+ jmp incsp2 ; Drop 16 bit
+
+;
+; Convert TOS from int to long
+;
+
+tosulong:
+ pha
+ jsr decsp2 ; Make room
+ ldy #2
+ lda (sp),y
+ ldy #0
+ sta (sp),y
+ ldy #3
+ lda (sp),y
+ ldy #1
+ sta (sp),y
+ lda #0 ; Zero extend
+toslong2:
+ iny
+ sta (sp),y
+ iny
+ sta (sp),y
+ pla
+ rts
+
+toslong:
+ pha
+ jsr decsp2 ; Make room
+ ldy #2
+ lda (sp),y
+ ldy #0
+ sta (sp),y
+ ldy #3
+ lda (sp),y
+ bmi toslong1
+ ldy #1
+ sta (sp),y
+ lda #$00 ; Positive, high word is zero
+ bne toslong2
+toslong1:
+ ldy #1
+ sta (sp),y
+ lda #$FF
+ bne toslong2
+
+;
+; Convert AX from int to long in EAX
+;
+
+axulong:
+ ldy #0
+ sty sreg
+ sty sreg+1
+ rts
+
+axlong: cpx #$80 ; Positive?
+ bcc axulong ; Yes, handle like unsigned type
+ ldy #$ff
+ sty sreg
+ sty sreg+1
+ rts
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 31.08.1998
+;
+; CC65 runtime: Load a indirect from address in ax
+;
+
+ .export ldai, ldaidx
+ .importzp ptr1
+
+ldai: ldy #$00
+ldaidx: sta ptr1
+ stx ptr1+1
+ ldx #$00
+ lda (ptr1),y
+ bpl L9
+ dex
+L9: rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 31.08.1998
+;
+; CC65 runtime: Load a from offset in stack
+;
+
+ .export ldasp, ldaysp
+ .importzp sp
+
+ldasp: ldy #0
+ldaysp: ldx #0
+ lda (sp),y
+ bpl L9 ; Jump if positive
+ dex
+L9: rts
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 11.04.1999
+;
+; CC65 runtime: Load an unsigned char indirect from pointer somewhere in stack
+;
+
+ .export ldau00sp, ldau0ysp
+ .importzp sp, ptr1
+
+ldau00sp:
+ ldy #1
+ldau0ysp:
+ lda (sp),y
+ sta ptr1+1
+ dey
+ lda (sp),y
+ sta ptr1
+ ldx #0
+ lda (ptr1,x)
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 31.08.1998
+;
+; CC65 runtime: Load a unsigned indirect from address in ax
+;
+
+ .export ldaui, ldauidx
+ .importzp ptr1
+
+ldaui:
+ ldy #0
+ldauidx:
+ sta ptr1
+ stx ptr1+1
+ ldx #0
+ lda (ptr1),y
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 11.04.1999
+;
+; CC65 runtime: Load an unsigned char indirect from pointer somewhere in stack
+;
+
+ .export ldaui0sp, ldauiysp
+ .importzp sp, ptr1
+
+ldaui0sp:
+ ldy #1
+ldauiysp:
+ lda (sp),y
+ sta ptr1+1
+ dey
+ lda (sp),y
+ sta ptr1
+ txa
+ tay
+ ldx #0
+ lda (ptr1),y
+ rts
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 31.08.1998
+;
+; CC65 runtime: Load a unsigned from offset in stack
+;
+
+ .export ldausp, ldauysp
+ .importzp sp
+
+ldausp: ldy #0
+ldauysp:
+ ldx #0
+ lda (sp),y
+ rts
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 31.08.1998
+;
+; CC65 runtime: Load ax indirect from address in ax
+;
+
+ .export ldaxi, ldaxidx
+ .importzp ptr1
+
+ldaxi: ldy #1
+ldaxidx:
+ sta ptr1
+ stx ptr1+1
+ lda (ptr1),y
+ tax
+ dey
+ lda (ptr1),y
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 31.08.1998
+;
+; CC65 runtime: Load ax from offset in stack
+;
+
+ .export ldax0sp, ldaxysp
+ .importzp sp
+
+; Beware: The optimizer knows about the value in Y after return!
+
+ldax0sp:
+ ldy #1
+ldaxysp:
+ lda (sp),y ; get high byte
+ tax ; and save it
+ bne L1 ; Try to generate FAST code
+ dey ; point to lo byte
+ lda (sp),y ; load low byte
+ rts
+
+L1: php ; Save Z flag
+ dey
+ lda (sp),y
+ plp
+ rts
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 29.12.1999
+;
+; CC65 runtime: Load eax from immidiate value following the call
+;
+
+ .export ldeax
+ .importzp sreg, ptr4
+
+
+ldeax: pla ; Low byte of return address
+ sta ptr4
+ pla ; high byte of return address
+ sta ptr4+1
+ ldy #4 ; high byte of value
+ lda (ptr4),y
+ sta sreg+1
+ dey
+ lda (ptr4),y
+ sta sreg
+ dey
+ lda (ptr4),y
+ tax
+ dey
+ lda (ptr4),y
+ tay ; Save low byte
+ clc
+ lda #4
+ adc ptr4
+ sta ptr4
+ lda ptr4+1
+ adc #$00
+ pha ; High byte of new return address
+ lda ptr4
+ pha ; Low byte of new return address
+ tya ; Low byte of fetched value
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 31.08.1998
+;
+; CC65 runtime: Load eax indirect from address in ax
+;
+
+ .export ldeaxidx, ldeaxi
+ .importzp sreg, ptr1
+
+ldeaxi: ldy #3
+ldeaxidx:
+ sta ptr1
+ stx ptr1+1
+ lda (ptr1),y
+ dey
+ sta sreg+1
+ lda (ptr1),y
+ dey
+ sta sreg
+ lda (ptr1),y
+ dey
+ tax
+ lda (ptr1),y
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 29.12.1999
+;
+; CC65 runtime: Decrement eax by value in Y
+;
+
+ .export deceaxy
+ .importzp ptr4, sreg
+
+deceaxy:
+ sty ptr4
+ sec
+ sbc ptr4
+ sta ptr4
+ txa
+ sbc #0
+ tax
+ lda sreg
+ sbc #0
+ sta sreg
+ lda sreg+1
+ sbc #0
+ sta sreg+1
+ lda ptr4
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 17.08.1998
+;
+; CC65 runtime: division for signed long ints
+;
+
+; When negating values, we will ignore the possibility here, that one of the
+; values if $80000000, in which case the negate will fail.
+
+ .export tosdiveax
+ .import poplsargs, udiv32, adjlsres
+ .importzp ptr1
+
+tosdiveax:
+ jsr poplsargs ; Get arguments from stack, adjust sign
+ jsr udiv32 ; Do the division
+ lda ptr1 ; Result is in (ptr1:sreg)
+ ldx ptr1+1
+ jmp adjlsres ; Adjust the sign of the result if needed
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Compare <= for signed ints
+;
+
+ .export tosle00, toslea0, tosleax
+ .import tosicmp, boolle
+
+tosle00:
+ lda #$00
+toslea0:
+ ldx #$00
+tosleax:
+ jsr tosicmp ; Set flags
+ jmp boolle ; Convert to boolean
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: function epilogue
+;
+
+; exit a function. pop stack and rts. The function comes in different
+; flavours that provide default values for the return val, or drop a local
+; stack frame with size in y.
+
+ .export leave00, leave0, leavey00, leavey0, leavey
+ .export leave
+ .import addysp
+ .importzp sp
+
+leave00:
+ lda #0
+leave0: ldx #0
+ beq leave
+
+leavey00:
+ lda #0 ; "return 0"
+leavey0:
+ ldx #0 ; return < 256
+leavey:
+ jsr addysp ; drop stack frame
+leave: pha ; save A a sec
+ ldy #0
+ lda (sp),y ; that's the pushed arg size
+ sec ; Count the byte, the count's stored in
+ adc sp
+ sta sp
+ bcc L1
+ inc sp+1
+L1: pla ; Get return value back
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 21.08.1998
+;
+; CC65 runtime: Load effective address with offset in Y relative to SP
+;
+
+ .export lea0sp, leaysp, plea0sp, pleaysp
+ .import pushax
+ .importzp sp
+
+lea0sp: ldy #0 ; Load offset zero
+leaysp: tya
+ ldx sp+1 ; Get high byte
+ clc
+ adc sp
+ bcc L8
+ inx
+L8: rts
+
+
+plea0sp:
+ ldy #0
+pleaysp:
+ tya
+ ldx sp+1 ; Get high byte
+ clc
+ adc sp
+ bcc L9
+ inx
+L9: jmp pushax
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 05.08.1998
+;
+; CC65 runtime: long equal
+;
+
+ .export toseqeax
+ .import lcmp, booleq
+
+toseqeax:
+ jsr lcmp ; Set flags
+ jmp booleq ; Convert to boolean
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 07.08.1998
+;
+; CC65 runtime: Compare >= for long ints
+;
+
+ .export tosgeeax
+ .import lcmp, boolge
+
+tosgeeax:
+ jsr lcmp ; Set the flags
+ jmp boolge ; Convert to boolean
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 07.08.1998
+;
+; CC65 runtime: Compare > for long ints
+;
+
+ .export tosgteax
+ .import lcmp, boolgt
+
+tosgteax:
+ jsr lcmp ; Set the flags
+ jmp boolgt ; Convert to boolean
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 29.12.1999
+;
+; CC65 runtime: Increment eax by value in Y
+;
+
+ .export inceaxy
+ .importzp ptr4, sreg
+
+inceaxy:
+ sty ptr4
+ clc
+ adc ptr4
+ bcc inceax9
+ inx
+ bne inceax9
+ inc sreg
+ bne inceax9
+ inc sreg+1
+inceax9:
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 07.08.1998
+;
+; CC65 runtime: Compare <= for long ints
+;
+
+ .export tosleeax
+ .import lcmp, boolle
+
+tosleeax:
+ jsr lcmp ; Set the flags
+ jmp boolle ; Convert to boolean
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 07.08.1998
+;
+; CC65 runtime: Compare < for long ints
+;
+
+ .export toslteax
+ .import lcmp, boollt
+
+toslteax:
+ jsr lcmp ; Set the flags
+ jmp boollt ; Convert to boolean
--- /dev/null
+;
+; Ullrich von Bassewitz, 07.08.1998
+;
+; CC65 runtime: modulo operation for long signed ints
+;
+
+; When negating values, we will ignore the possibility here, that one of the
+; values if $8000, in which case the negate will fail.
+
+ .export tosmodeax
+ .import poplsargs, udiv32, adjlsres
+ .importzp sreg, ptr1, ptr2, tmp3, tmp4
+
+tosmodeax:
+ jsr poplsargs ; Get arguments from stack, adjust sign
+ jsr udiv32 ; Do the division
+ lda ptr1 ; Remainder is in (ptr2:tmp3:tmp4)
+ lda ptr2
+ ldx ptr2+1
+ ldy tmp3
+ sty sreg
+ ldy tmp4
+ sty sreg+1
+ jmp adjlsres ; Adjust the sign of the result if needed
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 13.08.1998
+;
+; CC65 runtime: multiplication for long (unsigned) ints
+;
+
+ .export tosumuleax, tosmuleax
+ .import addysp1
+ .importzp sp, sreg, tmp1, tmp2, tmp3, tmp4, ptr1, ptr3, ptr4
+
+tosmuleax:
+tosumuleax:
+mul32: sta ptr1
+ stx ptr1+1 ; op2 now in ptr1/sreg
+ ldy #0
+ lda (sp),y
+ sta ptr3
+ iny
+ lda (sp),y
+ sta ptr3+1
+ iny
+ lda (sp),y
+ sta ptr4
+ iny
+ lda (sp),y
+ sta ptr4+1 ; op1 in pre3/ptr4
+ jsr addysp1 ; Drop TOS
+
+; Do (ptr1:sreg)*(ptr3:ptr4) --> EAX.
+
+ lda #0
+ sta tmp4
+ sta tmp3
+ sta tmp2
+ ldy #32
+L0: lsr tmp4
+ ror tmp3
+ ror tmp2
+ ror a
+ ror sreg+1
+ ror sreg
+ ror ptr1+1
+ ror ptr1
+ bcc L1
+ clc
+ adc ptr3
+ pha
+ lda ptr3+1
+ adc tmp2
+ sta tmp2
+ lda ptr4
+ adc tmp3
+ sta tmp3
+ lda ptr4+1
+ adc tmp4
+ sta tmp4
+ pla
+L1: dey
+ bpl L0
+ lda ptr1 ; Load the low result word
+ ldx ptr1+1
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 05.08.1998
+;
+; CC65 runtime: long not equal
+;
+
+ .export tosneeax
+ .import lcmp, boolne
+
+tosneeax:
+ jsr lcmp ; Set flags
+ jmp boolne ; Convert to boolean
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: negation on longs
+;
+
+;
+; eax = -eax
+;
+ .export negeax
+ .importzp sreg
+
+negeax: clc
+ eor #$FF
+ adc #1
+ pha
+ txa
+ eor #$FF
+ adc #0
+ tax
+ lda sreg
+ eor #$FF
+ adc #0
+ sta sreg
+ lda sreg+1
+ eor #$FF
+ adc #0
+ sta sreg+1
+ pla
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: or on longs
+;
+
+ .export tosoreax
+ .import addysp1
+ .importzp sp, sreg, tmp1
+
+tosoreax:
+ ldy #0
+ ora (sp),y ; byte 0
+ sta tmp1
+ iny
+ txa
+ ora (sp),y ; byte 1
+ tax
+ iny
+ lda sreg
+ ora (sp),y ; byte 2
+ sta sreg
+ iny
+ lda sreg+1
+ ora (sp),y ; byte 3
+ sta sreg+1
+
+ lda tmp1
+ jmp addysp1
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 29.12.1999
+;
+; CC65 runtime: long pop
+;
+
+ .export popeax
+ .import incsp4
+ .importzp sp, sreg
+
+
+popeax: ldy #3
+ lda (sp),y
+ sta sreg+1
+ dey
+ lda (sp),y
+ sta sreg
+ dey
+ lda (sp),y
+ tax
+ dey
+ lda (sp),y
+ jmp incsp4
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: long push
+;
+
+;
+; push eax on stack
+;
+ .export push0ax, pusheax
+ .import decsp4
+ .importzp sp, sreg
+
+push0ax:
+ ldy #0
+ sty sreg
+ sty sreg+1
+pusheax:
+ jsr decsp4
+ pha
+ ldy #0
+ sta (sp),y
+ iny
+ txa
+ sta (sp),y
+ iny
+ lda sreg
+ sta (sp),y
+ iny
+ lda sreg+1
+ sta (sp),y
+ pla
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 05.08.1998
+;
+; CC65 runtime: long sub reversed
+;
+
+;
+; EAX = EAX - TOS
+;
+ .export tosrsubeax
+ .import addysp1
+ .importzp sp, sreg, tmp1
+
+tosrsubeax:
+ ldy #0
+ sec
+ sbc (sp),y ; byte 0
+ sta tmp1 ; use as temp storage
+ txa
+ iny
+ sbc (sp),y ; byte 1
+ tax
+ iny
+ lda sreg
+ sbc (sp),y ; byte 2
+ sta sreg
+ iny
+ lda sreg+1
+ sbc (sp),y ; byte 3
+ sta sreg+1
+ lda tmp1
+ jmp addysp1 ; drop TOS
+
--- /dev/null
+;
+; lruntime.s
+;
+; Ullrich von Bassewitz, 22.06.1998
+;
+
+; Runtime support for longs.
+
+ .import popax, pusheax, staspic
+ .importzp sp, sreg, tmp2, ptr1
+
+;
+; leax (sp),y
+;
+ .export ldeax0sp, ldeaxysp
+
+ldeax0sp:
+ ldy #3
+ldeaxysp:
+ lda (sp),y
+ sta sreg+1
+ dey
+ lda (sp),y
+ sta sreg
+ dey
+ lda (sp),y
+ tax
+ dey
+ lda (sp),y
+ rts
+
+;
+; push a long from (sp),y
+;
+ .export pushlysp
+
+pushlysp:
+ iny
+ iny
+ lda (sp),y
+ iny
+ sta sreg
+ lda (sp),y
+ sta sreg+1
+ dey
+ dey
+ lda (sp),y
+ dey
+ tax
+ lda (sp),y
+ jmp pusheax
+
+;
+; eax --> ((sp)); pop
+;
+ .export steaxspp
+
+steaxspp:
+ pha
+ txa
+ pha
+ jsr popax ; get address
+ sta ptr1
+ stx ptr1+1
+ ldy #3
+ lda sreg+1
+ sta (ptr1),y
+ dey
+ lda sreg
+ sta (ptr1),y
+ dey
+ pla
+ tax
+ sta (ptr1),y
+ dey
+ pla
+ sta (ptr1),y
+ rts
+
+;
+; eax --> ((sp)),y
+;
+ .export steaxspidx
+
+steaxspidx:
+ jsr staspic ; Get pointer, store a
+ pha
+ iny
+ lda tmp2
+ sta (ptr1),y
+ iny
+ tax
+ lda sreg
+ sta (ptr1),y
+ iny
+ lda sreg+1
+ sta (ptr1),y
+ pla
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 08.08.1998
+;
+; CC65 runtime: save ax into temp storage/restore ax from temp storage
+;
+
+ .export saveeax, resteax
+ .importzp sreg, regsave
+
+saveeax:
+ sta regsave
+ stx regsave+1
+ lda sreg
+ sta regsave+2
+ lda sreg+1
+ sta regsave+3
+ lda regsave
+ rts
+
+resteax:
+ lda regsave+3
+ sta sreg+1
+ lda regsave+2
+ sta sreg
+ ldx regsave+1
+ lda regsave
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 13.08.1998
+;
+; CC65 runtime: helper stuff for mod/div/mul with long signed ints
+;
+
+; When negating values, we will ignore the possibility here, that one of the
+; values if $80000000, in which case the negate will fail.
+
+ .export poplsargs, adjlsres
+ .import getlop, negeax
+ .importzp sreg, tmp1, ptr1, ptr3, ptr4
+
+poplsargs:
+ jsr getlop ; Get the operands
+
+; Calculate the sign of the result, that is sign(op1) * sign(op2) and
+; remember it.
+
+ lda sreg+1
+ eor ptr4+1
+ sta tmp1 ; Save it across call
+
+; Make both operands positive
+
+ lda sreg+1 ; Is the operand negative?
+ bpl L1 ; Jump if not
+
+ clc ; Make it positive
+ lda ptr1
+ eor #$FF
+ adc #$01
+ sta ptr1
+ lda ptr1+1
+ eor #$FF
+ adc #$00
+ sta ptr1+1
+ lda sreg
+ eor #$FF
+ adc #$00
+ sta sreg
+ lda sreg+1
+ eor #$FF
+ adc #$00
+ sta sreg+1
+
+L1: lda ptr4+1 ; Is the operand nagative?
+ bpl L2 ; Jump if not
+
+ clc ; Make it positive
+ lda ptr3
+ eor #$FF
+ adc #$01
+ sta ptr3
+ lda ptr3+1
+ eor #$FF
+ adc #$00
+ sta ptr3+1
+ lda ptr4
+ eor #$FF
+ adc #$00
+ sta ptr4
+ lda ptr4+1
+ eor #$FF
+ adc #$00
+ sta ptr4+1
+
+L2: rts
+
+; Adjust the result of a mod/div/mul operation
+
+adjlsres:
+ ldy tmp1 ; Check if we must adjust the sign
+ bpl L2
+ jmp negeax ; Netage value
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 20.09.1998
+;
+; CC65 runtime: left shift support for longs
+;
+
+
+ .export tosasleax, tosshleax
+ .import addysp1
+ .importzp sp, sreg, ptr1, ptr2
+
+
+tosshleax:
+tosasleax:
+
+; Get the lhs from stack into ptr1/ptr2
+
+ pha
+ ldy #0
+ lda (sp),y
+ sta ptr1
+ iny
+ lda (sp),y
+ sta ptr1+1
+ iny
+ lda (sp),y
+ sta ptr2
+ iny
+ lda (sp),y
+ sta ptr2+1
+ pla
+ jsr addysp1
+
+; Check for shift overflow or zero shift
+
+ tay ; Low byte of shift count into y
+ txa ; Get byte 2
+ ora sreg
+ ora sreg+1 ; Check high 24 bit
+ bne @L6 ; Shift count too large
+ cpy #32
+ bcs @L6
+
+ cpy #0 ; Shift count zero?
+ beq @L5
+
+; We must shift. Shift by multiples of eight if possible
+
+ tya
+@L1: cmp #8
+ bcc @L3
+ sbc #8
+ ldx ptr2
+ stx ptr2+1
+ ldx ptr1+1
+ stx ptr2
+ ldx ptr1
+ stx ptr1+1
+ ldx #0
+ stx ptr1
+ beq @L1
+
+; Shift count is now less than eight. Do a real shift.
+
+@L3: tay ; Shift count to Y
+ lda ptr1 ; Get one byte into A for speed
+ cpy #0
+ beq @L4a ; Jump if done
+@L4: asl a
+ rol ptr1+1
+ rol ptr2
+ rol ptr2+1
+ dey
+ bne @L4
+
+; Put the result in place
+
+@L4a: ldx ptr2
+ stx sreg
+ ldx ptr2+1
+ stx sreg+1
+ ldx ptr1+1
+@L5: rts
+
+; Jump here if shift count overflow
+
+@L6: lda #0
+ sta sreg+1
+ sta sreg
+ tax
+ rts
+
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 20.09.1998
+;
+; CC65 runtime: right shift support for longs
+;
+
+
+ .export tosasreax, tosshreax
+ .import addysp1
+ .importzp sp, sreg, ptr1, ptr2
+
+; --------------------------------------------------------------------
+; signed shift
+
+.proc tosasreax
+
+ jsr getlhs ; Get the lhs from the stack
+
+ jsr checkovf ; Check for overflow
+ bcs L6 ; Jump if shift count too large
+
+ cpy #0 ; Shift count zero?
+ beq L5
+
+; We must shift. Shift by multiples of eight if possible
+
+ tya
+L1: cmp #8
+ bcc L3
+ sbc #8
+ ldx ptr1+1
+ stx ptr1
+ ldx ptr2
+ stx ptr1+1
+ ldy #0
+ ldx ptr2+1
+ stx ptr2
+ bpl L2
+ dey ; Get sign
+L2: sty ptr2+1
+ jmp L1
+
+; Shift count is now less than eight. Do a real shift.
+
+L3: tay ; Shift count to Y
+ lda ptr2+1 ; Get one byte into A for speed
+ cpy #0
+ beq L4a ; Jump if done
+L4: cmp #$80 ; Get sign bit into C
+ ror a
+ ror ptr2
+ ror ptr1+1
+ ror ptr1
+ dey
+ bne L4
+
+; Put the result in place
+
+L4a: sta sreg+1
+ lda ptr2
+ sta sreg
+ ldx ptr1+1
+ lda ptr1
+L5: rts
+
+; Jump here if shift count overflow
+
+L6: ldx #0
+ lda ptr2+1 ; Check sign
+ bpl L7
+ dex
+L7: stx sreg+1
+ stx sreg
+ txa
+ rts
+
+.endproc
+
+; --------------------------------------------------------------------
+; unsigned shift
+
+.proc tosshreax
+
+ jsr getlhs ; Get the lhs from the stack
+
+ jsr checkovf ; Check for overflow
+ bcs L6 ; Jump if shift count too large
+
+ cpy #0 ; Shift count zero?
+ beq L5
+
+; We must shift. Shift by multiples of eight if possible
+
+ tya
+L1: cmp #8
+ bcc L3
+ sbc #8
+ ldx ptr1+1
+ stx ptr1
+ ldx ptr2
+ stx ptr1+1
+ ldx ptr2+1
+ stx ptr2
+ ldx #0
+ stx ptr2+1
+ beq L1
+
+; Shift count is now less than eight. Do a real shift.
+
+L3: tay ; Shift count to Y
+ lda ptr2+1 ; Get one byte into A for speed
+ cpy #0
+ beq L4a ; Jump if done
+L4: lsr a
+ ror ptr2
+ ror ptr1+1
+ ror ptr1
+ dey
+ bne L4
+
+; Put the result in place
+
+L4a: sta sreg+1
+ lda ptr2
+ sta sreg
+ ldx ptr1+1
+ lda ptr1
+L5: rts
+
+; Jump here if shift count overflow
+
+L6: lda #0
+ sta sreg+1
+ sta sreg
+ tax
+ rts
+
+.endproc
+
+; --------------------------------------------------------------------
+; Helpers
+
+.proc getlhs ; Get the lhs from stack into ptr1/ptr2
+
+ pha
+ ldy #0
+ lda (sp),y
+ sta ptr1
+ iny
+ lda (sp),y
+ sta ptr1+1
+ iny
+ lda (sp),y
+ sta ptr2
+ iny
+ lda (sp),y
+ sta ptr2+1
+ pla
+ jmp addysp1
+
+.endproc
+
+
+.proc checkovf ; Check for shift overflow
+
+ tay ; Low byte of shift count into y
+ txa ; Get byte 2
+ ora sreg
+ ora sreg+1 ; Check high 24 bit
+ bne TooLarge ; Shift count too large
+ cpy #32
+ bcc Ok
+TooLarge:
+ sec
+Ok: rts
+
+.endproc
+
+
+
+
+
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 05.08.1998
+;
+; CC65 runtime: long sub
+;
+
+;
+; EAX = TOS - EAX
+;
+ .export tossubeax
+ .import addysp1
+ .importzp sp, sreg, tmp1, tmp2
+
+tossubeax:
+ ldy #0
+ sec
+ sta tmp1
+ lda (sp),y
+ sbc tmp1 ; byte 0
+ sta tmp2 ; use as temp storage
+ iny
+ stx tmp1
+ lda (sp),y
+ sbc tmp1 ; byte 1
+ tax
+ iny
+ lda (sp),y
+ sbc sreg ; byte 2
+ sta sreg
+ iny
+ lda (sp),y
+ sbc sreg+1 ; byte 3
+ sta sreg+1
+ lda tmp2 ; load byte 0
+ jmp addysp1 ; drop TOS
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 07.04.2000
+;
+; CC65 runtime: -= operator
+;
+; On entry, the low byte of the address of the variable to decrement is
+; in ptr1, the high byte is in Y, and the decrement is in eax.
+;
+
+ .export lsubeq1, lsubeqa, lsubeq
+ .importzp sreg, ptr1, tmp1
+
+
+lsubeq1:
+ lda #$01
+
+lsubeqa:
+ ldx #$00
+ stx sreg
+ stx sreg+1
+
+lsubeq: sty ptr1+1 ; Store high byte of address
+ ldy #$00 ; Address low byte
+ sec
+
+ sta tmp1
+ lda (ptr1),y ; Load byte 0
+ sbc tmp1
+ sta (ptr1),y
+ pha ; Save byte 0 of result for later
+
+ iny ; Address byte 1
+ stx tmp1
+ lda (ptr1),y ; Load byte 1
+ sbc tmp1
+ sta (ptr1),y
+ tax
+
+ iny ; Address byte 2
+ lda (ptr1),y
+ sbc sreg
+ sta (ptr1),y
+ sta sreg
+
+ iny ; Address byte 3
+ lda (ptr1),y
+ sbc sreg+1
+ sta (ptr1),y
+ sta sreg+1
+
+ pla ; Retrieve byte 0 of result
+
+ rts ; Done
+
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 08.10.1998
+;
+; CC65 runtime: -= operator for longs on the stack
+;
+
+ .export lsubeq0sp, lsubeqysp
+ .importzp sp, sreg, tmp1, tmp2
+
+lsubeq0sp:
+ ldy #0
+lsubeqysp:
+ sec
+ sta tmp1
+ stx tmp2
+ lda (sp),y
+ sbc tmp1
+ sta (sp),y
+ pha
+ iny
+ lda (sp),y
+ sbc tmp2
+ sta (sp),y
+ tax
+ iny
+ lda (sp),y
+ sbc sreg
+ sta (sp),y
+ sta sreg
+ iny
+ lda (sp),y
+ sbc sreg+1
+ sta (sp),y
+ sta sreg+1
+ pla
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 29.12.1999
+;
+; CC65 runtime: Exchange lo and hi part of eax
+;
+
+ .export swapeax
+ .importzp sreg
+
+swapeax:
+ ldy sreg
+ sta sreg
+ lda sreg+1
+ stx sreg+1
+ tax
+ tya
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 17.08.1998
+;
+; CC65 runtime: switch statement with long selector
+;
+
+; Subroutine to handle a switch statement with an int selector. The table
+; is located at the return address from the function. It contains the negative
+; of the case label count as first word, followed by three words for each case
+; label, the first two being the value, and the second one the label to jump
+; to in case of a match. The default case is located at the end of the table.
+
+ .export lswitch
+ .importzp sreg, ptr1, ptr2, ptr3
+
+lswitch:
+ sta ptr1
+ stx ptr1+1 ; Save AX
+ clc
+ pla
+ adc #1
+ sta ptr2
+ pla
+ adc #0
+ sta ptr2+1 ; Get pointer to table
+
+ ldy #0
+ lda (ptr2),y
+ sta ptr3
+ iny
+ lda (ptr2),y
+ sta ptr3+1 ; Remember the count of labels
+
+ ldy #0
+ clc ; Skip the label count
+ lda ptr2
+ adc #2
+ sta ptr2
+ bcc L2
+ inc ptr2+1
+ bne L2 ; Branch always
+
+; Search for the label
+
+L0: lda (ptr2),y
+ cmp ptr1
+ bne L1
+ iny
+ lda (ptr2),y
+ cmp ptr1+1
+ bne L1
+ iny
+ lda (ptr2),y
+ cmp sreg
+ bne L1
+ iny
+ lda (ptr2),y
+ cmp sreg+1
+ beq L3
+L1: clc
+ lda ptr2
+ adc #6 ; Skip table entry
+ sta ptr2
+ bcc L2
+ inc ptr2+1
+
+; Check if there are any labels left
+
+L2: inc ptr3
+ bne L0
+ inc ptr3+1
+ bne L0
+
+; Out of labels
+
+ jmp (ptr2)
+
+; Label found
+
+L3: ldy #4 ; Jump label offset
+ lda (ptr2),y
+ sta ptr3
+ iny
+ lda (ptr2),y
+ sta ptr3+1
+ jmp (ptr3)
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Compare < for signed ints
+;
+
+ .export toslt00, toslta0, tosltax
+ .import tosicmp, boollt
+
+toslt00:
+ lda #$00
+toslta0:
+ ldx #$00
+tosltax:
+ jsr tosicmp ; Set flags
+ jmp boollt ; Convert to boolean
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 07.08.1998
+;
+; CC65 runtime: test long in eax
+;
+
+ .export utsteax, tsteax
+ .importzp sreg, tmp1
+
+tsteax:
+utsteax:
+ tay ; Save value
+ stx tmp1
+ ora tmp1
+ ora sreg
+ ora sreg+1
+ beq L9
+ tya
+ ldy #1 ; Force NE
+L9: rts
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 17.08.1998
+;
+; CC65 runtime: division for long unsigned ints
+;
+
+ .export tosudiveax, getlop, udiv32
+ .import addysp1
+ .importzp sp, sreg, tmp3, tmp4, ptr1, ptr2, ptr3, ptr4
+
+tosudiveax:
+ jsr getlop ; Get the paramameters
+ jsr udiv32 ; Do the division
+ lda ptr1 ; Result is in ptr1:sreg
+ ldx ptr1+1
+ rts
+
+; Pop the parameters for the long division and put it into the relevant
+; memory cells. Called from the signed divisions also.
+
+getlop: sta ptr3 ; Put right operand in place
+ stx ptr3+1
+ lda sreg
+ sta ptr4
+ lda sreg+1
+ sta ptr4+1
+
+ ldy #0 ; Put left operand in place
+ lda (sp),y
+ sta ptr1
+ iny
+ lda (sp),y
+ sta ptr1+1
+ iny
+ lda (sp),y
+ sta sreg
+ iny
+ lda (sp),y
+ sta sreg+1
+ jmp addysp1 ; Drop parameters
+
+; Do (ptr1:sreg) / (ptr3:ptr4) --> (ptr1:sreg), remainder in (ptr2:tmp3:tmp4)
+; This is also the entry point for the signed division
+
+udiv32: lda #0
+ sta ptr2+1
+ sta tmp3
+ sta tmp4
+; sta ptr1+1
+ ldy #32
+L0: asl ptr1
+ rol ptr1+1
+ rol sreg
+ rol sreg+1
+ rol a
+ rol ptr2+1
+ rol tmp3
+ rol tmp4
+
+; Do a subtraction. we do not have enough space to store the intermediate
+; result, so we may have to do the subtraction twice.
+
+ pha
+ cmp ptr3
+ lda ptr2+1
+ sbc ptr3+1
+ lda tmp3
+ sbc ptr4
+ lda tmp4
+ sbc ptr4+1
+ bcc L1
+
+; Overflow, do the subtraction again, this time store the result
+
+ sta ptr4+1 ; We have the high byte already
+ pla
+ sbc ptr3 ; byte 0
+ pha
+ lda ptr2+1
+ sbc ptr3+1
+ sta ptr2+1 ; byte 1
+ lda tmp3
+ sbc ptr4
+ sta tmp3 ; byte 2
+ inc ptr1 ; Set result bit
+
+L1: pla
+ dey
+ bne L0
+ sta ptr2
+ rts
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 10.12.1998
+;
+; CC65 runtime: Compare >= for long unsigneds
+;
+
+ .export tosugeeax
+ .import lcmp, booluge
+
+tosugeeax:
+ jsr lcmp ; Set the flags
+ jmp booluge ; Convert to boolean
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 10.12.1998
+;
+; CC65 runtime: Compare > for long unsigneds
+;
+
+ .export tosugteax
+ .import lcmp, boolugt
+
+tosugteax:
+ jsr lcmp ; Set the flags
+ jmp boolugt ; Convert to boolean
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 10.12.1998
+;
+; CC65 runtime: Compare <= for long unsigneds
+;
+
+ .export tosuleeax
+ .import lcmp, boolule
+
+tosuleeax:
+ jsr lcmp ; Set the flags
+ jmp boolule ; Convert to boolean
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 10.12.1998
+;
+; CC65 runtime: Compare < for long unsigneds
+;
+
+ .export tosulteax
+ .import lcmp, boolult
+
+tosulteax:
+ jsr lcmp ; Set the flags
+ jmp boolult ; Convert to boolean
--- /dev/null
+;
+; Ullrich von Bassewitz, 27.09.1998
+;
+; CC65 runtime: modulo operation for long unsigned ints
+;
+
+ .export tosumodeax
+ .import getlop, udiv32
+ .importzp sreg, tmp3, tmp4, ptr2
+
+tosumodeax:
+ jsr getlop ; Get the paramameters
+ jsr udiv32 ; Do the division
+ lda tmp3 ; Remainder is in ptr2:tmp3:tmp4
+ sta sreg
+ lda tmp4
+ sta sreg
+ lda ptr2
+ ldx ptr2+1
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: xor on longs
+;
+
+ .export tosxoreax
+ .import addysp1
+ .importzp sp, sreg, tmp1
+
+tosxoreax:
+ ldy #0
+ eor (sp),y ; byte 0
+ sta tmp1
+ iny
+ txa
+ eor (sp),y ; byte 1
+ tax
+ iny
+ lda sreg
+ eor (sp),y ; byte 2
+ sta sreg
+ iny
+ lda sreg+1
+ eor (sp),y ; byte 3
+ sta sreg+1
+
+ lda tmp1
+ jmp addysp1
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 05.10.1998
+;
+; CC65 runtime: Make boolean according to flags
+;
+
+ .export boolne, booleq, boollt, boolle, boolgt, boolge
+ .export boolult, boolule, boolugt, booluge
+
+
+boolne: bne ret1
+ ldx #$00
+ txa
+ rts
+
+
+booleq: beq ret1
+ ldx #$00
+ txa
+ rts
+
+
+boolle: beq ret1
+boollt: bmi ret1
+ ldx #$00
+ txa
+ rts
+
+
+boolgt: beq L0
+boolge: bpl ret1
+L0: ldx #$00
+ txa
+ rts
+
+
+boolule:
+ beq ret1
+boolult:
+ bcc ret1
+ ldx #$00
+ txa
+ rts
+
+
+boolugt:
+ beq L1
+booluge:
+ bcs ret1
+L1: ldx #$00
+ txa
+ rts
+
+
+ret1: ldx #$00
+ lda #$01
+ rts
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 07.08.1998
+;
+; CC65 runtime: modulo operation for signed ints
+;
+
+; When negating values, we will ignore the possibility here, that one of the
+; values if $8000, in which case the negate will fail.
+
+ .export tosmoda0, tosmodax
+ .import popsargs, udiv16, adjsres
+ .importzp ptr1
+
+tosmoda0:
+ ldx #0
+tosmodax:
+ jsr popsargs ; Get arguments from stack, adjust sign
+ jsr udiv16 ; Do the division
+ lda ptr1 ; Result is in sreg, remainder in ptr1
+ ldx ptr1+1
+ jmp adjsres ; Adjust the sign of the result if needed
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 07.08.1998
+;
+; CC65 runtime: multiplication for ints
+;
+
+ .export tosumula0, tosumulax, tosmula0, tosmulax
+ .import popsreg
+ .importzp sreg, tmp1, ptr4
+
+tosmula0:
+tosumula0:
+ ldx #0
+tosmulax:
+tosumulax:
+mul16: sta ptr4
+ stx ptr4+1 ; Save right operand
+ jsr popsreg ; Get left operand
+
+; Do ptr4*sreg --> AX (see mult-div.s from "The Fridge").
+
+ lda #0
+ sta tmp1
+ ldx sreg+1 ; Get into register for speed
+ ldy #16 ; Number of bits
+L0: lsr tmp1
+ ror a
+ ror ptr4+1
+ ror ptr4
+ bcc L1
+ clc
+ adc sreg
+ pha
+ txa ; hi byte of left op
+ adc tmp1
+ sta tmp1
+ pla
+L1: dey
+ bpl L0
+ lda ptr4 ; Load the result
+ ldx ptr4+1
+ rts ; Done
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Compare != for ints
+;
+
+ .export tosne00, tosnea0, tosneax
+ .import tosicmp, boolne
+
+tosne00:
+ lda #$00
+tosnea0:
+ ldx #$00
+tosneax:
+ jsr tosicmp ; Set flags
+ jmp boolne ; Convert to boolean
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 05.08.1998
+;
+; CC65 runtime: negation on ints
+;
+
+ .export negax
+
+negax: clc
+ eor #$FF
+ adc #1
+ pha
+ txa
+ eor #$FF
+ adc #0
+ tax
+ pla
+ rts
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 05.08.1998
+;
+; CC65 runtime: or on ints
+;
+
+ .export tosora0, tosorax
+ .import addysp1
+ .importzp sp, tmp1
+
+tosora0:
+ ldx #$00
+tosorax:
+ ldy #0
+ ora (sp),y
+ sta tmp1
+ iny
+ txa
+ ora (sp),y
+ tax
+ lda tmp1
+ jmp addysp1 ; drop TOS, set condition codes
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 21.08.1998
+;
+; CC65 runtime: Pop TOS into sreg
+;
+
+ .export popsreg
+ .import incsp2
+ .importzp sp, sreg
+
+popsreg:
+ pha ; save A
+ ldy #0
+ lda (sp),y ; get lo byte
+ sta sreg ; store it
+ iny
+ lda (sp),y ; get hi byte
+ sta sreg+1 ; store it
+ pla ; get A back
+ jmp incsp2 ; bump stack and return
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 05.08.1998
+;
+; CC65 runtime: Push ints onto the stack
+;
+
+;
+; push/pop things on stack
+;
+ .export push0, push1, push2, push3, push4, push5
+ .export push6, push7, pusha0, pushaFF, pushax
+ .export pusha, pushaysp, pushc0, pushc1, pushc2
+ .importzp sp
+
+pushaFF:
+ ldx #$FF
+ bne pushax
+
+push7: lda #7
+ bne pusha0
+push6: lda #6
+ bne pusha0
+push5: lda #5
+ bne pusha0
+push4: lda #4
+ bne pusha0
+push3: lda #3
+ bne pusha0
+push2: lda #2
+ bne pusha0
+push1: lda #1
+ bne pusha0
+push0: lda #0
+; beq pusha0
+pusha0: ldx #0
+
+; This function is used *a lot*, so don't call any subroutines here.
+; Beware: The value in ax must not be changed by this function!
+; Beware^2: The optimizer knows about the value of Y after the function
+; returns!
+
+pushax: ldy sp
+ beq @L1
+ dey
+ beq @L2
+ dey
+@L0: sty sp
+ ldy #0 ; get index
+ sta (sp),y ; store lo byte
+ pha ; save it
+ txa ; get hi byte
+ iny ; bump idx
+ sta (sp),y ; store hi byte
+ pla ; get A back
+ rts ; done
+
+@L1: dey
+@L2: dey
+ dec sp+1
+ bne @L0 ; Branch always
+
+; Push for chars, same warning as above: The optimizer expects the value
+; 0 in the Y register after this function.
+
+pushc2: lda #2
+ bne pusha
+pushc1: lda #1
+ bne pusha
+pushc0: lda #0
+ beq pusha
+pushaysp:
+ lda (sp),y
+pusha: ldy sp
+ beq @L1
+ dec sp
+ ldy #0
+ sta (sp),y
+ rts
+
+@L1: dec sp+1
+ dec sp
+ sta (sp),y
+ rts
--- /dev/null
+;
+; Ullrich von Bassewitz, 31.08.1998
+;
+; CC65 runtime: Push word from stack
+;
+
+ .export pushb, pushbidx
+ .import pushax
+ .importzp ptr1
+
+pushbidx:
+ sty ptr1
+ clc
+ adc ptr1
+ bcc pushb
+ inx
+pushb: sta ptr1
+ stx ptr1+1
+ ldx #0 ; Load index/high byte
+ lda (ptr1,x)
+ bpl L1
+ dex ; Make high byte FF
+L1: jmp pushax
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 31.08.1998
+;
+; CC65 runtime: Load a from stack slot and push as word
+;
+
+ .export pushbsp, pushbysp
+ .import pusha0
+ .importzp sp
+
+pushbsp:
+ ldy #0
+pushbysp:
+ lda (sp),y ; get lo byte
+ jmp pusha0 ; promote to unsigned and push
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 31.08.1998
+;
+; CC65 runtime: Push word from stack
+;
+
+ .export pushw, pushwidx
+ .import pushax
+ .importzp ptr1
+
+pushwidx:
+ sty ptr1
+ clc
+ adc ptr1
+ bcc pushw
+ inx
+pushw: sta ptr1
+ stx ptr1+1
+ ldy #1
+ lda (ptr1),y
+ tax
+ dey
+ lda (ptr1),y
+ jmp pushax
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 31.08.1998
+;
+; CC65 runtime: Load word from stack slot and push
+;
+
+ .export pushwysp, pushw0sp
+ .import pushax
+ .importzp sp
+
+pushw0sp:
+ ldy #1
+pushwysp:
+ lda (sp),y ; get hi byte
+ tax
+ dey
+ lda (sp),y ; get lo byte
+ jmp pushax ; push that
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 05.08.1998
+;
+; CC65 runtime: sub ints reversed
+;
+
+ .export tosrsuba0, tosrsubax
+ .import addysp1
+ .importzp sp, tmp1
+
+;
+; AX = AX - TOS
+;
+
+tosrsuba0:
+ ldx #0
+tosrsubax:
+ ldy #0
+ sec
+ sbc (sp),y ; lo byte
+ sta tmp1 ; save lo byte
+ txa
+ iny
+ sbc (sp),y ; hi byte
+ tax
+ lda tmp1
+ jmp addysp1 ; drop TOS, set condition codes
+
+
--- /dev/null
+;
+; Runtime code for cc65.
+;
+
+
+ .import ldai, ldaxi, pushax
+ .importzp sp, tmp1, tmp2, tmp3, ptr1, ptr4
+
+
+; Pop a from stack
+ .export popa
+
+popa: ldy #0
+ lda (sp),y ; Read byte
+ inc sp
+ bne *+4
+ inc sp+1
+ rts
+
+;
+; pop a from stack and load x with zero
+;
+
+ .export popa0
+
+popa0: ldy #0
+ lda (sp),y ; load low byte
+ ldx #0
+ beq incsp2
+
+;
+; pop a/x from stack. This function will run directly into incsp2
+;
+
+ .export popax ; pop stack into AX
+
+popax: ldy #1
+ lda (sp),y ; get hi byte
+ tax ; into x
+ dey
+ lda (sp),y ; get lo byte
+
+;
+; routines for inc/dec'ing sp
+;
+
+ .export addysp, addysp1
+ .export incsp1, incsp2, incsp3, incsp4
+ .export incsp5, incsp6, incsp7, incsp8
+
+; do this by hand, cause it gets used a lot
+
+incsp2: ldy sp ; 3
+ iny ; 2
+ beq @L1 ; 2
+ iny ; 2
+ beq @L2 ; 2
+ sty sp ; 3
+ rts
+
+@L1: iny ; 2
+@L2: sty sp ; 3
+ inc sp+1 ; 5
+ rts
+
+; Hand optimize this one also...
+
+incsp1: inc sp
+ bne *+4
+ inc sp+1
+ rts
+
+incsp3: ldy #3
+ bne addysp
+
+incsp4: ldy #4
+ bne addysp
+
+incsp5: ldy #5
+ bne addysp
+
+incsp6: ldy #6
+ bne addysp
+
+incsp7: ldy #7
+ bne addysp
+
+incsp8: ldy #8
+ bne addysp
+
+addysp1:
+ iny
+addysp: pha ; save A
+ clc
+ tya ; get the value
+ adc sp ; add lo byte
+ sta sp ; put it back
+ bcc addysp_1 ; if no carry, we're done
+ inc sp+1 ; inc hi byte
+addysp_1:
+ pla ; get A back
+ rts
+
+
+;
+;
+ .export subysp ; sub Y from SP
+ .export decsp1, decsp2, decsp3, decsp4
+ .export decsp5, decsp6, decsp7, decsp8
+
+; Do this one by hand, cause it gets used a lot
+
+decsp2: ldy sp
+ beq @L1
+ dey
+ beq @L2
+ dey
+ sty sp
+ rts
+
+@L1: dey
+@L2: dey
+ sty sp
+ dec sp+1
+ rts
+
+; Decrement by 1 also done as fast as possible
+
+decsp1: ldy sp
+ bne *+4
+ dec sp+1
+ dec sp
+ rts
+
+decsp3: ldy #3
+ bne subysp
+
+decsp4: ldy #4
+ bne subysp
+
+decsp5: ldy #5
+ bne subysp
+
+decsp6: ldy #6
+ bne subysp
+
+decsp7: ldy #7
+ bne subysp
+
+decsp8: ldy #8
+; bne subysp
+
+subysp: pha ; save A
+ sty tmp1 ; save the value
+ lda sp ; get lo byte
+ sec
+ sbc tmp1 ; sub y val
+ sta sp ; put it back
+ bcs *+4
+ dec sp+1
+ pla ; get A back
+ rts ; done
+
+;
+; Various kinds of store operators
+;
+; store AX at SP@@(Y)
+
+ .export staxspidx, staspidx, staspic
+staxspidx:
+ jsr staspic ; use common part
+ pha
+ iny
+ lda tmp2
+ sta (ptr4),y
+ tax
+ pla
+ rts
+staspidx:
+ jsr staspic ; use common part
+ ldx tmp2
+ rts
+
+staspic:
+ sta tmp1
+ stx tmp2
+ sty tmp3
+ jsr popax ; get the pointer
+ sta ptr4
+ stx ptr4+1
+ ldy tmp3
+ lda tmp1
+ sta (ptr4),y
+ rts
+
+; ax --> (sp),y
+
+
+ .export staxspp ; store AX thru (sp), and pop
+staxspp:
+ ldy #0
+ pha
+ lda (sp),y
+ sta ptr1
+ iny
+ lda (sp),y
+ sta ptr1+1
+ txa
+ sta (ptr1),y
+ pla
+ dey
+ sta (ptr1),y
+ jmp incsp2 ; Drop address
+
+
+ .export staspp ; store A thru (sp), and pop
+staspp:
+ ldy #1
+ pha
+ lda (sp),y
+ sta ptr1+1
+ dey
+ lda (sp),y
+ sta ptr1
+ pla
+ sta (ptr1),y
+ jmp incsp2 ; Drop address
+
+
+;
+; Boolean function return entries.
+;
+
+ .export return0, return1
+
+return1:
+ ldx #0
+ lda #1
+ rts
+
+return0:
+ lda #0
+ tax
+ rts
+
+;
+; random stuff
+;
+
+; (a/x) 16--> (--sp)
+
+ .export pushwaxi
+pushwaxi: ; push word at (ax)
+ jsr ldaxi
+ jmp pushax
+
+; (a/x) 8--> (--sp)
+
+ .export pushbaxi ; push byte at (ax)
+pushbaxi:
+ jsr ldai
+ jmp pushax
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 07.08.1998
+;
+; CC65 runtime: helper stuff for mod/div/mul with signed ints
+;
+
+; When negating values, we will ignore the possibility here, that one of the
+; values if $8000, in which case the negate will fail.
+
+ .export popsargs, adjsres
+ .import negax, popax
+ .importzp sreg, tmp1, tmp2, ptr4
+
+popsargs:
+ stx tmp1 ; Remember sign
+ cpx #0
+ bpl L1
+ jsr negax ; Negate accumulator
+L1: sta ptr4
+ stx ptr4+1 ; Save right operand
+
+ jsr popax
+ stx tmp2 ; Remember sign
+ cpx #0
+ bpl L2
+ jsr negax
+L2: sta sreg
+ stx sreg+1
+
+; Calculate the sign of the result, that is sign(op1) * sign(op2)
+
+ lda tmp1
+ eor tmp2
+ sta tmp2 ; Save it across call
+L3: rts
+
+; Adjust the result of a mod/div/mul operation
+
+adjsres:
+
+; Check if we must adjust the sign
+
+ ldy tmp2
+ bpl L3
+ jmp negax ; Adjust sign
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 05.08.1998
+;
+; CC65 runtime: left shift support for ints
+;
+
+ .export tosasla0, tosaslax, tosshla0, tosshlax
+ .import popsreg, return0
+ .importzp sreg
+
+tosshla0:
+tosasla0:
+ ldx #0
+tosshlax:
+tosaslax:
+ jsr popsreg ; get TOS into sreg
+ cpx #0
+ bne TooLarge
+ cmp #16
+ bcs TooLarge
+
+ cmp #8 ; Shift count greater 8?
+ beq L3 ; Jump if exactly 8
+ bcc L1 ; Jump if no
+
+; Shift count is greater 8. Do the first 8 bits the fast way
+
+ ldy sreg
+ sty sreg+1
+ stx sreg ; Low byte = 0
+ sec
+ sbc #8
+
+; Shift count less than 8 if we come here
+
+L1: tay ; Shift count --> Y
+ beq Zero ; Done if shift count zero
+
+ lda sreg ; get low byte for faster shift
+
+; Do the actual shift
+
+L2: asl a
+ rol sreg+1
+ dey
+ bne L2
+
+; Done with shift
+
+ ldx sreg+1
+ rts
+
+; Shift count == 8
+
+L3: txa ; X == 0, now A == 0
+ ldx sreg
+ rts
+
+; Shift count was zero
+
+Zero: lda sreg
+ ldx sreg+1
+ rts
+
+; Shift count too large, result is zero
+
+TooLarge:
+ jmp return0
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 05.08.1998
+;
+; CC65 runtime: right shift support for ints
+;
+
+
+; --------------------------------------------------------------------
+; signed shift
+
+ .export tosasra0, tosasrax
+ .import popsreg, return0
+ .importzp sreg
+
+tosasra0:
+ ldx #0
+tosasrax:
+ jsr popsreg ; get TOS into sreg
+ cpx #0
+ bne TooLarge
+ cmp #16
+ bcs TooLarge
+
+ cmp #8 ; Shift count greater 8?
+ beq L4 ; Jump if exactly 8
+ bcc L2 ; Jump if no
+
+; Shift count is greater 8. Do the first 8 bits the fast way
+
+ ldy #0
+ ldx sreg+1
+ stx sreg
+ bpl L1
+ dey ; Create correct sign bits
+L1: sty sreg+1
+ sec
+ sbc #8
+
+; Shift count less than 8 if we come here
+
+L2: tay ; Shift count --> Y
+ beq Zero ; Done if shift count zero
+
+ lda sreg ; get low byte for faster shift
+ ldx sreg+1 ; get high byte
+
+; Do the actual shift
+
+L3: cpx #$80 ; get bit 7 into carry
+ ror sreg+1
+ ror a
+ dey
+ bne L3
+
+; Done with shift
+
+ ldx sreg+1
+ rts
+
+; Shift count == 8
+
+L4: lda sreg+1 ; X is zero
+ bpl *+3
+ dex ; X == 0xFF
+ rts
+
+; Shift count was zero
+
+Zero: lda sreg
+ ldx sreg+1
+ rts
+
+; Shift count too large, result is zero
+
+TooLarge:
+ jmp return0
+
+
+; --------------------------------------------------------------------
+; unsigned shift
+
+ .export tosshra0, tosshrax
+
+tosshra0:
+ ldx #0
+tosshrax:
+ jsr popsreg ; get TOS into sreg
+ cpx #0
+ bne TooLarge
+ cmp #16
+ bcs TooLarge
+
+ cmp #8 ; Shift count greater 8?
+ beq L8 ; Jump if exactly 8
+ bcc L6 ; Jump if no
+
+; Shift count is greater 8. Do the first 8 bits the fast way
+
+ sbc #8 ; Carry already set
+ ldy sreg+1
+ sty sreg
+ stx sreg+1 ; High byte = 0
+
+; Shift count less than 8 if we come here
+
+L6: tay ; Shift count --> Y
+ beq Zero ; Done if shift count zero
+
+ lda sreg ; get low byte for faster shift
+
+; Do the actual shift
+
+L7: lsr sreg+1
+ ror a
+ dey
+ bne L7
+
+; Done with shift
+
+ ldx sreg+1
+ rts
+
+; Shift count == 8
+
+L8: lda sreg+1 ; X is zero
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Scale the primary register
+;
+
+ .export shrax1
+ .importzp tmp1
+
+shrax1: stx tmp1
+ lsr tmp1
+ ror a
+ ldx tmp1
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Scale the primary register by 4
+;
+
+ .export shrax2
+ .importzp tmp1
+
+shrax2: stx tmp1
+ lsr tmp1
+ ror a
+ lsr tmp1
+ ror a
+ ldx tmp1
+ rts
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Scale the primary register by 8
+;
+
+ .export shrax3
+ .importzp tmp1
+
+shrax3: stx tmp1
+ lsr tmp1
+ ror a
+ lsr tmp1
+ ror a
+ lsr tmp1
+ ror a
+ ldx tmp1
+ rts
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Scale the 32 bit primary register by 2
+;
+
+ .export shreax1
+ .importzp sreg, tmp1
+
+shreax1:
+ stx tmp1
+ lsr sreg+1
+ ror sreg
+ ror tmp1
+ ror a
+ ldx tmp1
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Scale the 32 bit primary register by 4
+;
+
+ .export shreax2
+ .importzp sreg, tmp1
+
+shreax2:
+ stx tmp1
+ lsr sreg+1
+ ror sreg
+ ror tmp1
+ ror a
+ lsr sreg+1
+ ror sreg
+ ror tmp1
+ ror a
+ ldx tmp1
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Scale the 32 bit primary register by 8
+;
+
+ .export shreax3
+ .importzp sreg, tmp1
+
+shreax3:
+ stx tmp1
+ lsr sreg+1
+ ror sreg
+ ror tmp1
+ ror a
+ lsr sreg+1
+ ror sreg
+ ror tmp1
+ ror a
+ lsr sreg+1
+ ror sreg
+ ror tmp1
+ ror a
+ ldx tmp1
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 31.08.1998
+;
+; CC65 runtime: Store ax at (sp),y
+;
+
+ .export staxysp, stax0sp
+ .importzp sp
+
+stax0sp:
+ ldy #0
+staxysp:
+ sta (sp),y
+ iny
+ pha
+ txa
+ sta (sp),y
+ pla
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 31.08.1998
+;
+; CC65 runtime: Store eax at (sp),y
+;
+
+ .export steaxysp, steax0sp
+ .importzp sp, sreg
+
+steax0sp:
+ ldy #0
+steaxysp:
+ sta (sp),y
+ iny
+ pha
+ txa
+ sta (sp),y
+ iny
+ lda sreg
+ sta (sp),y
+ iny
+ lda sreg+1
+ sta (sp),y
+ pla
+ rts
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 05.08.1998
+;
+; CC65 runtime: sub ints
+;
+
+ .export tossuba0, tossubax
+ .import addysp1
+ .importzp sp, ptr1
+
+;
+; AX = TOS - AX
+;
+
+tossuba0:
+ ldx #0
+tossubax:
+ ldy #0
+ sta ptr1
+ stx ptr1+1
+ lda (sp),y ; lo byte
+ sec
+ sbc ptr1
+ sta ptr1 ; save lo byte
+ iny
+ lda (sp),y
+ sbc ptr1+1
+ tax
+ lda ptr1
+ jmp addysp1 ; drop TOS, set condition codes
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 08.10.1998
+;
+; CC65 runtime: -= operator for ints on the stack
+;
+
+ .export subeq0sp, subeqysp
+ .importzp sp, tmp1, tmp2
+
+subeq0sp:
+ ldy #0
+subeqysp:
+ sec
+ sta tmp1
+ stx tmp2
+ lda (sp),y
+ sbc tmp1
+ sta (sp),y
+ pha
+ iny
+ lda (sp),y
+ sbc tmp2
+ sta (sp),y
+ tax
+ pla
+ rts
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: swap ax with TOS
+;
+
+ .export swapstk
+ .importzp sp, ptr4
+
+swapstk:
+ sta ptr4
+ stx ptr4+1
+ ldy #1 ; index
+ lda (sp),y
+ tax
+ lda ptr4+1
+ sta (sp),y
+ dey
+ lda (sp),y
+ pha
+ lda ptr4
+ sta (sp),y
+ pla
+ rts ; whew!
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 17.08.1998
+;
+; CC65 runtime: switch statement with int selector
+;
+
+; Subroutine to handle a switch statement with an int selector. The table
+; is located at the return address from the function. It contains the negative
+; of the case label count as first word, followed by two words for each case
+; label, the first one being the value, and the second one the label to jump
+; to in case of a match. The default case is located at the end of the table.
+
+ .export switch
+ .importzp ptr1, ptr2, ptr3
+
+switch: sta ptr1
+ stx ptr1+1 ; Save AX
+ clc
+ pla
+ adc #1
+ sta ptr2
+ pla
+ adc #0
+ sta ptr2+1 ; Get pointer to table
+
+ ldy #0
+ lda (ptr2),y
+ sta ptr3
+ iny
+ lda (ptr2),y
+ sta ptr3+1 ; Remember the count of labels
+
+ ldy #0
+ clc ; Skip the label count
+ lda ptr2
+ adc #2
+ sta ptr2
+ bcc L2
+ inc ptr2+1
+ bne L2 ; Branch always
+
+; Search for the label
+
+L0: lda (ptr2),y
+ iny
+ cmp ptr1
+ beq L4
+L1: iny
+ iny
+ iny ; Overflow only here
+ bne L2
+ inc ptr2+1 ; Bump high byte
+
+; Check if there are any labels left
+
+L2: inc ptr3
+ bne L0
+ inc ptr3+1
+ bne L0
+
+; Out of labels
+
+ tya
+ clc
+ adc ptr2
+ sta ptr2
+ bcc L3
+ inc ptr2+1
+L3: jmp (ptr2)
+
+
+; Check high byte
+
+L4: lda (ptr2),y
+ cmp ptr1+1
+ bne L1
+
+; Label found
+
+ iny
+ lda (ptr2),y
+ sta ptr3
+ iny
+ lda (ptr2),y
+ sta ptr3+1
+ jmp (ptr3)
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 07.08.1998
+;
+; CC65 runtime: test int in ax
+;
+
+ .export utsta0, utstax, tsta0, tstax
+
+tsta0:
+utsta0: ldx #0
+tstax:
+utstax: cpx #0
+ bne L1
+ cmp #0
+L1: rts
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 07.08.1998
+;
+; CC65 runtime: division for unsigned ints
+;
+
+ .export tosudiva0, tosudivax, udiv16
+ .import popsreg
+ .importzp sreg, ptr1, ptr4
+
+tosudiva0:
+ ldx #0
+tosudivax:
+ sta ptr4
+ stx ptr4+1 ; Save right operand
+ jsr popsreg ; Get left operand
+
+; Do the division
+
+ jsr udiv16
+
+; Result is in sreg, remainder in ptr1
+
+ lda sreg
+ ldx sreg+1
+ rts
+
+; Do (sreg/ptr4) -> sreg (see mult-div.s from "The Fridge").
+; This is also the entry point for the signed division
+
+udiv16: lda #0
+ sta ptr1+1
+ ldy #16
+L0: asl sreg
+ rol sreg+1
+ rol a
+ rol ptr1+1
+ pha
+ cmp ptr4
+ lda ptr1+1
+ sbc ptr4+1
+ bcc L1
+ sta ptr1+1
+ pla
+ sbc ptr4
+ pha
+ inc sreg
+L1: pla
+ dey
+ bne L0
+ sta ptr1
+ rts
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Compare >= for unsigned ints
+;
+
+ .export tosuge00, tosugea0, tosugeax
+ .import tosicmp, booluge
+
+
+tosuge00:
+ lda #$00
+tosugea0:
+ ldx #$00
+tosugeax:
+ jsr tosicmp ; Set flags
+ jmp booluge ; Convert to boolean
+
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Compare > for unsigned ints
+;
+
+ .export tosugt00, tosugta0, tosugtax
+ .import tosicmp, boolugt
+
+
+tosugt00:
+ lda #$00
+tosugta0:
+ ldx #$00
+tosugtax:
+ jsr tosicmp ; Set flags
+ jmp boolugt ; Convert to boolean
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Compare <= for unsigned ints
+;
+
+ .export tosule00, tosulea0, tosuleax
+ .import tosicmp, boolule
+
+tosule00:
+ lda #$00
+tosulea0:
+ ldx #$00
+tosuleax:
+ jsr tosicmp ; Set flags
+ jmp boolule ; Convert to boolean
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 06.08.1998
+;
+; CC65 runtime: Compare < for unsigned ints
+;
+
+ .export tosult00, tosulta0, tosultax
+ .import tosicmp, boolult, return0
+
+
+tosult00 = return0 ; This is always false
+
+tosulta0:
+ ldx #$00
+tosultax:
+ jsr tosicmp ; Set flags
+ jmp boolult ; Convert to boolean
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 07.08.1998
+;
+; CC65 runtime: modulo operation for unsigned ints
+;
+
+ .export tosumoda0, tosumodax
+ .import popsreg, udiv16
+ .importzp ptr1, ptr4
+
+tosumoda0:
+ ldx #0
+tosumodax:
+ sta ptr4
+ stx ptr4+1 ; Save right operand
+ jsr popsreg ; Get right operand
+
+; Do the division
+
+ jsr udiv16
+
+; Result is in sreg, remainder in ptr1
+
+ lda ptr1
+ ldx ptr1+1
+ rts
+
+
--- /dev/null
+;
+; Ullrich von Bassewitz, 05.08.1998
+;
+; CC65 runtime: xor on ints
+;
+
+ .export tosxora0, tosxorax
+ .import addysp1
+ .importzp sp, tmp1
+
+tosxora0:
+ ldx #$00
+tosxorax:
+ ldy #0
+ eor (sp),y
+ sta tmp1
+ iny
+ txa
+ eor (sp),y
+ tax
+ lda tmp1
+ jmp addysp1 ; drop TOS, set condition codes
+
--- /dev/null
+nachtm
+hello
+sieve
+*.map
+*.d64
+*.s
+*.lbl
--- /dev/null
+#
+# Makefile for cc65 samples
+#
+
+# Enter the target system here
+SYS = c64
+
+CRT0 = ../lib/$(SYS).o
+CLIB = ../lib/$(SYS).lib
+CC = ../cc65/cc65
+CL = ../cl65/cl65
+AS = ../binutils/ca65/ca65
+LD = ../binutils/ld65/ld65
+C1541 = c1541
+
+
+.c.o:
+ @echo $<
+ @$(CL) -c -Oirs -t $(SYS) -I../include/ $<
+
+.s.o:
+ @echo $<
+ @$(CL) -c $(basename $<).s
+
+
+.PHONY: all
+all: nachtm hello sieve
+
+nachtm: $(CRT0) nachtm.o $(CLIB)
+ @$(LD) -t $(SYS) -m nachtm.map -Ln nachtm.lbl -o $@ $^
+
+hello: $(CRT0) hello.o $(CLIB)
+ @$(LD) -t $(SYS) -m hello.map -Ln hello.lbl -o $@ $^
+
+sieve: $(CRT0) sieve.o $(CLIB)
+ @$(LD) -t $(SYS) -m sieve.map -Ln sieve.lbl -o $@ $^
+
+.PHONY: disk
+disk: c64.d64
+
+c64.d64: all
+ $(C1541) < c1541.rsp
+
+.PHONY: clean
+clean:
+ rm -f *~ *.map *.o *.s *.lbl
+
+.PHONY: zap
+zap: clean
+ rm -f nachtm hello
+
+
+
+
--- /dev/null
+att c64.d64
+
+delete nachtm
+delete hello
+write nachtm
+write hello
+quit
+
+
--- /dev/null
+/*
+ * Fancy hello world program using cc65.
+ *
+ * Ullrich von Bassewitz (ullrich@von-bassewitz.de)
+ *
+ */
+
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <conio.h>
+#include <dbg.h>
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+static const char Text [] = "Hello world!";
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+int main (void)
+{
+ unsigned char XSize, YSize;
+
+ /* Set screen colors, hide the cursor */
+ textcolor (COLOR_WHITE);
+ bordercolor (COLOR_BLACK);
+ bgcolor (COLOR_BLACK);
+ cursor (0);
+
+ /* Clear the screen, put cursor in upper left corner */
+ clrscr ();
+
+ /* Ask for the screen size */
+ screensize (&XSize, &YSize);
+
+ /* Draw a border around the screen */
+
+ /* Top line */
+ cputc (CH_ULCORNER);
+ chline (XSize - 2);
+ cputc (CH_URCORNER);
+
+ /* Vertical line, left side */
+ cvlinexy (0, 1, YSize - 2);
+
+ /* Bottom line */
+ cputc (CH_LLCORNER);
+ chline (XSize - 2);
+ cputc (CH_LRCORNER);
+
+ /* Vertical line, right side */
+ cvlinexy (XSize - 1, 1, YSize - 2);
+
+ /* Write the greeting in the mid of the screen */
+ gotoxy ((XSize - strlen (Text)) / 2, YSize / 2);
+ cprintf ("%s", Text);
+
+ /* Wait for the user to press a key */
+ (void) cgetc ();
+
+ /* Clear the screen again */
+ clrscr ();
+
+ /* Done */
+ return EXIT_SUCCESS;
+}
+
+
+
--- /dev/null
+/*
+ * "Eine kleine Nachtmusik" by Wolfgang Amadeus Mozart, KV 525
+ *
+ * First version in 1987 by
+ * Joachim von Bassewitz (joachim@von-bassewitz.de) and
+ * Ullrich von Bassewitz (ullrich@von-bassewitz.de).
+ *
+ * C conversion in 1998 by
+ * Ullrich von Bassewitz (ullrich@von-bassewitz.de)
+ *
+ */
+
+
+
+#include <stdio.h>
+#include <time.h>
+#include <conio.h>
+#include <cbm.h>
+#include <dbg.h>
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Tables with voice data.
+ *
+ * Bit Description
+ * -------------------------------------------
+ * 15 Pause bit.
+ * 12-14 Octave
+ * 8-11 Tone (index into frequency table)
+ * 7 Unused. Was thought as a control bit in the original version to
+ * change SID parameters, but this was never implemented.
+ * 0-6 Length of the tone in ticks.
+ *
+ */
+
+
+
+static int Voice1 [] = {
+ 0x5708,0x8004,0x5204,0x5708,0x8004,0x5204,0x5704,0x5204,0x5704,0x5B04,
+ 0x6208,0x8008,0x6008,0x8004,0x5904,0x6008,0x8004,0x5904,0x6004,0x5904,
+ 0x5604,0x5904,0x5208,0x8008,0x5704,0x8004,0x570C,0x5B01,0x5B01,0x5B01,
+ 0x5B01,0x5904,0x5704,0x5704,0x5604,0x560C,0x5901,0x5901,0x5901,0x5901,
+ 0x6004,0x5604,0x5901,0x5901,0x5901,0x5901,0x5704,0x570C,0x5B01,0x5B01,
+ 0x5B01,0x5B01,0x5904,0x5704,0x5701,0x5701,0x5701,0x5701,0x5604,0x560C,
+ 0x5901,0x5901,0x5901,0x5901,0x6004,0x5604,0x5704,0x5704,0x5601,0x5601,
+ 0x5601,0x5601,0x5401,0x5401,0x5602,0x5704,0x5704,0x5901,0x5901,0x5901,
+ 0x5901,0x5701,0x5701,0x5902,0x5B04,0x5B04,0x6001,0x6001,0x6001,0x6001,
+ 0x5B01,0x5B01,0x6001,0x6001,0x6208,0x8008,0x5201,0x5201,0x5201,0x5201,
+ 0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,
+ 0x5201,0x5201,0x5410,0x5008,0x5008,0x4B08,0x4B08,0x4908,0x4908,0x4701,
+ 0x4701,0x4701,0x4701,0x4604,0x4404,0x4604,0x4704,0x8004,0x4904,0x8004,
+ 0x4B04,0x800C,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,
+ 0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5410,0x5201,
+ 0x5201,0x5201,0x5201,0x5004,0x5004,0x5004,0x5001,0x5001,0x5001,0x5001,
+ 0x4B04,0x4B04,0x4B04,0x4B01,0x4B01,0x4B01,0x4B01,0x4904,0x4904,0x4904,
+ 0x4701,0x4701,0x4701,0x4701,0x4601,0x4601,0x4601,0x4601,0x4401,0x4401,
+ 0x4401,0x4401,0x4604,0x4701,0x4701,0x4701,0x4701,0x4701,0x4701,0x4701,
+ 0x4701,0x4701,0x4701,0x4701,0x4701,0x4701,0x4701,0x4701,0x4701,0x4704,
+ 0x4701,0x4701,0x4601,0x4701,0x4901,0x4901,0x4901,0x4901,0x4604,0x4B01,
+ 0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,
+ 0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B04,0x4B01,0x4B01,0x4901,0x4B01,
+ 0x5001,0x5001,0x5001,0x5001,0x4904,0x5210,0x5408,0x5608,0x5708,0x5908,
+ 0x5B08,0x6108,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,
+ 0x6201,0x6201,0x6201,0x6201,0x5904,0x6101,0x6101,0x6101,0x6101,0x6101,
+ 0x6101,0x5902,0x6101,0x6101,0x6101,0x6101,0x6101,0x6101,0x5902,0x6201,
+ 0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,
+ 0x6201,0x5904,0x6101,0x6101,0x6101,0x6101,0x6101,0x6101,0x5902,0x6101,
+ 0x6101,0x6101,0x6101,0x6101,0x6101,0x5902,0x6204,0x6208,0x6208,0x6208,
+ 0x6201,0x6201,0x6201,0x6201,0x6204,0x6208,0x6208,0x6208,0x6204,0x6104,
+ 0x5904,0x6204,0x5904,0x6004,0x5904,0x6204,0x5904,0x6104,0x4904,0x4904,
+ 0x4904,0x4908,0x8008,0x590A,0x5702,0x5602,0x5402,0x5204,0x8004,0x5B04,
+ 0x8004,0x5704,0x8004,0x5404,0x8004,0x5B04,0x800C,0x5601,0x5601,0x5601,
+ 0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5401,0x5401,0x5201,
+ 0x5201,0x5101,0x5101,0x4B04,0x8004,0x5704,0x8004,0x5601,0x5601,0x5601,
+ 0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,
+ 0x5601,0x5601,0x5601,0x5408,0x8008,0x5901,0x5901,0x5901,0x5901,0x5901,
+ 0x5901,0x5901,0x5901,0x5901,0x5901,0x5701,0x5701,0x5601,0x5601,0x5401,
+ 0x5401,0x5204,0x8004,0x5B04,0x8004,0x5704,0x8004,0x5404,0x8004,0x5908,
+ 0x8004,0x5704,0x6104,0x6204,0x8004,0x5B04,0x5B01,0x5B01,0x5B01,0x5B01,
+ 0x5904,0x8004,0x5104,0x5208,0x8004,0x5904,0x6201,0x6201,0x6201,0x6201,
+ 0x6101,0x6101,0x6101,0x6101,0x5B01,0x5B01,0x5B01,0x5B01,0x5904,0x5B01,
+ 0x5B01,0x5B01,0x5B01,0x5904,0x8004,0x5904,0x5904,0x5904,0x5904,0x5904,
+ 0x5B01,0x5B01,0x5B01,0x5B01,0x5904,0x8004,0x5904,0x6204,0x6104,0x5B04,
+ 0x5904,0x5B01,0x5B01,0x5B01,0x5B01,0x5904,0x8004,0x5904,0x5904,0x5904,
+ 0x5904,0x5904,0x5B01,0x5B01,0x5B01,0x5B01,0x5904,0x8008,0x5B0A,0x5901,
+ 0x5901,0x5701,0x5701,0x5601,0x5601,0x5708,0x8008,0x590A,0x5701,0x5701,
+ 0x5601,0x5601,0x5401,0x5401,0x5608,0x8008,0x5B01,0x5B01,0x5B01,0x5B01,
+ 0x6101,0x6101,0x6201,0x6201,0x6104,0x5B04,0x5B01,0x5B01,0x5B01,0x5B01,
+ 0x5904,0x5604,0x5904,0x5901,0x5901,0x5901,0x5901,0x5704,0x5604,0x5404,
+ 0x5208,0x8004,0x5904,0x6201,0x6201,0x6201,0x6201,0x6101,0x6101,0x6101,
+ 0x6101,0x5B01,0x5B01,0x5B01,0x5B01,0x5904,0x5B01,0x5B01,0x5B01,0x5B01,
+ 0x5904,0x8004,0x5904,0x5904,0x5904,0x5904,0x5904,0x5B01,0x5B01,0x5B01,
+ 0x5B01,0x5904,0x8004,0x5904,0x6201,0x6201,0x6201,0x6201,0x6101,0x6101,
+ 0x6101,0x6101,0x5B01,0x5B01,0x5B01,0x5B01,0x5904,0x5B01,0x5B01,0x5B01,
+ 0x5B01,0x5904,0x8004,0x5904,0x5904,0x5904,0x5904,0x5904,0x5B01,0x5B01,
+ 0x5B01,0x5B01,0x5904,0x8008,0x5B0A,0x5901,0x5901,0x5701,0x5701,0x5601,
+ 0x5601,0x5708,0x8008,0x590A,0x5701,0x5701,0x5601,0x5601,0x5401,0x5401,
+ 0x5608,0x8008,0x5B01,0x5B01,0x5B01,0x5B01,0x6101,0x6101,0x6201,0x6201,
+ 0x6104,0x5B04,0x5B01,0x5B01,0x5B01,0x5B01,0x5904,0x5604,0x5904,0x5901,
+ 0x5901,0x5901,0x5901,0x5704,0x5604,0x5404,0x5204,0x4904,0x4B04,0x5104,
+ 0x5204,0x5204,0x5401,0x5401,0x5401,0x5401,0x5201,0x5201,0x5401,0x5401,
+ 0x5604,0x5104,0x5204,0x5404,0x5604,0x5604,0x5701,0x5701,0x5701,0x5701,
+ 0x5601,0x5601,0x5701,0x5701,0x5904,0x5904,0x5A04,0x5802,0x5A02,0x5B08,
+ 0x8008,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,
+ 0x4B01,0x4B01,0x4B01,0x5404,0x5201,0x5201,0x5201,0x5201,0x5101,0x5101,
+ 0x5101,0x5101,0x5B01,0x5B01,0x5B01,0x5B01,0x5901,0x5901,0x5901,0x5901,
+ 0x6204,0x8004,0x6604,0x8004,0x6204,0x800C,0x5708,0x8004,0x5204,0x5708,
+ 0x8004,0x5204,0x5704,0x5204,0x5704,0x5B04,0x6208,0x8008,0x6008,0x8004,
+ 0x5904,0x6008,0x8004,0x5904,0x6004,0x5904,0x5604,0x5904,0x5208,0x8008,
+ 0x5704,0x8004,0x570C,0x5B01,0x5B01,0x5B01,0x5B01,0x5904,0x5704,0x5704,
+ 0x5604,0x560C,0x5901,0x5901,0x5901,0x5901,0x6004,0x5604,0x5901,0x5901,
+ 0x5901,0x5901,0x5704,0x570C,0x5B01,0x5B01,0x5B01,0x5B01,0x5904,0x5704,
+ 0x5701,0x5701,0x5701,0x5701,0x5604,0x560C,0x5901,0x5901,0x5901,0x5901,
+ 0x6004,0x5604,0x5704,0x5704,0x5601,0x5601,0x5601,0x5601,0x5401,0x5401,
+ 0x5602,0x5704,0x5704,0x5901,0x5901,0x5901,0x5901,0x5701,0x5701,0x5902,
+ 0x5B04,0x5B04,0x6001,0x6001,0x6001,0x6001,0x5B01,0x5B01,0x6001,0x6001,
+ 0x6208,0x8008,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,
+ 0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5410,0x5008,
+ 0x5008,0x4B08,0x4B08,0x4908,0x4908,0x4701,0x4701,0x4701,0x4701,0x4604,
+ 0x4404,0x4604,0x4704,0x8004,0x4904,0x8004,0x4B04,0x800C,0x5201,0x5201,
+ 0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,
+ 0x5201,0x5201,0x5201,0x5201,0x5410,0x5201,0x5201,0x5201,0x5201,0x5004,
+ 0x5004,0x5004,0x5001,0x5001,0x5001,0x5001,0x4B04,0x4B04,0x4B04,0x4B01,
+ 0x4B01,0x4B01,0x4B01,0x4904,0x4904,0x4904,0x4701,0x4701,0x4701,0x4701,
+ 0x4601,0x4601,0x4601,0x4601,0x4401,0x4401,0x4401,0x4401,0x4604,0x4701,
+ 0x4701,0x4701,0x4701,0x4701,0x4701,0x4701,0x4701,0x4701,0x4701,0x4701,
+ 0x4701,0x4701,0x4701,0x4701,0x4701,0x4704,0x4701,0x4701,0x4601,0x4701,
+ 0x4901,0x4901,0x4901,0x4901,0x4604,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,
+ 0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,
+ 0x4B01,0x4B04,0x4B01,0x4B01,0x4901,0x4B01,0x5001,0x5001,0x5001,0x5001,
+ 0x4904,0x5210,0x5408,0x5608,0x5708,0x5908,0x5B08,0x6108,0x6201,0x6201,
+ 0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,
+ 0x5904,0x6101,0x6101,0x6101,0x6101,0x6101,0x6101,0x5902,0x6101,0x6101,
+ 0x6101,0x6101,0x6101,0x6101,0x5902,0x6201,0x6201,0x6201,0x6201,0x6201,
+ 0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x5904,0x6101,0x6101,
+ 0x6101,0x6101,0x6101,0x6101,0x5902,0x6101,0x6101,0x6101,0x6101,0x6101,
+ 0x6101,0x5902,0x6204,0x6208,0x6208,0x6208,0x6201,0x6201,0x6201,0x6201,
+ 0x6204,0x6208,0x6208,0x6208,0x6204,0x6104,0x5904,0x6204,0x5904,0x6004,
+ 0x5904,0x6204,0x5904,0x6104,0x4904,0x4904,0x4904,0x4908,0x8008,0x590A,
+ 0x5702,0x5602,0x5402,0x5204,0x8004,0x5B04,0x8004,0x5704,0x8004,0x5404,
+ 0x8004,0x5B04,0x800C,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,
+ 0x5601,0x5601,0x5601,0x5401,0x5401,0x5201,0x5201,0x5101,0x5101,0x4B04,
+ 0x8004,0x5704,0x8004,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,
+ 0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5408,
+ 0x8008,0x5901,0x5901,0x5901,0x5901,0x5901,0x5901,0x5901,0x5901,0x5901,
+ 0x5901,0x5701,0x5701,0x5601,0x5601,0x5401,0x5401,0x5204,0x8004,0x5B04,
+ 0x8004,0x5704,0x8004,0x5404,0x8004,0x5908,0x8004,0x5704,0x6104,0x6204,
+ 0x8004,0x5B04,0x5B01,0x5B01,0x5B01,0x5B01,0x5904,0x8004,0x5104,0x5208,
+ 0x8004,0x5904,0x6201,0x6201,0x6201,0x6201,0x6101,0x6101,0x6101,0x6101,
+ 0x5B01,0x5B01,0x5B01,0x5B01,0x5904,0x5B01,0x5B01,0x5B01,0x5B01,0x5904,
+ 0x8004,0x5904,0x5904,0x5904,0x5904,0x5904,0x5B01,0x5B01,0x5B01,0x5B01,
+ 0x5904,0x8004,0x5904,0x6204,0x6104,0x5B04,0x5904,0x5B01,0x5B01,0x5B01,
+ 0x5B01,0x5904,0x8004,0x5904,0x5904,0x5904,0x5904,0x5904,0x5B01,0x5B01,
+ 0x5B01,0x5B01,0x5904,0x8008,0x5B0A,0x5901,0x5901,0x5701,0x5701,0x5601,
+ 0x5601,0x5708,0x8008,0x590A,0x5701,0x5701,0x5601,0x5601,0x5401,0x5401,
+ 0x5608,0x8008,0x5B01,0x5B01,0x5B01,0x5B01,0x6101,0x6101,0x6201,0x6201,
+ 0x6104,0x5B04,0x5B01,0x5B01,0x5B01,0x5B01,0x5904,0x5604,0x5904,0x5901,
+ 0x5901,0x5901,0x5901,0x5704,0x5604,0x5404,0x5208,0x8004,0x5904,0x6201,
+ 0x6201,0x6201,0x6201,0x6101,0x6101,0x6101,0x6101,0x5B01,0x5B01,0x5B01,
+ 0x5B01,0x5904,0x5B01,0x5B01,0x5B01,0x5B01,0x5904,0x8004,0x5904,0x5904,
+ 0x5904,0x5904,0x5904,0x5B01,0x5B01,0x5B01,0x5B01,0x5904,0x8004,0x5904,
+ 0x6201,0x6201,0x6201,0x6201,0x6101,0x6101,0x6101,0x6101,0x5B01,0x5B01,
+ 0x5B01,0x5B01,0x5904,0x5B01,0x5B01,0x5B01,0x5B01,0x5904,0x8004,0x5904,
+ 0x5904,0x5904,0x5904,0x5904,0x5B01,0x5B01,0x5B01,0x5B01,0x5904,0x8008,
+ 0x5B0A,0x5901,0x5901,0x5701,0x5701,0x5601,0x5601,0x5708,0x8008,0x590A,
+ 0x5701,0x5701,0x5601,0x5601,0x5401,0x5401,0x5608,0x8008,0x5B01,0x5B01,
+ 0x5B01,0x5B01,0x6101,0x6101,0x6201,0x6201,0x6104,0x5B04,0x5B01,0x5B01,
+ 0x5B01,0x5B01,0x5904,0x5604,0x5904,0x5901,0x5901,0x5901,0x5901,0x5704,
+ 0x5604,0x5404,0x5204,0x4904,0x4B04,0x5104,0x5204,0x5204,0x5401,0x5401,
+ 0x5401,0x5401,0x5201,0x5201,0x5401,0x5401,0x5604,0x5104,0x5204,0x5404,
+ 0x5604,0x5604,0x5701,0x5701,0x5701,0x5701,0x5601,0x5601,0x5701,0x5701,
+ 0x5904,0x5904,0x5A04,0x5802,0x5A02,0x5B08,0x8008,0x4B01,0x4B01,0x4B01,
+ 0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x5404,
+ 0x5201,0x5201,0x5201,0x5201,0x5101,0x5101,0x5101,0x5101,0x5B01,0x5B01,
+ 0x5B01,0x5B01,0x5901,0x5901,0x5901,0x5901,0x6204,0x8004,0x6604,0x8004,
+ 0x6204,0x800C,0x5208,0x8004,0x4904,0x5208,0x8004,0x4904,0x5204,0x4904,
+ 0x5204,0x5604,0x5908,0x8008,0x5908,0x8004,0x5604,0x5908,0x8004,0x5604,
+ 0x5904,0x5604,0x5304,0x5604,0x4B08,0x8014,0x5704,0x6001,0x6001,0x6001,
+ 0x6001,0x5B01,0x5B01,0x5B01,0x5B01,0x5901,0x5901,0x5901,0x5901,0x5704,
+ 0x5901,0x5901,0x5901,0x5901,0x5704,0x8004,0x5704,0x5704,0x5704,0x5704,
+ 0x5704,0x5901,0x5901,0x5901,0x5901,0x5704,0x8004,0x5704,0x6001,0x6001,
+ 0x6001,0x6001,0x5B01,0x5B01,0x5B01,0x5B01,0x5901,0x5901,0x5901,0x5901,
+ 0x5704,0x5901,0x5901,0x5901,0x5901,0x5704,0x8004,0x5704,0x5704,0x5704,
+ 0x5704,0x5704,0x5901,0x5901,0x5901,0x5901,0x5704,0x8004,0x5704,0x6001,
+ 0x6001,0x6001,0x6001,0x5B01,0x5B01,0x5B01,0x5B01,0x5901,0x5901,0x5901,
+ 0x5901,0x5704,0x5901,0x5901,0x5901,0x5901,0x5804,0x8004,0x5804,0x5804,
+ 0x5804,0x5804,0x5804,0x5B01,0x5B01,0x5B01,0x5B01,0x5904,0x8004,0x5904,
+ 0x6001,0x6001,0x6001,0x6001,0x5A01,0x5A01,0x5A01,0x5A01,0x5901,0x5901,
+ 0x5901,0x5901,0x5704,0x5701,0x5701,0x5701,0x5701,0x5604,0x8004,0x5604,
+ 0x5604,0x5604,0x5604,0x5604,0x5901,0x5901,0x5901,0x5901,0x5704,0x8004,
+ 0x5304,0x5704,0x5504,0x5304,0x5204,0x5201,0x5201,0x5201,0x5201,0x5104,
+ 0x8004,0x5104,0x5104,0x5104,0x5104,0x5104,0x5401,0x5401,0x5401,0x5401,
+ 0x5204,0x8004,0x4201,0x4201,0x4201,0x4201,0x4401,0x4401,0x4401,0x4401,
+ 0x4601,0x4601,0x4601,0x4601,0x4701,0x4701,0x4701,0x4701,0x4901,0x4901,
+ 0x4901,0x4901,0x5001,0x5001,0x5001,0x5001,0x4A04,0x8004,0x4601,0x4601,
+ 0x4601,0x4601,0x4701,0x4701,0x4701,0x4701,0x4901,0x4901,0x4901,0x4901,
+ 0x4A01,0x4A01,0x4A01,0x4A01,0x5101,0x5101,0x5101,0x5101,0x5401,0x5401,
+ 0x5401,0x5401,0x5204,0x8004,0x5201,0x5201,0x5201,0x5201,0x5401,0x5401,
+ 0x5401,0x5401,0x5601,0x5601,0x5601,0x5601,0x5701,0x5701,0x5701,0x5701,
+ 0x5901,0x5901,0x5901,0x5901,0x5A01,0x5A01,0x5A01,0x5A01,0x5A01,0x5A01,
+ 0x5A01,0x5A01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,
+ 0x6001,0x6001,0x6001,0x6001,0x6001,0x6001,0x6001,0x6001,0x6108,0x6201,
+ 0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,
+ 0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,
+ 0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,
+ 0x6201,0x6210,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,
+ 0x5601,0x5601,0x5601,0x5601,0x5401,0x5401,0x5602,0x5708,0x8004,0x5204,
+ 0x5708,0x8004,0x5204,0x5704,0x5204,0x5704,0x5B04,0x6208,0x8008,0x6008,
+ 0x8004,0x5904,0x6008,0x8004,0x5904,0x6004,0x5904,0x5604,0x5904,0x5208,
+ 0x8008,0x5704,0x8004,0x570C,0x5B01,0x5B01,0x5B01,0x5B01,0x5904,0x5704,
+ 0x5701,0x5701,0x5701,0x5701,0x5604,0x560C,0x5901,0x5901,0x5901,0x5901,
+ 0x6004,0x5604,0x5901,0x5901,0x5901,0x5901,0x5704,0x570C,0x5B01,0x5B01,
+ 0x5B01,0x5B01,0x5904,0x5704,0x5701,0x5701,0x5701,0x5701,0x5604,0x560C,
+ 0x5901,0x5901,0x5901,0x5901,0x6004,0x5604,0x5704,0x5704,0x5601,0x5601,
+ 0x5601,0x5601,0x5401,0x5401,0x5602,0x5704,0x5704,0x5901,0x5901,0x5901,
+ 0x5901,0x5701,0x5701,0x5902,0x5B04,0x5B04,0x6001,0x6001,0x6001,0x6001,
+ 0x5B01,0x5B01,0x6001,0x6001,0x6208,0x8008,0x5201,0x5201,0x5201,0x5201,
+ 0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,
+ 0x5201,0x5201,0x5410,0x5008,0x5008,0x4B08,0x4B08,0x4908,0x4908,0x4701,
+ 0x4701,0x4701,0x4701,0x4604,0x4404,0x4604,0x4704,0x8004,0x4904,0x8004,
+ 0x4B04,0x800C,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,
+ 0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5410,0x5201,
+ 0x5201,0x5201,0x5201,0x5004,0x5004,0x5004,0x5001,0x5001,0x5001,0x5001,
+ 0x4B04,0x4B04,0x4B04,0x4B01,0x4B01,0x4B01,0x4B01,0x4904,0x4904,0x4904,
+ 0x4701,0x4701,0x4701,0x4701,0x4604,0x4404,0x4604,0x4714,0x4701,0x4701,
+ 0x4601,0x4701,0x4901,0x4901,0x4901,0x4901,0x4604,0x4B14,0x4B01,0x4B01,
+ 0x4901,0x4B01,0x5001,0x5001,0x5001,0x5001,0x4904,0x5210,0x5408,0x5608,
+ 0x5708,0x5908,0x5B08,0x5108,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,
+ 0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x5904,0x6101,0x6101,0x6101,
+ 0x6101,0x6101,0x6101,0x5902,0x5101,0x5101,0x5101,0x5101,0x5101,0x5101,
+ 0x5902,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,
+ 0x6201,0x6201,0x6201,0x5904,0x6101,0x6101,0x6101,0x6101,0x6101,0x6101,
+ 0x5902,0x5101,0x5101,0x5101,0x5101,0x5101,0x5101,0x5902,0x6204,0x5904,
+ 0x6104,0x5904,0x6204,0x5904,0x6104,0x5904,0x6204,0x4204,0x4204,0x4204,
+ 0x4208,0x8008,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,
+ 0x5201,0x5201,0x5001,0x5001,0x4B01,0x4B01,0x4901,0x4901,0x4704,0x8004,
+ 0x5404,0x8004,0x5004,0x8004,0x4904,0x8004,0x5204,0x800C,0x5B01,0x5B01,
+ 0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5901,0x5901,
+ 0x5701,0x5701,0x5601,0x5601,0x5404,0x8004,0x6004,0x8004,0x5B01,0x5B01,
+ 0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,
+ 0x5B01,0x5B01,0x5B01,0x5B01,0x5908,0x8008,0x8004,0x6204,0x6204,0x6204,
+ 0x6204,0x6204,0x6204,0x6204,0x6204,0x6204,0x6204,0x6204,0x6201,0x6201,
+ 0x6201,0x6201,0x6001,0x6001,0x6001,0x6001,0x5901,0x5901,0x5901,0x5901,
+ 0x5604,0x5601,0x5601,0x5601,0x5601,0x5704,0x8004,0x5404,0x5401,0x5401,
+ 0x5401,0x5401,0x5204,0x8004,0x4604,0x4708,0x8004,0x5204,0x5701,0x5701,
+ 0x5701,0x5701,0x5601,0x5601,0x5601,0x5601,0x5401,0x5401,0x5401,0x5401,
+ 0x5204,0x5401,0x5401,0x5401,0x5401,0x5204,0x8004,0x5204,0x5204,0x5204,
+ 0x5204,0x5204,0x5401,0x5401,0x5401,0x5401,0x5204,0x8004,0x5204,0x5704,
+ 0x5604,0x5404,0x5204,0x5401,0x5401,0x5401,0x5401,0x5204,0x8004,0x5204,
+ 0x5204,0x5204,0x5204,0x5204,0x5401,0x5401,0x5401,0x5401,0x5204,0x8008,
+ 0x540A,0x5201,0x5201,0x5001,0x5001,0x4B01,0x4B01,0x5008,0x8008,0x520A,
+ 0x5001,0x5001,0x4B01,0x4B01,0x4901,0x4901,0x4B08,0x8008,0x5401,0x5401,
+ 0x5401,0x5401,0x5601,0x5601,0x5701,0x5701,0x5604,0x5404,0x5401,0x5401,
+ 0x5401,0x5401,0x5204,0x4B04,0x5204,0x5201,0x5201,0x5201,0x5201,0x5004,
+ 0x4B04,0x4904,0x4708,0x8004,0x5204,0x5701,0x5701,0x5701,0x5701,0x5601,
+ 0x5601,0x5601,0x5601,0x5401,0x5401,0x5401,0x5401,0x5204,0x5401,0x5401,
+ 0x5401,0x5401,0x5204,0x8004,0x5204,0x5204,0x5204,0x5204,0x5204,0x5401,
+ 0x5401,0x5401,0x5401,0x5204,0x8004,0x5204,0x5701,0x5701,0x5701,0x5701,
+ 0x5601,0x5601,0x5601,0x5601,0x5401,0x5401,0x5401,0x5401,0x5204,0x5401,
+ 0x5401,0x5401,0x5401,0x5204,0x8004,0x5204,0x5204,0x5204,0x5204,0x5204,
+ 0x5401,0x5401,0x5401,0x5401,0x5204,0x8008,0x640A,0x6201,0x6201,0x6001,
+ 0x6001,0x5B01,0x5B01,0x6008,0x8008,0x620A,0x6001,0x6001,0x5B01,0x5B01,
+ 0x5901,0x5901,0x5B08,0x8008,0x5401,0x5401,0x5401,0x5401,0x5601,0x5601,
+ 0x5701,0x5701,0x5604,0x5404,0x5204,0x5704,0x5B04,0x6204,0x6201,0x6201,
+ 0x6201,0x6201,0x6004,0x5B04,0x5904,0x5704,0x4204,0x4404,0x4604,0x4704,
+ 0x4704,0x4901,0x4901,0x4901,0x4901,0x4701,0x4701,0x4901,0x4901,0x4B04,
+ 0x4604,0x4704,0x4904,0x4B04,0x4B04,0x5001,0x5001,0x5001,0x5001,0x4B01,
+ 0x4B01,0x5001,0x5001,0x5204,0x5204,0x5301,0x5301,0x5301,0x5301,0x5101,
+ 0x5101,0x5301,0x5301,0x5408,0x8008,0x440C,0x4904,0x4704,0x4604,0x4404,
+ 0x4204,0x5201,0x5201,0x5201,0x5201,0x5101,0x5101,0x5101,0x5101,0x5001,
+ 0x5001,0x5001,0x5001,0x4B01,0x4B01,0x4B01,0x4B01,0x5201,0x5201,0x5201,
+ 0x5201,0x5101,0x5101,0x5101,0x5101,0x5001,0x5001,0x5001,0x5001,0x4B04,
+ 0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,
+ 0x4401,0x4401,0x4904,0x4701,0x4701,0x4701,0x4701,0x4601,0x4601,0x4601,
+ 0x4601,0x4401,0x4401,0x4401,0x4401,0x4204,0x5201,0x5201,0x5201,0x5201,
+ 0x5401,0x5401,0x5401,0x5401,0x5601,0x5601,0x5601,0x5601,0x5701,0x5701,
+ 0x5701,0x5701,0x5201,0x5201,0x5201,0x5201,0x5401,0x5401,0x5401,0x5401,
+ 0x5601,0x5601,0x5601,0x5601,0x5704,0x5908,0x8008,0x6208,0x8008,0x5708,
+ 0x8004,0x5204,0x4B04,0x4704,0x4B04,0x5204,0x5704,0x5204,0x5704,0x5B04,
+ 0x6208,0x5608,0x5708,0x8004,0x5204,0x4B04,0x4704,0x4B04,0x5204,0x5704,
+ 0x5204,0x5704,0x5B04,0x6208,0x5608,0x5708,0x8008,0x5708,0x8008,0x5708,
+ 0x4706,0x4702,0x4708,0x8008,0x5208,0x8004,0x4904,0x5208,0x8004,0x4904,
+ 0x5204,0x4904,0x5204,0x5604,0x5908,0x8008,0x5908,0x8004,0x5604,0x5908,
+ 0x8004,0x5604,0x5904,0x5604,0x5304,0x5604,0x4B08,0x8014,0x5704,0x6001,
+ 0x6001,0x6001,0x6001,0x5B01,0x5B01,0x5B01,0x5B01,0x5901,0x5901,0x5901,
+ 0x5901,0x5704,0x5901,0x5901,0x5901,0x5901,0x5704,0x8004,0x5704,0x5704,
+ 0x5704,0x5704,0x5704,0x5901,0x5901,0x5901,0x5901,0x5704,0x8004,0x5704,
+ 0x6001,0x6001,0x6001,0x6001,0x5B01,0x5B01,0x5B01,0x5B01,0x5901,0x5901,
+ 0x5901,0x5901,0x5704,0x5901,0x5901,0x5901,0x5901,0x5704,0x8004,0x5704,
+ 0x5704,0x5704,0x5704,0x5704,0x5901,0x5901,0x5901,0x5901,0x5704,0x8004,
+ 0x5704,0x6001,0x6001,0x6001,0x6001,0x5B01,0x5B01,0x5B01,0x5B01,0x5901,
+ 0x5901,0x5901,0x5901,0x5704,0x5901,0x5901,0x5901,0x5901,0x5804,0x8004,
+ 0x5804,0x5804,0x5804,0x5804,0x5804,0x5B01,0x5B01,0x5B01,0x5B01,0x5904,
+ 0x8004,0x5904,0x6001,0x6001,0x6001,0x6001,0x5A01,0x5A01,0x5A01,0x5A01,
+ 0x5901,0x5901,0x5901,0x5901,0x5704,0x5701,0x5701,0x5701,0x5701,0x5604,
+ 0x8004,0x5604,0x5604,0x5604,0x5604,0x5604,0x5901,0x5901,0x5901,0x5901,
+ 0x5704,0x8004,0x5304,0x5704,0x5504,0x5304,0x5204,0x5201,0x5201,0x5201,
+ 0x5201,0x5104,0x8004,0x5104,0x5104,0x5104,0x5104,0x5104,0x5401,0x5401,
+ 0x5401,0x5401,0x5204,0x8004,0x4201,0x4201,0x4201,0x4201,0x4401,0x4401,
+ 0x4401,0x4401,0x4601,0x4601,0x4601,0x4601,0x4701,0x4701,0x4701,0x4701,
+ 0x4901,0x4901,0x4901,0x4901,0x5001,0x5001,0x5001,0x5001,0x4A04,0x8004,
+ 0x4601,0x4601,0x4601,0x4601,0x4701,0x4701,0x4701,0x4701,0x4901,0x4901,
+ 0x4901,0x4901,0x4A01,0x4A01,0x4A01,0x4A01,0x5101,0x5101,0x5101,0x5101,
+ 0x5401,0x5401,0x5401,0x5401,0x5204,0x8004,0x5201,0x5201,0x5201,0x5201,
+ 0x5401,0x5401,0x5401,0x5401,0x5601,0x5601,0x5601,0x5601,0x5701,0x5701,
+ 0x5701,0x5701,0x5901,0x5901,0x5901,0x5901,0x5A01,0x5A01,0x5A01,0x5A01,
+ 0x5A01,0x5A01,0x5A01,0x5A01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,
+ 0x5B01,0x5B01,0x6001,0x6001,0x6001,0x6001,0x6001,0x6001,0x6001,0x6001,
+ 0x6108,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,
+ 0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,
+ 0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,
+ 0x6201,0x6201,0x6201,0x6210,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,
+ 0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5401,0x5401,0x5602,0x5708,
+ 0x8004,0x5204,0x5708,0x8004,0x5204,0x5704,0x5204,0x5704,0x5B04,0x6208,
+ 0x8008,0x6008,0x8004,0x5904,0x6008,0x8004,0x5904,0x6004,0x5904,0x5604,
+ 0x5904,0x5208,0x8008,0x5704,0x8004,0x570C,0x5B01,0x5B01,0x5B01,0x5B01,
+ 0x5904,0x5704,0x5701,0x5701,0x5701,0x5701,0x5604,0x560C,0x5901,0x5901,
+ 0x5901,0x5901,0x6004,0x5604,0x5901,0x5901,0x5901,0x5901,0x5704,0x570C,
+ 0x5B01,0x5B01,0x5B01,0x5B01,0x5904,0x5704,0x5701,0x5701,0x5701,0x5701,
+ 0x5604,0x560C,0x5901,0x5901,0x5901,0x5901,0x6004,0x5604,0x5704,0x5704,
+ 0x5601,0x5601,0x5601,0x5601,0x5401,0x5401,0x5602,0x5704,0x5704,0x5901,
+ 0x5901,0x5901,0x5901,0x5701,0x5701,0x5902,0x5B04,0x5B04,0x6001,0x6001,
+ 0x6001,0x6001,0x5B01,0x5B01,0x6001,0x6001,0x6208,0x8008,0x5201,0x5201,
+ 0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,
+ 0x5201,0x5201,0x5201,0x5201,0x5410,0x5008,0x5008,0x4B08,0x4B08,0x4908,
+ 0x4908,0x4701,0x4701,0x4701,0x4701,0x4604,0x4404,0x4604,0x4704,0x8004,
+ 0x4904,0x8004,0x4B04,0x800C,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,
+ 0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,
+ 0x5410,0x5201,0x5201,0x5201,0x5201,0x5004,0x5004,0x5004,0x5001,0x5001,
+ 0x5001,0x5001,0x4B04,0x4B04,0x4B04,0x4B01,0x4B01,0x4B01,0x4B01,0x4904,
+ 0x4904,0x4904,0x4701,0x4701,0x4701,0x4701,0x4604,0x4404,0x4604,0x4714,
+ 0x4701,0x4701,0x4601,0x4701,0x4901,0x4901,0x4901,0x4901,0x4604,0x4B14,
+ 0x4B01,0x4B01,0x4901,0x4B01,0x5001,0x5001,0x5001,0x5001,0x4904,0x5210,
+ 0x5408,0x5608,0x5708,0x5908,0x5B08,0x5108,0x6201,0x6201,0x6201,0x6201,
+ 0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x5904,0x6101,
+ 0x6101,0x6101,0x6101,0x6101,0x6101,0x5902,0x5101,0x5101,0x5101,0x5101,
+ 0x5101,0x5101,0x5902,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,0x6201,
+ 0x6201,0x6201,0x6201,0x6201,0x6201,0x5904,0x6101,0x6101,0x6101,0x6101,
+ 0x6101,0x6101,0x5902,0x5101,0x5101,0x5101,0x5101,0x5101,0x5101,0x5902,
+ 0x6204,0x5904,0x6104,0x5904,0x6204,0x5904,0x6104,0x5904,0x6204,0x4204,
+ 0x4204,0x4204,0x4208,0x8008,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,
+ 0x5201,0x5201,0x5201,0x5201,0x5001,0x5001,0x4B01,0x4B01,0x4901,0x4901,
+ 0x4704,0x8004,0x5404,0x8004,0x5004,0x8004,0x4904,0x8004,0x5204,0x800C,
+ 0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,
+ 0x5901,0x5901,0x5701,0x5701,0x5601,0x5601,0x5404,0x8004,0x6004,0x8004,
+ 0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,
+ 0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5B01,0x5908,0x8008,0x8004,0x6204,
+ 0x6204,0x6204,0x6204,0x6204,0x6204,0x6204,0x6204,0x6204,0x6204,0x6204,
+ 0x6201,0x6201,0x6201,0x6201,0x6001,0x6001,0x6001,0x6001,0x5901,0x5901,
+ 0x5901,0x5901,0x5604,0x5601,0x5601,0x5601,0x5601,0x5704,0x8004,0x5404,
+ 0x5401,0x5401,0x5401,0x5401,0x5204,0x8004,0x4604,0x4708,0x8004,0x5204,
+ 0x5701,0x5701,0x5701,0x5701,0x5601,0x5601,0x5601,0x5601,0x5401,0x5401,
+ 0x5401,0x5401,0x5204,0x5401,0x5401,0x5401,0x5401,0x5204,0x8004,0x5204,
+ 0x5204,0x5204,0x5204,0x5204,0x5401,0x5401,0x5401,0x5401,0x5204,0x8004,
+ 0x5204,0x5704,0x5604,0x5404,0x5204,0x5401,0x5401,0x5401,0x5401,0x5204,
+ 0x8004,0x5204,0x5204,0x5204,0x5204,0x5204,0x5401,0x5401,0x5401,0x5401,
+ 0x5204,0x8008,0x540A,0x5201,0x5201,0x5001,0x5001,0x4B01,0x4B01,0x5008,
+ 0x8008,0x520A,0x5001,0x5001,0x4B01,0x4B01,0x4901,0x4901,0x4B08,0x8008,
+ 0x5401,0x5401,0x5401,0x5401,0x5601,0x5601,0x5701,0x5701,0x5604,0x5404,
+ 0x5401,0x5401,0x5401,0x5401,0x5204,0x4B04,0x5204,0x5201,0x5201,0x5201,
+ 0x5201,0x5004,0x4B04,0x4904,0x4708,0x8004,0x5204,0x5701,0x5701,0x5701,
+ 0x5701,0x5601,0x5601,0x5601,0x5601,0x5401,0x5401,0x5401,0x5401,0x5204,
+ 0x5401,0x5401,0x5401,0x5401,0x5204,0x8004,0x5204,0x5204,0x5204,0x5204,
+ 0x5204,0x5401,0x5401,0x5401,0x5401,0x5204,0x8004,0x5204,0x5701,0x5701,
+ 0x5701,0x5701,0x5601,0x5601,0x5601,0x5601,0x5401,0x5401,0x5401,0x5401,
+ 0x5204,0x5401,0x5401,0x5401,0x5401,0x5204,0x8004,0x5204,0x5204,0x5204,
+ 0x5204,0x5204,0x5401,0x5401,0x5401,0x5401,0x5204,0x8008,0x640A,0x6201,
+ 0x6201,0x6001,0x6001,0x5B01,0x5B01,0x6008,0x8008,0x620A,0x6001,0x6001,
+ 0x5B01,0x5B01,0x5901,0x5901,0x5B08,0x8008,0x5401,0x5401,0x5401,0x5401,
+ 0x5601,0x5601,0x5701,0x5701,0x5604,0x5404,0x5204,0x5704,0x5B04,0x6204,
+ 0x6201,0x6201,0x6201,0x6201,0x6004,0x5B04,0x5904,0x5704,0x4204,0x4404,
+ 0x4604,0x4704,0x4704,0x4901,0x4901,0x4901,0x4901,0x4701,0x4701,0x4901,
+ 0x4901,0x4B04,0x4604,0x4704,0x4904,0x4B04,0x4B04,0x5001,0x5001,0x5001,
+ 0x5001,0x4B01,0x4B01,0x5001,0x5001,0x5204,0x5204,0x5301,0x5301,0x5301,
+ 0x5301,0x5101,0x5101,0x5301,0x5301,0x5408,0x8008,0x440C,0x4904,0x4704,
+ 0x4604,0x4404,0x4204,0x5201,0x5201,0x5201,0x5201,0x5101,0x5101,0x5101,
+ 0x5101,0x5001,0x5001,0x5001,0x5001,0x4B01,0x4B01,0x4B01,0x4B01,0x5201,
+ 0x5201,0x5201,0x5201,0x5101,0x5101,0x5101,0x5101,0x5001,0x5001,0x5001,
+ 0x5001,0x4B04,0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,
+ 0x4401,0x4401,0x4401,0x4401,0x4904,0x4701,0x4701,0x4701,0x4701,0x4601,
+ 0x4601,0x4601,0x4601,0x4401,0x4401,0x4401,0x4401,0x4204,0x5201,0x5201,
+ 0x5201,0x5201,0x5401,0x5401,0x5401,0x5401,0x5601,0x5601,0x5601,0x5601,
+ 0x5701,0x5701,0x5701,0x5701,0x5201,0x5201,0x5201,0x5201,0x5401,0x5401,
+ 0x5401,0x5401,0x5601,0x5601,0x5601,0x5601,0x5704,0x5908,0x8008,0x6208,
+ 0x8008,0x5708,0x8004,0x5204,0x4B04,0x4704,0x4B04,0x5204,0x5704,0x5204,
+ 0x5704,0x5B04,0x6208,0x5608,0x5708,0x8004,0x5204,0x4B04,0x4704,0x4B04,
+ 0x5204,0x5704,0x5204,0x5704,0x5B04,0x6208,0x5608,0x5708,0x8008,0x5708,
+ 0x8008,0x5708,0x4706,0x4702,0x4708,0x8008,
+ 0x0000
+};
+
+static int Voice2 [] = {
+ 0x4708,0x8004,0x4204,0x4708,0x8004,0x4204,0x4704,0x4204,0x4704,0x4B04,
+ 0x5208,0x8008,0x5008,0x8004,0x4904,0x5008,0x8004,0x4904,0x5004,0x4904,
+ 0x4604,0x4904,0x4208,0x8008,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,
+ 0x4704,0x4704,0x4904,0x4904,0x4904,0x4904,0x4901,0x4901,0x4901,0x4901,
+ 0x5004,0x4601,0x4601,0x4601,0x4601,0x4904,0x4704,0x4704,0x4704,0x4704,
+ 0x4704,0x4704,0x4704,0x4704,0x4904,0x4904,0x4904,0x4904,0x4901,0x4901,
+ 0x4901,0x4901,0x5004,0x4601,0x4601,0x4601,0x4601,0x4904,0x4210,0x4210,
+ 0x4210,0x4208,0x8028,0x3610,0x3710,0x4008,0x4008,0x3908,0x3208,0x3204,
+ 0x8004,0x4204,0x8004,0x4208,0x8028,0x4601,0x4601,0x4601,0x4601,0x4601,
+ 0x4601,0x4601,0x4601,0x4601,0x4601,0x4601,0x4601,0x4601,0x4601,0x4601,
+ 0x4601,0x4710,0x4008,0x4004,0x4004,0x3908,0x3904,0x3904,0x3704,0x3704,
+ 0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,
+ 0x3704,0x3704,0x3704,0x3704,0x3704,0x4704,0x4704,0x4704,0x4704,0x4704,
+ 0x4904,0x4904,0x4704,0x4704,0x4604,0x4604,0x4704,0x4704,0x4404,0x4404,
+ 0x4210,0x4410,0x4210,0x4410,0x4604,0x4704,0x4904,0x4704,0x4604,0x4704,
+ 0x4904,0x4604,0x4B04,0x4904,0x4704,0x4904,0x4B04,0x4904,0x4804,0x4B04,
+ 0x4904,0x4904,0x4904,0x4904,0x4904,0x4904,0x4904,0x4904,0x4904,0x3904,
+ 0x3904,0x3904,0x3908,0x8020,0x4604,0x8004,0x3B04,0x8004,0x4704,0x8004,
+ 0x4404,0x8004,0x4104,0x800C,0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,
+ 0x4401,0x4401,0x4204,0x8004,0x4404,0x8004,0x4201,0x4201,0x4201,0x4201,
+ 0x4201,0x4201,0x4201,0x4201,0x4201,0x4201,0x4201,0x4201,0x4201,0x4201,
+ 0x4201,0x4201,0x4108,0x8010,0x4101,0x4101,0x4101,0x4101,0x4101,0x4101,
+ 0x4101,0x4101,0x4204,0x8004,0x4604,0x8004,0x3B04,0x8004,0x3704,0x8004,
+ 0x3408,0x8004,0x4404,0x4704,0x4604,0x8004,0x5704,0x5701,0x5701,0x5701,
+ 0x5701,0x5604,0x8004,0x4704,0x4204,0x4204,0x4404,0x4404,0x4604,0x4604,
+ 0x4204,0x4204,0x4104,0x4104,0x4204,0x4204,0x4404,0x4404,0x4104,0x4104,
+ 0x4204,0x4204,0x4404,0x4404,0x4604,0x4604,0x4204,0x4204,0x4104,0x4104,
+ 0x4204,0x4204,0x4404,0x4404,0x4104,0x4104,0x4204,0x4204,0x4604,0x4404,
+ 0x4304,0x3B04,0x4104,0x4304,0x4404,0x4704,0x4404,0x4204,0x4104,0x3904,
+ 0x3B04,0x4104,0x5204,0x5204,0x5204,0x5204,0x5204,0x5204,0x5204,0x5204,
+ 0x5204,0x4904,0x4904,0x4904,0x4904,0x4904,0x4904,0x4704,0x4604,0x4204,
+ 0x4404,0x4404,0x4604,0x4604,0x4204,0x4204,0x4104,0x4104,0x4204,0x4204,
+ 0x4404,0x4404,0x4104,0x4104,0x4204,0x4204,0x4404,0x4404,0x4604,0x4604,
+ 0x4204,0x4204,0x4104,0x4104,0x4204,0x4204,0x4404,0x4404,0x4104,0x4104,
+ 0x4204,0x4204,0x4604,0x4404,0x4304,0x3B04,0x4104,0x4304,0x4404,0x4704,
+ 0x4404,0x4204,0x4104,0x3904,0x3B04,0x4104,0x4204,0x5204,0x5204,0x5204,
+ 0x5204,0x5204,0x5204,0x5204,0x5204,0x4904,0x4904,0x4904,0x4904,0x4904,
+ 0x4904,0x4704,0x4604,0x3904,0x3B04,0x4104,0x4204,0x4204,0x4404,0x4404,
+ 0x4604,0x4104,0x4204,0x4404,0x4604,0x4604,0x4704,0x4704,0x4904,0x4904,
+ 0x4A04,0x4A04,0x4B08,0x8008,0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,
+ 0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,
+ 0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,0x4201,0x4201,
+ 0x4201,0x4201,0x4104,0x5204,0x8004,0x5204,0x8004,0x5204,0x800C,0x4708,
+ 0x8004,0x4204,0x4708,0x8004,0x4204,0x4704,0x4204,0x4704,0x4B04,0x5208,
+ 0x8008,0x5008,0x8004,0x4904,0x5008,0x8004,0x4904,0x5004,0x4904,0x4604,
+ 0x4904,0x4208,0x8008,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,
+ 0x4704,0x4904,0x4904,0x4904,0x4904,0x4901,0x4901,0x4901,0x4901,0x5004,
+ 0x4601,0x4601,0x4601,0x4601,0x4904,0x4704,0x4704,0x4704,0x4704,0x4704,
+ 0x4704,0x4704,0x4704,0x4904,0x4904,0x4904,0x4904,0x4901,0x4901,0x4901,
+ 0x4901,0x5004,0x4601,0x4601,0x4601,0x4601,0x4904,0x4210,0x4210,0x4210,
+ 0x4208,0x8028,0x3610,0x3710,0x4008,0x4008,0x3908,0x3208,0x3204,0x8004,
+ 0x4204,0x8004,0x4208,0x8028,0x4601,0x4601,0x4601,0x4601,0x4601,0x4601,
+ 0x4601,0x4601,0x4601,0x4601,0x4601,0x4601,0x4601,0x4601,0x4601,0x4601,
+ 0x4710,0x4008,0x4004,0x4004,0x3908,0x3904,0x3904,0x3704,0x3704,0x3704,
+ 0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,
+ 0x3704,0x3704,0x3704,0x3704,0x4704,0x4704,0x4704,0x4704,0x4704,0x4904,
+ 0x4904,0x4704,0x4704,0x4604,0x4604,0x4704,0x4704,0x4404,0x4404,0x4210,
+ 0x4410,0x4210,0x4410,0x4604,0x4704,0x4904,0x4704,0x4604,0x4704,0x4904,
+ 0x4604,0x4B04,0x4904,0x4704,0x4904,0x4B04,0x4904,0x4804,0x4B04,0x4904,
+ 0x4904,0x4904,0x4904,0x4904,0x4904,0x4904,0x4904,0x4904,0x3904,0x3904,
+ 0x3904,0x3908,0x8020,0x4604,0x8004,0x3B04,0x8004,0x4704,0x8004,0x4404,
+ 0x8004,0x4104,0x800C,0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,
+ 0x4401,0x4204,0x8004,0x4404,0x8004,0x4201,0x4201,0x4201,0x4201,0x4201,
+ 0x4201,0x4201,0x4201,0x4201,0x4201,0x4201,0x4201,0x4201,0x4201,0x4201,
+ 0x4201,0x4108,0x8010,0x4101,0x4101,0x4101,0x4101,0x4101,0x4101,0x4101,
+ 0x4101,0x4204,0x8004,0x4604,0x8004,0x3B04,0x8004,0x3704,0x8004,0x3408,
+ 0x8004,0x4404,0x4704,0x4604,0x8004,0x5704,0x5701,0x5701,0x5701,0x5701,
+ 0x5604,0x8004,0x4704,0x4204,0x4204,0x4404,0x4404,0x4604,0x4604,0x4204,
+ 0x4204,0x4104,0x4104,0x4204,0x4204,0x4404,0x4404,0x4104,0x4104,0x4204,
+ 0x4204,0x4404,0x4404,0x4604,0x4604,0x4204,0x4204,0x4104,0x4104,0x4204,
+ 0x4204,0x4404,0x4404,0x4104,0x4104,0x4204,0x4204,0x4604,0x4404,0x4304,
+ 0x3B04,0x4104,0x4304,0x4404,0x4704,0x4404,0x4204,0x4104,0x3904,0x3B04,
+ 0x4104,0x5204,0x5204,0x5204,0x5204,0x5204,0x5204,0x5204,0x5204,0x5204,
+ 0x4904,0x4904,0x4904,0x4904,0x4904,0x4904,0x4704,0x4604,0x4204,0x4404,
+ 0x4404,0x4604,0x4604,0x4204,0x4204,0x4104,0x4104,0x4204,0x4204,0x4404,
+ 0x4404,0x4104,0x4104,0x4204,0x4204,0x4404,0x4404,0x4604,0x4604,0x4204,
+ 0x4204,0x4104,0x4104,0x4204,0x4204,0x4404,0x4404,0x4104,0x4104,0x4204,
+ 0x4204,0x4604,0x4404,0x4304,0x3B04,0x4104,0x4304,0x4404,0x4704,0x4404,
+ 0x4204,0x4104,0x3904,0x3B04,0x4104,0x4204,0x5204,0x5204,0x5204,0x5204,
+ 0x5204,0x5204,0x5204,0x5204,0x4904,0x4904,0x4904,0x4904,0x4904,0x4904,
+ 0x4704,0x4604,0x3904,0x3B04,0x4104,0x4204,0x4204,0x4404,0x4404,0x4604,
+ 0x4104,0x4204,0x4404,0x4604,0x4604,0x4704,0x4704,0x4904,0x4904,0x4A04,
+ 0x4A04,0x4B08,0x8008,0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,
+ 0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,
+ 0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,0x4401,0x4201,0x4201,0x4201,
+ 0x4201,0x4104,0x5204,0x8004,0x5204,0x8004,0x5204,0x800C,0x4208,0x8004,
+ 0x3904,0x4208,0x8004,0x3904,0x4204,0x3904,0x4204,0x4604,0x4908,0x8008,
+ 0x4908,0x8004,0x4604,0x4908,0x8004,0x4604,0x4904,0x4604,0x4304,0x4604,
+ 0x3B08,0x8008,0x4004,0x4004,0x4204,0x4204,0x4404,0x4404,0x4004,0x4004,
+ 0x3B04,0x3B04,0x4004,0x4004,0x4204,0x4204,0x3B04,0x3B04,0x4004,0x4004,
+ 0x4204,0x4204,0x4404,0x4404,0x4004,0x4004,0x3B04,0x3B04,0x4004,0x4004,
+ 0x4204,0x4204,0x3B04,0x3B04,0x4004,0x4004,0x4204,0x4204,0x4404,0x4404,
+ 0x4004,0x4004,0x3B04,0x3B04,0x4004,0x4004,0x4204,0x4204,0x3B04,0x3B04,
+ 0x3904,0x3904,0x3B04,0x3B04,0x4004,0x4004,0x3904,0x3904,0x3904,0x3904,
+ 0x3A04,0x3A04,0x4004,0x4004,0x3904,0x3904,0x3704,0x3704,0x3604,0x3604,
+ 0x3704,0x3704,0x4604,0x4604,0x4704,0x4704,0x4604,0x4604,0x4704,0x3704,
+ 0x3604,0x3704,0x3908,0x8004,0x3201,0x3201,0x3201,0x3201,0x3401,0x3401,
+ 0x3401,0x3401,0x3601,0x3601,0x3601,0x3601,0x3701,0x3701,0x3701,0x3701,
+ 0x3901,0x3901,0x3901,0x3901,0x4001,0x4001,0x4001,0x4001,0x3A04,0x8004,
+ 0x3601,0x3601,0x3601,0x3601,0x3701,0x3701,0x3701,0x3701,0x3901,0x3901,
+ 0x3901,0x3901,0x3A01,0x3A01,0x3A01,0x3A01,0x4101,0x4101,0x4101,0x4101,
+ 0x4401,0x4401,0x4401,0x4401,0x4204,0x8038,0x4B04,0x4B04,0x4B01,0x4B01,
+ 0x4B01,0x4B01,0x5004,0x4904,0x4904,0x4901,0x4901,0x4901,0x4901,0x4B04,
+ 0x4704,0x4704,0x4701,0x4701,0x4701,0x4701,0x4B04,0x4B01,0x4B01,0x4B01,
+ 0x4B01,0x4904,0x4704,0x4204,0x3B08,0x8004,0x4204,0x4708,0x8004,0x4204,
+ 0x4704,0x4204,0x4704,0x4B04,0x5208,0x8008,0x5008,0x8004,0x4904,0x5008,
+ 0x8004,0x4904,0x5004,0x4904,0x4604,0x4904,0x4208,0x8008,0x4704,0x4704,
+ 0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,
+ 0x4701,0x4701,0x4701,0x4701,0x4B04,0x4401,0x4401,0x4401,0x4401,0x4704,
+ 0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,
+ 0x4704,0x4704,0x4701,0x4701,0x4701,0x4701,0x4B04,0x4401,0x4401,0x4401,
+ 0x4401,0x4704,0x4210,0x4210,0x4210,0x4208,0x8028,0x3610,0x3710,0x4008,
+ 0x4008,0x3908,0x3908,0x3204,0x8004,0x4204,0x8004,0x4208,0x8028,0x4601,
+ 0x4601,0x4601,0x4601,0x4601,0x4601,0x4601,0x4601,0x4601,0x4601,0x4601,
+ 0x4601,0x4601,0x4601,0x4601,0x4601,0x4710,0x4008,0x4004,0x4004,0x3908,
+ 0x3904,0x3904,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,
+ 0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x4704,
+ 0x4704,0x4704,0x4704,0x4704,0x4904,0x4904,0x4704,0x4704,0x4604,0x4604,
+ 0x4704,0x4704,0x4404,0x4404,0x4210,0x4410,0x4210,0x4410,0x4208,0x4408,
+ 0x4208,0x4408,0x4204,0x3204,0x3204,0x3204,0x3208,0x8020,0x3B04,0x8004,
+ 0x3404,0x8004,0x4004,0x8004,0x3904,0x8004,0x3604,0x800C,0x4901,0x4901,
+ 0x4901,0x4901,0x4901,0x4901,0x4901,0x4901,0x4704,0x8004,0x4904,0x8004,
+ 0x4B10,0x4908,0x8008,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,
+ 0x5201,0x5201,0x5201,0x5001,0x5001,0x4B01,0x4B01,0x4901,0x4901,0x4704,
+ 0x8004,0x5404,0x8004,0x5004,0x8004,0x4904,0x8004,0x5208,0x8004,0x5004,
+ 0x5001,0x5001,0x5001,0x5001,0x4B04,0x8004,0x5004,0x5001,0x5001,0x5001,
+ 0x5001,0x4B04,0x8004,0x4004,0x3704,0x3704,0x3904,0x3904,0x3B04,0x3B04,
+ 0x3704,0x3704,0x3604,0x3604,0x3704,0x3704,0x3904,0x3904,0x3604,0x3604,
+ 0x3704,0x3704,0x3904,0x3904,0x3B04,0x3B04,0x3704,0x3704,0x3604,0x3604,
+ 0x3704,0x3704,0x3904,0x3904,0x3604,0x3604,0x3704,0x4704,0x4B04,0x4904,
+ 0x4804,0x4404,0x4604,0x4804,0x4904,0x5004,0x4904,0x4704,0x4604,0x4204,
+ 0x4404,0x4604,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,
+ 0x4704,0x4204,0x4204,0x4204,0x4204,0x4204,0x4204,0x4004,0x3B04,0x3704,
+ 0x3904,0x3904,0x3B04,0x3B04,0x3704,0x3704,0x3604,0x3604,0x3704,0x3704,
+ 0x3904,0x3904,0x3604,0x3604,0x3704,0x4704,0x4904,0x4904,0x4B04,0x4B04,
+ 0x4704,0x4704,0x4604,0x4604,0x4704,0x4704,0x4904,0x4904,0x4604,0x4604,
+ 0x4704,0x4704,0x4B04,0x4904,0x4804,0x4404,0x4604,0x4804,0x4904,0x5004,
+ 0x4904,0x4704,0x4604,0x4204,0x4404,0x4604,0x4704,0x4704,0x4704,0x4704,
+ 0x4704,0x4704,0x4704,0x4704,0x4701,0x4701,0x4701,0x4701,0x4904,0x5004,
+ 0x5004,0x5004,0x5004,0x5004,0x4B04,0x4904,0x4204,0x4404,0x4604,0x4704,
+ 0x4704,0x4904,0x4904,0x4B04,0x3604,0x3704,0x3904,0x3B04,0x3B04,0x4004,
+ 0x4004,0x4004,0x4004,0x4104,0x4104,0x4208,0x8008,0x3901,0x3901,0x3901,
+ 0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,
+ 0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,
+ 0x3901,0x3701,0x3701,0x3701,0x3701,0x3604,0x3708,0x8018,0x3901,0x3901,
+ 0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,
+ 0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,
+ 0x3901,0x3901,0x3701,0x3701,0x3701,0x3701,0x3604,0x3708,0x8008,0x4708,
+ 0x8008,0x4408,0x8008,0x4708,0x8008,0x3710,0x3710,0x3710,0x3708,0x3908,
+ 0x3710,0x3710,0x3710,0x3708,0x3908,0x3704,0x3B04,0x4204,0x4704,0x4B04,
+ 0x4704,0x5204,0x4B04,0x4708,0x3706,0x3702,0x3708,0x8008,0x4208,0x8004,
+ 0x3904,0x4208,0x8004,0x3904,0x4204,0x3904,0x4204,0x4604,0x4908,0x8008,
+ 0x4908,0x8004,0x4604,0x4908,0x8004,0x4604,0x4904,0x4604,0x4304,0x4604,
+ 0x3B08,0x8008,0x4004,0x4004,0x4204,0x4204,0x4404,0x4404,0x4004,0x4004,
+ 0x3B04,0x3B04,0x4004,0x4004,0x4204,0x4204,0x3B04,0x3B04,0x4004,0x4004,
+ 0x4204,0x4204,0x4404,0x4404,0x4004,0x4004,0x3B04,0x3B04,0x4004,0x4004,
+ 0x4204,0x4204,0x3B04,0x3B04,0x4004,0x4004,0x4204,0x4204,0x4404,0x4404,
+ 0x4004,0x4004,0x3B04,0x3B04,0x4004,0x4004,0x4204,0x4204,0x3B04,0x3B04,
+ 0x3904,0x3904,0x3B04,0x3B04,0x4004,0x4004,0x3904,0x3904,0x3904,0x3904,
+ 0x3A04,0x3A04,0x4004,0x4004,0x3904,0x3904,0x3704,0x3704,0x3604,0x3604,
+ 0x3704,0x3704,0x4604,0x4604,0x4704,0x4704,0x4604,0x4604,0x4704,0x3704,
+ 0x3604,0x3704,0x3908,0x8004,0x3201,0x3201,0x3201,0x3201,0x3401,0x3401,
+ 0x3401,0x3401,0x3601,0x3601,0x3601,0x3601,0x3701,0x3701,0x3701,0x3701,
+ 0x3901,0x3901,0x3901,0x3901,0x4001,0x4001,0x4001,0x4001,0x3A04,0x8004,
+ 0x3601,0x3601,0x3601,0x3601,0x3701,0x3701,0x3701,0x3701,0x3901,0x3901,
+ 0x3901,0x3901,0x3A01,0x3A01,0x3A01,0x3A01,0x4101,0x4101,0x4101,0x4101,
+ 0x4401,0x4401,0x4401,0x4401,0x4204,0x8038,0x4B04,0x4B04,0x4B01,0x4B01,
+ 0x4B01,0x4B01,0x5004,0x4904,0x4904,0x4901,0x4901,0x4901,0x4901,0x4B04,
+ 0x4704,0x4704,0x4701,0x4701,0x4701,0x4701,0x4B04,0x4B01,0x4B01,0x4B01,
+ 0x4B01,0x4904,0x4704,0x4204,0x3B08,0x8004,0x4204,0x4708,0x8004,0x4204,
+ 0x4704,0x4204,0x4704,0x4B04,0x5208,0x8008,0x5008,0x8004,0x4904,0x5008,
+ 0x8004,0x4904,0x5004,0x4904,0x4604,0x4904,0x4208,0x8008,0x4704,0x4704,
+ 0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,
+ 0x4701,0x4701,0x4701,0x4701,0x4B04,0x4401,0x4401,0x4401,0x4401,0x4704,
+ 0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,
+ 0x4704,0x4704,0x4701,0x4701,0x4701,0x4701,0x4B04,0x4401,0x4401,0x4401,
+ 0x4401,0x4704,0x4210,0x4210,0x4210,0x4208,0x8028,0x3610,0x3710,0x4008,
+ 0x4008,0x3908,0x3908,0x3204,0x8004,0x4204,0x8004,0x4208,0x8028,0x4601,
+ 0x4601,0x4601,0x4601,0x4601,0x4601,0x4601,0x4601,0x4601,0x4601,0x4601,
+ 0x4601,0x4601,0x4601,0x4601,0x4601,0x4710,0x4008,0x4004,0x4004,0x3908,
+ 0x3904,0x3904,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,
+ 0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x4704,
+ 0x4704,0x4704,0x4704,0x4704,0x4904,0x4904,0x4704,0x4704,0x4604,0x4604,
+ 0x4704,0x4704,0x4404,0x4404,0x4210,0x4410,0x4210,0x4410,0x4208,0x4408,
+ 0x4208,0x4408,0x4204,0x3204,0x3204,0x3204,0x3208,0x8020,0x3B04,0x8004,
+ 0x3404,0x8004,0x4004,0x8004,0x3904,0x8004,0x3604,0x800C,0x4901,0x4901,
+ 0x4901,0x4901,0x4901,0x4901,0x4901,0x4901,0x4704,0x8004,0x4904,0x8004,
+ 0x4B10,0x4908,0x8008,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,0x5201,
+ 0x5201,0x5201,0x5201,0x5001,0x5001,0x4B01,0x4B01,0x4901,0x4901,0x4704,
+ 0x8004,0x5404,0x8004,0x5004,0x8004,0x4904,0x8004,0x5208,0x8004,0x5004,
+ 0x5001,0x5001,0x5001,0x5001,0x4B04,0x8004,0x5004,0x5001,0x5001,0x5001,
+ 0x5001,0x4B04,0x8004,0x4004,0x3704,0x3704,0x3904,0x3904,0x3B04,0x3B04,
+ 0x3704,0x3704,0x3604,0x3604,0x3704,0x3704,0x3904,0x3904,0x3604,0x3604,
+ 0x3704,0x3704,0x3904,0x3904,0x3B04,0x3B04,0x3704,0x3704,0x3604,0x3604,
+ 0x3704,0x3704,0x3904,0x3904,0x3604,0x3604,0x3704,0x4704,0x4B04,0x4904,
+ 0x4804,0x4404,0x4604,0x4804,0x4904,0x5004,0x4904,0x4704,0x4604,0x4204,
+ 0x4404,0x4604,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,0x4704,
+ 0x4704,0x4204,0x4204,0x4204,0x4204,0x4204,0x4204,0x4004,0x3B04,0x3704,
+ 0x3904,0x3904,0x3B04,0x3B04,0x3704,0x3704,0x3604,0x3604,0x3704,0x3704,
+ 0x3904,0x3904,0x3604,0x3604,0x3704,0x4704,0x4904,0x4904,0x4B04,0x4B04,
+ 0x4704,0x4704,0x4604,0x4604,0x4704,0x4704,0x4904,0x4904,0x4604,0x4604,
+ 0x4704,0x4704,0x4B04,0x4904,0x4804,0x4404,0x4604,0x4804,0x4904,0x5004,
+ 0x4904,0x4704,0x4604,0x4204,0x4404,0x4604,0x4704,0x4704,0x4704,0x4704,
+ 0x4704,0x4704,0x4704,0x4704,0x4701,0x4701,0x4701,0x4701,0x4904,0x5004,
+ 0x5004,0x5004,0x5004,0x5004,0x4B04,0x4904,0x4204,0x4404,0x4604,0x4704,
+ 0x4704,0x4904,0x4904,0x4B04,0x3604,0x3704,0x3904,0x3B04,0x3B04,0x4004,
+ 0x4004,0x4004,0x4004,0x4104,0x4104,0x4208,0x8008,0x3901,0x3901,0x3901,
+ 0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,
+ 0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,
+ 0x3901,0x3701,0x3701,0x3701,0x3701,0x3604,0x3708,0x8018,0x3901,0x3901,
+ 0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,
+ 0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,
+ 0x3901,0x3901,0x3701,0x3701,0x3701,0x3701,0x3604,0x3708,0x8008,0x4708,
+ 0x8008,0x4408,0x8008,0x4708,0x8008,0x3710,0x3710,0x3710,0x3708,0x3908,
+ 0x3710,0x3710,0x3710,0x3708,0x3908,0x3704,0x3B04,0x4204,0x4704,0x4B04,
+ 0x4704,0x5204,0x4B04,0x4708,0x3706,0x3702,0x3708,0x8008,
+ 0x0000
+};
+
+static int Voice3 [] = {
+ 0x3708,0x8004,0x3204,0x3708,0x8004,0x3204,0x3704,0x3204,0x3704,0x3B04,
+ 0x3208,0x8008,0x4008,0x8004,0x3904,0x4008,0x8004,0x3904,0x4004,0x3904,
+ 0x3604,0x4904,0x4208,0x8008,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,
+ 0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,
+ 0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,
+ 0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3904,0x3904,
+ 0x3B04,0x3B04,0x3604,0x3604,0x3704,0x3704,0x3904,0x3904,0x3B08,0x8028,
+ 0x3210,0x3410,0x3008,0x3008,0x3208,0x3208,0x2B04,0x8004,0x3204,0x8004,
+ 0x3708,0x8008,0x4B10,0x5010,0x3201,0x3201,0x3201,0x3201,0x3201,0x3201,
+ 0x3201,0x3201,0x3201,0x3201,0x3201,0x3201,0x3201,0x3201,0x3201,0x3201,
+ 0x3410,0x3008,0x3008,0x3208,0x3208,0x3B14,0x3B02,0x3901,0x3B01,0x4004,
+ 0x3904,0x4714,0x4702,0x4601,0x4701,0x4904,0x4604,0x3704,0x3704,0x3704,
+ 0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3604,0x3604,0x3704,
+ 0x3704,0x3404,0x3404,0x3204,0x3204,0x3204,0x3204,0x3204,0x3204,0x3204,
+ 0x3204,0x3204,0x3204,0x3204,0x3204,0x3204,0x3204,0x3204,0x3204,0x3204,
+ 0x3404,0x3604,0x3404,0x3204,0x3404,0x3604,0x3204,0x3704,0x3904,0x3B04,
+ 0x3904,0x3704,0x3904,0x3B04,0x3804,0x3904,0x3904,0x3904,0x3904,0x3904,
+ 0x3904,0x3904,0x3904,0x3904,0x2904,0x2904,0x2904,0x2908,0x8008,0x490A,
+ 0x4702,0x4602,0x4402,0x4204,0x8004,0x3304,0x8004,0x3404,0x8004,0x3204,
+ 0x8004,0x3104,0x8004,0x2904,0x800C,0x2A01,0x2A01,0x2A01,0x2A01,0x2A01,
+ 0x2A01,0x2A01,0x2A01,0x2B04,0x8004,0x2704,0x8004,0x2908,0x3901,0x3901,
+ 0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,
+ 0x3801,0x3801,0x3801,0x3801,0x3701,0x3701,0x3701,0x3701,0x3401,0x3401,
+ 0x3401,0x3401,0x3204,0x8004,0x3404,0x8004,0x3604,0x8004,0x3304,0x8004,
+ 0x3404,0x8004,0x3204,0x8004,0x3104,0x8004,0x2904,0x8004,0x2B04,0x8004,
+ 0x3704,0x8004,0x3904,0x8004,0x2904,0x8004,0x4604,0x4604,0x4704,0x4704,
+ 0x4904,0x4904,0x4604,0x4604,0x4404,0x4404,0x4604,0x4604,0x4704,0x4704,
+ 0x4404,0x4404,0x4604,0x4604,0x4704,0x4704,0x4904,0x4904,0x4604,0x4604,
+ 0x4404,0x4404,0x4604,0x4604,0x4704,0x4704,0x4404,0x4404,0x4608,0x8008,
+ 0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,
+ 0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5408,0x8008,0x5401,0x5401,
+ 0x5401,0x5401,0x5401,0x5401,0x5401,0x5401,0x5401,0x5401,0x5401,0x5401,
+ 0x5401,0x5401,0x5401,0x5401,0x5204,0x5604,0x5704,0x5904,0x5701,0x5701,
+ 0x5701,0x5701,0x5901,0x5901,0x5B01,0x5B01,0x5904,0x5704,0x5701,0x5701,
+ 0x5701,0x5701,0x5604,0x5204,0x5604,0x5601,0x5601,0x5601,0x5601,0x5404,
+ 0x5204,0x5104,0x5204,0x4604,0x4704,0x4704,0x4904,0x4904,0x4604,0x4604,
+ 0x4404,0x4404,0x4604,0x4604,0x4704,0x4704,0x4404,0x4404,0x4604,0x4604,
+ 0x4704,0x4704,0x4904,0x4904,0x4604,0x4604,0x4404,0x4404,0x4604,0x4604,
+ 0x4704,0x4704,0x4404,0x4404,0x4608,0x8008,0x5601,0x5601,0x5601,0x5601,
+ 0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,
+ 0x5601,0x5601,0x5408,0x8008,0x5401,0x5401,0x5401,0x5401,0x5401,0x5401,
+ 0x5401,0x5401,0x5401,0x5401,0x5401,0x5401,0x5401,0x5401,0x5401,0x5401,
+ 0x5204,0x5504,0x5704,0x5904,0x5701,0x5701,0x5701,0x5701,0x5901,0x5901,
+ 0x5B01,0x5B01,0x5904,0x5704,0x5701,0x5701,0x5701,0x5701,0x5604,0x5204,
+ 0x5604,0x5601,0x5601,0x5601,0x5601,0x5404,0x5204,0x5104,0x3204,0x2904,
+ 0x2B04,0x3104,0x3204,0x3204,0x3404,0x3404,0x3604,0x3104,0x3204,0x3404,
+ 0x3604,0x3604,0x3704,0x3704,0x3904,0x3904,0x3A04,0x3A04,0x3B08,0x8008,
+ 0x3710,0x3910,0x4204,0x8004,0x4204,0x8004,0x4204,0x800C,0x3708,0x8004,
+ 0x3204,0x3708,0x8004,0x3204,0x3704,0x3204,0x3704,0x3B04,0x3208,0x8008,
+ 0x4008,0x8004,0x3904,0x4008,0x8004,0x3904,0x4004,0x3904,0x3604,0x4904,
+ 0x4208,0x8008,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,
+ 0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,
+ 0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,
+ 0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3904,0x3904,0x3B04,0x3B04,
+ 0x3604,0x3604,0x3704,0x3704,0x3904,0x3904,0x3B08,0x8028,0x3210,0x3410,
+ 0x3008,0x3008,0x3208,0x3208,0x2B04,0x8004,0x3204,0x8004,0x3708,0x8008,
+ 0x4B10,0x5010,0x3201,0x3201,0x3201,0x3201,0x3201,0x3201,0x3201,0x3201,
+ 0x3201,0x3201,0x3201,0x3201,0x3201,0x3201,0x3201,0x3201,0x3410,0x3008,
+ 0x3008,0x3208,0x3208,0x3B14,0x3B02,0x3901,0x3B01,0x4004,0x3904,0x4714,
+ 0x4702,0x4601,0x4701,0x4904,0x4604,0x3704,0x3704,0x3704,0x3704,0x3704,
+ 0x3704,0x3704,0x3704,0x3704,0x3704,0x3604,0x3604,0x3704,0x3704,0x3404,
+ 0x3404,0x3204,0x3204,0x3204,0x3204,0x3204,0x3204,0x3204,0x3204,0x3204,
+ 0x3204,0x3204,0x3204,0x3204,0x3204,0x3204,0x3204,0x3204,0x3404,0x3604,
+ 0x3404,0x3204,0x3404,0x3604,0x3204,0x3704,0x3904,0x3B04,0x3904,0x3704,
+ 0x3904,0x3B04,0x3804,0x3904,0x3904,0x3904,0x3904,0x3904,0x3904,0x3904,
+ 0x3904,0x3904,0x2904,0x2904,0x2904,0x2908,0x8008,0x490A,0x4702,0x4602,
+ 0x4402,0x4204,0x8004,0x3304,0x8004,0x3404,0x8004,0x3204,0x8004,0x3104,
+ 0x8004,0x2904,0x800C,0x2A01,0x2A01,0x2A01,0x2A01,0x2A01,0x2A01,0x2A01,
+ 0x2A01,0x2B04,0x8004,0x2704,0x8004,0x2908,0x3901,0x3901,0x3901,0x3901,
+ 0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3901,0x3801,0x3801,
+ 0x3801,0x3801,0x3701,0x3701,0x3701,0x3701,0x3401,0x3401,0x3401,0x3401,
+ 0x3204,0x8004,0x3404,0x8004,0x3604,0x8004,0x3304,0x8004,0x3404,0x8004,
+ 0x3204,0x8004,0x3104,0x8004,0x2904,0x8004,0x2B04,0x8004,0x3704,0x8004,
+ 0x3904,0x8004,0x2904,0x8004,0x4604,0x4604,0x4704,0x4704,0x4904,0x4904,
+ 0x4604,0x4604,0x4404,0x4404,0x4604,0x4604,0x4704,0x4704,0x4404,0x4404,
+ 0x4604,0x4604,0x4704,0x4704,0x4904,0x4904,0x4604,0x4604,0x4404,0x4404,
+ 0x4604,0x4604,0x4704,0x4704,0x4404,0x4404,0x4608,0x8008,0x5601,0x5601,
+ 0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,
+ 0x5601,0x5601,0x5601,0x5601,0x5408,0x8008,0x5401,0x5401,0x5401,0x5401,
+ 0x5401,0x5401,0x5401,0x5401,0x5401,0x5401,0x5401,0x5401,0x5401,0x5401,
+ 0x5401,0x5401,0x5204,0x5604,0x5704,0x5904,0x5701,0x5701,0x5701,0x5701,
+ 0x5901,0x5901,0x5B01,0x5B01,0x5904,0x5704,0x5701,0x5701,0x5701,0x5701,
+ 0x5604,0x5204,0x5604,0x5601,0x5601,0x5601,0x5601,0x5404,0x5204,0x5104,
+ 0x5204,0x4604,0x4704,0x4704,0x4904,0x4904,0x4604,0x4604,0x4404,0x4404,
+ 0x4604,0x4604,0x4704,0x4704,0x4404,0x4404,0x4604,0x4604,0x4704,0x4704,
+ 0x4904,0x4904,0x4604,0x4604,0x4404,0x4404,0x4604,0x4604,0x4704,0x4704,
+ 0x4404,0x4404,0x4608,0x8008,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,
+ 0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,0x5601,
+ 0x5408,0x8008,0x5401,0x5401,0x5401,0x5401,0x5401,0x5401,0x5401,0x5401,
+ 0x5401,0x5401,0x5401,0x5401,0x5401,0x5401,0x5401,0x5401,0x5204,0x5504,
+ 0x5704,0x5904,0x5701,0x5701,0x5701,0x5701,0x5901,0x5901,0x5B01,0x5B01,
+ 0x5904,0x5704,0x5701,0x5701,0x5701,0x5701,0x5604,0x5204,0x5604,0x5601,
+ 0x5601,0x5601,0x5601,0x5404,0x5204,0x5104,0x3204,0x2904,0x2B04,0x3104,
+ 0x3204,0x3204,0x3404,0x3404,0x3604,0x3104,0x3204,0x3404,0x3604,0x3604,
+ 0x3704,0x3704,0x3904,0x3904,0x3A04,0x3A04,0x3B08,0x8008,0x3710,0x3910,
+ 0x4204,0x8004,0x4204,0x8004,0x4204,0x800C,0x3208,0x8004,0x2904,0x3208,
+ 0x8004,0x2904,0x3204,0x2904,0x3204,0x3604,0x4908,0x8008,0x3908,0x8004,
+ 0x3604,0x3908,0x8004,0x3604,0x3904,0x3604,0x3304,0x3604,0x2B08,0x8008,
+ 0x4404,0x4404,0x4504,0x4504,0x4704,0x4704,0x4404,0x4404,0x4204,0x4204,
+ 0x4404,0x4404,0x4504,0x4504,0x4204,0x4204,0x4404,0x4404,0x4504,0x4504,
+ 0x4704,0x4704,0x4404,0x4404,0x4204,0x4204,0x4404,0x4404,0x4504,0x4504,
+ 0x4204,0x4204,0x4404,0x4404,0x4504,0x4504,0x4704,0x4704,0x4404,0x4404,
+ 0x4204,0x4204,0x4404,0x4404,0x4504,0x4504,0x4204,0x4204,0x4004,0x4004,
+ 0x4204,0x4204,0x4404,0x4404,0x4004,0x4004,0x4004,0x4004,0x4204,0x4204,
+ 0x4304,0x4304,0x4004,0x4004,0x3A04,0x3A04,0x3904,0x3904,0x3A04,0x3A04,
+ 0x4904,0x4904,0x4A04,0x4A04,0x4904,0x4904,0x4A04,0x4A04,0x4904,0x4704,
+ 0x4608,0x8004,0x2201,0x2201,0x2201,0x2201,0x2401,0x2401,0x2401,0x2401,
+ 0x2601,0x2601,0x2601,0x2601,0x2701,0x2701,0x2701,0x2701,0x2901,0x2901,
+ 0x2901,0x2901,0x3001,0x3001,0x3001,0x3001,0x2A04,0x8004,0x2601,0x2601,
+ 0x2601,0x2601,0x2701,0x2701,0x2701,0x2701,0x2901,0x2901,0x2901,0x2901,
+ 0x2A01,0x2A01,0x2A01,0x2A01,0x2101,0x2101,0x2101,0x2101,0x3401,0x3401,
+ 0x3401,0x3401,0x3204,0x8004,0x4204,0x4404,0x4504,0x4704,0x4904,0x4A08,
+ 0x4B08,0x5008,0x5108,0x5204,0x5204,0x5201,0x5201,0x5201,0x5201,0x5404,
+ 0x5004,0x5004,0x5001,0x5001,0x5001,0x5001,0x5204,0x4B04,0x4B04,0x4B01,
+ 0x4B01,0x4B01,0x4B01,0x5204,0x5201,0x5201,0x5201,0x5201,0x5004,0x4B04,
+ 0x4904,0x4708,0x8004,0x3204,0x3708,0x8004,0x3204,0x3704,0x3204,0x3704,
+ 0x3B04,0x4208,0x8008,0x4008,0x8004,0x3904,0x4008,0x8004,0x3904,0x4004,
+ 0x3904,0x3604,0x3904,0x3208,0x8008,0x3704,0x3704,0x3704,0x3704,0x3704,
+ 0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,
+ 0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,
+ 0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3904,
+ 0x3904,0x3B04,0x3B04,0x3704,0x3704,0x3904,0x3904,0x3B04,0x3B04,0x4008,
+ 0x8008,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,
+ 0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x5010,0x4908,0x4908,
+ 0x4708,0x4708,0x4408,0x4408,0x4008,0x3908,0x4204,0x8004,0x4604,0x8004,
+ 0x4704,0x800C,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,
+ 0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x5010,0x4B01,
+ 0x4B01,0x4B01,0x4B01,0x4904,0x4904,0x4904,0x4901,0x4901,0x4901,0x4901,
+ 0x4704,0x4704,0x4704,0x4408,0x4404,0x4404,0x4008,0x4004,0x4004,0x3B14,
+ 0x3B01,0x3B01,0x3901,0x3B01,0x4001,0x4001,0x4001,0x4001,0x3904,0x4714,
+ 0x4701,0x4701,0x4601,0x4701,0x4901,0x4901,0x4901,0x4901,0x4604,0x4B10,
+ 0x5010,0x4B08,0x5210,0x5708,0x5610,0x5710,0x5610,0x5710,0x5608,0x5708,
+ 0x5608,0x5708,0x5604,0x4204,0x4204,0x4204,0x4208,0x8008,0x4201,0x4201,
+ 0x4201,0x4201,0x4201,0x4201,0x4201,0x4201,0x4201,0x4201,0x4001,0x4001,
+ 0x3B01,0x3B01,0x3901,0x3901,0x3704,0x8004,0x4404,0x8004,0x4004,0x8004,
+ 0x3904,0x8004,0x4204,0x800C,0x4B0A,0x4902,0x4702,0x4602,0x5404,0x8004,
+ 0x5004,0x8004,0x3208,0x4201,0x4201,0x4201,0x4201,0x4201,0x4201,0x4201,
+ 0x4201,0x4201,0x4201,0x4201,0x4201,0x4101,0x4101,0x4101,0x4101,0x4001,
+ 0x4001,0x4001,0x4001,0x3901,0x3901,0x3901,0x3901,0x3704,0x8004,0x3904,
+ 0x8004,0x3B04,0x8004,0x3804,0x8004,0x3904,0x8004,0x3704,0x8004,0x3604,
+ 0x8004,0x3204,0x8004,0x3404,0x8004,0x3004,0x8004,0x3204,0x8004,0x3204,
+ 0x8004,0x2708,0x8018,0x3208,0x8018,0x2708,0x8018,0x3208,0x8018,0x3B08,
+ 0x8008,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,
+ 0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4908,0x8008,0x4901,
+ 0x4901,0x4901,0x4901,0x4901,0x4901,0x4901,0x4901,0x4901,0x4901,0x4901,
+ 0x4901,0x4901,0x4901,0x4901,0x4901,0x4704,0x4B04,0x5004,0x5204,0x5001,
+ 0x5001,0x5001,0x5001,0x5201,0x5201,0x5401,0x5401,0x5204,0x5004,0x5001,
+ 0x5001,0x5001,0x5001,0x4B04,0x4704,0x4B04,0x4B01,0x4B01,0x4B01,0x4B01,
+ 0x4904,0x4704,0x4604,0x4704,0x3B04,0x4004,0x4004,0x4204,0x4204,0x3B04,
+ 0x3B04,0x3904,0x3904,0x3B04,0x3B04,0x4004,0x4004,0x3904,0x3904,0x3B04,
+ 0x4B04,0x5004,0x5004,0x5204,0x5204,0x4B04,0x4B04,0x4904,0x4904,0x4B04,
+ 0x4B04,0x5004,0x5004,0x4904,0x4904,0x8004,0x3704,0x3B04,0x3904,0x3804,
+ 0x3404,0x3604,0x3804,0x3904,0x4004,0x3904,0x3704,0x3604,0x3204,0x3404,
+ 0x3604,0x3704,0x3704,0x3904,0x3B04,0x4004,0x4004,0x4004,0x4004,0x4204,
+ 0x4204,0x4204,0x4204,0x3204,0x3204,0x3204,0x3204,0x3704,0x3204,0x3404,
+ 0x3604,0x3704,0x3704,0x3904,0x3904,0x3B04,0x3604,0x3704,0x3904,0x3B04,
+ 0x3B04,0x4004,0x4004,0x4204,0x4204,0x4304,0x4304,0x4408,0x8008,0x3001,
+ 0x3001,0x3001,0x3001,0x3001,0x3001,0x3001,0x3001,0x3001,0x3001,0x3001,
+ 0x3001,0x3001,0x3001,0x3001,0x3001,0x3210,0x2708,0x8018,0x3001,0x3001,
+ 0x3001,0x3001,0x3001,0x3001,0x3001,0x3001,0x3001,0x3001,0x3001,0x3001,
+ 0x3001,0x3001,0x3001,0x3001,0x3210,0x2708,0x8018,0x3008,0x8008,0x3208,
+ 0x8008,0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,
+ 0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,
+ 0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,
+ 0x2704,0x2704,0x2704,0x2704,0x2B04,0x3204,0x3704,0x3B04,0x3704,0x4204,
+ 0x3B04,0x3708,0x2706,0x2702,0x2708,0x8008,0x3208,0x8004,0x2904,0x3208,
+ 0x8004,0x2904,0x3204,0x2904,0x3204,0x3604,0x4908,0x8008,0x3908,0x8004,
+ 0x3604,0x3908,0x8004,0x3604,0x3904,0x3604,0x3304,0x3604,0x2B08,0x8008,
+ 0x4404,0x4404,0x4504,0x4504,0x4704,0x4704,0x4404,0x4404,0x4204,0x4204,
+ 0x4404,0x4404,0x4504,0x4504,0x4204,0x4204,0x4404,0x4404,0x4504,0x4504,
+ 0x4704,0x4704,0x4404,0x4404,0x4204,0x4204,0x4404,0x4404,0x4504,0x4504,
+ 0x4204,0x4204,0x4404,0x4404,0x4504,0x4504,0x4704,0x4704,0x4404,0x4404,
+ 0x4204,0x4204,0x4404,0x4404,0x4504,0x4504,0x4204,0x4204,0x4004,0x4004,
+ 0x4204,0x4204,0x4404,0x4404,0x4004,0x4004,0x4004,0x4004,0x4204,0x4204,
+ 0x4304,0x4304,0x4004,0x4004,0x3A04,0x3A04,0x3904,0x3904,0x3A04,0x3A04,
+ 0x4904,0x4904,0x4A04,0x4A04,0x4904,0x4904,0x4A04,0x4A04,0x4904,0x4704,
+ 0x4608,0x8004,0x2201,0x2201,0x2201,0x2201,0x2401,0x2401,0x2401,0x2401,
+ 0x2601,0x2601,0x2601,0x2601,0x2701,0x2701,0x2701,0x2701,0x2901,0x2901,
+ 0x2901,0x2901,0x3001,0x3001,0x3001,0x3001,0x2A04,0x8004,0x2601,0x2601,
+ 0x2601,0x2601,0x2701,0x2701,0x2701,0x2701,0x2901,0x2901,0x2901,0x2901,
+ 0x2A01,0x2A01,0x2A01,0x2A01,0x2101,0x2101,0x2101,0x2101,0x3401,0x3401,
+ 0x3401,0x3401,0x3204,0x8004,0x4204,0x4404,0x4504,0x4704,0x4904,0x4A08,
+ 0x4B08,0x5008,0x5108,0x5204,0x5204,0x5201,0x5201,0x5201,0x5201,0x5404,
+ 0x5004,0x5004,0x5001,0x5001,0x5001,0x5001,0x5204,0x4B04,0x4B04,0x4B01,
+ 0x4B01,0x4B01,0x4B01,0x5204,0x5201,0x5201,0x5201,0x5201,0x5004,0x4B04,
+ 0x4904,0x4708,0x8004,0x3204,0x3708,0x8004,0x3204,0x3704,0x3204,0x3704,
+ 0x3B04,0x4208,0x8008,0x4008,0x8004,0x3904,0x4008,0x8004,0x3904,0x4004,
+ 0x3904,0x3604,0x3904,0x3208,0x8008,0x3704,0x3704,0x3704,0x3704,0x3704,
+ 0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,
+ 0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,
+ 0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3704,0x3904,
+ 0x3904,0x3B04,0x3B04,0x3704,0x3704,0x3904,0x3904,0x3B04,0x3B04,0x4008,
+ 0x8008,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,
+ 0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x5010,0x4908,0x4908,
+ 0x4708,0x4708,0x4408,0x4408,0x4008,0x3908,0x4204,0x8004,0x4604,0x8004,
+ 0x4704,0x800C,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,
+ 0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x5010,0x4B01,
+ 0x4B01,0x4B01,0x4B01,0x4904,0x4904,0x4904,0x4901,0x4901,0x4901,0x4901,
+ 0x4704,0x4704,0x4704,0x4408,0x4404,0x4404,0x4008,0x4004,0x4004,0x3B14,
+ 0x3B01,0x3B01,0x3901,0x3B01,0x4001,0x4001,0x4001,0x4001,0x3904,0x4714,
+ 0x4701,0x4701,0x4601,0x4701,0x4901,0x4901,0x4901,0x4901,0x4604,0x4B10,
+ 0x5010,0x4B08,0x5210,0x5708,0x5610,0x5710,0x5610,0x5710,0x5608,0x5708,
+ 0x5608,0x5708,0x5604,0x4204,0x4204,0x4204,0x4208,0x8008,0x4201,0x4201,
+ 0x4201,0x4201,0x4201,0x4201,0x4201,0x4201,0x4201,0x4201,0x4001,0x4001,
+ 0x3B01,0x3B01,0x3901,0x3901,0x3704,0x8004,0x4404,0x8004,0x4004,0x8004,
+ 0x3904,0x8004,0x4204,0x800C,0x4B0A,0x4902,0x4702,0x4602,0x5404,0x8004,
+ 0x5004,0x8004,0x3208,0x4201,0x4201,0x4201,0x4201,0x4201,0x4201,0x4201,
+ 0x4201,0x4201,0x4201,0x4201,0x4201,0x4101,0x4101,0x4101,0x4101,0x4001,
+ 0x4001,0x4001,0x4001,0x3901,0x3901,0x3901,0x3901,0x3704,0x8004,0x3904,
+ 0x8004,0x3B04,0x8004,0x3804,0x8004,0x3904,0x8004,0x3704,0x8004,0x3604,
+ 0x8004,0x3204,0x8004,0x3404,0x8004,0x3004,0x8004,0x3204,0x8004,0x3204,
+ 0x8004,0x2708,0x8018,0x3208,0x8018,0x2708,0x8018,0x3208,0x8018,0x3B08,
+ 0x8008,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,
+ 0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4B01,0x4908,0x8008,0x4901,
+ 0x4901,0x4901,0x4901,0x4901,0x4901,0x4901,0x4901,0x4901,0x4901,0x4901,
+ 0x4901,0x4901,0x4901,0x4901,0x4901,0x4704,0x4B04,0x5004,0x5204,0x5001,
+ 0x5001,0x5001,0x5001,0x5201,0x5201,0x5401,0x5401,0x5204,0x5004,0x5001,
+ 0x5001,0x5001,0x5001,0x4B04,0x4704,0x4B04,0x4B01,0x4B01,0x4B01,0x4B01,
+ 0x4904,0x4704,0x4604,0x4704,0x3B04,0x4004,0x4004,0x4204,0x4204,0x3B04,
+ 0x3B04,0x3904,0x3904,0x3B04,0x3B04,0x4004,0x4004,0x3904,0x3904,0x3B04,
+ 0x4B04,0x5004,0x5004,0x5204,0x5204,0x4B04,0x4B04,0x4904,0x4904,0x4B04,
+ 0x4B04,0x5004,0x5004,0x4904,0x4904,0x8004,0x3704,0x3B04,0x3904,0x3804,
+ 0x3404,0x3604,0x3804,0x3904,0x4004,0x3904,0x3704,0x3604,0x3204,0x3404,
+ 0x3604,0x3704,0x3704,0x3904,0x3B04,0x4004,0x4004,0x4004,0x4004,0x4204,
+ 0x4204,0x4204,0x4204,0x3204,0x3204,0x3204,0x3204,0x3704,0x3204,0x3404,
+ 0x3604,0x3704,0x3704,0x3904,0x3904,0x3B04,0x3604,0x3704,0x3904,0x3B04,
+ 0x3B04,0x4004,0x4004,0x4204,0x4204,0x4304,0x4304,0x4408,0x8008,0x3001,
+ 0x3001,0x3001,0x3001,0x3001,0x3001,0x3001,0x3001,0x3001,0x3001,0x3001,
+ 0x3001,0x3001,0x3001,0x3001,0x3001,0x3210,0x2708,0x8018,0x3001,0x3001,
+ 0x3001,0x3001,0x3001,0x3001,0x3001,0x3001,0x3001,0x3001,0x3001,0x3001,
+ 0x3001,0x3001,0x3001,0x3001,0x3210,0x2708,0x8018,0x3008,0x8008,0x3208,
+ 0x8008,0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,
+ 0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,
+ 0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,0x2704,
+ 0x2704,0x2704,0x2704,0x2704,0x2B04,0x3204,0x3704,0x3B04,0x3704,0x4204,
+ 0x3B04,0x3708,0x2706,0x2702,0x2708,0x8008,
+ 0x0000
+};
+
+
+
+/* Screen sizes */
+#ifdef __CBM610__
+# define MAX_X 80
+#else
+# define MAX_X 40
+#endif
+
+
+
+#ifdef __C64__
+static unsigned long FreqTab [12] = {
+#ifndef NTSC
+ /* PAL */
+ 0x008B38, 0x009381, 0x009C45, 0x00A590, 0x00AF68, 0x00B9D6,
+ 0x00C4E4, 0x00D099, 0x00DCFF, 0x00EA24, 0x00F810, 0x0106D1,
+#else
+ /* NTSC */
+ 0x00861E, 0x008E19, 0x00968B, 0x009F7F, 0x00A8FA, 0x00B307,
+ 0x00BDAD, 0x00C8F4, 0x00D4E6, 0x00E18F, 0x00EEF9, 0x00FD2F,
+#endif
+};
+#endif
+
+#ifdef __C128__
+static unsigned long FreqTab [12] = {
+ 0x00892B, 0x009153, 0x0099F7, 0x00A31E, 0x00ACD2, 0x00B718,
+ 0x00C1FD, 0x00CD85, 0x00D9BD, 0x00E6B0, 0x00F467, 0x0102F0,
+};
+#endif
+
+#ifdef __CBM610__
+static unsigned long FreqTab [12] = {
+ 0x004495, 0x0048AA, 0x004CFB, 0x00518F, 0x005669, 0x005B8C,
+ 0x0060FE, 0x0066C3, 0x006CDE, 0x007358, 0x007A34, 0x008178,
+};
+#endif
+
+
+
+typedef struct {
+ unsigned char DoneMask; /* Set this if we're done */
+ unsigned char Trigger; /* Trigger value */
+ unsigned char Ticks; /* Ticks for this tone */
+ unsigned Freq; /* Actual frequency value */
+ int* Data; /* Pointer to data */
+ struct __sid_voice* Voice; /* Pointer to sid registers */
+} VoiceCtrl;
+
+/* Control structs for all three voices */
+static VoiceCtrl V1 = {
+ 0x01, 0x11, 0, 0, Voice1, &SID.v1
+};
+static VoiceCtrl V2 = {
+ 0x02, 0x41, 0, 0, Voice2, &SID.v2
+};
+static VoiceCtrl V3 = {
+ 0x04, 0x11, 0, 0, Voice3, &SID.v3
+};
+
+/* Pointers to the structs for easy reference */
+static VoiceCtrl* V [3] = {
+ &V1, &V2, &V3
+};
+
+/* Variable that contains the time of the next clock tick to play a note */
+static unsigned char NextClock;
+
+/* Start- and runtime */
+static clock_t StartTime;
+
+/* Number of ticks for each tone */
+#define TICKS_PER_TONE 4
+
+/* Done flag. Contains one bit for each voice. Will contain 0x07 if all
+ * voices have finished playing.
+ */
+static unsigned char Done;
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+static void MakeTeeLine (unsigned char Y)
+/* Make a divider line */
+{
+ cputcxy (0, Y, CH_LTEE);
+ chline (MAX_X - 2);
+ cputc (CH_RTEE);
+}
+
+
+
+static void MakeNiceScreen (void)
+/* Make a nice screen */
+{
+ typedef struct {
+ unsigned char X;
+ unsigned char Y;
+ char* Msg;
+ } TextDesc;
+ static TextDesc Text [] = {
+ { (MAX_X / 2) - 11, 2, "Wolfgang Amadeus Mozart" },
+ { (MAX_X / 2) - 12, 4, "\"Eine kleine Nachtmusik\"" },
+ { (MAX_X / 2) - 4, 5, "(KV 525)" },
+ { (MAX_X / 2) - 14, 9, "Ported to the SID in 1987 by" },
+ { (MAX_X / 2) - 10, 11, "Joachim von Bassewitz" },
+ { (MAX_X / 2) - 13, 12, "(joachim@von-bassewitz.de)" },
+ { (MAX_X / 2) - 1, 13, "and" },
+ { (MAX_X / 2) - 10, 14, "Ullrich von Bassewitz" },
+ { (MAX_X / 2) - 13, 15, "(ullrich@von-bassewitz.de)" },
+ { (MAX_X / 2) - 9, 18, "C Implementation by" },
+ { (MAX_X / 2) - 10, 19, "Ullrich von Bassewitz" },
+ { (MAX_X / 2) - 11, 23, "Press any key to quit..." },
+ };
+
+ TextDesc* T;
+ unsigned char I;
+
+ /* Clear the screen hide the cursor, set colors */
+#ifdef __CBM610__
+ textcolor (COLOR_WHITE);
+#else
+ textcolor (COLOR_GRAY3);
+#endif
+ bordercolor (COLOR_BLACK);
+ bgcolor (COLOR_BLACK);
+ clrscr ();
+ cursor (0);
+
+ /* Top line */
+ cputcxy (0, 0, CH_ULCORNER);
+ chline (MAX_X - 2);
+ cputc (CH_URCORNER);
+
+ /* Left line */
+ cvlinexy (0, 1, 23);
+
+ /* Bottom line */
+ cputc (CH_LLCORNER);
+ chline (MAX_X - 2);
+ cputc (CH_LRCORNER);
+
+ /* Right line */
+ cvlinexy (MAX_X - 1, 1, 23);
+
+ /* Several divider lines */
+ MakeTeeLine (7);
+ MakeTeeLine (22);
+
+ /* Write something into the frame */
+ for (I = 0, T = Text; I < sizeof (Text) / sizeof (Text [0]); ++I) {
+ cputsxy (T->X, T->Y, T->Msg);
+ ++T;
+ }
+}
+
+
+
+static void TimeSync (void)
+/* Sync the time for the next tone */
+{
+ static unsigned char Clock;
+
+ do {
+ Clock = clock ();
+ } while (Clock != NextClock);
+ NextClock = Clock + TICKS_PER_TONE;
+}
+
+
+
+static void DisplayTime (void)
+/* Display the running time */
+{
+ clock_t Time = (clock () - StartTime) / CLOCKS_PER_TICK;
+ unsigned Sec = Time % 60;
+ unsigned Min = Time / 60;
+
+ gotoxy (1, 0);
+ cprintf ("%02d:%02d", Min, Sec);
+}
+
+
+
+/* On the 610, the SID is in another bank (the system bank), so we cannot
+ * just write to the memory space.
+ */
+#ifdef __CBM610__
+# define outb(addr,val) pokebsys ((unsigned)(addr), val)
+# define outw(addr,val) pokewsys ((unsigned)(addr), val)
+#else
+# define outb(addr,val) (*(addr)) = (val)
+# define outw(addr,val) (*(addr)) = (val)
+#endif
+
+
+
+int main (void)
+{
+ unsigned char I;
+ unsigned char Tone;
+ unsigned char Octave;
+ unsigned Val;
+ struct __sid_voice* Voice;
+ VoiceCtrl* VC;
+
+ /* Initialize the debugger */
+ DbgInit (0);
+
+ /* Make a nice screen */
+ MakeNiceScreen ();
+
+ /* Initialize the SID */
+ outw (&SID.v1.pw, 0x0800);
+ outb (&SID.v1.ad, 0x33);
+ outb (&SID.v1.sr, 0xF0);
+ outw (&SID.v2.pw, 0x0800);
+ outb (&SID.v2.ad, 0x77);
+ outb (&SID.v2.sr, 0x74);
+ outw (&SID.v3.pw, 0x0800);
+ outb (&SID.v3.ad, 0x77);
+ outb (&SID.v3.sr, 0xD2);
+ outw (&SID.flt_freq, 0xF0F0);
+ outb (&SID.flt_ctrl, 0xF2);
+ outb (&SID.amp, 0x5F);
+
+ /* Sync the clock */
+ NextClock = StartTime = clock ();
+ NextClock += TICKS_PER_TONE;
+
+ /* Play each voice until all three are done */
+ while (Done != 0x07) {
+
+ /* Display the time in the lower left corner */
+ DisplayTime ();
+
+ /* Wait for the next run */
+ TimeSync ();
+
+ /* Check for a key */
+ if (kbhit ()) {
+ if (cgetc () == 'd') {
+ /* Start the debugger */
+ BREAK ();
+ } else {
+ /* Stop playing music */
+ break;
+ }
+ }
+
+ /* Play all three voices */
+ for (I = 0; I < 3; ++I) {
+
+ /* Get a pointer to this voice */
+ VC = V [I];
+ Voice = VC->Voice;
+
+ /* Is this voice done? */
+ if (Done & VC->DoneMask) {
+ /* Voice already done */
+ continue;
+ }
+
+ /* Do we have any more ticks to play? */
+ if (VC->Ticks == 0) {
+ /* We need new data */
+ if ((Val = *VC->Data) == 0) {
+ /* End of data. Mark the voice as done */
+ Done |= VC->DoneMask;
+ continue;
+ }
+ ++VC->Data;
+
+ /* Get the ticks from the data */
+ VC->Ticks = (Val & 0x7F) - 1;
+
+ /* Check if this is a tone or a pause */
+ if (Val & 0x8000) {
+ /* This is a pause. Remember it and shut off the SID */
+ outb (&Voice->ctrl, VC->Trigger & 0xFE);
+ } else {
+ /* This is a tone. Extract the attributes. */
+ Tone = (Val >> 8) & 0x0F;
+ Octave = ((Val >> 12) & 0x07) ^ 0x07;
+ /* Calculate the frequency */
+ VC->Freq = FreqTab [Tone] >> Octave;
+ /* Set the frequency */
+ outw (&Voice->freq, VC->Freq);
+ /* Start the tone */
+ outb (&Voice->ctrl, VC->Trigger);
+ }
+ } else {
+ /* Decrement the ticks. If this is the last tick of a tone,
+ * reset bit 0 of the trigger value and write it back to the
+ * SID to start the release phase.
+ */
+ if (--(VC->Ticks) == 0) {
+ outb (&Voice->ctrl, VC->Trigger & 0xFE);
+ }
+ }
+ }
+ }
+
+ /* Reset the SID */
+ outb (&SID.v1.ctrl, 0x00);
+ outb (&SID.v2.ctrl, 0x00);
+ outb (&SID.v3.ctrl, 0x00);
+
+ /* Clear the screen */
+ clrscr ();
+
+ /* If we have a character, remove it from the buffer */
+ if (kbhit ()) {
+ cgetc ();
+ }
+
+ /* Done */
+ return 0;
+}
+
+
+
--- /dev/null
+/*
+ * Calculate all primes up to a specific number.
+ */
+
+
+
+#include <stdio.h>
+#include <conio.h>
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+#define COUNT 8192 /* Up to what number? */
+#define SQRT_COUNT 91 /* Sqrt of COUNT */
+
+static unsigned char Sieve[COUNT];
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+int main (void)
+{
+ /* This is an example where register variables make sense */
+ register unsigned char* S;
+ register unsigned I;
+ register unsigned J;
+
+ /* Execute the sieve */
+ I = 2;
+ while (I < SQRT_COUNT) {
+ if (Sieve[I] == 0) {
+ /* Prime number - mark multiples */
+ S = &Sieve[J = I*2];
+ while (J < COUNT) {
+ *S = 1;
+ S += I;
+ J += I;
+ }
+ }
+ ++I;
+ }
+
+ /* Print the result */
+ for (I = 2; I < COUNT; ++I) {
+ if (Sieve[I] == 0) {
+ printf ("%4d\n", I);
+ }
+ if (kbhit() && cgetc() == 'q') {
+ break;
+ }
+ }
+
+ return 0;
+}
+
+
+
--- /dev/null
+.depend
+ar65
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* add.c */
+/* */
+/* Object file adding for the ar65 archiver */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <stdlib.h>
+
+#include "error.h"
+#include "objfile.h"
+#include "library.h"
+#include "add.h"
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void AddObjFiles (int argc, char* argv [])
+/* Add object files to a library */
+{
+ int I;
+
+ /* Check the argument count */
+ if (argc <= 0) {
+ Error ("No library name given");
+ }
+ if (argc <= 1) {
+ Error ("No object files to add");
+ }
+
+ /* Open the library, read the index */
+ LibOpen (argv [0], 0, 1);
+
+ /* Add the object files */
+ I = 1;
+ while (I < argc) {
+ ObjAdd (argv [I]);
+ ++I;
+ }
+
+ /* Create a new library file and close the old one */
+ LibClose ();
+
+ /* Successful end */
+ exit (EXIT_SUCCESS);
+}
+
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* add.h */
+/* */
+/* Object file adding for the ar65 archiver */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef ADD_H
+#define ADD_H
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void AddObjFiles (int argc, char* argv []);
+/* Add object files to a library */
+
+
+
+/* End of add.h */
+
+#endif
+
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* del.h */
+/* */
+/* Object file deleting for the ar65 archiver */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <stdlib.h>
+
+#include "error.h"
+#include "objdata.h"
+#include "library.h"
+#include "del.h"
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void DelObjFiles (int argc, char* argv [])
+/* Delete modules from a library */
+{
+ int I;
+
+ /* Check the argument count */
+ if (argc <= 0) {
+ Error ("No library name given");
+ }
+ if (argc <= 1) {
+ Error ("No modules to delete");
+ }
+
+ /* Open the library, read the index */
+ LibOpen (argv [0], 1, 1);
+
+ /* Delete the modules */
+ I = 1;
+ while (I < argc) {
+ /* Delete the module from the list */
+ DelObjData (argv [I]);
+ ++I;
+ }
+
+ /* Create a new library file and close the old one */
+ LibClose ();
+
+ /* Successful end */
+ exit (EXIT_SUCCESS);
+}
+
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* del.h */
+/* */
+/* Object file deleting for the ar65 archiver */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef DEL_H
+#define DEL_H
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void DelObjFiles (int argc, char* argv []);
+/* Delete modules from a library */
+
+
+
+/* End of del.h */
+
+#endif
+
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* global.c */
+/* */
+/* Error handling for the ar65 archiver */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "error.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Messages for internal compiler errors */
+const char _MsgCheckFailed [] =
+ "Check failed: `%s' (= %d), file `%s', line %u\n";
+const char _MsgPrecondition [] =
+ "Precondition violated: `%s' (= %d), file `%s', line %u\n";
+const char _MsgFail [] =
+ "%s, file `%s', line %u\n";
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void Warning (const char* Format, ...)
+/* Print a warning message */
+{
+ va_list ap;
+ va_start (ap, Format);
+ fprintf (stderr, "Warning: ");
+ vfprintf (stderr, Format, ap);
+ putc ('\n', stderr);
+ va_end (ap);
+}
+
+
+
+void Error (const char* Format, ...)
+/* Print an error message and die */
+{
+ va_list ap;
+ va_start (ap, Format);
+ fprintf (stderr, "Error: ");
+ vfprintf (stderr, Format, ap);
+ putc ('\n', stderr);
+ va_end (ap);
+ exit (EXIT_FAILURE);
+}
+
+
+
+void Internal (const char* Format, ...)
+/* Print an internal error message and die */
+{
+ va_list ap;
+ va_start (ap, Format);
+ fprintf (stderr, "Internal error: ");
+ vfprintf (stderr, Format, ap);
+ putc ('\n', stderr);
+ va_end (ap);
+ exit (EXIT_FAILURE);
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* global.h */
+/* */
+/* Error handling for the ar65 archiver */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef ERROR_H
+#define ERROR_H
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Messages for internal compiler errors */
+extern const char _MsgCheckFailed [];
+extern const char _MsgPrecondition [];
+extern const char _MsgFail [];
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void Warning (const char* Format, ...);
+/* Print a warning message */
+
+void Error (const char* Format, ...);
+/* Print an error message and die */
+
+void Internal (const char* Format, ...);
+/* Print an internal error message and die */
+
+#define CHECK(c) \
+ if (!(c)) \
+ Internal (_MsgCheckFailed, #c, c, __FILE__, __LINE__)
+
+#define PRECONDITION(c) \
+ if (!(c)) \
+ Internal (_MsgPrecondition, #c, c, __FILE__, __LINE__)
+
+#define FAIL(s) \
+ Internal (_MsgFail, s, __FILE__, __LINE__)
+
+
+
+/* End of error.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* exports.c */
+/* */
+/* Duplicate export checking for the ar65 archiver */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <string.h>
+
+#include "../common/hashstr.h"
+
+#include "mem.h"
+#include "error.h"
+#include "objdata.h"
+#include "exports.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* A hash table entry */
+typedef struct HashEntry_ HashEntry;
+struct HashEntry_ {
+ HashEntry* Next; /* Next in list */
+ unsigned Module; /* Module index */
+ char Name [1]; /* Name of identifier */
+};
+
+/* Hash table */
+#define HASHTAB_SIZE 4783
+static HashEntry* HashTab [HASHTAB_SIZE];
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+static HashEntry* NewHashEntry (const char* Name, unsigned Module)
+/* Create and return a new hash entry */
+{
+ /* Get the length of the name */
+ unsigned Len = strlen (Name);
+
+ /* Get memory for the struct */
+ HashEntry* H = Xmalloc (sizeof (HashEntry) + Len);
+
+ /* Initialize the fields and return it */
+ H->Next = 0;
+ H->Module = Module;
+ memcpy (H->Name, Name, Len);
+ H->Name [Len] = '\0';
+ return H;
+}
+
+
+
+void ExpInsert (const char* Name, unsigned Module)
+/* Insert an exported identifier and check if it's already in the list */
+{
+ HashEntry* L;
+
+ /* Create a hash value for the given name */
+ unsigned HashVal = HashStr (Name) % HASHTAB_SIZE;
+
+ /* Create a new hash entry */
+ HashEntry* H = NewHashEntry (Name, Module);
+
+ /* Search through the list in that slot and print matching duplicates */
+ if (HashTab [HashVal] == 0) {
+ /* The slot is empty */
+ HashTab [HashVal] = H;
+ return;
+ }
+ L = HashTab [HashVal];
+ while (1) {
+ if (strcmp (L->Name, Name) == 0) {
+ /* Duplicate entry */
+ Warning ("External symbol `%s' in module `%s' is duplicated in "
+ "module `%s'",
+ Name, GetObjName (L->Module), GetObjName (Module));
+ }
+ if (L->Next == 0) {
+ break;
+ } else {
+ L = L->Next;
+ }
+ }
+ L->Next = H;
+}
+
+
+
+int ExpFind (const char* Name)
+/* Check for an identifier in the list. Return -1 if not found, otherwise
+ * return the number of the module, that exports the identifer.
+ */
+{
+ /* Get a pointer to the list with the symbols hash value */
+ HashEntry* L = HashTab [HashStr (Name) % HASHTAB_SIZE];
+ while (L) {
+ /* Search through the list in that slot */
+ if (strcmp (L->Name, Name) == 0) {
+ /* Entry found */
+ return L->Module;
+ }
+ L = L->Next;
+ }
+
+ /* Not found */
+ return -1;
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* exports.h */
+/* */
+/* Duplicate export checking for the ar65 archiver */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef EXPORTS_H
+#define EXPORTS_H
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void ExpInsert (const char* Name, unsigned Module);
+/* Insert an exported identifier and check if it's already in the list */
+
+int ExpFind (const char* Name);
+/* Check for an identifier in the list. Return -1 if not found, otherwise
+ * return the number of the module, that exports the identifer.
+ */
+
+
+
+/* End of exports.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* extract.c */
+/* */
+/* Object file extraction for the ar65 archiver */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <stdlib.h>
+
+#include "mem.h"
+#include "error.h"
+#include "objfile.h"
+#include "library.h"
+#include "extract.h"
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void ExtractObjFiles (int argc, char* argv [])
+/* Extract object files from a library */
+{
+ int I;
+
+ /* Check the argument count */
+ if (argc <= 0) {
+ Error ("No library name given");
+ }
+ if (argc <= 1) {
+ Error ("No object files to add");
+ }
+
+ /* Open the library, read the index */
+ LibOpen (argv [0], 1, 0);
+
+ /* Extract the object files */
+ I = 1;
+ while (I < argc) {
+ ObjExtract (argv [I]);
+ ++I;
+ }
+
+ /* Create a new library file and close the old one */
+ LibClose ();
+
+ /* Successful end */
+ exit (EXIT_SUCCESS);
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* extract.h */
+/* */
+/* Object file extraction for the ar65 archiver */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef EXTRACT_H
+#define EXTRACT_H
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void ExtractObjFiles (int argc, char* argv []);
+/* Extract object files from a library */
+
+
+
+/* End of extract.h */
+
+#endif
+
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* fileio.c */
+/* */
+/* File I/O for the ar65 archiver */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <string.h>
+
+#include "error.h"
+#include "mem.h"
+#include "fileio.h"
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void Write8 (FILE* F, unsigned char Val)
+/* Write an 8 bit value to the file */
+{
+ if (putc (Val, F) == EOF) {
+ Error ("Write error (disk full?)");
+ }
+}
+
+
+
+void Write16 (FILE* F, unsigned Val)
+/* Write a 16 bit value to the file */
+{
+ Write8 (F, (unsigned char) Val);
+ Write8 (F, (unsigned char) (Val >> 8));
+}
+
+
+
+void Write32 (FILE* F, unsigned long Val)
+/* Write a 32 bit value to the file */
+{
+ Write8 (F, (unsigned char) Val);
+ Write8 (F, (unsigned char) (Val >> 8));
+ Write8 (F, (unsigned char) (Val >> 16));
+ Write8 (F, (unsigned char) (Val >> 24));
+}
+
+
+
+void WriteStr (FILE* F, const char* S)
+/* Write a string to the file */
+{
+ unsigned Len = strlen (S);
+ if (Len > 255) {
+ Internal ("String too long");
+ }
+ Write8 (F, (unsigned char) Len);
+ WriteData (F, S, Len);
+}
+
+
+
+void WriteData (FILE* F, const void* Data, unsigned Size)
+/* Write data to the file */
+{
+ if (fwrite (Data, 1, Size, F) != Size) {
+ Error ("Write error (disk full?)");
+ }
+}
+
+
+
+unsigned Read8 (FILE* F)
+/* Read an 8 bit value from the file */
+{
+ int C = getc (F);
+ if (C == EOF) {
+ Error ("Read error (file corrupt?)");
+ }
+ return C;
+}
+
+
+
+unsigned Read16 (FILE* F)
+/* Read a 16 bit value from the file */
+{
+ unsigned Lo = Read8 (F);
+ unsigned Hi = Read8 (F);
+ return (Hi << 8) | Lo;
+}
+
+
+
+unsigned long Read32 (FILE* F)
+/* Read a 32 bit value from the file */
+{
+ unsigned long Lo = Read16 (F);
+ unsigned long Hi = Read16 (F);
+ return (Hi << 16) | Lo;
+}
+
+
+
+char* ReadStr (FILE* F)
+/* Read a string from the file (the memory will be malloc'ed) */
+{
+ /* Read the length byte */
+ unsigned Len = Read8 (F);
+
+ /* Allocate memory and read the string itself */
+ char* S = Xmalloc (Len + 1);
+ ReadData (F, S, Len);
+
+ /* Terminate the string and return it */
+ S [Len] = '\0';
+ return S;
+}
+
+
+
+void* ReadData (FILE* F, void* Data, unsigned Size)
+/* Read data from the file */
+{
+ if (fread (Data, 1, Size, F) != Size) {
+ Error ("Read error (file corrupt?)");
+ }
+ return Data;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* fileio.h */
+/* */
+/* File I/O for the ar65 archiver */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef FILEIO_H
+#define FILEIO_H
+
+
+
+#include <stdio.h>
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void Write8 (FILE* F, unsigned char Val);
+/* Write an 8 bit value to the file */
+
+void Write16 (FILE* F, unsigned Val);
+/* Write a 16 bit value to the file */
+
+void Write32 (FILE* F, unsigned long Val);
+/* Write a 32 bit value to the file */
+
+void WriteStr (FILE* F, const char* S);
+/* Write a string to the file */
+
+void WriteData (FILE* F, const void* Data, unsigned Size);
+/* Write data to the file */
+
+unsigned Read8 (FILE* F);
+/* Read an 8 bit value from the file */
+
+unsigned Read16 (FILE* F);
+/* Read a 16 bit value from the file */
+
+unsigned long Read32 (FILE* F);
+/* Read a 32 bit value from the file */
+
+char* ReadStr (FILE* F);
+/* Read a string from the file (the memory will be malloc'ed) */
+
+void* ReadData (FILE* F, void* Data, unsigned Size);
+/* Read data from the file */
+
+
+
+/* End of fileio.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* global.c */
+/* */
+/* Global variables for the ar65 archiver */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include "global.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+const char* ProgName = "ar65"; /* Program name */
+
+int Verbose = 0; /* Verbose operation flag */
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* global.h */
+/* */
+/* Global variables for the ar65 archiver */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef GLOBAL_H
+#define GLOBAL_H
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+extern const char* ProgName; /* Program name */
+
+extern int Verbose; /* Verbose operation flag */
+
+
+
+/* End of global.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* library.c */
+/* */
+/* Library data structures and helpers for the ar65 archiver */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "../common/libdefs.h"
+#include "../common/symdefs.h"
+#include "../common/exprdefs.h"
+#include "../common/filepos.h"
+#include "../common/bitops.h"
+
+#include "mem.h"
+#include "error.h"
+#include "global.h"
+#include "fileio.h"
+#include "objdata.h"
+#include "exports.h"
+#include "library.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* File descriptor for the library file */
+FILE* NewLib = 0;
+static FILE* Lib = 0;
+static const char* LibName = 0;
+
+/* The library header */
+static LibHeader Header = {
+ LIB_MAGIC,
+ LIB_VERSION
+};
+
+
+
+/*****************************************************************************/
+/* Writing file data structures */
+/*****************************************************************************/
+
+
+
+static void ReadHeader (void)
+/* Read the header of a library file */
+{
+ /* Seek to position zero */
+ fseek (Lib, 0, SEEK_SET);
+
+ /* Read the header fields, checking magic and version */
+ Header.Magic = Read32 (Lib);
+ if (Header.Magic != LIB_MAGIC) {
+ Error ("`%s' is not a valid library file", LibName);
+ }
+ Header.Version = Read16 (Lib);
+ if (Header.Version != LIB_VERSION) {
+ Error ("Wrong data version in `%s'", LibName);
+ }
+ Header.Flags = Read16 (Lib);
+ Header.IndexOffs = Read32 (Lib);
+}
+
+
+
+static void ReadIndexEntry (void)
+/* Read one entry in the index */
+{
+ /* Create a new entry and insert it into the list */
+ ObjData* O = NewObjData ();
+
+ /* Module name/flags/MTime/Start/Size */
+ O->Name = ReadStr (Lib);
+ O->Flags = Read16 (Lib);
+ O->MTime = Read32 (Lib);
+ O->Start = Read32 (Lib);
+ O->Size = Read32 (Lib);
+
+ /* Exports */
+ O->ExportSize = Read16 (Lib);
+ O->Exports = Xmalloc (O->ExportSize);
+ ReadData (Lib, O->Exports, O->ExportSize);
+
+ /* Imports */
+ O->ImportSize = Read16 (Lib);
+ O->Imports = Xmalloc (O->ImportSize);
+ ReadData (Lib, O->Imports, O->ImportSize);
+}
+
+
+
+static void ReadIndex (void)
+/* Read the index of a library file */
+{
+ unsigned Count;
+
+ /* Seek to the start of the index */
+ fseek (Lib, Header.IndexOffs, SEEK_SET);
+
+ /* Read the object file count and calculate the cross ref size */
+ Count = Read16 (Lib);
+
+ /* Read all entries in the index */
+ while (Count--) {
+ ReadIndexEntry ();
+ }
+}
+
+
+
+/*****************************************************************************/
+/* Writing file data structures */
+/*****************************************************************************/
+
+
+
+static void WriteHeader (void)
+/* Write the header to the library file */
+{
+ /* Seek to position zero */
+ fseek (NewLib, 0, SEEK_SET);
+
+ /* Write the header fields */
+ Write32 (NewLib, Header.Magic);
+ Write16 (NewLib, Header.Version);
+ Write16 (NewLib, Header.Flags);
+ Write32 (NewLib, Header.IndexOffs);
+}
+
+
+
+static void WriteIndexEntry (ObjData* O)
+/* Write one index entry */
+{
+ /* Module name/flags/MTime/start/size */
+ WriteStr (NewLib, O->Name);
+ Write16 (NewLib, O->Flags & ~OBJ_HAVEDATA);
+ Write32 (NewLib, O->MTime);
+ Write32 (NewLib, O->Start);
+ Write32 (NewLib, O->Size);
+
+ /* Exports */
+ Write16 (NewLib, O->ExportSize);
+ WriteData (NewLib, O->Exports, O->ExportSize);
+
+ /* Imports */
+ Write16 (NewLib, O->ImportSize);
+ WriteData (NewLib, O->Imports, O->ImportSize);
+}
+
+
+
+static void WriteIndex (void)
+/* Write the index of a library file */
+{
+ ObjData* O;
+
+ /* Sync I/O in case the last operation was a read */
+ fseek (NewLib, 0, SEEK_CUR);
+
+ /* Remember the current offset in the header */
+ Header.IndexOffs = ftell (NewLib);
+
+ /* Write the object file count */
+ Write16 (NewLib, ObjCount);
+
+ /* Write the object files */
+ O = ObjRoot;
+ while (O) {
+ WriteIndexEntry (O);
+ O = O->Next;
+ }
+}
+
+
+
+/*****************************************************************************/
+/* High level stuff */
+/*****************************************************************************/
+
+
+
+void LibOpen (const char* Name, int MustExist, int NeedTemp)
+/* Open an existing library and a temporary copy. If MustExist is true, the
+ * old library is expected to exist. If NeedTemp is true, a temporary library
+ * is created.
+ */
+{
+ /* Remember the name */
+ LibName = StrDup (Name);
+
+ /* Open the existing library for reading */
+ Lib = fopen (Name, "rb");
+ if (Lib == 0) {
+
+ /* File does not exist */
+ if (MustExist) {
+ Error ("Library `%s' does not exist", Name);
+ } else {
+ Warning ("Library `%s' not found - will be created", Name);
+ }
+
+ } else {
+
+ /* We have an existing file: Read the header */
+ ReadHeader ();
+
+ /* Now read the existing index */
+ ReadIndex ();
+
+ }
+
+ if (NeedTemp) {
+ /* Create the temporary library */
+ NewLib = tmpfile ();
+ if (NewLib == 0) {
+ Error ("Cannot create temporary file: %s", strerror (errno));
+ }
+
+ /* Write a dummy header to the temp file */
+ WriteHeader ();
+ }
+}
+
+
+
+unsigned long LibCopyTo (FILE* F, unsigned long Bytes)
+/* Copy data from F to the temp library file, return the start position in
+ * the temporary library file.
+ */
+{
+ unsigned char Buf [4096];
+
+ /* Remember the position */
+ unsigned long Pos = ftell (NewLib);
+
+ /* Copy loop */
+ while (Bytes) {
+ unsigned Count = (Bytes > sizeof (Buf))? sizeof (Buf) : Bytes;
+ ReadData (F, Buf, Count);
+ WriteData (NewLib, Buf, Count);
+ Bytes -= Count;
+ }
+
+ /* Return the start position */
+ return Pos;
+}
+
+
+
+void LibCopyFrom (unsigned long Pos, unsigned long Bytes, FILE* F)
+/* Copy data from the library file into another file */
+{
+ unsigned char Buf [4096];
+
+ /* Seek to the correct position */
+ fseek (Lib, Pos, SEEK_SET);
+
+ /* Copy loop */
+ while (Bytes) {
+ unsigned Count = (Bytes > sizeof (Buf))? sizeof (Buf) : Bytes;
+ ReadData (Lib, Buf, Count);
+ WriteData (F, Buf, Count);
+ Bytes -= Count;
+ }
+}
+
+
+
+static void SkipExpr (unsigned char** Buf)
+/* Skip an expression in Buf */
+{
+ /* Get the operation and skip it */
+ unsigned char Op = **Buf;
+ ++(*Buf);
+
+ /* Filter leaf nodes */
+ switch (Op) {
+
+ case EXPR_NULL:
+ return;
+
+ case EXPR_LITERAL:
+ /* 32 bit literal value */
+ *Buf += 4;
+ return;
+
+ case EXPR_SYMBOL:
+ /* 16 bit symbol index */
+ *Buf += 2;
+ return;
+
+ case EXPR_SEGMENT:
+ /* 8 bit segment number */
+ *Buf += 1;
+ return;
+ }
+
+ /* What's left are unary and binary nodes */
+ SkipExpr (Buf); /* Skip left */
+ SkipExpr (Buf); /* Skip right */
+}
+
+
+
+static void LibCheckExports (ObjData* O)
+/* Insert all exports from the given object file into the global list
+ * checking for duplicates.
+ */
+{
+ char Name [256];
+
+ /* Get a pointer to the buffer */
+ unsigned char* Exports = O->Exports;
+
+ /* First two bytes are export count */
+ unsigned Lo = *Exports++;
+ unsigned Hi = *Exports++;
+ unsigned Count = (Hi << 8) + Lo;
+
+ /* Read the exports */
+ if (Verbose > 1) {
+ printf ("Module `%s' (%u exports):\n", O->Name, Count);
+ }
+ while (Count--) {
+
+ unsigned char Len;
+
+ /* Get the export tag */
+ unsigned char Tag = *Exports++;
+
+ /* Next thing is name of symbol */
+ Len = *Exports++;
+ memcpy (Name, Exports, Len);
+ Name [Len] = '\0';
+ Exports += Len;
+
+ /* Skip value of symbol */
+ if (Tag & EXP_EXPR) {
+ /* Expression tree */
+ SkipExpr (&Exports);
+ } else {
+ /* Constant 32 bit value */
+ Exports += 4;
+ }
+
+ /* Skip the position */
+ Exports += POS_SIZE;
+
+ /* Insert the name into the hash table */
+ if (Verbose > 1) {
+ printf (" %s\n", Name);
+ }
+ ExpInsert (Name, O->Index);
+ }
+}
+
+
+
+void LibClose (void)
+/* Write remaining data, close both files and copy the temp file to the old
+ * filename
+ */
+{
+ /* Do we have a temporary library? */
+ if (NewLib) {
+
+ unsigned I;
+ unsigned char Buf [4096];
+ size_t Count;
+
+ /* Index the object files and make an array containing the objects */
+ MakeObjPool ();
+
+ /* Walk through the object file list, inserting exports into the
+ * export list checking for duplicates. Copy any data that is still
+ * in the old library into the new one.
+ */
+ for (I = 0; I < ObjCount; ++I) {
+
+ /* Get a pointer to the object */
+ ObjData* O = ObjPool [I];
+
+ /* Check exports, make global export table */
+ LibCheckExports (O);
+
+ /* Copy data if needed */
+ if ((O->Flags & OBJ_HAVEDATA) == 0) {
+ /* Data is still in the old library */
+ fseek (Lib, O->Start, SEEK_SET);
+ O->Start = ftell (NewLib);
+ LibCopyTo (Lib, O->Size);
+ O->Flags |= OBJ_HAVEDATA;
+ }
+ }
+
+ /* Write the index */
+ WriteIndex ();
+
+ /* Write the updated header */
+ WriteHeader ();
+
+ /* Close the file */
+ if (Lib && fclose (Lib) != 0) {
+ Error ("Error closing library: %s", strerror (errno));
+ }
+
+ /* Reopen the library and truncate it */
+ Lib = fopen (LibName, "wb");
+ if (Lib == 0) {
+ Error ("Cannot open library `%s' for writing: %s",
+ LibName, strerror (errno));
+ }
+
+ /* Copy the new library to the new one */
+ fseek (NewLib, 0, SEEK_SET);
+ while ((Count = fread (Buf, 1, sizeof (Buf), NewLib)) != 0) {
+ if (fwrite (Buf, 1, Count, Lib) != Count) {
+ Error ("Cannot write to `%s': %s", LibName, strerror (errno));
+ }
+ }
+ }
+
+ /* Close both files */
+ if (Lib && fclose (Lib) != 0) {
+ Error ("Problem closing `%s': %s", LibName, strerror (errno));
+ }
+ if (NewLib && fclose (NewLib) != 0) {
+ Error ("Problem closing temporary library file: %s", strerror (errno));
+ }
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* library.h */
+/* */
+/* Library data structures and helpers for the ar65 archiver */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef LIBRARY_H
+#define LIBRARY_H
+
+
+
+#include <stdio.h>
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* File descriptor for the new library file */
+extern FILE* NewLib;
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void LibOpen (const char* Name, int MustExist, int NeedTemp);
+/* Open an existing library and a temporary copy. If MustExist is true, the
+ * old library is expected to exist. If NeedTemp is true, a temporary library
+ * is created.
+ */
+
+unsigned long LibCopyTo (FILE* F, unsigned long Bytes);
+/* Copy data from F to the temp library file, return the start position in
+ * the temporary library file.
+ */
+
+void LibCopyFrom (unsigned long Pos, unsigned long Bytes, FILE* F);
+/* Copy data from the library file into another file */
+
+void LibClose (void);
+/* Write remaining data, close both files and copy the temp file to the old
+ * filename
+ */
+
+
+
+/* End of library.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* list.c */
+/* */
+/* Module listing for the ar65 archiver */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "error.h"
+#include "objdata.h"
+#include "library.h"
+#include "list.h"
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void ListObjFiles (int argc, char* argv [])
+/* List modules in a library */
+{
+ ObjData* O;
+
+ /* Check the argument count */
+ if (argc <= 0) {
+ Error ("No library name given");
+ }
+ if (argc > 2) {
+ Error ("Too many arguments");
+ }
+
+ /* Open the library, read the index */
+ LibOpen (argv [0], 1, 0);
+
+ /* List the modules */
+ O = ObjRoot;
+ while (O) {
+ printf ("%s\n", O->Name);
+ O = O->Next;
+ }
+
+ /* Create a new library file and close the old one */
+ LibClose ();
+
+ /* Successful end */
+ exit (EXIT_SUCCESS);
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* list.h */
+/* */
+/* Module listing for the ar65 archiver */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef LIST_H
+#define LIST_H
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void ListObjFiles (int argc, char* argv []);
+/* List modules in a library */
+
+
+
+/* End of list.h */
+
+#endif
+
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* main.c */
+/* */
+/* Main program for the ar65 archiver */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "../common/version.h"
+
+#include "global.h"
+#include "error.h"
+#include "mem.h"
+#include "add.h"
+#include "del.h"
+#include "list.h"
+#include "extract.h"
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+static void Usage (void)
+/* Print usage information and exit */
+{
+ fprintf (stderr,
+ "Usage: %s <operation> lib file|module ...\n"
+ "Operation is one of:\n"
+ "\ta\tAdd modules\n"
+ "\td\tDelete modules\n"
+ "\tl\tList library contents\n"
+ "\tx\tExtract modules\n"
+ "\tV\tPrint the archiver version\n",
+ ProgName);
+ exit (EXIT_FAILURE);
+}
+
+
+
+int main (int argc, char* argv [])
+/* Assembler main program */
+{
+ int I;
+
+ /* We must have a file name */
+ if (argc < 2) {
+ Usage ();
+ }
+
+ /* Check the parameters */
+ I = 1;
+ while (I < argc) {
+
+ /* Get the argument */
+ const char* Arg = argv [I];
+
+ /* Check for an option */
+ if (strlen (Arg) != 1) {
+ Usage ();
+ }
+ switch (Arg [0]) {
+
+ case 'a':
+ AddObjFiles (argc - I - 1, &argv [I+1]);
+ break;
+
+ case 'd':
+ DelObjFiles (argc - I - 1, &argv [I+1]);
+ break;
+
+ case 'l':
+ ListObjFiles (argc - I - 1, &argv [I+1]);
+ break;
+
+ case 'v':
+ ++Verbose;
+ break;
+
+ case 'x':
+ ExtractObjFiles (argc - I - 1, &argv [I+1]);
+ break;
+
+ case 'V':
+ fprintf (stderr,
+ "ar65 V%u.%u.%u - (C) Copyright 1998-1999 Ullrich von Bassewitz\n",
+ VER_MAJOR, VER_MINOR, VER_PATCH);
+ break;
+
+ default:
+ fprintf (stderr, "Unknown option: %s\n", Arg);
+ Usage ();
+
+ }
+
+ /* Next argument */
+ ++I;
+ }
+
+ /* Return an apropriate exit code */
+ return EXIT_SUCCESS;
+}
+
+
+
--- /dev/null
+#
+# gcc Makefile for ar65
+#
+
+CFLAGS = -g -O2 -Wall
+CC = gcc
+LDFLAGS =
+
+OBJS = add.o \
+ del.o \
+ error.o \
+ exports.o \
+ extract.o \
+ fileio.o \
+ global.o \
+ library.o \
+ list.o \
+ main.o \
+ mem.o \
+ objdata.o \
+ objfile.o
+
+LIBS = ../common/common.a
+
+
+EXECS = ar65
+
+.PHONY: all
+ifeq (.depend,$(wildcard .depend))
+all : $(EXECS)
+include .depend
+else
+all: depend
+ @$(MAKE) -f make/gcc.mak all
+endif
+
+
+
+ar65: $(OBJS) $(LIBS)
+ $(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS)
+
+clean:
+ rm -f *~ core
+
+zap: clean
+ rm -f *.o $(EXECS) .depend
+
+# ------------------------------------------------------------------------------
+# Make the dependencies
+
+.PHONY: depend dep
+depend dep: $(OBJS:.o=.c)
+ @echo "Creating dependency information"
+ $(CC) -MM $^ > .depend
+
+
--- /dev/null
+#
+# ar65 Makefile for the Watcom compiler
+#
+
+# ------------------------------------------------------------------------------
+# Generic stuff
+
+.AUTODEPEND
+.SUFFIXES .ASM .C .CC .CPP
+.SWAP
+
+AR = WLIB
+LD = WLINK
+
+!if !$d(TARGET)
+!if $d(__OS2__)
+TARGET = OS2
+!else
+TARGET = NT
+!endif
+!endif
+
+# target specific macros.
+!if $(TARGET)==OS2
+
+# --------------------- OS2 ---------------------
+SYSTEM = os2v2
+CC = WCC386
+CCCFG = -bt=$(TARGET) -d1 -onatx -zp4 -5 -zq -w2
+
+!elif $(TARGET)==DOS32
+
+# -------------------- DOS4G --------------------
+SYSTEM = dos4g
+CC = WCC386
+CCCFG = -bt=$(TARGET) -d1 -onatx -zp4 -5 -zq -w2
+
+!elif $(TARGET)==DOS
+
+# --------------------- DOS ---------------------
+SYSTEM = dos
+CC = WCC
+CCCFG = -bt=$(TARGET) -d1 -onatx -zp2 -2 -ml -zq -w2
+
+!elif $(TARGET)==NT
+
+# --------------------- NT ----------------------
+SYSTEM = nt
+CC = WCC386
+CCCFG = -bt=$(TARGET) -d1 -onatx -zp4 -5 -zq -w2
+
+!else
+!error
+!endif
+
+# ------------------------------------------------------------------------------
+# Implicit rules
+
+.c.obj:
+ $(CC) $(CCCFG) $<
+
+
+# ------------------------------------------------------------------------------
+# All library OBJ files
+
+OBJS = add.obj \
+ del.obj \
+ error.obj \
+ exports.obj \
+ extract.obj \
+ fileio.obj \
+ global.obj \
+ library.obj \
+ list.obj \
+ main.obj \
+ mem.obj \
+ objdata.obj \
+ objfile.obj
+
+LIBS = ..\common\common.lib
+
+
+# ------------------------------------------------------------------------------
+# Main targets
+
+all: ar65
+
+ar65: ar65.exe
+
+
+# ------------------------------------------------------------------------------
+# Other targets
+
+
+ar65.exe: $(OBJS) $(LIBS)
+ $(LD) system $(SYSTEM) @&&|
+DEBUG ALL
+OPTION QUIET
+NAME $<
+FILE add.obj
+FILE del.obj
+FILE error.obj
+FILE exports.obj
+FILE extract.obj
+FILE fileio.obj
+FILE global.obj
+FILE library.obj
+FILE list.obj
+FILE main.obj
+FILE mem.obj
+FILE objdata.obj
+FILE objfile.obj
+LIBRARY ..\common\common.lib
+|
+
+
+clean:
+ @if exist *.obj del *.obj
+ @if exist ar65.exe del ar65.exe
+
+strip:
+ @-wstrip ar65.exe
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* mem.c */
+/* */
+/* Memory allocation for the ar65 archiver */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "error.h"
+#include "mem.h"
+
+
+
+/*****************************************************************************/
+/* code */
+/*****************************************************************************/
+
+
+
+void* Xmalloc (size_t size)
+/* Allocate memory, check for out of memory condition. Do some debugging */
+{
+ void* p;
+
+ p = malloc (size);
+ if (p == 0 && size != 0) {
+ Error ("Out of memory");
+ }
+
+ /* Return a pointer to the block */
+ return p;
+}
+
+
+
+void Xfree (const void* block)
+/* Free the block, do some debugging */
+{
+ free ((void*) block);
+}
+
+
+
+char* StrDup (const char* s)
+/* Duplicate a string on the heap. The function checks for out of memory */
+{
+ unsigned len;
+
+ len = strlen (s) + 1;
+ return memcpy (Xmalloc (len), s, len);
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* mem.h */
+/* */
+/* Memory allocation for the ar65 archiver */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef MEM_H
+#define MEM_H
+
+
+
+#include <stddef.h>
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void* Xmalloc (size_t size);
+/* Allocate memory, check for out of memory condition. Do some debugging */
+
+void Xfree (const void* block);
+/* Free the block, do some debugging */
+
+char* StrDup (const char* s);
+/* Duplicate a string on the heap. The function checks for out of memory */
+
+
+
+/* End of mem.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* objdata.c */
+/* */
+/* Handling object file data for the ar65 archiver */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <string.h>
+
+#include "mem.h"
+#include "error.h"
+#include "objdata.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Object data list management */
+unsigned ObjCount = 0; /* Count of object files in the list */
+ObjData* ObjRoot = 0; /* List of object files */
+ObjData* ObjLast = 0; /* Last entry in list */
+ObjData** ObjPool = 0; /* Object files as array */
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+ObjData* NewObjData (void)
+/* Allocate a new structure on the heap, insert it into the list, return it */
+{
+ /* Allocate memory */
+ ObjData* O = Xmalloc (sizeof (ObjData));
+
+ /* Initialize the data */
+ O->Next = 0;
+ O->Name = 0;
+ O->Index = ~0;
+ O->Flags = 0;
+ O->MTime = 0;
+ O->Start = 0;
+ O->Size = 0;
+ O->ImportSize = 0;
+ O->Imports = 0;
+ O->ExportSize = 0;
+ O->Exports = 0;
+
+ /* Link it into the list */
+ if (ObjLast) {
+ ObjLast->Next = O;
+ ObjLast = O;
+ } else {
+ /* First entry */
+ ObjRoot = ObjLast = O;
+ }
+
+ /* One object file more now */
+ ++ObjCount;
+
+ /* Return the new entry */
+ return O;
+}
+
+
+
+void FreeObjData (ObjData* O)
+/* Free a complete struct */
+{
+ Xfree (O->Name);
+ Xfree (O->Imports);
+ Xfree (O->Exports);
+ Xfree (O);
+}
+
+
+
+ObjData* FindObjData (const char* Module)
+/* Search for the module with the given name and return it. Return NULL if the
+ * module is not in the list.
+ */
+{
+ /* Hmm. Maybe we should hash the module names? */
+ ObjData* O = ObjRoot;
+ while (O) {
+ if (strcmp (O->Name, Module) == 0) {
+ return O;
+ }
+ O = O->Next;
+ }
+ return 0;
+}
+
+
+
+void DelObjData (const char* Module)
+/* Delete the object module from the list */
+{
+ ObjData* O = ObjRoot;
+ ObjData* Last = 0;
+ while (O) {
+ if (strcmp (O->Name, Module) == 0) {
+ /* Found the module, remove it from the list */
+ if (Last == 0) {
+ /* This was the first entry in the list */
+ ObjRoot = O->Next;
+ } else {
+ Last->Next = O->Next;
+ }
+ if (ObjLast == O) {
+ /* O was the last object in the list */
+ ObjLast = Last;
+ }
+ --ObjCount;
+
+ /* Free the entry */
+ FreeObjData (O);
+
+ /* Done */
+ return;
+ }
+ Last = O;
+ O = O->Next;
+ }
+
+ /* Not found! */
+ Warning ("Module `%s' not found in library", Module);
+}
+
+
+
+void MakeObjPool (void)
+/* Allocate memory, index the entries and make the ObjPool valid */
+{
+ ObjData* O;
+ unsigned Index;
+
+ /* Allocate memory for the pool */
+ ObjPool = Xmalloc (ObjCount * sizeof (ObjData*));
+
+ /* Setup the pointers and index the objects */
+ Index = 0;
+ O = ObjRoot;
+ while (O) {
+
+ /* Safety */
+ CHECK (Index < ObjCount);
+
+ /* Set the Index */
+ O->Index = Index;
+
+ /* Set the pool pointer */
+ ObjPool [Index] = O;
+
+ /* Next object */
+ ++Index;
+ O = O->Next;
+ }
+}
+
+
+
+const char* GetObjName (unsigned Index)
+/* Get the name of a module by index */
+{
+ PRECONDITION (ObjPool != 0 && Index < ObjCount && ObjPool [Index] != 0);
+ return ObjPool [Index]->Name;
+}
+
+
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* objdata.h */
+/* */
+/* Handling object file data for the ar65 archiver */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef OBJDATA_H
+#define OBJDATA_H
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Values for the Flags field */
+#define OBJ_HAVEDATA 0x0001 /* The object data is in the tmp file */
+#define OBJ_MARKED 0x0002 /* Generic marker bit */
+
+
+/* Internal structure holding object file data */
+typedef struct ObjData_ ObjData;
+struct ObjData_ {
+ ObjData* Next; /* Linked list of all objects */
+ char* Name; /* Module name */
+ unsigned Index; /* Module index */
+ unsigned Flags;
+ unsigned long MTime; /* Modifiation time of object file */
+ unsigned long Start; /* Start offset of data in library */
+ unsigned long Size; /* Size of data in library */
+ unsigned long ImportSize; /* Size of imports */
+ void* Imports; /* Imports as raw data */
+ unsigned long ExportSize; /* Size of exports */
+ void* Exports; /* Exports as raw data */
+};
+
+
+
+/* Object data list management */
+extern unsigned ObjCount; /* Count of files in the list */
+extern ObjData* ObjRoot; /* List of object files */
+extern ObjData* ObjLast; /* Last entry in list */
+extern ObjData** ObjPool; /* Object files as array */
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+ObjData* NewObjData (void);
+/* Allocate a new structure on the heap, insert it into the list, return it */
+
+void FreeObjData (ObjData* O);
+/* Free a complete struct */
+
+ObjData* FindObjData (const char* Module);
+/* Search for the module with the given name and return it. Return NULL if the
+ * module is not in the list.
+ */
+
+void DelObjData (const char* Module);
+/* Delete the object module from the list */
+
+void MakeObjPool (void);
+/* Allocate memory, index the entries and make the ObjPool valid */
+
+const char* GetObjName (unsigned Index);
+/* Get the name of a module by index */
+
+
+
+/* End of objdata.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* objfile.c */
+/* */
+/* Object file handling for the ar65 archiver */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <string.h>
+#include <errno.h>
+#ifdef __WATCOMC__
+/* Watcom has the file in the wrong directory */
+# include <sys/utime.h>
+#else
+# include <sys/types.h> /* FreeBSD needs this */
+# include <utime.h>
+#endif
+#include <time.h>
+#include <sys/stat.h>
+
+#include "error.h"
+#include "mem.h"
+#include "objdata.h"
+#include "fileio.h"
+#include "library.h"
+#include "objfile.h"
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+static const char* GetModule (const char* Name)
+/* Get a module name from the file name */
+{
+ /* Make a module name from the file name */
+ const char* Module = Name + strlen (Name);
+ while (Module > Name) {
+ --Module;
+ if (*Module == '/' || *Module == '\\') {
+ ++Module;
+ break;
+ }
+ }
+ if (*Module == 0) {
+ Error ("Cannot make module name from `%s'", Name);
+ }
+ return Module;
+}
+
+
+
+void ObjReadHeader (FILE* Obj, ObjHeader* H, const char* Name)
+/* Read the header of the object file checking the signature */
+{
+ H->Magic = Read32 (Obj);
+ if (H->Magic != OBJ_MAGIC) {
+ Error ("`%s' is not an object file", Name);
+ }
+ H->Version = Read16 (Obj);
+ if (H->Version != OBJ_VERSION) {
+ Error ("Object file `%s' has wrong version", Name);
+ }
+ H->Flags = Read16 (Obj);
+ H->OptionOffs = Read32 (Obj);
+ H->OptionSize = Read32 (Obj);
+ H->FileOffs = Read32 (Obj);
+ H->FileSize = Read32 (Obj);
+ H->SegOffs = Read32 (Obj);
+ H->SegSize = Read32 (Obj);
+ H->ImportOffs = Read32 (Obj);
+ H->ImportSize = Read32 (Obj);
+ H->ExportOffs = Read32 (Obj);
+ H->ExportSize = Read32 (Obj);
+ H->DbgSymOffs = Read32 (Obj);
+ H->DbgSymSize = Read32 (Obj);
+}
+
+
+
+void ObjWriteHeader (FILE* Obj, ObjHeader* H)
+/* Write the header of the object file */
+{
+ Write32 (Obj, H->Magic);
+ Write16 (Obj, H->Version);
+ Write16 (Obj, H->Flags);
+ Write32 (Obj, H->OptionOffs);
+ Write32 (Obj, H->OptionSize);
+ Write32 (Obj, H->FileOffs);
+ Write32 (Obj, H->FileSize);
+ Write32 (Obj, H->SegOffs);
+ Write32 (Obj, H->SegSize);
+ Write32 (Obj, H->ImportOffs);
+ Write32 (Obj, H->ImportSize);
+ Write32 (Obj, H->ExportOffs);
+ Write32 (Obj, H->ExportSize);
+ Write32 (Obj, H->DbgSymOffs);
+ Write32 (Obj, H->DbgSymSize);
+}
+
+
+
+void ObjAdd (const char* Name)
+/* Add an object file to the library */
+{
+ struct stat StatBuf;
+ const char* Module;
+ ObjHeader H;
+ ObjData* O;
+
+ /* Open the object file */
+ FILE* Obj = fopen (Name, "rb");
+ if (Obj == 0) {
+ Error ("Could not open `%s': %s", Name, strerror (errno));
+ }
+
+ /* Get the modification time of the object file */
+ if (fstat (fileno (Obj), &StatBuf) != 0) {
+ Error ("Cannot stat object file `%s': %s", Name, strerror (errno));
+ }
+
+ /* Read and check the header */
+ ObjReadHeader (Obj, &H, Name);
+
+ /* Make a module name from the file name */
+ Module = GetModule (Name);
+
+ /* Check if we already have a module with this name */
+ O = FindObjData (Module);
+ if (O == 0) {
+ /* Not found, create a new entry */
+ O = NewObjData ();
+ } else {
+ /* Found - check the file modification times of the internal copy
+ * and the external one.
+ */
+ if (difftime ((time_t)O->MTime, StatBuf.st_mtime) > 0.0) {
+ Warning ("Replacing module `%s' by older version", O->Name);
+ }
+ }
+
+ /* Initialize the object module data structure */
+ O->Name = StrDup (Module);
+ O->Flags = OBJ_HAVEDATA;
+ O->MTime = StatBuf.st_mtime;
+ O->ImportSize = H.ImportSize;
+ O->Imports = Xmalloc (O->ImportSize);
+ O->ExportSize = H.ExportSize;
+ O->Exports = Xmalloc (O->ExportSize);
+
+ /* Read imports and exports */
+ fseek (Obj, H.ImportOffs, SEEK_SET);
+ ReadData (Obj, O->Imports, O->ImportSize);
+ fseek (Obj, H.ExportOffs, SEEK_SET);
+ ReadData (Obj, O->Exports, O->ExportSize);
+
+ /* Skip the object file header */
+ O->Start = ftell (NewLib);
+ fseek (NewLib, OBJ_HDR_SIZE, SEEK_CUR);
+
+ /* Copy the remaining sections */
+ fseek (Obj, H.DbgSymOffs, SEEK_SET);
+ H.DbgSymOffs = LibCopyTo (Obj, H.DbgSymSize) - O->Start;
+ fseek (Obj, H.OptionOffs, SEEK_SET);
+ H.OptionOffs = LibCopyTo (Obj, H.OptionSize) - O->Start;
+ fseek (Obj, H.SegOffs, SEEK_SET);
+ H.SegOffs = LibCopyTo (Obj, H.SegSize) - O->Start;
+ fseek (Obj, H.FileOffs, SEEK_SET);
+ H.FileOffs = LibCopyTo (Obj, H.FileSize) - O->Start;
+
+ /* Calculate the amount of data written */
+ O->Size = ftell (NewLib) - O->Start;
+
+ /* Clear the remaining header fields */
+ H.ImportOffs = H.ImportSize = 0;
+ H.ExportOffs = H.ExportSize = 0;
+
+ /* Seek back and write the updated header */
+ fseek (NewLib, O->Start, SEEK_SET);
+ ObjWriteHeader (NewLib, &H);
+
+ /* Now seek again to end of file */
+ fseek (NewLib, 0, SEEK_END);
+
+ /* Done, close the file (we read it only, so no error check) */
+ fclose (Obj);
+}
+
+
+
+void ObjExtract (const char* Name)
+/* Extract a module from the library */
+{
+ unsigned long ImportStart;
+ unsigned long ExportStart;
+ struct utimbuf U;
+ ObjHeader H;
+ FILE* Obj;
+
+
+ /* Make a module name from the file name */
+ const char* Module = GetModule (Name);
+
+ /* Try to find the module in the library */
+ ObjData* O = FindObjData (Module);
+
+ /* Bail out if the module does not exist */
+ if (O == 0) {
+ Error ("Module `%s' not found in library", Module);
+ }
+
+ /* Open the output file */
+ Obj = fopen (Name, "w+b");
+ if (Obj == 0) {
+ Error ("Cannot open target file `%s': %s", Name, strerror (errno));
+ }
+
+ /* Copy the first four segments including the header to the new file */
+ LibCopyFrom (O->Start, O->Size, Obj);
+
+ /* Write imports and exports */
+ ImportStart = ftell (Obj);
+ WriteData (Obj, O->Imports, O->ImportSize);
+ ExportStart = ftell (Obj);
+ WriteData (Obj, O->Exports, O->ExportSize);
+
+ /* Seek back and read the header */
+ fseek (Obj, 0, SEEK_SET);
+ ObjReadHeader (Obj, &H, Name);
+
+ /* Update the header fields */
+ H.ImportOffs = ImportStart;
+ H.ImportSize = O->ImportSize;
+ H.ExportOffs = ExportStart;
+ H.ExportSize = O->ExportSize;
+
+ /* Write the changed header */
+ fseek (Obj, 0, SEEK_SET);
+ ObjWriteHeader (Obj, &H);
+
+ /* Close the file */
+ if (fclose (Obj) != 0) {
+ Error ("Problem closing object file `%s': %s", Name, strerror (errno));
+ }
+
+ /* Set access and modification time */
+ U.actime = O->MTime;
+ U.modtime = O->MTime;
+ if (utime (Name, &U) != 0) {
+ Error ("Cannot set mod time on `%s': %s", Name, strerror (errno));
+ }
+}
+
+
+
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* objfile.h */
+/* */
+/* Object file handling for the ar65 archiver */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef OBJFILE_H
+#define OBJFILE_H
+
+
+
+#include <stdio.h>
+
+#include "../common/objdefs.h"
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void ObjReadHeader (FILE* Obj, ObjHeader* H, const char* Name);
+/* Read the header of the object file checking the signature */
+
+void ObjWriteHeader (FILE* Obj, ObjHeader* H);
+/* Write the header of the object file */
+
+void ObjAdd (const char* Name);
+/* Add an object file to the library */
+
+void ObjExtract (const char* Name);
+/* Extract a module from the library */
+
+
+
+/* End of objfile.h */
+
+#endif
+
+
+
--- /dev/null
+.depend
+ca65
--- /dev/null
+/*****************************************************************************/
+/* */
+/* condasm.c */
+/* */
+/* Conditional assembly support for ca65 */
+/* */
+/* */
+/* */
+/* (C) 2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include "error.h"
+#include "expr.h"
+#include "scanner.h"
+#include "symtab.h"
+#include "condasm.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Maximum count of nested .ifs */
+#define MAX_IFS 32
+
+/* Set of bitmapped flags for the if descriptor */
+enum {
+ ifNone = 0x0000, /* No flag */
+ ifCond = 0x0001, /* IF condition was true */
+ ifElse = 0x0002, /* We had a .ELSE branch */
+ ifNeedTerm = 0x0004 /* Need .ENDIF termination */
+};
+
+
+
+/*****************************************************************************/
+/* struct IfDesc */
+/*****************************************************************************/
+
+
+
+/* One .IF descriptor */
+typedef struct IfDesc_ IfDesc;
+struct IfDesc_ {
+ unsigned Flags; /* Bitmapped flags, see above */
+ FilePos Pos; /* File position of the .IF */
+ const char* Name; /* Name of the directive */
+};
+
+/* The .IF stack */
+static IfDesc IfStack [MAX_IFS];
+static unsigned IfCount = 0;
+
+
+
+static IfDesc* AllocIf (const char* Directive, int NeedTerm)
+/* Alloc a new element from the .IF stack */
+{
+ IfDesc* ID;
+
+ /* Check for stack overflow */
+ if (IfCount >= MAX_IFS) {
+ Error (ERR_IF_NESTING);
+ }
+
+ /* Alloc one element */
+ ID = &IfStack [IfCount++];
+
+ /* Initialize elements */
+ ID->Flags = NeedTerm? ifNeedTerm : ifNone;
+ ID->Pos = CurPos;
+ ID->Name = Directive;
+
+ /* Return the result */
+ return ID;
+}
+
+
+
+static IfDesc* GetCurrentIf (void)
+/* Return the current .IF descriptor */
+{
+ if (IfCount == 0) {
+ return 0;
+ } else {
+ return &IfStack [IfCount-1];
+ }
+}
+
+
+
+static void FreeIf (void)
+/* Free all .IF descriptors until we reach one with the NeedTerm bit set */
+{
+ int Done = 0;
+ do {
+ IfDesc* D = GetCurrentIf();
+ if (D == 0) {
+ Error (ERR_UNEXPECTED, ".ENDIF");
+ } else {
+ Done = (D->Flags & ifNeedTerm) != 0;
+ --IfCount;
+ }
+ } while (!Done);
+}
+
+
+
+static int GetCurrentIfCond (void)
+/* Return the current condition based on all conditions on the stack */
+{
+ unsigned Count;
+ for (Count = 0; Count < IfCount; ++Count) {
+ if ((IfStack[Count].Flags & ifCond) == 0) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+
+
+static void SetIfCond (IfDesc* ID, int C)
+/* Set the .IF condition */
+{
+ if (C) {
+ ID->Flags |= ifCond;
+ } else {
+ ID->Flags &= ~ifCond;
+ }
+}
+
+
+
+static void InvertIfCond (IfDesc* ID)
+/* Invert the current condition */
+{
+ ID->Flags ^= ifCond;
+}
+
+
+
+static int GetElse (const IfDesc* ID)
+/* Return true if we had a .ELSE */
+{
+ return (ID->Flags & ifElse) != 0;
+}
+
+
+
+static void SetElse (IfDesc* ID, int E)
+/* Set the .ELSE flag */
+{
+ if (E) {
+ ID->Flags |= ifElse;
+ } else {
+ ID->Flags &= ~ifElse;
+ }
+}
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void DoConditionals (void)
+/* Catch all for conditional directives */
+{
+ IfDesc* D;
+
+ int IfCond = GetCurrentIfCond ();
+ do {
+
+ switch (Tok) {
+
+ case TOK_ELSE:
+ D = GetCurrentIf ();
+ if (D == 0) {
+ Error (ERR_UNEXPECTED, ".ELSE");
+ } else if (GetElse(D)) {
+ /* We already had a .ELSE ! */
+ Error (ERR_DUPLICATE_ELSE);
+ } else {
+ /* Allow an .ELSE */
+ InvertIfCond (D);
+ SetElse (D, 1);
+ D->Pos = CurPos;
+ D->Name = ".ELSE";
+ IfCond = GetCurrentIfCond ();
+ }
+ NextTok ();
+ break;
+
+ case TOK_ELSEIF:
+ D = GetCurrentIf ();
+ if (D == 0) {
+ Error (ERR_UNEXPECTED, ".ELSEIF");
+ } else if (GetElse(D)) {
+ /* We already had a .ELSE */
+ Error (ERR_DUPLICATE_ELSE);
+ } else {
+ /* Handle as if there was an .ELSE first */
+ InvertIfCond (D);
+ SetElse (D, 1);
+
+ /* Allocate and prepare a new descriptor */
+ D = AllocIf (".ELSEIF", 0);
+ NextTok ();
+
+ /* Ignore the new condition if we are inside a false .ELSE
+ * branch. This way we won't get any errors about undefined
+ * symbols or similar...
+ */
+ if (IfCond == 0) {
+ SetIfCond (D, ConstExpression ());
+ }
+
+ /* Get the new overall condition */
+ IfCond = GetCurrentIfCond ();
+ }
+ break;
+
+ case TOK_ENDIF:
+ /* We're done with this .IF.. - remove the descriptor(s) */
+ FreeIf ();
+
+ /* Be sure not to read the next token until the .IF stack
+ * has been cleanup up, since we may be at end of file.
+ */
+ NextTok ();
+
+ /* Get the new overall condition */
+ IfCond = GetCurrentIfCond ();
+ break;
+
+ case TOK_IF:
+ D = AllocIf (".IF", 1);
+ NextTok ();
+ if (IfCond) {
+ SetIfCond (D, ConstExpression ());
+ }
+ IfCond = GetCurrentIfCond ();
+ break;
+
+ case TOK_IFBLANK:
+ D = AllocIf (".IFBLANK", 1);
+ NextTok ();
+ if (IfCond) {
+ SetIfCond (D, Tok == TOK_SEP);
+ }
+ IfCond = GetCurrentIfCond ();
+ break;
+
+ case TOK_IFCONST:
+ D = AllocIf (".IFCONST", 1);
+ NextTok ();
+ if (IfCond) {
+ ExprNode* Expr = Expression();
+ SetIfCond (D, IsConstExpr (Expr));
+ FreeExpr (Expr);
+ }
+ IfCond = GetCurrentIfCond ();
+ break;
+
+ case TOK_IFDEF:
+ D = AllocIf (".IFDEF", 1);
+ NextTok ();
+ if (IfCond) {
+ if (Tok != TOK_IDENT) {
+ ErrorSkip (ERR_IDENT_EXPECTED);
+ } else {
+ SetIfCond (D, SymIsDef (SVal));
+ NextTok ();
+ }
+ }
+ IfCond = GetCurrentIfCond ();
+ break;
+
+ case TOK_IFNBLANK:
+ D = AllocIf (".IFNBLANK", 1);
+ NextTok ();
+ if (IfCond) {
+ SetIfCond (D, Tok != TOK_SEP);
+ }
+ IfCond = GetCurrentIfCond ();
+ break;
+
+ case TOK_IFNCONST:
+ D = AllocIf (".IFNCONST", 1);
+ NextTok ();
+ if (IfCond) {
+ ExprNode* Expr = Expression();
+ SetIfCond (D, !IsConstExpr (Expr));
+ FreeExpr (Expr);
+ }
+ IfCond = GetCurrentIfCond ();
+ break;
+
+ case TOK_IFNDEF:
+ D = AllocIf (".IFNDEF", 1);
+ NextTok ();
+ if (IfCond) {
+ if (Tok != TOK_IDENT) {
+ ErrorSkip (ERR_IDENT_EXPECTED);
+ } else {
+ SetIfCond (D, !SymIsDef (SVal));
+ NextTok ();
+ }
+ }
+ IfCond = GetCurrentIfCond ();
+ break;
+
+ case TOK_IFNREF:
+ D = AllocIf (".IFNREF", 1);
+ NextTok ();
+ if (IfCond) {
+ if (Tok != TOK_IDENT) {
+ ErrorSkip (ERR_IDENT_EXPECTED);
+ } else {
+ SetIfCond (D, !SymIsRef (SVal));
+ NextTok ();
+ }
+ }
+ IfCond = GetCurrentIfCond ();
+ break;
+
+ case TOK_IFP02:
+ break;
+
+ case TOK_IFP816:
+ break;
+
+ case TOK_IFPC02:
+ break;
+
+ case TOK_IFREF:
+ D = AllocIf (".IFREF", 1);
+ NextTok ();
+ if (IfCond) {
+ if (Tok != TOK_IDENT) {
+ ErrorSkip (ERR_IDENT_EXPECTED);
+ } else {
+ SetIfCond (D, SymIsRef (SVal));
+ NextTok ();
+ }
+ }
+ IfCond = GetCurrentIfCond ();
+ break;
+
+ default:
+ // Skip tokens
+ NextTok ();
+
+ }
+
+ } while (IfCond == 0 && Tok != TOK_EOF);
+}
+
+
+
+void CheckOpenIfs (void)
+/* Called from the scanner before closing an input file. Will check for any
+ * open .ifs in this file.
+ */
+{
+ while (1) {
+ /* Get the current file number and check if the topmost entry on the
+ * .IF stack was inserted with this file number
+ */
+ IfDesc* D = GetCurrentIf ();
+ if (D == 0) {
+ /* There are no open .IFs */
+ break;
+ }
+
+ if (D->Pos.Name != CurPos.Name) {
+ /* The .if is from another file, bail out */
+ break;
+ }
+
+ /* Start of .if is in the file we're about to leave */
+ PError (&D->Pos, ERR_OPEN_IF);
+ FreeIf ();
+ }
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* condasm.h */
+/* */
+/* Conditional assembly support for ca65 */
+/* */
+/* */
+/* */
+/* (C) 2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef CONDASM_H
+#define CONDASM_H
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void DoConditionals (void);
+/* Catch all for conditional directives */
+
+void CheckOpenIfs (void);
+/* Called from the scanner before closing an input file. Will check for any
+ * open .ifs in this file.
+ */
+
+
+
+/* End of condasm.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* ea.c */
+/* */
+/* Effective address parsing for the ca65 macroassembler */
+/* */
+/* */
+/* */
+/* (C) 1998-2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include "error.h"
+#include "expr.h"
+#include "instr.h"
+#include "scanner.h"
+#include "ea.h"
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void GetEA (unsigned long* AddrMode, ExprNode** Expr, ExprNode** Bank)
+/* Parse an effective address, return the possible modes in AddrMode, and the
+ * expression involved (if any) in Expr.
+ */
+{
+ /* Clear the expressions */
+ *Bank = *Expr = 0;
+
+
+ if (Tok == TOK_SEP) {
+
+ *AddrMode = AM_IMPLICIT;
+
+ } else if (Tok == TOK_HASH) {
+
+ /* #val */
+ NextTok ();
+ *Expr = Expression ();
+ *AddrMode = AM_IMM;
+
+ } else if (Tok == TOK_A) {
+
+ NextTok ();
+ *AddrMode = AM_ACCU;
+
+ } else if (Tok == TOK_LBRACK) {
+
+ /* [dir] or [dir],y */
+ NextTok ();
+ *Expr = Expression ();
+ Consume (TOK_RBRACK, ERR_RBRACK_EXPECTED);
+ if (Tok == TOK_COMMA) {
+ /* [dir],y */
+ NextTok ();
+ Consume (TOK_Y, ERR_Y_EXPECTED);
+ *AddrMode = AM_DIR_IND_LONG_Y;
+ } else {
+ /* [dir] */
+ *AddrMode = AM_DIR_IND_LONG;
+ }
+
+ } else if (Tok == TOK_LPAREN) {
+
+ /* One of the indirect modes */
+ NextTok ();
+ *Expr = Expression ();
+
+ if (Tok == TOK_COMMA) {
+
+ /* (expr,X) or (rel,S),y */
+ NextTok ();
+ if (Tok == TOK_X) {
+ /* (adr,x) */
+ NextTok ();
+ *AddrMode = AM_ABS_X_IND | AM_DIR_X_IND;
+ ConsumeRParen ();
+ } else if (Tok == TOK_S) {
+ /* (rel,s),y */
+ NextTok ();
+ *AddrMode = AM_STACK_REL_IND_Y;
+ ConsumeRParen ();
+ ConsumeComma ();
+ Consume (TOK_Y, ERR_Y_EXPECTED);
+ } else {
+ Error (ERR_SYNTAX);
+ }
+
+ } else {
+
+ /* (adr) or (adr),y */
+ ConsumeRParen ();
+ if (Tok == TOK_COMMA) {
+ /* (adr),y */
+ NextTok ();
+ Consume (TOK_Y, ERR_Y_EXPECTED);
+ *AddrMode = AM_DIR_IND_Y;
+ } else {
+ /* (adr) */
+ *AddrMode = AM_ABS_IND | AM_DIR_IND;
+ }
+ }
+
+ } else {
+
+ /* Remaining stuff:
+ *
+ * adr
+ * bank.adr
+ * adr,x
+ * bank.adr,x
+ * adr,y
+ * adr,s
+ */
+ *Expr = Expression ();
+
+ if (Tok == TOK_DOT) {
+
+ /* Expr was a bank specification: bank.adr or bank.adr,x */
+ *Bank = *Expr;
+ NextTok ();
+ *Expr = Expression ();
+ if (Tok == TOK_COMMA) {
+ /* bank.adr,x */
+ NextTok ();
+ Consume (TOK_X, ERR_X_EXPECTED);
+ *AddrMode = AM_ABS_LONG_X;
+ } else {
+ /* bank.adr */
+ *AddrMode = AM_ABS_LONG;
+ }
+
+ } else {
+
+ if (Tok == TOK_COMMA) {
+
+ NextTok ();
+ switch (Tok) {
+
+ case TOK_X:
+ *AddrMode = AM_ABS_X | AM_DIR_X;
+ NextTok ();
+ break;
+
+ case TOK_Y:
+ *AddrMode = AM_ABS_Y | AM_DIR_Y;
+ NextTok ();
+ break;
+
+ case TOK_S:
+ *AddrMode = AM_STACK_REL;
+ NextTok ();
+ break;
+
+ default:
+ Error (ERR_SYNTAX);
+
+ }
+
+ } else {
+
+ *AddrMode = AM_ABS | AM_DIR;
+
+ }
+ }
+ }
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* ea.h */
+/* */
+/* Effective address parsing for the ca65 macroassembler */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef EA_H
+#define EA_H
+
+
+
+#include "expr.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void GetEA (unsigned long* AddrMode, ExprNode** Expr, ExprNode** Bank);
+/* Parse an effective address, return the possible modes in AddrMode, and the
+ * expression involved (if any) in Expr.
+ */
+
+
+
+/* End of ea.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* error.c */
+/* */
+/* Error handling for the ca65 macroassembler */
+/* */
+/* */
+/* */
+/* (C) 1998-2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "scanner.h"
+#include "error.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Warning level */
+unsigned WarnLevel = 1;
+
+/* Messages for internal compiler errors */
+const char _MsgCheckFailed [] =
+ "Check failed: `%s' (= %d), file `%s', line %u\n";
+const char _MsgPrecondition [] =
+ "Precondition violated: `%s' (= %d), file `%s', line %u\n";
+const char _MsgFail [] =
+ "%s, file `%s', line %u\n";
+
+
+/* Statistics */
+unsigned ErrorCount = 0;
+unsigned WarningCount = 0;
+
+
+
+/*****************************************************************************/
+/* Warnings */
+/*****************************************************************************/
+
+
+
+void WarningMsg (const FilePos* Pos, unsigned WarnNum, va_list ap)
+/* Print warning message. */
+{
+ static const struct {
+ unsigned char Level;
+ const char* Msg;
+ } Warnings [WARN_COUNT-1] = {
+ { 1, "Mask error" },
+ { 2, "Symbol `%s' is defined but never used" },
+ { 2, "Symbol `%s' is imported but never used" },
+ { 1, "Cannot track processor status byte" },
+ };
+
+ if (Warnings [WarnNum-1].Level <= WarnLevel) {
+ fprintf (stderr, "%s(%lu): Warning #%u: ",
+ GetFileName (Pos->Name), Pos->Line, WarnNum);
+ vfprintf (stderr, Warnings [WarnNum-1].Msg, ap);
+ fprintf (stderr, "\n");
+ ++WarningCount;
+ }
+}
+
+
+
+void Warning (unsigned WarnNum, ...)
+/* Print warning message. */
+{
+ va_list ap;
+ va_start (ap, WarnNum);
+ WarningMsg (&CurPos, WarnNum, ap);
+ va_end (ap);
+}
+
+
+
+void PWarning (const FilePos* Pos, unsigned WarnNum, ...)
+/* Print warning message giving an explicit file and position. */
+{
+ va_list ap;
+ va_start (ap, WarnNum);
+ WarningMsg (Pos, WarnNum, ap);
+ va_end (ap);
+}
+
+
+
+/*****************************************************************************/
+/* Errors */
+/*****************************************************************************/
+
+
+
+void ErrorMsg (const FilePos* Pos, unsigned ErrNum, va_list ap)
+/* Print an error message */
+{
+ static const char* Msgs [ERR_COUNT-1] = {
+ "Command/operation not implemented",
+ "Cannot open include file `%s': %s",
+ "Include nesting too deep",
+ "Invalid input character: %02X",
+ "Hex digit expected",
+ "Digit expected",
+ "`0' or `1' expected",
+ "Numerical overflow",
+ "Control statement expected",
+ "Too many characters",
+ "`:' expected",
+ "`(' expected",
+ "`)' expected",
+ "`]' expected",
+ "`,' expected",
+ "Boolean switch value expected (on/off/+/-)",
+ "`Y' expected",
+ "`X' expected",
+ "Integer constant expected",
+ "String constant expected",
+ "Character constant expected",
+ "Constant expression expected",
+ "Identifier expected",
+ "`.endmacro' expected",
+ "Option key expected",
+ "Command is only valid in 65816 mode",
+ "User error: %s",
+ "String constant too long",
+ "Newline in string constant",
+ "Illegal character constant",
+ "Illegal addressing mode",
+ "Illegal character to start local symbols",
+ "Illegal use of local symbol",
+ "Illegal segment name: `%s'",
+ "Illegal segment attribute",
+ "Illegal macro package name",
+ "Illegal emulation feature",
+ "Syntax error",
+ "Symbol `%s' is already defined",
+ "Undefined symbol `%s'",
+ "Symbol `%s' is marked as import",
+ "Symbol `%s' is marked as export",
+ "Exported symbol `%s' is undefined",
+ "Exported values must be constant",
+ ".IF nesting too deep",
+ "Unexpected end of line",
+ "Unexpected `%s'",
+ "Division by zero",
+ "Modulo operation with zero",
+ "Range error",
+ "Too many macro parameters",
+ "Macro parameter expected",
+ "Circular reference in symbol definition",
+ "Symbol redeclaration mismatch",
+ "Alignment value must be a power of 2",
+ "Duplicate `.ELSE'",
+ "Conditional assembly branch was never closed",
+ "Lexical level was not terminated correctly",
+ "Segment attribute mismatch",
+ "CPU not supported",
+ "Counter underflow",
+ "Undefined label",
+ };
+
+ fprintf (stderr, "%s(%lu): Error #%u: ",
+ GetFileName (Pos->Name), Pos->Line, ErrNum);
+ vfprintf (stderr, Msgs [ErrNum-1], ap);
+ fprintf (stderr, "\n");
+ ++ErrorCount;
+}
+
+
+
+void Error (unsigned ErrNum, ...)
+/* Print an error message */
+{
+ va_list ap;
+ va_start (ap, ErrNum);
+ ErrorMsg (&CurPos, ErrNum, ap);
+ va_end (ap);
+}
+
+
+
+void PError (const FilePos* Pos, unsigned ErrNum, ...)
+/* Print an error message giving an explicit file and position. */
+{
+ va_list ap;
+ va_start (ap, ErrNum);
+ ErrorMsg (Pos, ErrNum, ap);
+ va_end (ap);
+}
+
+
+
+void ErrorSkip (unsigned ErrNum, ...)
+/* Print an error message and skip the rest of the line */
+{
+ va_list ap;
+ va_start (ap, ErrNum);
+ ErrorMsg (&CurPos, ErrNum, ap);
+ va_end (ap);
+
+ SkipUntilSep ();
+}
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void Fatal (unsigned FatNum, ...)
+/* Print a message about a fatal error and die */
+{
+ static const char* Msgs [FAT_COUNT-1] = {
+ "Maximum number of input files reached",
+ "Out of memory",
+ "Too many segments",
+ "String too long",
+ "Cannot open input file `%s': %s",
+ "Cannot stat input file `%s': %s",
+ "Cannot open output file `%s': %s",
+ "Cannot write to output file `%s': %s",
+ "Cannot open listing file: %s",
+ "Cannot write to listing file: %s",
+ "Cannot read from listing file: %s",
+ "Macro nesting too deep",
+ "Too many symbols",
+ };
+ va_list ap;
+
+ va_start (ap, FatNum);
+ fprintf (stderr, "Fatal #%u: ", FatNum);
+ vfprintf (stderr, Msgs [FatNum-1], ap);
+ fprintf (stderr, "\n");
+ va_end (ap);
+
+ /* And die... */
+ exit (EXIT_FAILURE);
+}
+
+
+
+void Internal (const char* Format, ...)
+/* Print a message about an internal compiler error and die. */
+{
+ va_list ap;
+ va_start (ap, Format);
+ fprintf (stderr, "Internal assembler error\n");
+ vfprintf (stderr, Format, ap);
+ va_end (ap);
+ fprintf (stderr, "\n");
+
+ exit (EXIT_FAILURE);
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* error.h */
+/* */
+/* Error handling for the ca65 macroassembler */
+/* */
+/* */
+/* */
+/* (C) 1998-2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef ERROR_H
+#define ERROR_H
+
+
+
+#include "scanner.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Warning numbers */
+enum Warnings {
+ WARN_NONE, /* No warning */
+ WARN_MASK_ERROR,
+ WARN_SYM_NOT_REFERENCED,
+ WARN_IMPORT_NOT_REFERENCED,
+ WARN_CANNOT_TRACK_STATUS,
+ WARN_COUNT /* Warning count */
+};
+
+/* Error numbers */
+enum Errors {
+ ERR_NONE, /* No error */
+ ERR_NOT_IMPLEMENTED, /* Command/operation not implemented */
+ ERR_CANNOT_OPEN_INCLUDE,
+ ERR_INCLUDE_NESTING,
+ ERR_INVALID_CHAR,
+ ERR_HEX_DIGIT_EXPECTED,
+ ERR_DIGIT_EXPECTED,
+ ERR_01_EXPECTED,
+ ERR_NUM_OVERFLOW,
+ ERR_PSEUDO_EXPECTED,
+ ERR_TOO_MANY_CHARS,
+ ERR_COLON_EXPECTED,
+ ERR_LPAREN_EXPECTED,
+ ERR_RPAREN_EXPECTED,
+ ERR_RBRACK_EXPECTED,
+ ERR_COMMA_EXPECTED,
+ ERR_ONOFF_EXPECTED,
+ ERR_Y_EXPECTED,
+ ERR_X_EXPECTED,
+ ERR_INTCON_EXPECTED,
+ ERR_STRCON_EXPECTED,
+ ERR_CHARCON_EXPECTED,
+ ERR_CONSTEXPR_EXPECTED,
+ ERR_IDENT_EXPECTED,
+ ERR_ENDMACRO_EXPECTED,
+ ERR_OPTION_KEY_EXPECTED,
+ ERR_816_MODE_ONLY,
+ ERR_USER,
+ ERR_STRING_TOO_LONG,
+ ERR_NEWLINE_IN_STRING,
+ ERR_ILLEGAL_CHARCON,
+ ERR_ILLEGAL_ADDR_MODE,
+ ERR_ILLEGAL_LOCALSTART,
+ ERR_ILLEGAL_LOCAL_USE,
+ ERR_ILLEGAL_SEGMENT,
+ ERR_ILLEGAL_SEG_ATTR,
+ ERR_ILLEGAL_MACPACK,
+ ERR_ILLEGAL_FEATURE,
+ ERR_SYNTAX,
+ ERR_SYM_ALREADY_DEFINED,
+ ERR_SYM_UNDEFINED,
+ ERR_SYM_ALREADY_IMPORT,
+ ERR_SYM_ALREADY_EXPORT,
+ ERR_EXPORT_UNDEFINED,
+ ERR_EXPORT_MUST_BE_CONST,
+ ERR_IF_NESTING,
+ ERR_UNEXPECTED_EOL,
+ ERR_UNEXPECTED,
+ ERR_DIV_BY_ZERO,
+ ERR_MOD_BY_ZERO,
+ ERR_RANGE,
+ ERR_TOO_MANY_PARAMS,
+ ERR_MACRO_PARAM_EXPECTED,
+ ERR_CIRCULAR_REFERENCE,
+ ERR_SYM_REDECL_MISMATCH,
+ ERR_ALIGN,
+ ERR_DUPLICATE_ELSE,
+ ERR_OPEN_IF,
+ ERR_OPEN_PROC,
+ ERR_SEG_ATTR_MISMATCH,
+ ERR_CPU_NOT_SUPPORTED,
+ ERR_COUNTER_UNDERFLOW,
+ ERR_UNDEFINED_LABEL,
+ ERR_COUNT /* Error count */
+};
+
+/* Fatal errors */
+enum Fatals {
+ FAT_NONE,
+ FAT_MAX_INPUT_FILES,
+ FAT_OUT_OF_MEMORY,
+ FAT_TOO_MANY_SEGMENTS,
+ FAT_STRING_TOO_LONG,
+ FAT_CANNOT_OPEN_INPUT,
+ FAT_CANNOT_STAT_INPUT,
+ FAT_CANNOT_OPEN_OUTPUT,
+ FAT_CANNOT_WRITE_OUTPUT,
+ FAT_CANNOT_OPEN_LISTING,
+ FAT_CANNOT_WRITE_LISTING,
+ FAT_CANNOT_READ_LISTING,
+ FAT_MACRO_NESTING,
+ FAT_TOO_MANY_SYMBOLS,
+ FAT_COUNT /* Fatal error count */
+};
+
+
+
+/* Warning levels */
+extern unsigned WarnLevel;
+
+/* Messages for internal compiler errors */
+extern const char _MsgCheckFailed [];
+extern const char _MsgPrecondition [];
+extern const char _MsgFail [];
+
+/* Statistics */
+extern unsigned ErrorCount;
+extern unsigned WarningCount;
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void Warning (unsigned WarnNum, ...);
+/* Print warning message. */
+
+void PWarning (const FilePos* Pos, unsigned WarnNum, ...);
+/* Print warning message giving an explicit file and position. */
+
+void Error (unsigned ErrNum, ...);
+/* Print an error message */
+
+void PError (const FilePos* Pos, unsigned ErrNum, ...);
+/* Print an error message giving an explicit file and position. */
+
+void ErrorSkip (unsigned ErrNum, ...);
+/* Print an error message and skip the rest of the line */
+
+void Fatal (unsigned FatNum, ...);
+/* Print a message about a fatal error and die */
+
+void Internal (const char* Format, ...);
+/* Print a message about an internal compiler error and die. */
+
+#define CHECK(c) \
+ if (!(c)) \
+ Internal (_MsgCheckFailed, #c, c, __FILE__, __LINE__)
+
+#define PRECONDITION(c) \
+ if (!(c)) \
+ Internal (_MsgPrecondition, #c, c, __FILE__, __LINE__)
+
+#define FAIL(s) \
+ Internal (_MsgFail, s, __FILE__, __LINE__)
+
+
+
+/* End of error.h */
+
+#endif
+
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* expr.c */
+/* */
+/* Expression evaluation for the ca65 macroassembler */
+/* */
+/* */
+/* */
+/* (C) 1998-2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include "../common/exprdefs.h"
+
+#include "error.h"
+#include "global.h"
+#include "instr.h"
+#include "mem.h"
+#include "objcode.h"
+#include "objfile.h"
+#include "scanner.h"
+#include "symtab.h"
+#include "toknode.h"
+#include "ulabel.h"
+#include "expr.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Since all expressions are first packed into expression trees, and each
+ * expression tree node is allocated on the heap, we add some type of special
+ * purpose memory allocation here: Instead of freeing the nodes, we save some
+ * number of freed nodes for later and remember them in a single linked list
+ * using the Left link.
+ */
+#define MAX_FREE_NODES 64
+static ExprNode* FreeExprNodes = 0;
+static unsigned FreeNodeCount = 0;
+
+
+
+/*****************************************************************************/
+/* Helpers */
+/*****************************************************************************/
+
+
+
+static ExprNode* NewExprNode (void)
+/* Create a new expression node */
+{
+ ExprNode* N;
+
+ /* Do we have some nodes in the list already? */
+ if (FreeExprNodes) {
+ /* Use first node from list */
+ N = FreeExprNodes;
+ FreeExprNodes = N->Left;
+ } else {
+ /* Allocate fresh memory */
+ N = Xmalloc (sizeof (ExprNode));
+ }
+ N->Op = EXPR_NULL;
+ N->Left = N->Right = 0;
+ N->Obj = 0;
+
+ return N;
+}
+
+
+
+static void FreeExprNode (ExprNode* E)
+/* Free a node */
+{
+ if (E) {
+ if (FreeNodeCount < MAX_FREE_NODES) {
+ /* Remember this node for later */
+ E->Left = FreeExprNodes;
+ FreeExprNodes = E;
+ } else {
+ /* Free the memory */
+ Xfree (E);
+ }
+ }
+}
+
+
+
+/*****************************************************************************/
+/* Dump an expression tree on stdout for debugging */
+/*****************************************************************************/
+
+
+
+static void InternalDumpExpr (ExprNode* Expr)
+/* Dump an expression in UPN */
+{
+ if (Expr == 0) {
+ return;
+ }
+ InternalDumpExpr (Expr->Left);
+ InternalDumpExpr (Expr->Right);
+
+ switch (Expr->Op) {
+
+ case EXPR_LITERAL:
+ case EXPR_ULABEL:
+ printf (" $%04lX", Expr->V.Val & 0xFFFF);
+ break;
+
+ case EXPR_SYMBOL:
+ printf (" %s", GetSymName (Expr->V.Sym));
+ break;
+
+ case EXPR_SEGMENT:
+ printf (" SEG");
+ break;
+
+ case EXPR_PLUS:
+ printf (" +");
+ break;
+
+ case EXPR_MINUS:
+ printf (" -");
+ break;
+
+ case EXPR_MUL:
+ printf (" *");
+ break;
+
+ case EXPR_DIV:
+ printf (" /");
+ break;
+
+ case EXPR_MOD:
+ printf (" %%");
+ break;
+
+ case EXPR_OR:
+ printf (" OR");
+ break;
+
+ case EXPR_XOR:
+ printf (" XOR");
+ break;
+
+ case EXPR_AND:
+ printf (" AND");
+ break;
+
+ case EXPR_SHL:
+ printf (" SHL");
+ break;
+
+ case EXPR_SHR:
+ printf (" SHR");
+ break;
+
+ case EXPR_EQ:
+ printf (" =");
+ break;
+
+ case EXPR_NE:
+ printf ("<>");
+ break;
+
+ case EXPR_LT:
+ printf (" <");
+ break;
+
+ case EXPR_GT:
+ printf (" >");
+ break;
+
+ case EXPR_UNARY_MINUS:
+ printf (" NEG");
+ break;
+
+ case EXPR_NOT:
+ printf (" ~");
+ break;
+
+ case EXPR_LOBYTE:
+ printf (" LO");
+ break;
+
+ case EXPR_HIBYTE:
+ printf (" HI");
+ break;
+
+ case EXPR_SWAP:
+ printf (" SWAP");
+ break;
+
+ case EXPR_BAND:
+ printf (" BOOL_AND");
+ break;
+
+ case EXPR_BOR:
+ printf (" BOOL_OR");
+ break;
+
+ case EXPR_BXOR:
+ printf (" BOOL_XOR");
+ break;
+
+ case EXPR_BNOT:
+ printf (" BOOL_NOT");
+ break;
+
+ default:
+ Internal ("Unknown Op type: %u", Expr->Op);
+
+ }
+}
+
+
+
+void DumpExpr (ExprNode* Expr)
+/* Dump an expression tree to stdout */
+{
+ InternalDumpExpr (Expr);
+ printf ("\n");
+}
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+static ExprNode* Expr0 (void);
+
+
+
+int IsByteRange (long Val)
+/* Return true if this is a byte value */
+{
+ return (Val & ~0xFFL) == 0;
+}
+
+
+
+int IsWordRange (long Val)
+/* Return true if this is a word value */
+{
+ return (Val & ~0xFFFF) == 0;
+}
+
+
+
+static int FuncBlank (void)
+/* Handle the .BLANK builtin function */
+{
+ /* Assume no tokens if the closing brace follows (this is not correct in
+ * all cases, since the token may be the closing brace, but this will
+ * give a syntax error anyway and may not be handled by .BLANK.
+ */
+ if (Tok == TOK_RPAREN) {
+ /* No tokens */
+ return 1;
+ } else {
+ /* Skip any tokens */
+ int Braces = 0;
+ while (Tok != TOK_SEP && Tok != TOK_EOF) {
+ if (Tok == TOK_LPAREN) {
+ ++Braces;
+ } else if (Tok == TOK_RPAREN) {
+ if (Braces == 0) {
+ /* Done */
+ break;
+ } else {
+ --Braces;
+ }
+ }
+ NextTok ();
+ }
+ return 0;
+ }
+}
+
+
+
+static int FuncConst (void)
+/* Handle the .CONST builtin function */
+{
+ /* Read an expression */
+ ExprNode* Expr = Expression ();
+
+ /* Check the constness of the expression */
+ int Result = IsConstExpr (Expr);
+
+ /* Free the expression */
+ FreeExpr (Expr);
+
+ /* Done */
+ return Result;
+}
+
+
+
+static int FuncDefined (void)
+/* Handle the .DEFINED builtin function */
+{
+ int Result = 0;
+
+ if (Tok != TOK_IDENT) {
+ Error (ERR_IDENT_EXPECTED);
+ if (Tok != TOK_RPAREN) {
+ NextTok ();
+ }
+ } else {
+ Result = SymIsDef (SVal);
+ NextTok ();
+ }
+
+ /* Done */
+ return Result;
+}
+
+
+
+static int DoMatch (enum TC EqualityLevel)
+/* Handle the .MATCH and .XMATCH builtin functions */
+{
+ int Result;
+ TokNode* Root = 0;
+ TokNode* Last = 0;
+ TokNode* Node = 0;
+
+ /* A list of tokens follows. Read this list and remember it building a
+ * single linked list of tokens including attributes. The list is
+ * terminated by a comma.
+ */
+ while (Tok != TOK_COMMA) {
+
+ /* We may not end-of-line of end-of-file here */
+ if (Tok == TOK_SEP || Tok == TOK_EOF) {
+ Error (ERR_UNEXPECTED_EOL);
+ return 0;
+ }
+
+ /* Get a node with this token */
+ Node = NewTokNode ();
+
+ /* Insert the node into the list */
+ if (Last == 0) {
+ Root = Node;
+ } else {
+ Last->Next = Node;
+ }
+ Last = Node;
+
+ /* Skip the token */
+ NextTok ();
+ }
+
+ /* Skip the comma */
+ NextTok ();
+
+ /* Read the second list which is terminated by the right parenthesis and
+ * compare each token against the one in the first list.
+ */
+ Result = 1;
+ Node = Root;
+ while (Tok != TOK_RPAREN) {
+
+ /* We may not end-of-line of end-of-file here */
+ if (Tok == TOK_SEP || Tok == TOK_EOF) {
+ Error (ERR_UNEXPECTED_EOL);
+ return 0;
+ }
+
+ /* Compare the tokens if the result is not already known */
+ if (Result != 0) {
+ if (Node == 0) {
+ /* The second list is larger than the first one */
+ Result = 0;
+ } else if (TokCmp (Node) < EqualityLevel) {
+ /* Tokens do not match */
+ Result = 0;
+ }
+ }
+
+ /* Next token in first list */
+ if (Node) {
+ Node = Node->Next;
+ }
+
+ /* Next token in current list */
+ NextTok ();
+ }
+
+ /* Check if there are remaining tokens in the first list */
+ if (Node != 0) {
+ Result = 0;
+ }
+
+ /* Free the token list */
+ while (Root) {
+ Node = Root;
+ Root = Root->Next;
+ FreeTokNode (Node);
+ }
+
+ /* Done, return the result */
+ return Result;
+}
+
+
+
+static int FuncMatch (void)
+/* Handle the .MATCH function */
+{
+ return DoMatch (tcSameToken);
+}
+
+
+
+static int FuncReferenced (void)
+/* Handle the .REFERENCED builtin function */
+{
+ int Result = 0;
+
+ if (Tok != TOK_IDENT) {
+ Error (ERR_IDENT_EXPECTED);
+ if (Tok != TOK_RPAREN) {
+ NextTok ();
+ }
+ } else {
+ Result = SymIsRef (SVal);
+ NextTok ();
+ }
+
+ /* Done */
+ return Result;
+}
+
+
+
+static int FuncXMatch (void)
+/* Handle the .XMATCH function */
+{
+ return DoMatch (tcIdentical);
+}
+
+
+
+static ExprNode* Function (int (*F) (void))
+/* Handle builtin functions */
+{
+ long Result;
+
+ /* Skip the keyword */
+ NextTok ();
+
+ /* Expression must be enclosed in braces */
+ if (Tok != TOK_LPAREN) {
+ Error (ERR_LPAREN_EXPECTED);
+ SkipUntilSep ();
+ return LiteralExpr (0);
+ }
+ NextTok ();
+
+ /* Call the function itself */
+ Result = (F () != 0);
+
+ /* Closing brace must follow */
+ ConsumeRParen ();
+
+ /* Return an expression node with the boolean code */
+ return LiteralExpr (Result);
+}
+
+
+
+static ExprNode* Factor (void)
+{
+ ExprNode* N;
+ SymEntry* S;
+
+ switch (Tok) {
+
+ case TOK_INTCON:
+ case TOK_CHARCON:
+ N = LiteralExpr (IVal);
+ NextTok ();
+ break;
+
+ case TOK_NAMESPACE:
+ NextTok ();
+ if (Tok != TOK_IDENT) {
+ Error (ERR_IDENT_EXPECTED);
+ N = LiteralExpr (0); /* Dummy */
+ } else {
+ S = SymRefGlobal (SVal);
+ if (SymIsConst (S)) {
+ /* Use the literal value instead */
+ N = LiteralExpr (GetSymVal (S));
+ } else {
+ /* Create symbol node */
+ N = NewExprNode ();
+ N->Op = EXPR_SYMBOL;
+ N->V.Sym = S;
+ }
+ NextTok ();
+ }
+ break;
+
+ case TOK_IDENT:
+ S = SymRef (SVal);
+ if (SymIsConst (S)) {
+ /* Use the literal value instead */
+ N = LiteralExpr (GetSymVal (S));
+ } else {
+ /* Create symbol node */
+ N = NewExprNode ();
+ N->Op = EXPR_SYMBOL;
+ N->V.Sym = S;
+ }
+ NextTok ();
+ break;
+
+ case TOK_ULABEL:
+ N = ULabRef (IVal);
+ NextTok ();
+ break;
+
+ case TOK_MINUS:
+ NextTok ();
+ N = NewExprNode ();
+ N->Left = Factor ();
+ N->Op = EXPR_UNARY_MINUS;
+ break;
+
+ case TOK_NOT:
+ NextTok ();
+ N = NewExprNode ();
+ N->Left = Factor ();
+ N->Op = EXPR_NOT;
+ break;
+
+ case TOK_STAR:
+ case TOK_PC:
+ NextTok ();
+ N = CurrentPC ();
+ break;
+
+ case TOK_LT:
+ NextTok ();
+ N = NewExprNode ();
+ N->Left = Factor ();
+ N->Op = EXPR_LOBYTE;
+ break;
+
+ case TOK_GT:
+ NextTok ();
+ N = NewExprNode ();
+ N->Left = Factor ();
+ N->Op = EXPR_HIBYTE;
+ break;
+
+ case TOK_LPAREN:
+ NextTok ();
+ N = Expr0 ();
+ ConsumeRParen ();
+ break;
+
+ case TOK_BLANK:
+ N = Function (FuncBlank);
+ break;
+
+ case TOK_CONST:
+ N = Function (FuncConst);
+ break;
+
+ case TOK_CPU:
+ N = LiteralExpr (GetCPU());
+ NextTok ();
+ break;
+
+ case TOK_DEFINED:
+ N = Function (FuncDefined);
+ break;
+
+ case TOK_MATCH:
+ N = Function (FuncMatch);
+ break;
+
+ case TOK_REFERENCED:
+ N = Function (FuncReferenced);
+ break;
+
+ case TOK_XMATCH:
+ N = Function (FuncXMatch);
+ break;
+
+ default:
+ N = LiteralExpr (0); /* Dummy */
+ Error (ERR_SYNTAX);
+ NextTok ();
+ break;
+ }
+ return N;
+}
+
+
+
+static ExprNode* Term (void)
+{
+ ExprNode* Root;
+
+ /* Read left hand side */
+ Root = Factor ();
+
+ /* Handle multiplicative operations */
+ while (Tok == TOK_MUL || Tok == TOK_DIV || Tok == TOK_MOD ||
+ Tok == TOK_AND || Tok == TOK_XOR || Tok == TOK_SHL ||
+ Tok == TOK_SHR) {
+
+ /* Create a new node and insert the left expression */
+ ExprNode* Left = Root;
+ Root = NewExprNode ();
+ Root->Left = Left;
+
+ /* Determine the operator token */
+ switch (Tok) {
+ case TOK_MUL: Root->Op = EXPR_MUL; break;
+ case TOK_DIV: Root->Op = EXPR_DIV; break;
+ case TOK_MOD: Root->Op = EXPR_MOD; break;
+ case TOK_AND: Root->Op = EXPR_AND; break;
+ case TOK_XOR: Root->Op = EXPR_XOR; break;
+ case TOK_SHL: Root->Op = EXPR_SHL; break;
+ case TOK_SHR: Root->Op = EXPR_SHR; break;
+ default: Internal ("Invalid token");
+ }
+ NextTok ();
+
+ /* Parse the right hand side */
+ Root->Right = Factor ();
+
+ }
+
+ /* Return the expression tree we've created */
+ return Root;
+}
+
+
+
+static ExprNode* SimpleExpr (void)
+{
+ ExprNode* Root;
+
+ /* Read left hand side */
+ Root = Term ();
+
+ /* Handle additive operations */
+ while (Tok == TOK_PLUS || Tok == TOK_MINUS || Tok == TOK_OR) {
+
+ /* Create a new node and insert the left expression */
+ ExprNode* Left = Root;
+ Root = NewExprNode ();
+ Root->Left = Left;
+
+ /* Determine the operator token */
+ switch (Tok) {
+ case TOK_PLUS: Root->Op = EXPR_PLUS; break;
+ case TOK_MINUS: Root->Op = EXPR_MINUS; break;
+ case TOK_OR: Root->Op = EXPR_OR; break;
+ default: Internal ("Invalid token");
+ }
+ NextTok ();
+
+ /* Parse the right hand side */
+ Root->Right = Term ();
+
+ }
+
+ /* Return the expression tree we've created */
+ return Root;
+}
+
+
+
+static ExprNode* BoolExpr (void)
+/* Evaluate a boolean expression */
+{
+ /* Read left hand side */
+ ExprNode* Root = SimpleExpr ();
+
+ /* Handle booleans */
+ while (Tok == TOK_EQ || Tok == TOK_NE || Tok == TOK_LT ||
+ Tok == TOK_GT || Tok == TOK_LE || Tok == TOK_GE) {
+
+ /* Create a new node and insert the left expression */
+ ExprNode* Left = Root;
+ Root = NewExprNode ();
+ Root->Left = Left;
+
+ /* Determine the operator token */
+ switch (Tok) {
+ case TOK_EQ: Root->Op = EXPR_EQ; break;
+ case TOK_NE: Root->Op = EXPR_NE; break;
+ case TOK_LT: Root->Op = EXPR_LT; break;
+ case TOK_GT: Root->Op = EXPR_GT; break;
+ case TOK_LE: Root->Op = EXPR_LE; break;
+ case TOK_GE: Root->Op = EXPR_GE; break;
+ default: Internal ("Invalid token");
+ }
+ NextTok ();
+
+ /* Parse the right hand side */
+ Root->Right = SimpleExpr ();
+
+ }
+
+ /* Return the expression tree we've created */
+ return Root;
+}
+
+
+
+static ExprNode* Expr2 (void)
+/* Boolean operators: AND and XOR */
+{
+ /* Read left hand side */
+ ExprNode* Root = BoolExpr ();
+
+ /* Handle booleans */
+ while (Tok == TOK_BAND || Tok == TOK_BXOR) {
+
+ /* Create a new node and insert the left expression */
+ ExprNode* Left = Root;
+ Root = NewExprNode ();
+ Root->Left = Left;
+
+ /* Determine the operator token */
+ switch (Tok) {
+ case TOK_BAND: Root->Op = EXPR_BAND; break;
+ case TOK_BXOR: Root->Op = EXPR_BXOR; break;
+ default: Internal ("Invalid token");
+ }
+ NextTok ();
+
+ /* Parse the right hand side */
+ Root->Right = BoolExpr ();
+
+ }
+
+ /* Return the expression tree we've created */
+ return Root;
+}
+
+
+
+static ExprNode* Expr1 (void)
+/* Boolean operators: OR */
+{
+ /* Read left hand side */
+ ExprNode* Root = Expr2 ();
+
+ /* Handle booleans */
+ while (Tok == TOK_BOR) {
+
+ /* Create a new node and insert the left expression */
+ ExprNode* Left = Root;
+ Root = NewExprNode ();
+ Root->Left = Left;
+
+ /* Determine the operator token */
+ switch (Tok) {
+ case TOK_BOR: Root->Op = EXPR_BOR; break;
+ default: Internal ("Invalid token");
+ }
+ NextTok ();
+
+ /* Parse the right hand side */
+ Root->Right = Expr2 ();
+
+ }
+
+ /* Return the expression tree we've created */
+ return Root;
+}
+
+
+
+static ExprNode* Expr0 (void)
+/* Boolean operators: NOT */
+{
+ ExprNode* Root;
+
+ /* Handle booleans */
+ if (Tok == TOK_BNOT) {
+
+ /* Create a new node */
+ Root = NewExprNode ();
+
+ /* Determine the operator token */
+ switch (Tok) {
+ case TOK_BNOT: Root->Op = EXPR_BNOT; break;
+ default: Internal ("Invalid token");
+ }
+ NextTok ();
+
+ /* Parse the left hand side, allow more BNOTs */
+ Root->Left = Expr0 ();
+
+ } else {
+
+ /* Read left hand side */
+ Root = Expr1 ();
+
+ }
+
+ /* Return the expression tree we've created */
+ return Root;
+}
+
+
+
+static ExprNode* SimplifyExpr (ExprNode* Root)
+/* Try to simplify the given expression tree */
+{
+ if (Root) {
+ SimplifyExpr (Root->Left);
+ SimplifyExpr (Root->Right);
+ if (IsConstExpr (Root)) {
+ /* The complete expression is constant */
+ Root->V.Val = GetExprVal (Root);
+ Root->Op = EXPR_LITERAL;
+ FreeExpr (Root->Left);
+ FreeExpr (Root->Right);
+ Root->Left = Root->Right = 0;
+ }
+ }
+ return Root;
+}
+
+
+
+ExprNode* Expression (void)
+/* Evaluate an expression, build the expression tree on the heap and return
+ * a pointer to the root of the tree.
+ */
+{
+ return SimplifyExpr (Expr0 ());
+}
+
+
+
+long ConstExpression (void)
+/* Parse an expression. Check if the expression is const, and print an error
+ * message if not. Return the value of the expression, or a dummy, if it is
+ * not constant.
+ */
+{
+ /* Read the expression, and call finalize (exception here, since we
+ * expect a const).
+ */
+ ExprNode* Expr = FinalizeExpr (Expression ());
+
+ /* Return the value */
+ if (IsConstExpr (Expr)) {
+ return GetExprVal (Expr);
+ } else {
+ Error (ERR_CONSTEXPR_EXPECTED);
+ return 0;
+ }
+}
+
+
+
+ExprNode* LiteralExpr (long Val)
+/* Return an expression tree that encodes the given literal value */
+{
+ ExprNode* Expr = NewExprNode ();
+ Expr->Op = EXPR_LITERAL;
+ Expr->V.Val = Val;
+ return Expr;
+}
+
+
+
+ExprNode* CurrentPC (void)
+/* Return the current program counter as expression */
+{
+ ExprNode* Left;
+ ExprNode* Root;
+
+ if (RelocMode) {
+ /* Create SegmentBase + Offset */
+ Left = NewExprNode ();
+ Left->Op = EXPR_SEGMENT;
+ Left->V.SegNum = GetSegNum ();
+
+ Root = NewExprNode ();
+ Root->Left = Left;
+ Root->Right = LiteralExpr (GetPC ());
+ Root->Op = EXPR_PLUS;
+ } else {
+ /* Absolute mode, just return PC value */
+ Root = LiteralExpr (GetPC ());
+ }
+
+ return Root;
+}
+
+
+
+ExprNode* SwapExpr (ExprNode* Expr)
+/* Return an extended expression with lo and hi bytes swapped */
+{
+ ExprNode* N = NewExprNode ();
+ N->Op = EXPR_SWAP;
+ N->Left = Expr;
+ return N;
+}
+
+
+
+ExprNode* BranchExpr (unsigned Offs)
+/* Return an expression that encodes the difference between current PC plus
+ * offset and the target expression (that is, Expression() - (*+Offs) ).
+ */
+{
+ ExprNode* N;
+ ExprNode* Root;
+ ExprNode* Left;
+
+ /* Create *+Offs */
+ if (RelocMode) {
+ Left = NewExprNode ();
+ Left->Op = EXPR_SEGMENT;
+ Left->V.SegNum = GetSegNum ();
+
+ N = NewExprNode ();
+ N->Left = Left;
+ N->Right = LiteralExpr (GetPC () + Offs);
+ N->Op = EXPR_PLUS;
+ } else {
+ N = LiteralExpr (GetPC () + Offs);
+ }
+
+ /* Create the root node */
+ Root = NewExprNode ();
+ Root->Left = Expression ();
+ Root->Right = N;
+ Root->Op = EXPR_MINUS;
+
+ /* Return the result */
+ return SimplifyExpr (Root);
+}
+
+
+
+ExprNode* ULabelExpr (unsigned Num)
+/* Return an expression for an unnamed label with the given index */
+{
+ /* Get an expression node */
+ ExprNode* Node = NewExprNode ();
+
+ /* Set the values */
+ Node->Op = EXPR_ULABEL;
+ Node->V.Val = Num;
+
+ /* Return the new node */
+ return Node;
+}
+
+
+
+void FreeExpr (ExprNode* Root)
+/* Free the expression, Root is pointing to. */
+{
+ if (Root) {
+ FreeExpr (Root->Left);
+ FreeExpr (Root->Right);
+ FreeExprNode (Root);
+ }
+}
+
+
+
+ExprNode* ForceWordExpr (ExprNode* Expr)
+/* Force the given expression into a word and return the result. */
+{
+ /* And the expression by $FFFF to force it into word size */
+ ExprNode* Root = NewExprNode ();
+ Root->Left = Expr;
+ Root->Op = EXPR_AND;
+ Root->Right = LiteralExpr (0xFFFF);
+
+ /* Return the result */
+ return Root;
+}
+
+
+
+int IsConstExpr (ExprNode* Root)
+/* Return true if the given expression is a constant expression, that is, one
+ * with no references to external symbols.
+ */
+{
+ int Const;
+ SymEntry* Sym;
+
+ if (EXPR_IS_LEAF (Root->Op)) {
+ switch (Root->Op) {
+
+ case EXPR_LITERAL:
+ return 1;
+
+ case EXPR_SYMBOL:
+ Sym = Root->V.Sym;
+ if (SymHasUserMark (Sym)) {
+ if (Verbose) {
+ DumpExpr (Root);
+ }
+ PError (GetSymPos (Sym), ERR_CIRCULAR_REFERENCE);
+ Const = 0;
+ } else {
+ SymMarkUser (Sym);
+ Const = SymIsConst (Sym);
+ SymUnmarkUser (Sym);
+ }
+ return Const;
+
+ default:
+ return 0;
+
+ }
+ } else if (EXPR_IS_UNARY (Root->Op)) {
+
+ return IsConstExpr (Root->Left);
+
+ } else {
+
+ /* We must handle shortcut boolean expressions here */
+ switch (Root->Op) {
+
+ case EXPR_BAND:
+ if (IsConstExpr (Root->Left)) {
+ /* lhs is const, if it is zero, don't eval right */
+ if (GetExprVal (Root->Left) == 0) {
+ return 1;
+ } else {
+ return IsConstExpr (Root->Right);
+ }
+ } else {
+ /* lhs not const --> tree not const */
+ return 0;
+ }
+ break;
+
+ case EXPR_BOR:
+ if (IsConstExpr (Root->Left)) {
+ /* lhs is const, if it is not zero, don't eval right */
+ if (GetExprVal (Root->Left) != 0) {
+ return 1;
+ } else {
+ return IsConstExpr (Root->Right);
+ }
+ } else {
+ /* lhs not const --> tree not const */
+ return 0;
+ }
+ break;
+
+ default:
+ /* All others are handled normal */
+ return IsConstExpr (Root->Left) && IsConstExpr (Root->Right);
+ }
+ }
+}
+
+
+
+static void CheckByteExpr (const ExprNode* N, int* IsByte)
+/* Internal routine that is recursively called to check if there is a zeropage
+ * symbol in the expression tree.
+ */
+{
+ if (N) {
+ switch (N->Op & EXPR_TYPEMASK) {
+
+ case EXPR_LEAFNODE:
+ switch (N->Op) {
+
+ case EXPR_SYMBOL:
+ if (SymIsZP (N->V.Sym)) {
+ *IsByte = 1;
+ }
+ break;
+
+ case EXPR_SEGMENT:
+ if (GetSegType (N->V.SegNum) == SEGTYPE_ZP) {
+ *IsByte = 1;
+ }
+ break;
+
+ }
+ break;
+
+ case EXPR_UNARYNODE:
+ CheckByteExpr (N->Left, IsByte);
+ break;
+
+ case EXPR_BINARYNODE:
+ CheckByteExpr (N->Left, IsByte);
+ CheckByteExpr (N->Right, IsByte);
+ break;
+
+ default:
+ Internal ("Unknown expression op: %02X", N->Op);
+ }
+ }
+}
+
+
+
+int IsByteExpr (ExprNode* Root)
+/* Return true if this is a byte expression */
+{
+ int IsByte;
+
+ if (IsConstExpr (Root)) {
+ if (Root->Op != EXPR_LITERAL) {
+ SimplifyExpr (Root);
+ }
+ return IsByteRange (GetExprVal (Root));
+ } else if (Root->Op == EXPR_LOBYTE || Root->Op == EXPR_HIBYTE) {
+ /* Symbol forced to have byte range */
+ IsByte = 1;
+ } else {
+ /* We have undefined symbols in the expression. Assume that the
+ * expression is a byte expression if there is at least one symbol
+ * declared as zeropage in it. Being wrong here is not a very big
+ * problem since the linker knows about all symbols and detects
+ * error like mixing absolute and zeropage labels.
+ */
+ IsByte = 0;
+ CheckByteExpr (Root, &IsByte);
+ }
+ return IsByte;
+}
+
+
+
+long GetExprVal (ExprNode* Expr)
+/* Get the value of a constant expression */
+{
+ long Right, Left;
+
+ switch (Expr->Op) {
+
+ case EXPR_LITERAL:
+ return Expr->V.Val;
+
+ case EXPR_SYMBOL:
+ return GetSymVal (Expr->V.Sym);
+
+ case EXPR_PLUS:
+ return GetExprVal (Expr->Left) + GetExprVal (Expr->Right);
+
+ case EXPR_MINUS:
+ return GetExprVal (Expr->Left) - GetExprVal (Expr->Right);
+
+ case EXPR_MUL:
+ return GetExprVal (Expr->Left) * GetExprVal (Expr->Right);
+
+ case EXPR_DIV:
+ Left = GetExprVal (Expr->Left);
+ Right = GetExprVal (Expr->Right);
+ if (Right == 0) {
+ Error (ERR_DIV_BY_ZERO);
+ return 0;
+ }
+ return Left / Right;
+
+ case EXPR_MOD:
+ Left = GetExprVal (Expr->Left);
+ Right = GetExprVal (Expr->Right);
+ if (Right == 0) {
+ Error (ERR_MOD_BY_ZERO);
+ return 0;
+ }
+ return Left % Right;
+
+ case EXPR_OR:
+ return GetExprVal (Expr->Left) | GetExprVal (Expr->Right);
+
+ case EXPR_XOR:
+ return GetExprVal (Expr->Left) ^ GetExprVal (Expr->Right);
+
+ case EXPR_AND:
+ return GetExprVal (Expr->Left) & GetExprVal (Expr->Right);
+
+ case EXPR_SHL:
+ return GetExprVal (Expr->Left) << GetExprVal (Expr->Right);
+
+ case EXPR_SHR:
+ return GetExprVal (Expr->Left) >> GetExprVal (Expr->Right);
+
+ case EXPR_EQ:
+ return (GetExprVal (Expr->Left) == GetExprVal (Expr->Right));
+
+ case EXPR_NE:
+ return (GetExprVal (Expr->Left) != GetExprVal (Expr->Right));
+
+ case EXPR_LT:
+ return (GetExprVal (Expr->Left) < GetExprVal (Expr->Right));
+
+ case EXPR_GT:
+ return (GetExprVal (Expr->Left) > GetExprVal (Expr->Right));
+
+ case EXPR_LE:
+ return (GetExprVal (Expr->Left) <= GetExprVal (Expr->Right));
+
+ case EXPR_GE:
+ return (GetExprVal (Expr->Left) >= GetExprVal (Expr->Right));
+
+ case EXPR_UNARY_MINUS:
+ return -GetExprVal (Expr->Left);
+
+ case EXPR_NOT:
+ return ~GetExprVal (Expr->Left);
+
+ case EXPR_LOBYTE:
+ return GetExprVal (Expr->Left) & 0xFF;
+
+ case EXPR_HIBYTE:
+ return (GetExprVal (Expr->Left) >> 8) & 0xFF;
+
+ case EXPR_SWAP:
+ Left = GetExprVal (Expr->Left);
+ return ((Left >> 8) & 0x00FF) | ((Left << 8) & 0xFF00);
+
+ case EXPR_BAND:
+ return GetExprVal (Expr->Left) && GetExprVal (Expr->Right);
+
+ case EXPR_BOR:
+ return GetExprVal (Expr->Left) || GetExprVal (Expr->Right);
+
+ case EXPR_BXOR:
+ return (GetExprVal (Expr->Left) != 0) ^ (GetExprVal (Expr->Right) != 0);
+
+ case EXPR_BNOT:
+ return !GetExprVal (Expr->Left);
+
+ case EXPR_ULABEL:
+ Internal ("GetExprVal called for EXPR_ULABEL");
+ /* NOTREACHED */
+ return 0;
+
+ default:
+ Internal ("Unknown Op type: %u", Expr->Op);
+ /* NOTREACHED */
+ return 0;
+ }
+}
+
+
+
+static ExprNode* RemoveSyms (ExprNode* Expr, int MustClone)
+/* Remove resolved symbols from the tree by cloning symbol expressions */
+{
+ /* Accept NULL pointers */
+ if (Expr == 0) {
+ return 0;
+ }
+
+ /* Special node handling */
+ switch (Expr->Op) {
+
+ case EXPR_SYMBOL:
+ if (SymHasExpr (Expr->V.Sym)) {
+ /* The symbol has an expression tree */
+ SymEntry* Sym = Expr->V.Sym;
+ if (SymHasUserMark (Sym)) {
+ /* Circular definition */
+ if (Verbose) {
+ DumpExpr (Expr);
+ }
+ PError (GetSymPos (Sym), ERR_CIRCULAR_REFERENCE);
+ return LiteralExpr (0); /* Return a dummy value */
+ }
+ SymMarkUser (Sym);
+ Expr = RemoveSyms (GetSymExpr (Sym), 1);
+ SymUnmarkUser (Sym);
+ return Expr;
+ } else if (SymIsConst (Expr->V.Sym)) {
+ /* The symbol is a constant */
+ return LiteralExpr (GetSymVal (Expr->V.Sym));
+ }
+ break;
+
+ case EXPR_ULABEL:
+ if (ULabCanResolve ()) {
+ ExprNode* NewExpr = ULabResolve (Expr->V.Val);
+ FreeExpr (Expr);
+ Expr = NewExpr;
+ }
+ break;
+
+ }
+
+ /* Clone the current node if needed */
+ if (MustClone) {
+
+ /* Create a new node */
+ ExprNode* Clone = NewExprNode ();
+
+ /* Clone the operation */
+ Clone->Op = Expr->Op;
+
+ /* Clone the attribute if needed */
+ switch (Expr->Op) {
+
+ case EXPR_LITERAL:
+ case EXPR_ULABEL:
+ Clone->V.Val = Expr->V.Val;
+ break;
+
+ case EXPR_SYMBOL:
+ Clone->V.Sym = Expr->V.Sym;
+ break;
+
+ case EXPR_SEGMENT:
+ Clone->V.SegNum = Expr->V.SegNum;
+ break;
+
+ }
+
+ /* Clone the tree nodes */
+ Clone->Left = RemoveSyms (Expr->Left, MustClone);
+ Clone->Right = RemoveSyms (Expr->Right, MustClone);
+
+ /* Done */
+ return Clone;
+
+ } else {
+
+ /* Nothing to clone */
+ Expr->Left = RemoveSyms (Expr->Left, MustClone);
+ Expr->Right = RemoveSyms (Expr->Right, MustClone);
+
+ /* Done */
+ return Expr;
+
+ }
+}
+
+
+
+static ExprNode* ConstExtract (ExprNode* Expr, long* Val, int Sign)
+/* Extract and evaluate all constant factors in an subtree that has only
+ * additions and subtractions.
+ */
+{
+ if (Expr->Op == EXPR_LITERAL) {
+ if (Sign < 0) {
+ *Val -= Expr->V.Val;
+ } else {
+ *Val += Expr->V.Val;
+ }
+ FreeExprNode (Expr);
+ return 0;
+ }
+
+ if (Expr->Op == EXPR_PLUS || Expr->Op == EXPR_MINUS) {
+ ExprNode* Left;
+ ExprNode* Right;
+ Left = ConstExtract (Expr->Left, Val, Sign);
+ if (Expr->Op == EXPR_MINUS) {
+ Sign = -Sign;
+ }
+ Right = ConstExtract (Expr->Right, Val, Sign);
+ if (Left == 0 && Right == 0) {
+ FreeExprNode (Expr);
+ return 0;
+ } else if (Left == 0) {
+ FreeExprNode (Expr);
+ return Right;
+ } else if (Right == 0) {
+ FreeExprNode (Expr);
+ return Left;
+ } else {
+ /* Check for SEG - SEG which is now possible */
+ if (Left->Op == EXPR_SEGMENT && Right->Op == EXPR_SEGMENT &&
+ Left->V.SegNum == Right->V.SegNum) {
+ /* SEG - SEG, remove it completely */
+ FreeExprNode (Left);
+ FreeExprNode (Right);
+ FreeExprNode (Expr);
+ return 0;
+ } else {
+ Expr->Left = Left;
+ Expr->Right = Right;
+ return Expr;
+ }
+ }
+ }
+
+ /* Some other sort of node, finalize the terms */
+ if (Expr->Left) {
+ Expr->Left = FinalizeExpr (Expr->Left);
+ }
+ if (Expr->Right) {
+ Expr->Right = FinalizeExpr (Expr->Right);
+ }
+
+ return Expr;
+}
+
+
+
+ExprNode* FinalizeExpr (ExprNode* Expr)
+/* Resolve any symbols by cloning the symbol expression tree instead of the
+ * symbol reference, then try to simplify the expression as much as possible.
+ * This function must only be called if all symbols are resolved (no undefined
+ * symbol errors).
+ */
+{
+ long Val = 0;
+ ExprNode* N;
+
+ Expr = RemoveSyms (Expr, 0);
+ Expr = ConstExtract (Expr, &Val, 1);
+ if (Expr == 0) {
+ /* Reduced to a literal value */
+ Expr = LiteralExpr (Val);
+ } else if (Val) {
+ /* Extracted a value */
+ N = NewExprNode ();
+ N->Op = EXPR_PLUS;
+ N->Left = Expr;
+ N->Right = LiteralExpr (Val);
+ Expr = N;
+ }
+ return Expr;
+}
+
+
+
+ExprNode* CloneExpr (ExprNode* Expr)
+/* Clone the given expression tree. The function will simply clone symbol
+ * nodes, it will not resolve them.
+ */
+{
+ ExprNode* Clone;
+
+ /* Accept NULL pointers */
+ if (Expr == 0) {
+ return 0;
+ }
+
+ /* Get a new node */
+ Clone = NewExprNode ();
+
+ /* Clone the operation */
+ Clone->Op = Expr->Op;
+
+ /* Clone the attribute if needed */
+ switch (Expr->Op) {
+
+ case EXPR_LITERAL:
+ case EXPR_ULABEL:
+ Clone->V.Val = Expr->V.Val;
+ break;
+
+ case EXPR_SYMBOL:
+ Clone->V.Sym = Expr->V.Sym;
+ break;
+
+ case EXPR_SEGMENT:
+ Clone->V.SegNum = Expr->V.SegNum;
+ break;
+
+ }
+
+ /* Clone the tree nodes */
+ Clone->Left = CloneExpr (Expr->Left);
+ Clone->Right = CloneExpr (Expr->Right);
+
+ /* Done */
+ return Clone;
+}
+
+
+
+void WriteExpr (ExprNode* Expr)
+/* Write the given expression to the object file */
+{
+ /* Null expressions are encoded by a type byte of zero */
+ if (Expr == 0) {
+ ObjWrite8 (0);
+ return;
+ }
+
+ /* Write the expression code */
+ ObjWrite8 (Expr->Op);
+
+ /* If the is a leafnode, write the expression attribute, otherwise
+ * write the expression operands.
+ */
+ switch (Expr->Op) {
+
+ case EXPR_LITERAL:
+ ObjWrite32 (Expr->V.Val);
+ break;
+
+ case EXPR_SYMBOL:
+ /* Maybe we should use a code here? */
+ CHECK (SymIsImport (Expr->V.Sym)); /* Safety */
+ ObjWrite16 (GetSymIndex (Expr->V.Sym));
+ break;
+
+ case EXPR_SEGMENT:
+ ObjWrite8 (Expr->V.SegNum);
+ break;
+
+ case EXPR_ULABEL:
+ Internal ("WriteExpr: Cannot write EXPR_ULABEL nodes");
+ break;
+
+ default:
+ /* Not a leaf node */
+ WriteExpr (Expr->Left);
+ WriteExpr (Expr->Right);
+ break;
+
+ }
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* expr.h */
+/* */
+/* Expression evaluation for the ca65 macroassembler */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef EXPR_H
+#define EXPR_H
+
+
+
+#include "../common/exprdefs.h"
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+ExprNode* Expression (void);
+/* Evaluate an expression, build the expression tree on the heap and return
+ * a pointer to the root of the tree.
+ */
+
+long ConstExpression (void);
+/* Parse an expression. Check if the expression is const, and print an error
+ * message if not. Return the value of the expression, or a dummy, if it is
+ * not constant.
+ */
+
+void FreeExpr (ExprNode* Root);
+/* Free the expression tree, Root is pointing to. */
+
+ExprNode* LiteralExpr (long Val);
+/* Return an expression tree that encodes the given literal value */
+
+ExprNode* CurrentPC (void);
+/* Return the current program counter as expression */
+
+ExprNode* SwapExpr (ExprNode* Expr);
+/* Return an extended expression with lo and hi bytes swapped */
+
+ExprNode* BranchExpr (unsigned Offs);
+/* Return an expression that encodes the difference between current PC plus
+ * offset and the target expression (that is, Expression() - (*+Offs) ).
+ */
+
+ExprNode* ULabelExpr (unsigned Num);
+/* Return an expression for an unnamed label with the given index */
+
+ExprNode* ForceWordExpr (ExprNode* Expr);
+/* Force the given expression into a word and return the result. */
+
+int IsConstExpr (ExprNode* Root);
+/* Return true if the given expression is a constant expression, that is, one
+ * with no references to external symbols.
+ */
+
+int IsByteExpr (ExprNode* Root);
+/* Return true if this is a byte expression */
+
+long GetExprVal (ExprNode* Expr);
+/* Get the value of a constant expression */
+
+int IsByteRange (long Val);
+/* Return true if this is a byte value */
+
+int IsWordRange (long Val);
+/* Return true if this is a word value */
+
+void DumpExpr (ExprNode* Expr);
+/* Dump an expression tree to stdout */
+
+ExprNode* FinalizeExpr (ExprNode* Expr);
+/* Resolve any symbols by cloning the symbol expression tree instead of the
+ * symbol reference, then try to simplify the expression as much as possible.
+ * This function must only be called if all symbols are resolved (no undefined
+ * symbol errors).
+ */
+
+ExprNode* CloneExpr (ExprNode* Expr);
+/* Clone the given expression tree. The function will simply clone symbol
+ * nodes, it will not resolve them.
+ */
+
+void WriteExpr (ExprNode* Expr);
+/* Write the given expression to the object file */
+
+
+
+/* End of expr.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* fname.c */
+/* */
+/* File name handling utilities */
+/* */
+/* */
+/* */
+/* (C) 2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <string.h>
+
+#include "mem.h"
+#include "fname.h"
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+char* MakeFilename (const char* Origin, const char* Ext)
+/* Make a new file name from Origin and Ext. If Origin has an extension, it
+ * is removed and Ext is appended. If Origin has no extension, Ext is simply
+ * appended. The result is placed in a malloc'ed buffer and returned.
+ * The function may be used to create "foo.o" from "foo.s".
+ */
+{
+ /* Construct the name */
+ char* Result;
+ const char* P = strrchr (Origin, '.');
+ if (P == 0) {
+ /* No dot, add the extension */
+ Result = Xmalloc (strlen (Origin) + strlen (Ext) + 1);
+ strcpy (Result, Origin);
+ strcat (Result, Ext);
+ } else {
+ Result = Xmalloc (P - Origin + strlen (Ext) + 1);
+ memcpy (Result, Origin, P - Origin);
+ strcpy (Result + (P - Origin), Ext);
+ }
+ return Result;
+}
+
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* fname.h */
+/* */
+/* File name handling utilities */
+/* */
+/* */
+/* */
+/* (C) 2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef FNAME_H
+#define FNAME_H
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+char* MakeFilename (const char* Origin, const char* Ext);
+/* Make a new file name from Origin and Ext. If Origin has an extension, it
+ * is removed and Ext is appended. If Origin has no extension, Ext is simply
+ * appended. The result is placed in a malloc'ed buffer and returned.
+ * The function may be used to create "foo.o" from "foo.s".
+ */
+
+
+
+/* End of fname.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* fragment.c */
+/* */
+/* Data fragments for the ca65 crossassembler */
+/* */
+/* */
+/* */
+/* (C) 1998-2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include "fragment.h"
+
+
+
+/*****************************************************************************/
+/* struct Fragment */
+/*****************************************************************************/
+
+
+
+/* List of all fragments */
+Fragment* FragList = 0;
+Fragment* FragLast = 0;
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* fragment.h */
+/* */
+/* Data fragments for the ca65 crossassembler */
+/* */
+/* */
+/* */
+/* (C) 1998-2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef FRAGMENT_H
+#define FRAGMENT_H
+
+
+
+#include "../common/exprdefs.h"
+#include "../common/filepos.h"
+
+
+
+/*****************************************************************************/
+/* struct Fragment */
+/*****************************************************************************/
+
+
+
+typedef struct Fragment_ Fragment;
+struct Fragment_ {
+ Fragment* List; /* List of all fragments */
+ Fragment* Next; /* Fragment list in one segment */
+ Fragment* LineList; /* List of fragments for one src line */
+ FilePos Pos; /* File position for this fragment */
+ unsigned short Len; /* Length for this fragment */
+ unsigned char Type; /* Fragment type */
+ union {
+ unsigned char Data [4]; /* Literal values */
+ ExprNode* Expr; /* Expression */
+ } V;
+};
+
+
+
+/* List of all fragments */
+extern Fragment* FragList;
+extern Fragment* FragLast;
+
+
+
+/* End of fragment.h */
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* global.c */
+/* */
+/* Global variables for the ca65 macroassembler */
+/* */
+/* */
+/* */
+/* (C) 1998-2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include "global.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+const char* ProgName = "ca65"; /* Program name */
+
+/* File names */
+const char* InFile = 0; /* Name of input file */
+const char* OutFile = 0; /* Name of output file */
+const char* ListFile = 0; /* Name of listing file */
+
+/* Default extensions */
+const char ObjExt[] = ".o"; /* Default object extension */
+const char ListExt[] = ".lst"; /* Default listing extension */
+
+char LocalStart = '@'; /* This char starts local symbols */
+
+unsigned char IgnoreCase = 0; /* Ignore case on identifiers? */
+unsigned char AutoImport = 0; /* Mark unresolveds as import */
+unsigned char Verbose = 0; /* Verbose operation flag */
+unsigned char SmartMode = 0; /* Smart mode */
+unsigned char DbgSyms = 0; /* Add debug symbols */
+unsigned char Listing = 0; /* Create listing file */
+unsigned char LineCont = 0; /* Allow line continuation */
+
+/* Emulation features */
+unsigned char DollarIsPC = 0; /* Allow the $ symbol as current PC */
+unsigned char NoColonLabels = 0; /* Allow labels without a colon */
+unsigned char LooseStringTerm = 0; /* Allow ' as string terminator */
+unsigned char AtInIdents = 0; /* Allow '@' in identifiers */
+unsigned char DollarInIdents = 0; /* Allow '$' in identifiers */
+
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* global.h */
+/* */
+/* Global variables for the ca65 macroassembler */
+/* */
+/* */
+/* */
+/* (C) 1998-2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef GLOBAL_H
+#define GLOBAL_H
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+extern const char* ProgName; /* Program name */
+
+/* File names */
+extern const char* InFile; /* Name of input file */
+extern const char* OutFile; /* Name of output file */
+extern const char* ListFile; /* Name of listing file */
+
+/* Default extensions */
+extern const char ObjExt[]; /* Default object extension */
+extern const char ListExt[]; /* Default listing extension */
+
+extern char LocalStart; /* This char starts local symbols */
+
+extern unsigned char IgnoreCase; /* Ignore case on identifiers? */
+extern unsigned char AutoImport; /* Mark unresolveds as import */
+extern unsigned char Verbose; /* Verbose operation flag */
+extern unsigned char SmartMode; /* Smart mode */
+extern unsigned char DbgSyms; /* Add debug symbols */
+extern unsigned char Listing; /* Create listing file */
+extern unsigned char LineCont; /* Allow line continuation */
+
+/* Emulation features */
+extern unsigned char DollarIsPC; /* Allow the $ symbol as current PC */
+extern unsigned char NoColonLabels; /* Allow labels without a colon */
+extern unsigned char LooseStringTerm;/* Allow ' as string terminator */
+extern unsigned char AtInIdents; /* Allow '@' in identifiers */
+extern unsigned char DollarInIdents; /* Allow '$' in identifiers */
+
+
+
+/* End of global.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* instr.c */
+/* */
+/* Instruction encoding for the ca65 macroassembler */
+/* */
+/* */
+/* */
+/* (C) 1998-2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "../common/bitops.h"
+
+#include "ea.h"
+#include "error.h"
+#include "expr.h"
+#include "global.h"
+#include "objcode.h"
+#include "scanner.h"
+#include "instr.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Forwards for handler functions */
+static void PutPCRel8 (const InsDesc* Ins);
+static void PutPCRel16 (const InsDesc* Ins);
+static void PutBlockMove (const InsDesc* Ins);
+static void PutREP (const InsDesc* Ins);
+static void PutSEP (const InsDesc* Ins);
+static void PutAll (const InsDesc* Ins);
+
+
+
+/* Instruction table for the 6502 */
+#define INS_COUNT_6502 56
+static const struct {
+ unsigned Count;
+ InsDesc Ins[INS_COUNT_6502];
+} InsTab6502 = {
+ INS_COUNT_6502,
+ {
+ { "ADC", 0x080A26C, 0x60, 0, PutAll },
+ { "AND", 0x080A26C, 0x20, 0, PutAll },
+ { "ASL", 0x000006e, 0x02, 1, PutAll },
+ { "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
+ { "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
+ { "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
+ { "BIT", 0x000000C, 0x00, 2, PutAll },
+ { "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
+ { "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
+ { "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
+ { "BRK", 0x0000001, 0x00, 0, PutAll },
+ { "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
+ { "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
+ { "CLC", 0x0000001, 0x18, 0, PutAll },
+ { "CLD", 0x0000001, 0xd8, 0, PutAll },
+ { "CLI", 0x0000001, 0x58, 0, PutAll },
+ { "CLV", 0x0000001, 0xb8, 0, PutAll },
+ { "CMP", 0x080A26C, 0xc0, 0, PutAll },
+ { "CPX", 0x080000C, 0xe0, 1, PutAll },
+ { "CPY", 0x080000C, 0xc0, 1, PutAll },
+ { "DEC", 0x000006C, 0x00, 3, PutAll },
+ { "DEX", 0x0000001, 0xca, 0, PutAll },
+ { "DEY", 0x0000001, 0x88, 0, PutAll },
+ { "EOR", 0x080A26C, 0x40, 0, PutAll },
+ { "INC", 0x000006c, 0x00, 4, PutAll },
+ { "INX", 0x0000001, 0xe8, 0, PutAll },
+ { "INY", 0x0000001, 0xc8, 0, PutAll },
+ { "JMP", 0x0000808, 0x4c, 6, PutAll },
+ { "JSR", 0x0000008, 0x20, 7, PutAll },
+ { "LDA", 0x080A26C, 0xa0, 0, PutAll },
+ { "LDX", 0x080030C, 0xa2, 1, PutAll },
+ { "LDY", 0x080006C, 0xa0, 1, PutAll },
+ { "LSR", 0x000006F, 0x42, 1, PutAll },
+ { "NOP", 0x0000001, 0xea, 0, PutAll },
+ { "ORA", 0x080A26C, 0x00, 0, PutAll },
+ { "PHA", 0x0000001, 0x48, 0, PutAll },
+ { "PHP", 0x0000001, 0x08, 0, PutAll },
+ { "PLA", 0x0000001, 0x68, 0, PutAll },
+ { "PLP", 0x0000001, 0x28, 0, PutAll },
+ { "ROL", 0x000006F, 0x22, 1, PutAll },
+ { "ROR", 0x000006F, 0x62, 1, PutAll },
+ { "RTI", 0x0000001, 0x40, 0, PutAll },
+ { "RTS", 0x0000001, 0x60, 0, PutAll },
+ { "SBC", 0x080A26C, 0xe0, 0, PutAll },
+ { "SEC", 0x0000001, 0x38, 0, PutAll },
+ { "SED", 0x0000001, 0xf8, 0, PutAll },
+ { "SEI", 0x0000001, 0x78, 0, PutAll },
+ { "STA", 0x000A26C, 0x80, 0, PutAll },
+ { "STX", 0x000010c, 0x82, 1, PutAll },
+ { "STY", 0x000002c, 0x80, 1, PutAll },
+ { "TAX", 0x0000001, 0xaa, 0, PutAll },
+ { "TAY", 0x0000001, 0xa8, 0, PutAll },
+ { "TSX", 0x0000001, 0xba, 0, PutAll },
+ { "TXA", 0x0000001, 0x8a, 0, PutAll },
+ { "TXS", 0x0000001, 0x9a, 0, PutAll },
+ { "TYA", 0x0000001, 0x98, 0, PutAll }
+ }
+};
+
+/* Instruction table for the 65SC02 */
+#define INS_COUNT_65SC02 66
+static const struct {
+ unsigned Count;
+ InsDesc Ins[INS_COUNT_65SC02];
+} InsTab65SC02 = {
+ INS_COUNT_65SC02,
+ {
+ { "ADC", 0x080A66C, 0x60, 0, PutAll },
+ { "AND", 0x080A66C, 0x20, 0, PutAll },
+ { "ASL", 0x000006e, 0x02, 1, PutAll },
+ { "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
+ { "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
+ { "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
+ { "BIT", 0x080006C, 0x00, 2, PutAll },
+ { "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
+ { "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
+ { "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
+ { "BRA", 0x0020000, 0x80, 0, PutPCRel8 },
+ { "BRK", 0x0000001, 0x00, 0, PutAll },
+ { "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
+ { "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
+ { "CLC", 0x0000001, 0x18, 0, PutAll },
+ { "CLD", 0x0000001, 0xd8, 0, PutAll },
+ { "CLI", 0x0000001, 0x58, 0, PutAll },
+ { "CLV", 0x0000001, 0xb8, 0, PutAll },
+ { "CMP", 0x080A66C, 0xc0, 0, PutAll },
+ { "CPX", 0x080000C, 0xe0, 1, PutAll },
+ { "CPY", 0x080000C, 0xc0, 1, PutAll },
+ { "DEA", 0x0000001, 0x00, 3, PutAll }, /* == DEC */
+ { "DEC", 0x000006F, 0x00, 3, PutAll },
+ { "DEX", 0x0000001, 0xca, 0, PutAll },
+ { "DEY", 0x0000001, 0x88, 0, PutAll },
+ { "EOR", 0x080A66C, 0x40, 0, PutAll },
+ { "INA", 0x0000001, 0x00, 4, PutAll }, /* == INC */
+ { "INC", 0x000006f, 0x00, 4, PutAll },
+ { "INX", 0x0000001, 0xe8, 0, PutAll },
+ { "INY", 0x0000001, 0xc8, 0, PutAll },
+ { "JMP", 0x0010808, 0x4c, 6, PutAll },
+ { "JSR", 0x0000008, 0x20, 7, PutAll },
+ { "LDA", 0x080A66C, 0xa0, 0, PutAll },
+ { "LDX", 0x080030C, 0xa2, 1, PutAll },
+ { "LDY", 0x080006C, 0xa0, 1, PutAll },
+ { "LSR", 0x000006F, 0x42, 1, PutAll },
+ { "NOP", 0x0000001, 0xea, 0, PutAll },
+ { "ORA", 0x080A66C, 0x00, 0, PutAll },
+ { "PHA", 0x0000001, 0x48, 0, PutAll },
+ { "PHP", 0x0000001, 0x08, 0, PutAll },
+ { "PHX", 0x0000001, 0xda, 0, PutAll },
+ { "PHY", 0x0000001, 0x5a, 0, PutAll },
+ { "PLA", 0x0000001, 0x68, 0, PutAll },
+ { "PLP", 0x0000001, 0x28, 0, PutAll },
+ { "PLX", 0x0000001, 0xfa, 0, PutAll },
+ { "PLY", 0x0000001, 0x7a, 0, PutAll },
+ { "ROL", 0x000006F, 0x22, 1, PutAll },
+ { "ROR", 0x000006F, 0x62, 1, PutAll },
+ { "RTI", 0x0000001, 0x40, 0, PutAll },
+ { "RTS", 0x0000001, 0x60, 0, PutAll },
+ { "SBC", 0x080A66C, 0xe0, 0, PutAll },
+ { "SEC", 0x0000001, 0x38, 0, PutAll },
+ { "SED", 0x0000001, 0xf8, 0, PutAll },
+ { "SEI", 0x0000001, 0x78, 0, PutAll },
+ { "STA", 0x000A66C, 0x80, 0, PutAll },
+ { "STX", 0x000010c, 0x82, 1, PutAll },
+ { "STY", 0x000002c, 0x80, 1, PutAll },
+ { "STZ", 0x000006c, 0x04, 5, PutAll },
+ { "TAX", 0x0000001, 0xaa, 0, PutAll },
+ { "TAY", 0x0000001, 0xa8, 0, PutAll },
+ { "TRB", 0x000000c, 0x10, 1, PutAll },
+ { "TSB", 0x000000c, 0x00, 1, PutAll },
+ { "TSX", 0x0000001, 0xba, 0, PutAll },
+ { "TXA", 0x0000001, 0x8a, 0, PutAll },
+ { "TXS", 0x0000001, 0x9a, 0, PutAll },
+ { "TYA", 0x0000001, 0x98, 0, PutAll }
+ }
+};
+
+/* Instruction table for the 65816 */
+#define INS_COUNT_65816 101
+static const struct {
+ unsigned Count;
+ InsDesc Ins[INS_COUNT_65816];
+} InsTab65816 = {
+ INS_COUNT_65816,
+ {
+ { "ADC", 0x0b8f6fc, 0x60, 0, PutAll },
+ { "AND", 0x0b8f6fc, 0x20, 0, PutAll },
+ { "ASL", 0x000006e, 0x02, 1, PutAll },
+ { "BCC", 0x0020000, 0x90, 0, PutPCRel8 },
+ { "BCS", 0x0020000, 0xb0, 0, PutPCRel8 },
+ { "BEQ", 0x0020000, 0xf0, 0, PutPCRel8 },
+ { "BGE", 0x0020000, 0xb0, 0, PutPCRel8 }, /* == BCS */
+ { "BIT", 0x0a0006c, 0x00, 2, PutAll },
+ { "BLT", 0x0020000, 0x90, 0, PutPCRel8 }, /* == BCC */
+ { "BMI", 0x0020000, 0x30, 0, PutPCRel8 },
+ { "BNE", 0x0020000, 0xd0, 0, PutPCRel8 },
+ { "BPL", 0x0020000, 0x10, 0, PutPCRel8 },
+ { "BRA", 0x0020000, 0x80, 0, PutPCRel8 },
+ { "BRK", 0x0000001, 0x00, 0, PutAll },
+ { "BRL", 0x0040000, 0x82, 0, PutPCRel16 },
+ { "BVC", 0x0020000, 0x50, 0, PutPCRel8 },
+ { "BVS", 0x0020000, 0x70, 0, PutPCRel8 },
+ { "CLC", 0x0000001, 0x18, 0, PutAll },
+ { "CLD", 0x0000001, 0xd8, 0, PutAll },
+ { "CLI", 0x0000001, 0x58, 0, PutAll },
+ { "CLV", 0x0000001, 0xb8, 0, PutAll },
+ { "CMP", 0x0b8f6fc, 0xc0, 0, PutAll },
+ { "COP", 0x0000004, 0x02, 6, PutAll },
+ { "CPA", 0x0b8f6fc, 0xc0, 0, PutAll }, /* == CMP */
+ { "CPX", 0x0c0000c, 0xe0, 1, PutAll },
+ { "CPY", 0x0c0000c, 0xc0, 1, PutAll },
+ { "DEA", 0x0000001, 0x00, 3, PutAll }, /* == DEC */
+ { "DEC", 0x000006F, 0x00, 3, PutAll },
+ { "DEX", 0x0000001, 0xca, 0, PutAll },
+ { "DEY", 0x0000001, 0x88, 0, PutAll },
+ { "EOR", 0x0b8f6fc, 0x40, 0, PutAll },
+ { "INA", 0x0000001, 0x00, 4, PutAll }, /* == INC */
+ { "INC", 0x000006F, 0x00, 4, PutAll },
+ { "INX", 0x0000001, 0xe8, 0, PutAll },
+ { "INY", 0x0000001, 0xc8, 0, PutAll },
+ { "JML", 0x0000810, 0x5c, 1, PutAll },
+ { "JMP", 0x0010818, 0x4c, 6, PutAll },
+ { "JSL", 0x0000010, 0x20, 7, PutAll },
+ { "JSR", 0x0010018, 0x20, 7, PutAll },
+ { "LDA", 0x0b8f6fc, 0xa0, 0, PutAll },
+ { "LDX", 0x0c0030c, 0xa2, 1, PutAll },
+ { "LDY", 0x0c0006c, 0xa0, 1, PutAll },
+ { "LSR", 0x000006F, 0x42, 1, PutAll },
+ { "MVN", 0x1000000, 0x54, 0, PutBlockMove },
+ { "MVP", 0x1000000, 0x44, 0, PutBlockMove },
+ { "NOP", 0x0000001, 0xea, 0, PutAll },
+ { "ORA", 0x0b8f6fc, 0x00, 0, PutAll },
+ { "PEA", 0x0000008, 0xf4, 6, PutAll },
+ { "PEI", 0x0800000, 0xd4, 0, PutAll },
+ { "PER", 0x0040000, 0x62, 0, PutPCRel16 },
+ { "PHA", 0x0000001, 0x48, 0, PutAll },
+ { "PHB", 0x0000001, 0x8b, 0, PutAll },
+ { "PHD", 0x0000001, 0x0b, 0, PutAll },
+ { "PHK", 0x0000001, 0x4b, 0, PutAll },
+ { "PHP", 0x0000001, 0x08, 0, PutAll },
+ { "PHX", 0x0000001, 0xda, 0, PutAll },
+ { "PHY", 0x0000001, 0x5a, 0, PutAll },
+ { "PLA", 0x0000001, 0x68, 0, PutAll },
+ { "PLB", 0x0000001, 0xab, 0, PutAll },
+ { "PLD", 0x0000001, 0x2b, 0, PutAll },
+ { "PLP", 0x0000001, 0x28, 0, PutAll },
+ { "PLX", 0x0000001, 0xfa, 0, PutAll },
+ { "PLY", 0x0000001, 0x7a, 0, PutAll },
+ { "REP", 0x0800000, 0xc2, 1, PutREP },
+ { "ROL", 0x000006F, 0x22, 1, PutAll },
+ { "ROR", 0x000006F, 0x62, 1, PutAll },
+ { "RTI", 0x0000001, 0x40, 0, PutAll },
+ { "RTL", 0x0000001, 0x6b, 0, PutAll },
+ { "RTS", 0x0000001, 0x60, 0, PutAll },
+ { "SBC", 0x0b8f6fc, 0xe0, 0, PutAll },
+ { "SEC", 0x0000001, 0x38, 0, PutAll },
+ { "SED", 0x0000001, 0xf8, 0, PutAll },
+ { "SEI", 0x0000001, 0x78, 0, PutAll },
+ { "SEP", 0x0800000, 0xe2, 1, PutSEP },
+ { "STA", 0x018f6fc, 0x80, 0, PutAll },
+ { "STP", 0x0000001, 0xdb, 0, PutAll },
+ { "STX", 0x000010c, 0x82, 1, PutAll },
+ { "STY", 0x000002c, 0x80, 1, PutAll },
+ { "STZ", 0x000006c, 0x04, 5, PutAll },
+ { "SWA", 0x0000001, 0xeb, 0, PutAll }, /* == XBA */
+ { "TAD", 0x0000001, 0x5b, 0, PutAll }, /* == TCD */
+ { "TAS", 0x0000001, 0x1b, 0, PutAll }, /* == TCS */
+ { "TAX", 0x0000001, 0xaa, 0, PutAll },
+ { "TAY", 0x0000001, 0xa8, 0, PutAll },
+ { "TCD", 0x0000001, 0x5b, 0, PutAll },
+ { "TCS", 0x0000001, 0x1b, 0, PutAll },
+ { "TDA", 0x0000001, 0x7b, 0, PutAll }, /* == TDC */
+ { "TDC", 0x0000001, 0x7b, 0, PutAll },
+ { "TRB", 0x000000c, 0x10, 1, PutAll },
+ { "TSA", 0x0000001, 0x3b, 0, PutAll }, /* == TSC */
+ { "TSB", 0x000000c, 0x00, 1, PutAll },
+ { "TSC", 0x0000001, 0x3b, 0, PutAll },
+ { "TSX", 0x0000001, 0xba, 0, PutAll },
+ { "TXA", 0x0000001, 0x8a, 0, PutAll },
+ { "TXS", 0x0000001, 0x9a, 0, PutAll },
+ { "TXY", 0x0000001, 0x9b, 0, PutAll },
+ { "TYA", 0x0000001, 0x98, 0, PutAll },
+ { "TYX", 0x0000001, 0xbb, 0, PutAll },
+ { "WAI", 0x0000001, 0xcb, 0, PutAll },
+ { "XBA", 0x0000001, 0xeb, 0, PutAll },
+ { "XCE", 0x0000001, 0xfb, 0, PutAll }
+ }
+};
+
+#ifdef SUNPLUS
+/* Table for the SUNPLUS CPU */
+#include "sunplus.inc"
+#endif
+
+
+
+/* The current CPU and an array with instruction tables */
+static enum CPUType CPU = CPU_6502;
+static const InsTable* InsTabs[CPU_COUNT] = {
+ (const InsTable*) &InsTab6502,
+ (const InsTable*) &InsTab65SC02,
+ (const InsTable*) &InsTab65816,
+#ifdef SUNPLUS
+ (const InsTable*) &InsTabSunPlus,
+#else
+ NULL,
+#endif
+};
+const InsTable* InsTab = (const InsTable*) &InsTab6502;
+
+/* Table to build the effective opcode from a base opcode and an addressing
+ * mode.
+ */
+unsigned char EATab [9][AMI_COUNT] = {
+ { /* Table 0 */
+ 0x00, 0x00, 0x05, 0x0D, 0x0F, 0x15, 0x1D, 0x1F,
+ 0x00, 0x19, 0x12, 0x00, 0x07, 0x11, 0x17, 0x01,
+ 0x00, 0x00, 0x00, 0x03, 0x13, 0x09, 0x00, 0x09,
+ 0x00
+ },
+ { /* Table 1 */
+ 0x08, 0x08, 0x04, 0x0C, 0x00, 0x14, 0x1C, 0x00,
+ 0x14, 0x1C, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00
+ },
+ { /* Table 2 */
+ 0x00, 0x00, 0x24, 0x2C, 0x0F, 0x34, 0x3C, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00,
+ 0x00
+ },
+ { /* Table 3 */
+ 0x3A, 0x3A, 0xC6, 0xCE, 0x00, 0xD6, 0xDE, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00
+ },
+ { /* Table 4 */
+ 0x1A, 0x1A, 0xE6, 0xEE, 0x00, 0xF6, 0xFE, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00
+ },
+ { /* Table 5 */
+ 0x00, 0x00, 0x60, 0x98, 0x00, 0x70, 0x9E, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00
+ },
+ { /* Table 6 */
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00,
+ 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00
+ },
+ { /* Table 7 */
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00
+ },
+ { /* Table 8 */
+ 0x00, 0x40, 0x01, 0x41, 0x00, 0x09, 0x49, 0x00,
+ 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
+ 0x00
+ },
+};
+
+/* Table that encodes the additional bytes for each instruction */
+unsigned char ExtBytes [AMI_COUNT] = {
+ 0, /* Implicit */
+ 0, /* Accu */
+ 1, /* Direct */
+ 2, /* Absolute */
+ 3, /* Absolute long */
+ 1, /* Direct,X */
+ 2, /* Absolute,X */
+ 3, /* Absolute long,X */
+ 1, /* Direct,Y */
+ 2, /* Absolute,Y */
+ 1, /* (Direct) */
+ 2, /* (Absolute) */
+ 1, /* [Direct] */
+ 1, /* (Direct),Y */
+ 1, /* [Direct],Y */
+ 1, /* (Direct,X) */
+ 2, /* (Absolute,X) */
+ 1, /* Relative short */
+ 2, /* Relative long */
+ 1, /* r,s */
+ 1, /* (r,s),y */
+ 1, /* Immidiate accu */
+ 1, /* Immidiate index */
+ 1, /* Immidiate byte */
+ 2 /* Blockmove */
+};
+
+
+
+/*****************************************************************************/
+/* Handler functions */
+/*****************************************************************************/
+
+
+
+static long PutImmed8 (const InsDesc* Ins)
+/* Parse and emit an immediate 8 bit instruction. Return the value of the
+ * operand if it's available and const.
+ */
+{
+ ExprNode* Expr;
+ ExprNode* Bank;
+ unsigned long AddrMode;
+ unsigned char OpCode;
+ long Val = -1;
+
+ /* Get the addressing mode used */
+ GetEA (&AddrMode, &Expr, &Bank);
+
+ /* From the possible addressing modes, remove the ones that are invalid
+ * for this instruction or CPU.
+ */
+ AddrMode &= Ins->AddrMode;
+
+ /* If we have possible zero page addressing modes, and the expression
+ * involved (if any) is not in byte range, remove the zero page addressing
+ * modes.
+ */
+ if (Expr && (AddrMode & AM_ZP) && !IsByteExpr (Expr)) {
+ AddrMode &= ~AM_ZP;
+ }
+
+ /* Check if we have any adressing modes left */
+ if (AddrMode == 0) {
+ Error (ERR_ILLEGAL_ADDR_MODE);
+ return -1;
+ }
+ AddrMode = BitFind (AddrMode);
+
+ /* Build the opcode */
+ OpCode = Ins->BaseCode | EATab [Ins->ExtCode][AddrMode];
+
+ /* If we have an expression and it's const, get it's value */
+ if (Expr && IsConstExpr (Expr)) {
+ Val = GetExprVal (Expr);
+ }
+
+ /* Check how many extension bytes are needed and output the instruction */
+ switch (ExtBytes [AddrMode]) {
+
+ case 1:
+ Emit1 (OpCode, Expr);
+ break;
+
+ default:
+ Internal ("Invalid operand byte count: %u", ExtBytes [AddrMode]);
+ }
+
+ /* Return the expression value */
+ return Val;
+}
+
+
+
+static void PutPCRel8 (const InsDesc* Ins)
+/* Handle branches with a 8 bit distance */
+{
+ EmitPCRel (Ins->BaseCode, BranchExpr (2), 1);
+}
+
+
+
+static void PutPCRel16 (const InsDesc* Ins)
+/* Handle branches with an 16 bit distance and PER */
+{
+ EmitPCRel (Ins->BaseCode, BranchExpr (3), 2);
+}
+
+
+
+static void PutBlockMove (const InsDesc* Ins)
+/* Handle the blockmove instructions */
+{
+ Emit0 (Ins->BaseCode);
+ EmitByte (Expression ());
+ ConsumeComma ();
+ EmitByte (Expression ());
+}
+
+
+
+static void PutREP (const InsDesc* Ins)
+/* Emit a REP instruction, track register sizes */
+{
+ /* Use the generic handler */
+ long Val = PutImmed8 (Ins);
+
+ /* We track the status only for the 816 CPU and in smart mode */
+ if (CPU == CPU_65816 && SmartMode) {
+
+ /* Check the range for Val. */
+ if (Val < 0) {
+ /* We had an error */
+ Warning (WARN_CANNOT_TRACK_STATUS);
+ } else {
+ if (Val & 0x10) {
+ /* Index registers to 16 bit */
+ ExtBytes [AMI_IMM_INDEX] = 2;
+ }
+ if (Val & 0x20) {
+ /* Accu to 16 bit */
+ ExtBytes [AMI_IMM_ACCU] = 2;
+ }
+ }
+ }
+}
+
+
+
+static void PutSEP (const InsDesc* Ins)
+/* Emit a SEP instruction, track register sizes */
+{
+ /* Use the generic handler */
+ long Val = PutImmed8 (Ins);
+
+ /* We track the status only for the 816 CPU and in smart mode */
+ if (CPU == CPU_65816 && SmartMode) {
+
+ /* Check the range for Val. */
+ if (Val < 0) {
+ /* We had an error */
+ Warning (WARN_CANNOT_TRACK_STATUS);
+ } else {
+ if (Val & 0x10) {
+ /* Index registers to 8 bit */
+ ExtBytes [AMI_IMM_INDEX] = 1;
+ }
+ if (Val & 0x20) {
+ /* Accu to 8 bit */
+ ExtBytes [AMI_IMM_ACCU] = 1;
+ }
+ }
+ }
+}
+
+
+
+static void PutAll (const InsDesc* Ins)
+/* Handle all other instructions */
+{
+ ExprNode* Expr;
+ ExprNode* Bank;
+ unsigned long AddrModeSet;
+ unsigned char OpCode;
+ unsigned AddrMode;
+ unsigned long AddrModeBit;
+
+ /* Get the addressing mode used */
+ GetEA (&AddrModeSet, &Expr, &Bank);
+
+ /* From the possible addressing modes, remove the ones that are invalid
+ * for this instruction or CPU.
+ */
+ AddrModeSet &= Ins->AddrMode;
+
+ /* If we have possible zero page addressing modes, and the expression
+ * involved (if any) is not in byte range, remove the zero page addressing
+ * modes.
+ */
+ if (Expr && (AddrModeSet & AM_ZP) && !IsByteExpr (Expr)) {
+ AddrModeSet &= ~AM_ZP;
+ }
+
+ /* Check if we have any adressing modes left */
+ if (AddrModeSet == 0) {
+ Error (ERR_ILLEGAL_ADDR_MODE);
+ return;
+ }
+ AddrMode = BitFind (AddrModeSet);
+
+ /* Build the opcode */
+ OpCode = Ins->BaseCode | EATab [Ins->ExtCode][AddrMode];
+
+ /* Check how many extension bytes are needed and output the instruction */
+ switch (ExtBytes [AddrMode]) {
+
+ case 0:
+ Emit0 (OpCode);
+ break;
+
+ case 1:
+ Emit1 (OpCode, Expr);
+ break;
+
+ case 2:
+ AddrModeBit = (1L << AddrMode);
+ if (CPU == CPU_65816 && (AddrModeBit & (AM_ABS | AM_ABS_X | AM_ABS_Y))) {
+ /* This is a 16 bit mode that uses an address. If in 65816,
+ * mode, force this address into 16 bit range to allow
+ * addressing inside a 64K segment.
+ */
+ Emit2 (OpCode, ForceWordExpr (Expr));
+ } else {
+ Emit2 (OpCode, Expr);
+ }
+ break;
+
+ case 3:
+ if (Bank) {
+ /* Separate bank given */
+ Emit3b (OpCode, Expr, Bank);
+ } else {
+ /* One far argument */
+ Emit3 (OpCode, Expr);
+ }
+ break;
+
+ default:
+ Internal ("Invalid operand byte count: %u", ExtBytes [AddrMode]);
+
+ }
+}
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+static int CmpName (const void* Key, const void* Instr)
+/* Compare function for bsearch */
+{
+ return strcmp ((const char*)Key, ((const InsDesc*) Instr)->Mnemonic);
+}
+
+
+
+void SetCPU (enum CPUType NewCPU)
+/* Set a new CPU */
+{
+ /* Make sure the parameter is correct */
+ CHECK (NewCPU < CPU_COUNT);
+
+ /* Check if we have support for the new CPU, if so, use it */
+ if (InsTabs[NewCPU]) {
+ CPU = NewCPU;
+ InsTab = InsTabs[CPU];
+ } else {
+ Error (ERR_CPU_NOT_SUPPORTED);
+ }
+}
+
+
+
+enum CPUType GetCPU (void)
+/* Return the current CPU */
+{
+ return CPU;
+}
+
+
+
+int FindInstruction (const char* Ident)
+/* Check if Ident is a valid mnemonic. If so, return the index in the
+ * instruction table. If not, return -1.
+ */
+{
+ const InsDesc* I;
+ char Key [sizeof (I->Mnemonic)];
+
+ /* Accept only strings with the right length */
+ if (strlen (Ident) != sizeof (I->Mnemonic)-1) {
+ /* Wrong length */
+ return -1;
+ }
+
+ /* Make a copy, and uppercase that copy */
+ Key [0] = toupper (Ident [0]);
+ Key [1] = toupper (Ident [1]);
+ Key [2] = toupper (Ident [2]);
+ Key [3] = '\0';
+
+ /* Search for the key */
+ I = bsearch (Key, InsTab->Ins, InsTab->Count, sizeof (InsDesc), CmpName);
+ if (I == 0) {
+ /* Not found */
+ return -1;
+ } else {
+ /* Found, return the entry */
+ return I - InsTab->Ins;
+ }
+}
+
+
+
+void HandleInstruction (unsigned Index)
+/* Handle the mnemonic with the given index */
+{
+ /* Safety check */
+ PRECONDITION (Index < InsTab->Count);
+
+ /* Skip the mnemonic token */
+ NextTok ();
+
+ /* Call the handler */
+ InsTab->Ins[Index].Emit (&InsTab->Ins[Index]);
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* instr.h */
+/* */
+/* Instruction encoding for the ca65 macroassembler */
+/* */
+/* */
+/* */
+/* (C) 1998-2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef INSTR_H
+#define INSTR_H
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Supported CPUs */
+enum CPUType {
+ CPU_6502,
+ CPU_65C02,
+ CPU_65816,
+ CPU_SUNPLUS, /* Not in the freeware version - sorry */
+ CPU_COUNT /* Count of different CPUs */
+};
+
+/* Constants for the addressing mode. If an opcode is available in zero page
+ * and absolut adressing mode, both bits are set. When checking for valid
+ * modes, the zeropage bit is checked first. Similar, the implicit bit is set
+ * on accu adressing modes, so the 'A' for accu adressing is not needed (but
+ * may be specified).
+ * When assembling for the 6502 or 65C02, all addressing modes that are not
+ * available on these CPUs are removed before doing any checks.
+ */
+#define AM_IMPLICIT 0x00000003UL
+#define AM_ACCU 0x00000002UL
+#define AM_DIR 0x00000004UL
+#define AM_ABS 0x00000008UL
+#define AM_ABS_LONG 0x00000010UL
+#define AM_DIR_X 0x00000020UL
+#define AM_ABS_X 0x00000040UL
+#define AM_ABS_LONG_X 0x00000080UL
+#define AM_DIR_Y 0x00000100UL
+#define AM_ABS_Y 0x00000200UL
+#define AM_DIR_IND 0x00000400UL
+#define AM_ABS_IND 0x00000800UL
+#define AM_DIR_IND_LONG 0x00001000UL
+#define AM_DIR_IND_Y 0x00002000UL
+#define AM_DIR_IND_LONG_Y 0x00004000UL
+#define AM_DIR_X_IND 0x00008000UL
+#define AM_ABS_X_IND 0x00010000UL
+#define AM_REL 0x00020000UL
+#define AM_REL_LONG 0x00040000UL
+#define AM_STACK_REL 0x00080000UL
+#define AM_STACK_REL_IND_Y 0x00100000UL
+#define AM_IMM 0x00E00000UL
+#define AM_BLOCKMOVE 0x01000000UL
+
+/* Bitmask for all ZP operations that have correspondent ABS ops */
+#define AM_ZP (AM_DIR | AM_DIR_X | AM_DIR_Y | AM_DIR_IND | AM_DIR_X_IND)
+
+/* Bit numbers and count */
+#define AMI_IMM_ACCU 21
+#define AMI_IMM_INDEX 22
+#define AMI_COUNT 25
+
+
+
+/* Description for one instruction */
+typedef struct InsDesc_ InsDesc;
+struct InsDesc_ {
+ char Mnemonic [4];
+ unsigned long AddrMode; /* Valid adressing modes */
+ unsigned char BaseCode; /* Base opcode */
+ unsigned char ExtCode; /* Number of ext code table */
+ void (*Emit) (const InsDesc*);/* Handler function */
+};
+
+/* An instruction table */
+typedef struct InsTable_ InsTable;
+struct InsTable_ {
+ unsigned Count; /* Number of intstructions */
+ InsDesc Ins[1]; /* Varying length */
+};
+
+/* The instruction table for the currently active CPU */
+extern const InsTable* InsTab;
+
+/* Table to build the effective opcode from a base opcode and an addressing
+ * mode.
+ */
+extern unsigned char EATab [9][AMI_COUNT];
+
+/* Table that encodes the additional bytes for each instruction */
+extern unsigned char ExtBytes [AMI_COUNT];
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void SetCPU (enum CPUType NewCPU);
+/* Set a new CPU */
+
+enum CPUType GetCPU (void);
+/* Return the current CPU */
+
+int FindInstruction (const char* Ident);
+/* Check if Ident is a valid mnemonic. If so, return the index in the
+ * instruction table. If not, return -1.
+ */
+
+void HandleInstruction (unsigned Index);
+/* Handle the mnemonic with the given index */
+
+
+
+/* End of instr.h */
+
+#endif
+
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* listing.c */
+/* */
+/* Listing support for the ca65 crossassembler */
+/* */
+/* */
+/* */
+/* (C) 2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "../common/segdefs.h"
+#include "../common/version.h"
+
+#include "error.h"
+#include "fname.h"
+#include "global.h"
+#include "mem.h"
+#include "objcode.h"
+#include "listing.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Single linked list of lines */
+ListLine* LineList = 0; /* List of listing lines */
+ListLine* LineCur = 0; /* Current listing line */
+ListLine* LineLast = 0; /* Last (current) listing line */
+
+/* Page and other formatting */
+int PageLength = -1; /* Length of a listing page */
+static unsigned PageNumber = 1; /* Current listing page number */
+static unsigned PageLines = 0; /* Current line on page */
+static unsigned ListBytes = 12; /* Number of bytes to list for one line */
+
+/* Switch the listing on/off */
+static int ListingEnabled = 1; /* Enabled if > 0 */
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void NewListingLine (const char* Line, unsigned char File, unsigned char Depth)
+/* Create a new ListLine struct and insert it */
+{
+ /* Store only if listing is enabled */
+ if (Listing) {
+
+ ListLine* L;
+
+ /* Get the length of the line */
+ unsigned Len = strlen (Line);
+
+ /* Ignore trailing newlines */
+ while (Len > 0 && Line[Len-1] == '\n') {
+ --Len;
+ }
+
+ /* Allocate memory */
+ L = Xmalloc (sizeof (ListLine) + Len);
+
+ /* Initialize the fields. */
+ L->Next = 0;
+ L->FragList = 0;
+ L->FragLast = 0;
+ L->PC = GetPC ();
+ L->Reloc = RelocMode;
+ L->File = File;
+ L->Depth = Depth;
+ L->Output = (ListingEnabled > 0);
+ L->ListBytes = (unsigned char) ListBytes;
+ memcpy (L->Line, Line, Len);
+ L->Line [Len] = '\0';
+
+ /* Insert the line into the list of lines */
+ if (LineList == 0) {
+ LineList = L;
+ } else {
+ LineLast->Next = L;
+ }
+ LineLast = L;
+ }
+}
+
+
+
+void EnableListing (void)
+/* Enable output of lines to the listing */
+{
+ if (Listing) {
+ /* If we're about to enable the listing, do this for the current line
+ * also, so we will see the source line that did this.
+ */
+ if (ListingEnabled++ == 0) {
+ LineCur->Output = 1;
+ }
+ }
+}
+
+
+
+void DisableListing (void)
+/* Disable output of lines to the listing */
+{
+ if (Listing) {
+ if (ListingEnabled == 0) {
+ /* Cannot switch the listing off once more */
+ Error (ERR_COUNTER_UNDERFLOW);
+ } else {
+ --ListingEnabled;
+ }
+ }
+}
+
+
+
+void SetListBytes (int Bytes)
+/* Set the maximum number of bytes listed for one line */
+{
+ if (Bytes < 0) {
+ Bytes = 0; /* Encode "unlimited" as zero */
+ }
+ ListBytes = Bytes;
+}
+
+
+
+void InitListingLine (void)
+/* Initialize the current listing line */
+{
+ if (Listing) {
+ /* Make the last loaded line the current line */
+ LineCur = LineLast;
+
+ /* Set the values for this line */
+ CHECK (LineCur != 0);
+ LineCur->PC = GetPC ();
+ LineCur->Reloc = RelocMode;
+ LineCur->Output = (ListingEnabled > 0);
+ LineCur->ListBytes = (unsigned char) ListBytes;
+ }
+}
+
+
+
+static char* AddHex (char* S, unsigned Val)
+/* Add a hex byte in ASCII to the given string and return the new pointer */
+{
+ static const char HexTab [16] = {
+ '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
+ };
+
+ *S++ = HexTab [(Val >> 4) & 0x0F];
+ *S++ = HexTab [Val & 0x0F];
+
+ return S;
+}
+
+
+
+static void PrintPageHeader (FILE* F, const ListLine* L)
+/* Print the header for a new page. It is assumed that the given line is the
+ * last line of the previous page.
+ */
+{
+ /* Print the header on the new page */
+ fprintf (F,
+ "ca65 V%u.%u.%u - (C) Copyright 1998-2000 Ullrich von Bassewitz\n"
+ "Main file : %s\n"
+ "Current file: %s\n"
+ "\n",
+ VER_MAJOR, VER_MINOR, VER_PATCH,
+ InFile,
+ GetFileName (L->File));
+
+ /* Count pages, reset lines */
+ ++PageNumber;
+ PageLines = 4;
+}
+
+
+
+static void PrintLine (FILE* F, const char* Header, const char* Line, const ListLine* L)
+/* Print one line to the listing file, adding a newline and counting lines */
+{
+ /* Print the given line */
+ fprintf (F, "%s%s\n", Header, Line);
+
+ /* Increment the current line */
+ ++PageLines;
+
+ /* Switch to a new page if needed. Do not switch, if the current line is
+ * the last one, to avoid pages that consist of just the header.
+ */
+ if (PageLength > 0 && PageLines >= PageLength && L->Next != 0) {
+ /* Do a formfeed */
+ putc ('\f', F);
+ /* Print the header on the new page */
+ PrintPageHeader (F, L);
+ }
+}
+
+
+
+static char* AddMult (char* S, char C, unsigned Count)
+/* Add multiple instances of character C to S, return updated S. */
+{
+ memset (S, C, Count);
+ return S + Count;
+}
+
+
+
+static char* MakeLineHeader (char* H, const ListLine* L)
+/* Prepare the line header */
+{
+ char Mode;
+ char Depth;
+
+ /* Setup the PC mode */
+ Mode = (L->Reloc)? 'r' : ' ';
+
+ /* Set up the include depth */
+ Depth = (L->Depth < 10)? L->Depth + '0' : '+';
+
+ /* Format the line */
+ sprintf (H, "%06lX%c %c", L->PC, Mode, Depth);
+ memset (H+9, ' ', LINE_HEADER_LEN-9);
+
+ /* Return the buffer */
+ return H;
+}
+
+
+
+void CreateListing (void)
+/* Create the listing */
+{
+ FILE* F;
+ Fragment* Frag;
+ ListLine* L;
+ char HeaderBuf [LINE_HEADER_LEN+1];
+
+ /* Create the name of the listing file if needed */
+ if (ListFile == 0) {
+ ListFile = MakeFilename (InFile, ListExt);
+ }
+
+ /* Open the real listing file */
+ F = fopen (ListFile, "w");
+ if (F == 0) {
+ Fatal (FAT_CANNOT_OPEN_LISTING, strerror (errno));
+ }
+
+ /* Reset variables, print the header for the first page */
+ PageNumber = 0;
+ PrintPageHeader (F, LineList);
+
+ /* Terminate the header buffer. The last byte will never get overwritten */
+ HeaderBuf [LINE_HEADER_LEN] = '\0';
+
+ /* Walk through all listing lines */
+ L = LineList;
+ while (L) {
+
+ char* Buf;
+ char* B;
+ unsigned Count;
+ unsigned I;
+ char* Line;
+
+ /* If we should not output this line, go to the next */
+ if (L->Output == 0) {
+ L = L->Next;
+ continue;
+ }
+
+ /* If we don't have a fragment list for this line, things are easy */
+ if (L->FragList == 0) {
+ PrintLine (F, MakeLineHeader (HeaderBuf, L), L->Line, L);
+ L = L->Next;
+ continue;
+ }
+
+ /* Count the number of bytes in the complete fragment list */
+ Count = 0;
+ Frag = L->FragList;
+ while (Frag) {
+ Count += Frag->Len;
+ Frag = Frag->LineList;
+ }
+
+ /* Allocate memory for the given number of bytes */
+ Buf = Xmalloc (Count*2+1);
+
+ /* Copy an ASCII representation of the bytes into the buffer */
+ B = Buf;
+ Frag = L->FragList;
+ while (Frag) {
+
+ /* Write data depending on the type */
+ switch (Frag->Type) {
+
+ case FRAG_LITERAL:
+ for (I = 0; I < Frag->Len; ++I) {
+ B = AddHex (B, Frag->V.Data[I]);
+ }
+ break;
+
+ case FRAG_EXPR:
+ case FRAG_SEXPR:
+ B = AddMult (B, 'r', Frag->Len*2);
+ break;
+
+ case FRAG_FILL:
+ B = AddMult (B, 'x', Frag->Len*2);
+ break;
+
+ default:
+ Internal ("Invalid fragment type: %u", Frag->Type);
+
+ }
+
+ /* Next fragment */
+ Frag = Frag->LineList;
+
+ }
+
+ /* Limit the number of bytes actually printed */
+ if (L->ListBytes != 0) {
+ /* Not unlimited */
+ if (Count > L->ListBytes) {
+ Count = L->ListBytes;
+ }
+ }
+
+ /* Output the data. The format of a listing line is:
+ *
+ * PPPPPPm I 11 22 33 44
+ *
+ * where
+ *
+ * PPPPPP is the PC
+ * m is the mode ('r' or empty)
+ * I is the include level
+ * 11 .. are code or data bytes
+ */
+ Line = L->Line;
+ B = Buf;
+ while (Count) {
+
+ unsigned Chunk;
+ char* P;
+
+ /* Prepare the line header */
+ MakeLineHeader (HeaderBuf, L);
+
+ /* Get the number of bytes for the next line */
+ Chunk = Count;
+ if (Chunk > 4) {
+ Chunk = 4;
+ }
+ Count -= Chunk;
+
+ /* Increment the program counter. Since we don't need the PC stored
+ * in the LineList object for anything else, just increment this
+ * variable.
+ */
+ L->PC += Chunk;
+
+ /* Copy the bytes into the line */
+ P = HeaderBuf + 11;
+ for (I = 0; I < Chunk; ++I) {
+ *P++ = *B++;
+ *P++ = *B++;
+ *P++ = ' ';
+ }
+
+ /* Output this line */
+ PrintLine (F, HeaderBuf, Line, L);
+
+ /* Don't output a line twice */
+ Line = "";
+
+ }
+
+ /* Delete the temporary buffer */
+ Xfree (Buf);
+
+ /* Next line */
+ L = L->Next;
+
+ }
+
+ /* Close the listing file */
+ (void) fclose (F);
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* listing.h */
+/* */
+/* Listing support for the ca65 crossassembler */
+/* */
+/* */
+/* */
+/* (C) 2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef LISTING_H
+#define LISTING_H
+
+
+
+#include "fragment.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Length of the header of a listing line */
+#define LINE_HEADER_LEN 24
+
+/* One listing line as it is stored in memory */
+typedef struct ListLine_ ListLine;
+struct ListLine_ {
+ ListLine* Next; /* Pointer to next line */
+ Fragment* FragList; /* List of fragments for this line */
+ Fragment* FragLast; /* Last entry in fragment list */
+ unsigned long PC; /* Program counter for this line */
+ unsigned char Reloc; /* Relocatable mode? */
+ unsigned char File; /* From which file is the line? */
+ unsigned char Depth; /* Include depth */
+ unsigned char Output; /* Should we output this line? */
+ unsigned char ListBytes; /* How many bytes at max? */
+ char Line[1]; /* Line with dynamic length */
+};
+
+/* Single linked list of lines */
+extern ListLine* LineList; /* List of listing lines */
+extern ListLine* LineCur; /* Current listing line */
+extern ListLine* LineLast; /* Last listing line */
+
+/* Page formatting */
+#define MIN_PAGE_LEN 32
+#define MAX_PAGE_LEN 127
+extern int PageLength; /* Length of a listing page */
+
+/* Byte for one listing line */
+#define MIN_LIST_BYTES 4
+#define MAX_LIST_BYTES 255
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void NewListingLine (const char* Line, unsigned char File, unsigned char Depth);
+/* Create a new ListLine struct */
+
+void EnableListing (void);
+/* Enable output of lines to the listing */
+
+void DisableListing (void);
+/* Disable output of lines to the listing */
+
+void SetListBytes (int Bytes);
+/* Set the maximum number of bytes listed for one line */
+
+void InitListingLine (void);
+/* Initialize the current listing line */
+
+void CreateListing (void);
+/* Create the listing */
+
+
+
+/* End of listing.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* macpack.c */
+/* */
+/* Predefined macro packages for the ca65 macroassembler */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include "error.h"
+#include "scanner.h"
+#include "macpack.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Predefined packages */
+static const char MacGeneric [] = /* Generic macros */
+ ".macro add Arg\n"
+ " clc\n"
+ " adc Arg\n"
+ ".endmacro\n\n"
+ ".macro sub Arg\n"
+ " sec\n"
+ " sbc Arg\n"
+ ".endmacro\n\n";
+
+
+
+static const char MacLongBranch [] = /* Long branch macros */
+ ".macro jeq Target\n"
+ " .if .def(Target) .and ((*+2)-(Target) <= 127)\n"
+ " beq Target\n"
+ " .else\n"
+ " bne *+5\n"
+ " jmp Target\n"
+ " .endif\n"
+ ".endmacro\n\n"
+ ".macro jne Target\n"
+ " .if .def(Target) .and ((*+2)-(Target) <= 127)\n"
+ " bne Target\n"
+ " .else\n"
+ " beq *+5\n"
+ " jmp Target\n"
+ " .endif\n"
+ ".endmacro\n\n"
+ ".macro jmi Target\n"
+ " .if .def(Target) .and ((*+2)-(Target) <= 127)\n"
+ " bmi Target\n"
+ " .else\n"
+ " bpl *+5\n"
+ " jmp Target\n"
+ " .endif\n"
+ ".endmacro\n\n"
+ ".macro jpl Target\n"
+ " .if .def(Target) .and ((*+2)-(Target) <= 127)\n"
+ " bpl Target\n"
+ " .else\n"
+ " bmi *+5\n"
+ " jmp Target\n"
+ " .endif\n"
+ ".endmacro\n\n"
+ ".macro jcs Target\n"
+ " .if .def(Target) .and ((*+2)-(Target) <= 127)\n"
+ " bcs Target\n"
+ " .else\n"
+ " bcc *+5\n"
+ " jmp Target\n"
+ " .endif\n"
+ ".endmacro\n\n"
+ ".macro jcc Target\n"
+ " .if .def(Target) .and ((*+2)-(Target) <= 127)\n"
+ " bcc Target\n"
+ " .else\n"
+ " bcs *+5\n"
+ " jmp Target\n"
+ " .endif\n"
+ ".endmacro\n\n"
+ ".macro jvs Target\n"
+ " .if .def(Target) .and ((*+2)-(Target) <= 127)\n"
+ " bvs Target\n"
+ " .else\n"
+ " bvc *+5\n"
+ " jmp Target\n"
+ " .endif\n"
+ ".endmacro\n\n"
+ ".macro jvc Target\n"
+ " .if .def(Target) .and ((*+2)-(Target) <= 127)\n"
+ " bvc Target\n"
+ " .else\n"
+ " bvs *+5\n"
+ " jmp Target\n"
+ " .endif\n"
+ ".endmacro\n\n";
+
+
+
+/* Table with pointers to the different packages */
+static const char* MacPackages [] = {
+ MacGeneric,
+ MacLongBranch,
+};
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void InsertMacPack (unsigned Id)
+/* Insert the macro package with the given id in the input stream */
+{
+ /* Check the parameter */
+ CHECK (Id < sizeof (MacPackages) / sizeof (MacPackages [0]));
+
+ /* Insert the package */
+ NewInputData (MacPackages [Id], 0);
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* macpack.h */
+/* */
+/* Predefined macro packages for the ca65 macroassembler */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef MACPACK_H
+#define MACPACK_H
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Constants for the predefined packages */
+#define MAC_GENERIC 0
+#define MAC_LONGBRANCH 1
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void InsertMacPack (unsigned Id);
+/* Insert the macro package with the given id in the input stream */
+
+
+
+/* End of macpack.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* macro.c */
+/* */
+/* Macros for the ca65 macroassembler */
+/* */
+/* */
+/* */
+/* (C) 1998-2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <string.h>
+
+#include "../common/hashstr.h"
+
+#include "mem.h"
+#include "error.h"
+#include "scanner.h"
+#include "toknode.h"
+#include "pseudo.h"
+#include "macro.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Struct that describes an identifer (macro param, local list) */
+typedef struct IdDesc_ IdDesc;
+struct IdDesc_ {
+ IdDesc* Next; /* Linked list */
+ char Id [1]; /* Identifier, dynamically allocated */
+};
+
+
+
+/* Struct that describes a macro definition */
+typedef struct Macro_ Macro;
+struct Macro_ {
+ Macro* Next; /* Next macro with same hash */
+ Macro* List; /* List of all macros */
+ unsigned LocalCount; /* Count of local symbols */
+ IdDesc* Locals; /* List of local symbols */
+ unsigned ParamCount; /* Parameter count of macro */
+ IdDesc* Params; /* Identifiers of macro parameters */
+ unsigned TokCount; /* Number of tokens for this macro */
+ TokNode* TokRoot; /* Root of token list */
+ TokNode* TokLast; /* Pointer to last token in list */
+ unsigned char Style; /* Macro style */
+ char Name [1]; /* Macro name, dynamically allocated */
+};
+
+/* Macro hash table */
+#define HASHTAB_SIZE 117
+static Macro* MacroTab [HASHTAB_SIZE];
+
+/* Global macro data */
+static Macro* MacroRoot = 0; /* List of all macros */
+
+/* Structs that holds data for a macro expansion */
+typedef struct MacExp_ MacExp;
+struct MacExp_ {
+ MacExp* Next; /* Pointer to next expansion */
+ Macro* M; /* Which macro do we expand? */
+ TokNode* Exp; /* Pointer to current token */
+ TokNode* Final; /* Pointer to final token */
+ unsigned LocalStart; /* Start of counter for local symbol names */
+ unsigned ParamCount; /* Number of actual parameters */
+ TokNode** Params; /* List of actual parameters */
+ TokNode* ParamExp; /* Node for expanding parameters */
+};
+
+/* Data for macro expansions */
+#define MAX_MACRO_EXPANSIONS 255
+static unsigned MacroNesting = 0;
+static MacExp* CurMac = 0;
+static unsigned LocalName = 0;
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+static IdDesc* NewIdDesc (const char* Id)
+/* Create a new IdDesc, initialize and return it */
+{
+ /* Allocate memory */
+ unsigned Len = strlen (Id);
+ IdDesc* I = Xmalloc (sizeof (IdDesc) + Len);
+
+ /* Initialize the struct */
+ I->Next = 0;
+ memcpy (I->Id, Id, Len);
+ I->Id [Len] = '\0';
+
+ /* Return the new struct */
+ return I;
+}
+
+
+
+static Macro* NewMacro (const char* Name, unsigned HashVal, unsigned char Style)
+/* Generate a new macro entry, initialize and return it */
+{
+ /* Allocate memory */
+ unsigned Len = strlen (Name);
+ Macro* M = Xmalloc (sizeof (Macro) + Len);
+
+ /* Initialize the macro struct */
+ M->LocalCount = 0;
+ M->ParamCount = 0;
+ M->Params = 0;
+ M->TokCount = 0;
+ M->TokRoot = 0;
+ M->TokLast = 0;
+ M->Style = Style;
+ memcpy (M->Name, Name, Len);
+ M->Name [Len] = '\0';
+
+ /* Insert the macro into the global macro list */
+ M->List = MacroRoot;
+ MacroRoot = M;
+
+ /* Insert the macro into the hash table */
+ M->Next = MacroTab [HashVal];
+ MacroTab [HashVal] = M;
+
+ /* Return the new macro struct */
+ return M;
+}
+
+
+
+static MacExp* NewMacExp (Macro* M)
+/* Create a new expansion structure for the given macro */
+{
+ unsigned I;
+
+ /* Allocate memory */
+ MacExp* E = Xmalloc (sizeof (MacExp));
+
+ /* Initialize the data */
+ E->M = M;
+ E->Exp = M->TokRoot;
+ E->Final = 0;
+ E->LocalStart = LocalName;
+ LocalName += M->LocalCount;
+ E->ParamCount = 0;
+ E->Params = Xmalloc (M->ParamCount * sizeof (TokNode*));
+ E->ParamExp = 0;
+ for (I = 0; I < M->ParamCount; ++I) {
+ E->Params [I] = 0;
+ }
+
+ /* And return it... */
+ return E;
+}
+
+
+
+static void MacInsertExp (MacExp* E)
+/* Insert a macro expansion into the list */
+{
+ E->Next = CurMac;
+ CurMac = E;
+ ++MacroNesting;
+}
+
+
+
+static void FreeMacExp (void)
+/* Remove and free the current macro expansion */
+{
+ unsigned I;
+ MacExp* E;
+
+ /* Free the parameter list */
+ for (I = 0; I < CurMac->ParamCount; ++I) {
+ Xfree (CurMac->Params [I]);
+ }
+ Xfree (CurMac->Params);
+
+ /* Free the final token if we have one */
+ if (CurMac->Final) {
+ FreeTokNode (CurMac->Final);
+ }
+
+ /* Reset the list pointer */
+ E = CurMac;
+ CurMac = E->Next;
+ --MacroNesting;
+
+ /* Free the structure itself */
+ Xfree (E);
+}
+
+
+
+static void MacSkipDef (unsigned Style)
+/* Skip a macro definition */
+{
+ if (Style == MAC_STYLE_CLASSIC) {
+ /* Skip tokens until we reach the final .endmacro */
+ while (Tok != TOK_ENDMACRO && Tok != TOK_EOF) {
+ NextTok ();
+ }
+ if (Tok != TOK_EOF) {
+ SkipUntilSep ();
+ } else {
+ Error (ERR_ENDMACRO_EXPECTED);
+ }
+ } else {
+ /* Skip until end of line */
+ SkipUntilSep ();
+ }
+}
+
+
+
+static Macro* MacFind (const char* Name, unsigned HashVal)
+/* Search for a macro in the hash table */
+{
+ /* Search for the identifier */
+ Macro* M = MacroTab [HashVal];
+ while (M) {
+ if (strcmp (Name, M->Name) == 0) {
+ return M;
+ }
+ M = M->Next;
+ }
+ return 0;
+}
+
+
+
+void MacDef (unsigned Style)
+/* Parse a macro definition */
+{
+ Macro* M;
+ TokNode* T;
+ unsigned HashVal;
+ int HaveParams;
+
+ /* We expect a macro name here */
+ if (Tok != TOK_IDENT) {
+ Error (ERR_IDENT_EXPECTED);
+ MacSkipDef (Style);
+ return;
+ }
+
+ /* Generate the hash value */
+ HashVal = HashStr (SVal) % HASHTAB_SIZE;
+
+ /* Did we already define that macro? */
+ if (MacFind (SVal, HashVal) != 0) {
+ /* Macro is already defined */
+ Error (ERR_SYM_ALREADY_DEFINED, SVal);
+ /* Skip tokens until we reach the final .endmacro */
+ MacSkipDef (Style);
+ return;
+ }
+
+ /* Define the macro */
+ M = NewMacro (SVal, HashVal, Style);
+ NextTok ();
+
+ /* If we have a DEFINE style macro, we may have parameters in braces,
+ * otherwise we may have parameters without braces.
+ */
+ if (Style == MAC_STYLE_CLASSIC) {
+ HaveParams = 1;
+ } else {
+ if (Tok == TOK_LPAREN) {
+ HaveParams = 1;
+ NextTok ();
+ } else {
+ HaveParams = 0;
+ }
+ }
+
+ /* Parse the parameter list */
+ if (HaveParams) {
+
+ while (Tok == TOK_IDENT) {
+
+ /* Create a struct holding the identifier */
+ IdDesc* I = NewIdDesc (SVal);
+
+ /* Insert the struct into the list, checking for duplicate idents */
+ if (M->ParamCount == 0) {
+ M->Params = I;
+ } else {
+ IdDesc* List = M->Params;
+ while (1) {
+ if (strcmp (List->Id, SVal) == 0) {
+ Error (ERR_SYM_ALREADY_DEFINED, SVal);
+ }
+ if (List->Next == 0) {
+ break;
+ } else {
+ List = List->Next;
+ }
+ }
+ List->Next = I;
+ }
+ ++M->ParamCount;
+
+ /* Skip the name */
+ NextTok ();
+
+ /* Maybe there are more params... */
+ if (Tok == TOK_COMMA) {
+ NextTok ();
+ } else {
+ break;
+ }
+ }
+ }
+
+ /* For class macros, we expect a separator token, for define style macros,
+ * we expect the closing paren.
+ */
+ if (Style == MAC_STYLE_CLASSIC) {
+ ConsumeSep ();
+ } else if (HaveParams) {
+ ConsumeRParen ();
+ }
+
+ /* Preparse the macro body. We will read the tokens until we reach end of
+ * file, or a .endmacro (or end of line for DEFINE style macros) and store
+ * them into an token list internal to the macro. For classic macros, there
+ * the .LOCAL command is detected and removed at this time.
+ */
+ while (1) {
+
+ /* Check for end of macro */
+ if (Style == MAC_STYLE_CLASSIC) {
+ /* In classic macros, only .endmacro is allowed */
+ if (Tok == TOK_ENDMACRO) {
+ /* Done */
+ break;
+ }
+ /* May not have end of file in a macro definition */
+ if (Tok == TOK_EOF) {
+ Error (ERR_ENDMACRO_EXPECTED);
+ return;
+ }
+ } else {
+ /* Accept a newline or end of file for new style macros */
+ if (Tok == TOK_SEP || Tok == TOK_EOF) {
+ break;
+ }
+ }
+
+ /* Check for a .LOCAL declaration */
+ if (Tok == TOK_LOCAL && Style == MAC_STYLE_CLASSIC) {
+
+ while (1) {
+
+ IdDesc* I;
+
+ /* Skip .local or comma */
+ NextTok ();
+
+ /* Need an identifer */
+ if (Tok != TOK_IDENT) {
+ Error (ERR_IDENT_EXPECTED);
+ SkipUntilSep ();
+ break;
+ }
+
+ /* Put the identifier into the locals list and skip it */
+ I = NewIdDesc (SVal);
+ I->Next = M->Locals;
+ M->Locals = I;
+ ++M->LocalCount;
+ NextTok ();
+
+ /* Check for end of list */
+ if (Tok != TOK_COMMA) {
+ break;
+ }
+
+ }
+
+ /* We need end of line after the locals */
+ ConsumeSep ();
+ continue;
+ }
+
+ /* Create a token node for the current token */
+ T = NewTokNode ();
+
+ /* If the token is an ident, check if it is a local parameter */
+ if (Tok == TOK_IDENT) {
+ unsigned Count = 0;
+ IdDesc* I = M->Params;
+ while (I) {
+ if (strcmp (I->Id, SVal) == 0) {
+ /* Local param name, replace it */
+ T->Tok = TOK_MACPARAM;
+ T->IVal = Count;
+ break;
+ }
+ ++Count;
+ I = I->Next;
+ }
+ }
+
+ /* Insert the new token in the list */
+ if (M->TokCount == 0) {
+ /* First token */
+ M->TokRoot = M->TokLast = T;
+ } else {
+ /* We have already tokens */
+ M->TokLast->Next = T;
+ M->TokLast = T;
+ }
+ ++M->TokCount;
+
+ /* Read the next token */
+ NextTok ();
+ }
+
+ /* Skip the .endmacro for a classic macro */
+ if (Style == MAC_STYLE_CLASSIC) {
+ NextTok ();
+ }
+}
+
+
+
+static void StartExpClassic (Macro* M)
+/* Start expanding the classic macro M */
+{
+ MacExp* E;
+
+ /* Skip the macro name */
+ NextTok ();
+
+ /* Create a structure holding expansion data */
+ E = NewMacExp (M);
+
+ /* Read the actual parameters */
+ while (Tok != TOK_SEP && Tok != TOK_EOF) {
+
+ TokNode* Last;
+
+ /* Check for maximum parameter count */
+ if (E->ParamCount >= M->ParamCount) {
+ Error (ERR_TOO_MANY_PARAMS);
+ SkipUntilSep ();
+ break;
+ }
+
+ /* Read tokens for one parameter, accept empty params */
+ Last = 0;
+ while (Tok != TOK_COMMA && Tok != TOK_SEP) {
+
+ TokNode* T;
+
+ /* Check for end of file */
+ if (Tok == TOK_EOF) {
+ Error (ERR_SYNTAX);
+ return;
+ }
+
+ /* Get the next token in a node */
+ T = NewTokNode ();
+
+ /* Insert it into the list */
+ if (Last == 0) {
+ E->Params [E->ParamCount] = T;
+ } else {
+ Last->Next = T;
+ }
+ Last = T;
+
+ /* And skip it... */
+ NextTok ();
+ }
+
+ /* One parameter more */
+ ++E->ParamCount;
+
+ /* Check for a comma */
+ if (Tok == TOK_COMMA) {
+ NextTok ();
+ } else {
+ break;
+ }
+ }
+
+ /* Insert the newly created structure into the expansion list */
+ MacInsertExp (E);
+}
+
+
+
+static void StartExpDefine (Macro* M)
+/* Start expanding a DEFINE style macro */
+{
+ /* Create a structure holding expansion data */
+ MacExp* E = NewMacExp (M);
+
+ /* A define style macro must be called with as many actual parameters
+ * as there are formal ones. Get the parameter count.
+ */
+ unsigned Count = M->ParamCount;
+
+ /* Skip the current token */
+ NextTok ();
+
+ /* Read the actual parameters */
+ while (Count--) {
+
+ TokNode* Last;
+
+ /* Check if there is really a parameter */
+ if (Tok == TOK_SEP || Tok == TOK_EOF || Tok == TOK_COMMA) {
+ Error (ERR_MACRO_PARAM_EXPECTED);
+ SkipUntilSep ();
+ return;
+ }
+
+ /* Read tokens for one parameter */
+ Last = 0;
+ do {
+
+ TokNode* T;
+
+ /* Get the next token in a node */
+ T = NewTokNode ();
+
+ /* Insert it into the list */
+ if (Last == 0) {
+ E->Params [E->ParamCount] = T;
+ } else {
+ Last->Next = T;
+ }
+ Last = T;
+
+ /* And skip it... */
+ NextTok ();
+
+ } while (Tok != TOK_COMMA && Tok != TOK_SEP && Tok != TOK_EOF);
+
+ /* One parameter more */
+ ++E->ParamCount;
+
+ /* Check for a comma */
+ if (Count > 0) {
+ if (Tok == TOK_COMMA) {
+ NextTok ();
+ } else {
+ Error (ERR_COMMA_EXPECTED);
+ }
+ }
+ }
+
+ /* Macro expansion will overwrite the current token. This is a problem
+ * for define style macros since these are called from the scanner level.
+ * To avoid it, remember the current token and re-insert it if macro
+ * expansion is done.
+ */
+ E->Final = NewTokNode ();
+
+ /* Insert the newly created structure into the expansion list */
+ MacInsertExp (E);
+}
+
+
+
+void MacExpandStart (void)
+/* Start expanding the macro in SVal */
+{
+ Macro* M;
+
+ /* Beware of runoff macros */
+ if (MacroNesting == MAX_MACRO_EXPANSIONS) {
+ Fatal (FAT_MACRO_NESTING);
+ }
+
+ /* Search for the macro */
+ M = MacFind (SVal, HashStr (SVal) % HASHTAB_SIZE);
+ CHECK (M != 0);
+
+ /* Call the apropriate subroutine */
+ switch (M->Style) {
+ case MAC_STYLE_CLASSIC: StartExpClassic (M); break;
+ case MAC_STYLE_DEFINE: StartExpDefine (M); break;
+ default: Internal ("Invalid macro style: %d", M->Style);
+ }
+}
+
+
+
+int MacExpand (void)
+/* If we're currently expanding a macro, set the the scanner token and
+ * attribute to the next value and return true. If we are not expanding
+ * a macro, return false.
+ */
+{
+ if (MacroNesting == 0) {
+ /* Not expanding a macro */
+ return 0;
+ }
+
+ /* We're expanding a macro. Check if we are expanding one of the
+ * macro parameters.
+ */
+ if (CurMac->ParamExp) {
+
+ /* Ok, use token from parameter list */
+ TokSet (CurMac->ParamExp);
+
+ /* Set pointer to next token */
+ CurMac->ParamExp = CurMac->ParamExp->Next;
+
+ /* Done */
+ return 1;
+
+ } else if (CurMac->Exp) {
+
+ /* We're not expanding a parameter, use next macro token */
+ TokSet (CurMac->Exp);
+
+ /* Set pointer to next token */
+ CurMac->Exp = CurMac->Exp->Next;
+
+ /* Is it a request for actual parameter count? */
+ if (Tok == TOK_PARAMCOUNT) {
+ Tok = TOK_INTCON;
+ IVal = CurMac->ParamCount;
+ return 1;
+ }
+
+ /* Is it an .exitmacro command? */
+ if (Tok == TOK_EXITMACRO) {
+ /* Forced exit from macro expansion */
+ FreeMacExp ();
+ return MacExpand ();
+ }
+
+ /* Is it the name of a macro parameter? */
+ if (Tok == TOK_MACPARAM) {
+
+ /* Start to expand the parameter token list */
+ CurMac->ParamExp = CurMac->Params [IVal];
+
+ /* Recursive call to expand the parameter */
+ return MacExpand ();
+ }
+
+ /* If it's an identifier, it may in fact be a local symbol */
+ if (Tok == TOK_IDENT && CurMac->M->LocalCount) {
+ /* Search for the local symbol in the list */
+ unsigned Index = 0;
+ IdDesc* I = CurMac->M->Locals;
+ while (I) {
+ if (strcmp (SVal, I->Id) == 0) {
+ /* This is in fact a local symbol, change the name */
+ sprintf (SVal, "___%04X__", CurMac->LocalStart + Index);
+ break;
+ }
+ /* Next symbol */
+ ++Index;
+ I = I->Next;
+ }
+
+ /* Done */
+ return 1;
+ }
+
+ /* The token was successfully set */
+ return 1;
+
+ } else if (CurMac->Final) {
+
+ /* Set the final token and remove it */
+ TokSet (CurMac->Final);
+ FreeTokNode (CurMac->Final);
+ CurMac->Final = 0;
+
+ /* The token was successfully set */
+ return 1;
+
+ } else {
+
+ /* End of macro expansion */
+ FreeMacExp ();
+ return MacExpand ();
+
+ }
+}
+
+
+
+void MacAbort (void)
+/* Abort the current macro expansion */
+{
+ /* Must have an expansion */
+ CHECK (CurMac != 0);
+
+ /* Free current structure */
+ FreeMacExp ();
+}
+
+
+
+int IsMacro (const char* Name)
+/* Return true if the given name is the name of a macro */
+{
+ return MacFind (SVal, HashStr (SVal) % HASHTAB_SIZE) != 0;
+}
+
+
+
+int IsDefine (const char* Name)
+/* Return true if the given name is the name of a define style macro */
+{
+ Macro* M = MacFind (SVal, HashStr (SVal) % HASHTAB_SIZE);
+ return (M != 0 && M->Style == MAC_STYLE_DEFINE);
+}
+
+
+
+int InMacExpansion (void)
+/* Return true if we're currently expanding a macro */
+{
+ return MacroNesting != 0;
+}
+
+
+
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* macro.h */
+/* */
+/* Macros for the ca65 macroassembler */
+/* */
+/* */
+/* */
+/* (C) 1998-2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef MACRO_H
+#define MACRO_H
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Macro styles */
+#define MAC_STYLE_CLASSIC 0
+#define MAC_STYLE_DEFINE 1
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void MacDef (unsigned Style);
+/* Parse a macro definition */
+
+void MacExpandStart (void);
+/* Start expanding the macro in SVal */
+
+int MacExpand (void);
+/* If we're currently expanding a macro, set the the scanner token and
+ * attribute to the next value and return true. If we are not expanding
+ * a macro, return false.
+ */
+
+void MacAbort (void);
+/* Abort the current macro expansion */
+
+int IsMacro (const char* Name);
+/* Return true if the given name is the name of a macro */
+
+int IsDefine (const char* Name);
+/* Return true if the given name is the name of a define style macro */
+
+int InMacExpansion (void);
+/* Return true if we're currently expanding a macro */
+
+
+
+/* End of macro.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* main.c */
+/* */
+/* Main program for the ca65 macroassembler */
+/* */
+/* */
+/* */
+/* (C) 1998-2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
+
+#include "../common/version.h"
+
+#include "error.h"
+#include "expr.h"
+#include "global.h"
+#include "instr.h"
+#include "listing.h"
+#include "macro.h"
+#include "mem.h"
+#include "objcode.h"
+#include "objfile.h"
+#include "options.h"
+#include "pseudo.h"
+#include "scanner.h"
+#include "symtab.h"
+#include "ulabel.h"
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+static void Usage (void)
+/* Print usage information and exit */
+{
+ fprintf (stderr,
+ "Usage: %s [options] file\n"
+ "Options:\n"
+ "\t-g\t\tAdd debug info to object file\n"
+ "\t-i\t\tIgnore case of symbols\n"
+ "\t-l\t\tCreate a listing if assembly was ok\n"
+ "\t-o name\t\tName the output file\n"
+ "\t-s\t\tEnable smart mode\n"
+ "\t-v\t\tIncrease verbosity\n"
+ "\t-D name[=value]\tDefine a symbol\n"
+ "\t-U\t\tMark unresolved symbols as import\n"
+ "\t-V\t\tPrint the assembler version\n"
+ "\t-W n\t\tSet warning level n\n"
+ "\t--cpu type\tSet cpu type\n"
+ "\t--pagelength n\tSet the page length for the listing\n"
+ "\t--smart\t\tEnable smart mode\n",
+ ProgName);
+ exit (EXIT_FAILURE);
+}
+
+
+
+static void UnknownOption (const char* Arg)
+/* Print an error about an unknown option. Print usage information and exit */
+{
+ fprintf (stderr, "Unknown option: %s\n", Arg);
+ Usage ();
+}
+
+
+
+static void NeedArg (const char* Arg)
+/* Print an error about a missing option argument and exit. */
+{
+ fprintf (stderr, "Option requires an argument: %s\n", Arg);
+ exit (EXIT_FAILURE);
+}
+
+
+
+static void InvSym (const char* Def)
+/* Print an error about an invalid symbol definition and die */
+{
+ fprintf (stderr, "Invalid symbol definition: `%s'\n", Def);
+ exit (EXIT_FAILURE);
+}
+
+
+
+static const char* GetArg (int* ArgNum, char* argv [], unsigned Len)
+/* Get an option argument */
+{
+ const char* Arg = argv [*ArgNum];
+ if (Arg [Len] != '\0') {
+ /* Argument appended */
+ return Arg + Len;
+ } else {
+ /* Separate argument */
+ Arg = argv [*ArgNum + 1];
+ if (Arg == 0) {
+ /* End of arguments */
+ NeedArg (argv [*ArgNum]);
+ }
+ ++(*ArgNum);
+ return Arg;
+ }
+}
+
+
+
+static void SetOptions (void)
+/* Set the option for the translator */
+{
+ char Buf [256];
+
+ /* Set the translator */
+ sprintf (Buf, "ca65 V%u.%u.%u", VER_MAJOR, VER_MINOR, VER_PATCH);
+ OptTranslator (Buf);
+
+ /* Set date and time */
+ OptDateTime ((unsigned long) time(0));
+}
+
+
+
+static void DefineSymbol (const char* Def)
+/* Define a symbol from the command line */
+{
+ const char* P;
+ unsigned I;
+ long Val;
+ char SymName [MAX_STR_LEN+1];
+
+ /* The symbol must start with a character or underline */
+ if (Def [0] != '_' && !isalpha (Def [0])) {
+ InvSym (Def);
+ }
+ P = Def;
+
+ /* Copy the symbol, checking the rest */
+ I = 0;
+ while (isalnum (*P) || *P == '_') {
+ if (I <= MAX_STR_LEN) {
+ SymName [I++] = *P;
+ }
+ ++P;
+ }
+ SymName [I] = '\0';
+
+ /* Do we have a value given? */
+ if (*P != '=') {
+ if (*P != '\0') {
+ InvSym (Def);
+ }
+ Val = 0;
+ } else {
+ /* We have a value */
+ ++P;
+ if (*P == '$') {
+ ++P;
+ if (sscanf (P, "%lx", &Val) != 1) {
+ InvSym (Def);
+ }
+ } else {
+ if (sscanf (P, "%li", &Val) != 1) {
+ InvSym (Def);
+ }
+ }
+ }
+
+ /* Check if have already a symbol with this name */
+ if (SymIsDef (SymName)) {
+ fprintf (stderr, "`%s' is already defined\n", SymName);
+ exit (EXIT_FAILURE);
+ }
+
+ /* Define the symbol */
+ SymDef (SymName, LiteralExpr (Val), 0);
+}
+
+
+
+static void OptCPU (const char* Opt, const char* Arg)
+/* Handle the --cpu option */
+{
+ if (Arg == 0) {
+ NeedArg (Opt);
+ }
+ if (strcmp (Arg, "6502") == 0) {
+ SetCPU (CPU_6502);
+ } else if (strcmp (Arg, "65C02") == 0) {
+ SetCPU (CPU_65C02);
+ } else if (strcmp (Arg, "65816") == 0) {
+ SetCPU (CPU_65816);
+#ifdef SUNPLUS
+ } else if (strcmp (Arg, "sunplus") == 0) {
+ SetCPU (CPU_SUNPLUS);
+#endif
+ } else {
+ fprintf (stderr, "Invalid CPU: `%s'\n", Arg);
+ exit (EXIT_FAILURE);
+ }
+}
+
+
+
+static void OptPageLength (const char* Opt, const char* Arg)
+/* Handle the --pagelength option */
+{
+ int Len;
+ if (Arg == 0) {
+ NeedArg (Opt);
+ }
+ Len = atoi (Arg);
+ if (Len != -1 && (Len < MIN_PAGE_LEN || Len > MAX_PAGE_LEN)) {
+ fprintf (stderr, "Invalid page length: %d\n", Len);
+ exit (EXIT_FAILURE);
+ }
+ PageLength = Len;
+}
+
+
+
+static void OptSmart (const char* Opt)
+/* Handle the -s/--smart options */
+{
+ SmartMode = 1;
+}
+
+
+
+static void LongOption (int* ArgNum, char* argv [])
+/* Handle a long command line option */
+{
+ const char* Opt = argv [*ArgNum];
+ const char* Arg = argv [*ArgNum+1];
+
+ if (strcmp (Opt, "--cpu") == 0) {
+ OptCPU (Opt, Arg);
+ ++(*ArgNum);
+ } else if (strcmp (Opt, "--pagelength") == 0) {
+ OptPageLength (Opt, Arg);
+ ++(*ArgNum);
+ } else if (strcmp (Opt, "--smart") == 0) {
+ OptSmart (Opt);
+ } else {
+ UnknownOption (Opt);
+ }
+}
+
+
+
+static void OneLine (void)
+/* Assemble one line */
+{
+ char Ident [MAX_STR_LEN+1];
+ int Done = 0;
+
+ /* Initialize the listing line */
+ InitListingLine ();
+
+ if (Tok == TOK_COLON) {
+ /* An unnamed label */
+ ULabDef ();
+ NextTok ();
+ }
+
+ /* Assemble the line */
+ if (Tok == TOK_IDENT) {
+
+ /* Is it a macro? */
+ if (IsMacro (SVal)) {
+
+ /* Yes, start a macro expansion */
+ MacExpandStart ();
+ Done = 1;
+
+ } else {
+
+ /* No, label. Remember the identifier, then skip it */
+ int HadWS = WS; /* Did we have whitespace before the ident? */
+ strcpy (Ident, SVal);
+ NextTok ();
+
+ /* If a colon follows, this is a label definition. If there
+ * is no colon, it's an assignment.
+ */
+ if (Tok == TOK_EQ) {
+ /* Skip the '=' */
+ NextTok ();
+ /* Define the symbol with the expression following the
+ * '='
+ */
+ SymDef (Ident, Expression (), 0);
+ /* Don't allow anything after a symbol definition */
+ Done = 1;
+ } else {
+ /* Define a label */
+ SymDef (Ident, CurrentPC (), IsZPSeg ());
+ /* Skip the colon. If NoColonLabels is enabled, allow labels
+ * without a colon if there is no whitespace before the
+ * identifier.
+ */
+ if (Tok != TOK_COLON) {
+ if (HadWS || !NoColonLabels) {
+ Error (ERR_COLON_EXPECTED);
+ }
+ if (Tok == TOK_NAMESPACE) {
+ /* Smart :: handling */
+ NextTok ();
+ }
+ } else {
+ /* Skip the colon */
+ NextTok ();
+ }
+ }
+ }
+ }
+
+ if (!Done) {
+
+ if (TokIsPseudo (Tok)) {
+ /* A control command, IVal is index into table */
+ HandlePseudo ();
+ } else if (Tok == TOK_MNEMO) {
+ /* A mnemonic - assemble one instruction */
+ HandleInstruction (IVal);
+ } else if (Tok == TOK_IDENT && IsMacro (SVal)) {
+ /* A macro expansion */
+ MacExpandStart ();
+ }
+ }
+
+ /* Calling InitListingLine again here is part of a hack that introduces
+ * enough magic to make the PC output in the listing work.
+ */
+ InitListingLine ();
+
+ /* Line separator must come here */
+ ConsumeSep ();
+}
+
+
+
+static void Assemble (void)
+/* Start the ball rolling ... */
+{
+ /* Prime the pump */
+ NextTok ();
+
+ /* Assemble lines until end of file */
+ while (Tok != TOK_EOF) {
+ OneLine ();
+ }
+}
+
+
+
+static void CreateObjFile (void)
+/* Create the object file */
+{
+ /* Open the object, write the header */
+ ObjOpen ();
+
+ /* Write the object file options */
+ WriteOptions ();
+
+ /* Write the list of input files */
+ WriteFiles ();
+
+ /* Write the segment data to the file */
+ WriteSegments ();
+
+ /* Write the import list */
+ WriteImports ();
+
+ /* Write the export list */
+ WriteExports ();
+
+ /* Write debug symbols if requested */
+ WriteDbgSyms ();
+
+ /* Write an updated header and close the file */
+ ObjClose ();
+}
+
+
+
+int main (int argc, char* argv [])
+/* Assembler main program */
+{
+ int I;
+
+ /* Set the program name */
+ ProgName = argv [0];
+
+ /* We must have a file name */
+ if (argc < 2) {
+ Usage ();
+ }
+
+ /* Enter the base lexical level. We must do that here, since we may
+ * define symbols using -D.
+ */
+ SymEnterLevel ();
+
+ /* Check the parameters */
+ I = 1;
+ while (I < argc) {
+
+ /* Get the argument */
+ const char* Arg = argv [I];
+
+ /* Check for an option */
+ if (Arg [0] == '-') {
+ switch (Arg [1]) {
+
+ case '-':
+ LongOption (&I, argv);
+ break;
+
+ case 'g':
+ DbgSyms = 1;
+ break;
+
+ case 'i':
+ IgnoreCase = 1;
+ break;
+
+ case 'l':
+ Listing = 1;
+ break;
+
+ case 'o':
+ OutFile = GetArg (&I, argv, 2);
+ break;
+
+ case 's':
+ OptSmart (Arg);
+ break;
+
+ case 'v':
+ ++Verbose;
+ break;
+
+ case 'D':
+ DefineSymbol (GetArg (&I, argv, 2));
+ break;
+
+ case 'U':
+ AutoImport = 1;
+ break;
+
+ case 'V':
+ fprintf (stderr,
+ "ca65 V%u.%u.%u - (C) Copyright 1998-2000 Ullrich von Bassewitz\n",
+ VER_MAJOR, VER_MINOR, VER_PATCH);
+ break;
+
+ case 'W':
+ WarnLevel = atoi (GetArg (&I, argv, 2));
+ break;
+
+ default:
+ UnknownOption (Arg);
+ break;
+
+ }
+ } else {
+ /* Filename. Check if we already had one */
+ if (InFile) {
+ fprintf (stderr, "Don't know what to do with `%s'\n", Arg);
+ Usage ();
+ } else {
+ InFile = Arg;
+ }
+ }
+
+ /* Next argument */
+ ++I;
+ }
+
+ /* Do we have an input file? */
+ if (InFile == 0) {
+ fprintf (stderr, "No input file\n");
+ exit (EXIT_FAILURE);
+ }
+
+ /* Initialize the scanner, open the input file */
+ InitScanner (InFile);
+
+ /* Define the default options */
+ SetOptions ();
+
+ /* Assemble the input */
+ Assemble ();
+
+ /* If we didn't have any errors, check the unnamed labels */
+ if (ErrorCount == 0) {
+ ULabCheck ();
+ }
+
+ /* If we didn't have any errors, check the symbol table */
+ if (ErrorCount == 0) {
+ SymCheck ();
+ }
+
+ /* If we didn't have any errors, check and resolve the segment data */
+ if (ErrorCount == 0) {
+ SegCheck ();
+ }
+
+ /* Dump the data */
+ if (Verbose >= 2) {
+ SymDump (stdout);
+ SegDump ();
+ }
+
+ /* If we didn't have any errors, create the object and listing files */
+ if (ErrorCount == 0) {
+ CreateObjFile ();
+ if (Listing) {
+ CreateListing ();
+ }
+ }
+
+ /* Close the input file */
+ DoneScanner ();
+
+ /* Return an apropriate exit code */
+ return (ErrorCount == 0)? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+
+
--- /dev/null
+#
+# gcc Makefile for a65, link65 & libr65
+#
+
+CFLAGS = -g -O2 -Wall
+CC = gcc
+LDFLAGS =
+
+OBJS = condasm.o \
+ ea.o \
+ error.o \
+ expr.o \
+ fname.o \
+ fragment.o \
+ global.o \
+ instr.o \
+ listing.o \
+ macpack.o \
+ macro.o \
+ main.o \
+ mem.o \
+ objcode.o \
+ objfile.o \
+ options.o \
+ pseudo.o \
+ scanner.o \
+ strexpr.o \
+ symtab.o \
+ toknode.o \
+ ulabel.o
+
+LIBS = ../common/common.a
+
+EXECS = ca65
+
+.PHONY: all
+ifeq (.depend,$(wildcard .depend))
+all : $(EXECS)
+include .depend
+else
+all: depend
+ @$(MAKE) -f make/gcc.mak all
+endif
+
+
+
+ca65: $(OBJS) $(LIBS)
+ $(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS)
+
+clean:
+ rm -f *~ core *.lst
+
+zap: clean
+ rm -f *.o $(EXECS) .depend
+
+# ------------------------------------------------------------------------------
+# Make the dependencies
+
+.PHONY: depend dep
+depend dep: $(OBJS:.o=.c)
+ @echo "Creating dependency information"
+ $(CC) -MM $^ > .depend
+
--- /dev/null
+#
+# CA65 Makefile for the Watcom compiler
+#
+
+# ------------------------------------------------------------------------------
+# Generic stuff
+
+.AUTODEPEND
+.SUFFIXES .ASM .C .CC .CPP
+.SWAP
+
+AR = WLIB
+LD = WLINK
+
+!if !$d(TARGET)
+!if $d(__OS2__)
+TARGET = OS2
+!else
+TARGET = NT
+!endif
+!endif
+
+# target specific macros.
+!if $(TARGET)==OS2
+
+# --------------------- OS2 ---------------------
+SYSTEM = os2v2
+CC = WCC386
+CCCFG = -bt=$(TARGET) -d1 -onatx -zp4 -5 -zq -w2
+
+!elif $(TARGET)==DOS32
+
+# -------------------- DOS4G --------------------
+SYSTEM = dos4g
+CC = WCC386
+CCCFG = -bt=$(TARGET) -d1 -onatx -zp4 -5 -zq -w2
+
+!elif $(TARGET)==DOS
+
+# --------------------- DOS ---------------------
+SYSTEM = dos
+CC = WCC
+CCCFG = -bt=$(TARGET) -d1 -onatx -zp2 -2 -ml -zq -w2
+
+!elif $(TARGET)==NT
+
+# --------------------- NT ----------------------
+SYSTEM = nt
+CC = WCC386
+CCCFG = -bt=$(TARGET) -d1 -onatx -zp4 -5 -zq -w2
+
+!else
+!error
+!endif
+
+# ------------------------------------------------------------------------------
+# Implicit rules
+
+.c.obj:
+ $(CC) $(CCCFG) $<
+
+
+# ------------------------------------------------------------------------------
+# All library OBJ files
+
+OBJS = condasm.obj \
+ ea.obj \
+ error.obj \
+ expr.obj \
+ fname.obj \
+ fragment.obj \
+ global.obj \
+ instr.obj \
+ listing.obj \
+ macpack.obj \
+ macro.obj \
+ main.obj \
+ mem.obj \
+ objcode.obj \
+ objfile.obj \
+ options.obj \
+ pseudo.obj \
+ scanner.obj \
+ strexpr.obj \
+ symtab.obj \
+ toknode.obj \
+ ulabel.obj
+
+LIBS = ..\common\common.lib
+
+
+# ------------------------------------------------------------------------------
+# Main targets
+
+all: ca65
+
+ca65: ca65.exe
+
+
+# ------------------------------------------------------------------------------
+# Other targets
+
+
+ca65.exe: $(OBJS) $(LIBS)
+ $(LD) system $(SYSTEM) @&&|
+DEBUG ALL
+OPTION QUIET
+NAME $<
+FILE condasm.obj
+FILE ea.obj
+FILE error.obj
+FILE expr.obj
+FILE fname.obj
+FILE fragment.obj
+FILE global.obj
+FILE instr.obj
+FILE listing.obj
+FILE macpack.obj
+FILE macro.obj
+FILE main.obj
+FILE mem.obj
+FILE objcode.obj
+FILE objfile.obj
+FILE options.obj
+FILE pseudo.obj
+FILE scanner.obj
+FILE strexpr.obj
+FILE symtab.obj
+FILE toknode.obj
+FILE ulabel.obj
+LIBRARY ..\common\common.lib
+|
+
+clean:
+ @if exist *.obj del *.obj
+ @if exist ca65.exe del ca65.exe
+
+strip:
+ @-wstrip ca65.exe
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* mem.c */
+/* */
+/* Memory allocation for the ca65 macroassembler */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "error.h"
+#include "mem.h"
+
+
+
+/*****************************************************************************/
+/* code */
+/*****************************************************************************/
+
+
+
+void* Xmalloc (size_t size)
+/* Allocate memory, check for out of memory condition. Do some debugging */
+{
+ void* p;
+
+ p = malloc (size);
+ if (p == 0 && size != 0) {
+ Fatal (FAT_OUT_OF_MEMORY);
+ }
+
+ /* Return a pointer to the block */
+ return p;
+}
+
+
+
+void Xfree (const void* block)
+/* Free the block, do some debugging */
+{
+ free ((void*) block);
+}
+
+
+
+char* StrDup (const char* s)
+/* Duplicate a string on the heap. The function checks for out of memory */
+{
+ unsigned len;
+
+ len = strlen (s) + 1;
+ return memcpy (Xmalloc (len), s, len);
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* mem.h */
+/* */
+/* Memory allocation for the ca65 macroassembler */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef MEM_H
+#define MEM_H
+
+
+
+#include <stddef.h>
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void* Xmalloc (size_t size);
+/* Allocate memory, check for out of memory condition. Do some debugging */
+
+void Xfree (const void* block);
+/* Free the block, do some debugging */
+
+char* StrDup (const char* s);
+/* Duplicate a string on the heap. The function checks for out of memory */
+
+
+
+/* End of mem.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* objcode.c */
+/* */
+/* Objectcode management for the ca65 macroassembler */
+/* */
+/* */
+/* */
+/* (C) 1998-2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "../common/segdefs.h"
+
+#include "error.h"
+#include "fragment.h"
+#include "global.h"
+#include "listing.h"
+#include "mem.h"
+#include "objfile.h"
+#include "scanner.h"
+#include "symtab.h"
+#include "objcode.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Are we in absolute mode or in relocatable mode? */
+int RelocMode = 1;
+unsigned long AbsPC = 0; /* PC if in absolute mode */
+
+
+
+typedef struct Segment_ Segment;
+struct Segment_ {
+ Segment* List; /* List of all segments */
+ Fragment* Root; /* Root of fragment list */
+ Fragment* Last; /* Pointer to last fragment */
+ unsigned char Align; /* Segment alignment */
+ unsigned char SegType; /* True if zero page segment */
+ unsigned long PC;
+ unsigned Num; /* Segment number */
+ char* Name; /* Segment name */
+};
+
+
+
+/* Predefined segments */
+static Segment NullSeg = {
+ 0, 0, 0, 0, SEGTYPE_ABS, 0, 5, "NULL"
+};
+static Segment ZeropageSeg = {
+ &NullSeg, 0, 0, 0, SEGTYPE_ZP, 0, 4, "ZEROPAGE"
+};
+static Segment DataSeg = {
+ &ZeropageSeg, 0, 0, 0, SEGTYPE_ABS, 0, 3, "DATA"
+};
+static Segment BssSeg = {
+ &DataSeg, 0, 0, 0, SEGTYPE_ABS, 0, 2, "BSS"
+};
+static Segment RODataSeg = {
+ &BssSeg, 0, 0, 0, SEGTYPE_ABS, 0, 1, "RODATA"
+};
+static Segment CodeSeg = {
+ &RODataSeg, 0, 0, 0, SEGTYPE_ABS, 0, 0, "CODE"
+};
+
+/* Number of segments */
+static unsigned SegmentCount = 6;
+
+/* List of all segments */
+static Segment* SegmentList = &CodeSeg;
+static Segment* SegmentLast = &NullSeg;
+
+/* Currently active segment */
+static Segment* ActiveSeg = &CodeSeg;
+
+
+
+/*****************************************************************************/
+/* Segment management */
+/*****************************************************************************/
+
+
+
+static Segment* NewSegment (const char* Name, unsigned SegType)
+/* Create a new segment, insert it into the global list and return it */
+{
+ Segment* S;
+ const char* N;
+
+ /* Check for too many segments */
+ if (SegmentCount >= 256) {
+ Fatal (FAT_TOO_MANY_SEGMENTS);
+ }
+
+ /* Check the segment name for invalid names */
+ N = Name;
+ if ((*N != '_' && !isalpha (*N)) || strlen (Name) > 80) {
+ Error (ERR_ILLEGAL_SEGMENT, Name);
+ }
+ do {
+ if (*N != '_' && !isalnum (*N)) {
+ Error (ERR_ILLEGAL_SEGMENT, Name);
+ break;
+ }
+ ++N;
+ } while (*N);
+
+ /* Create a new segment */
+ S = Xmalloc (sizeof (*S));
+
+ /* Initialize it */
+ S->List = 0;
+ S->Root = 0;
+ S->Last = 0;
+ S->Align = 0;
+ S->SegType = SegType;
+ S->PC = 0;
+ S->Num = SegmentCount++;
+ S->Name = StrDup (Name);
+
+ /* Insert it into the segment list */
+ SegmentLast->List = S;
+ SegmentLast = S;
+
+ /* And return it... */
+ return S;
+}
+
+
+
+void UseCodeSeg (void)
+/* Use the code segment */
+{
+ ActiveSeg = &CodeSeg;
+}
+
+
+
+void UseRODataSeg (void)
+/* Use the r/o data segment */
+{
+ ActiveSeg = &RODataSeg;
+}
+
+
+
+void UseDataSeg (void)
+/* Use the data segment */
+{
+ ActiveSeg = &DataSeg;
+}
+
+
+
+void UseBssSeg (void)
+/* Use the BSS segment */
+{
+ ActiveSeg = &BssSeg;
+}
+
+
+
+void UseZeropageSeg (void)
+/* Use the zero page segment */
+{
+ ActiveSeg = &ZeropageSeg;
+}
+
+
+
+void UseNullSeg (void)
+/* Use the null segment */
+{
+ ActiveSeg = &NullSeg;
+}
+
+
+
+void UseSeg (const char* Name, unsigned SegType)
+/* Use the segment with the given name */
+{
+ Segment* Seg = SegmentList;
+ while (Seg) {
+ if (strcmp (Seg->Name, Name) == 0) {
+ /* We found this segment. Check if the type is identical */
+ if (SegType != SEGTYPE_DEFAULT && Seg->SegType != SegType) {
+ Error (ERR_SEG_ATTR_MISMATCH);
+ /* Use the new attribute to avoid errors */
+ Seg->SegType = SegType;
+ }
+ ActiveSeg = Seg;
+ return;
+ }
+ /* Check next segment */
+ Seg = Seg->List;
+ }
+
+ /* Segment is not in list, create a new one */
+ if (SegType == SEGTYPE_DEFAULT) {
+ SegType = SEGTYPE_ABS;
+ }
+ Seg = NewSegment (Name, SegType);
+ ActiveSeg = Seg;
+}
+
+
+
+unsigned long GetPC (void)
+/* Get the program counter of the current segment */
+{
+ return RelocMode? ActiveSeg->PC : AbsPC;
+}
+
+
+
+void SetAbsPC (unsigned long PC)
+/* Set the program counter in absolute mode */
+{
+ RelocMode = 0;
+ AbsPC = PC;
+}
+
+
+
+unsigned GetSegNum (void)
+/* Get the number of the current segment */
+{
+ return ActiveSeg->Num;
+}
+
+
+
+void SegAlign (unsigned Power, int Val)
+/* Align the PC segment to 2^Power. If Val is -1, emit fill fragments (the
+ * actual fill value will be determined by the linker), otherwise use the
+ * given value.
+ */
+{
+ unsigned char Data [4];
+ unsigned long Align = (1UL << Power) - 1;
+ unsigned long NewPC = (ActiveSeg->PC + Align) & ~Align;
+ unsigned long Count = NewPC - ActiveSeg->PC;
+
+ if (Val != -1) {
+ /* User defined fill value */
+ memset (Data, Val, sizeof (Data));
+ while (Count) {
+ if (Count > sizeof (Data)) {
+ EmitData (Data, sizeof (Data));
+ Count -= sizeof (Data);
+ } else {
+ EmitData (Data, Count);
+ Count = 0;
+ }
+ }
+ } else {
+ /* Linker defined fill value */
+ EmitFill (Count);
+ }
+
+ /* Remember the alignment in the header */
+ if (ActiveSeg->Align < Power) {
+ ActiveSeg->Align = Power;
+ }
+}
+
+
+
+int IsZPSeg (void)
+/* Return true if the current segment is a zeropage segment */
+{
+ return (ActiveSeg->SegType == SEGTYPE_ZP);
+}
+
+
+
+int IsFarSeg (void)
+/* Return true if the current segment is a far segment */
+{
+ return (ActiveSeg->SegType == SEGTYPE_FAR);
+}
+
+
+
+unsigned GetSegType (unsigned SegNum)
+/* Return the type of the segment with the given number */
+{
+ /* Search for the segment */
+ Segment* S = SegmentList;
+ while (S && SegNum) {
+ --SegNum;
+ S = S->List;
+ }
+
+ /* Did we find it? */
+ if (S == 0) {
+ FAIL ("Invalid segment number");
+ }
+
+ /* Return the segment type */
+ return S->SegType;
+}
+
+
+
+void SegCheck (void)
+/* Check the segments for range and other errors */
+{
+ Segment* S = SegmentList;
+ while (S) {
+ Fragment* F = S->Root;
+ while (F) {
+ if (F->Type == FRAG_EXPR || F->Type == FRAG_SEXPR) {
+ F->V.Expr = FinalizeExpr (F->V.Expr);
+ if (IsConstExpr (F->V.Expr)) {
+ /* We are able to evaluate the expression. Get the value
+ * and check for range errors.
+ */
+ unsigned I;
+ long Val = GetExprVal (F->V.Expr);
+ int Abs = (F->Type != FRAG_SEXPR);
+
+ if (F->Len == 1) {
+ if (Abs) {
+ /* Absolute value */
+ if (Val > 255) {
+ PError (&F->Pos, ERR_RANGE);
+ }
+ } else {
+ /* PC relative value */
+ if (Val < -128 || Val > 127) {
+ PError (&F->Pos, ERR_RANGE);
+ }
+ }
+ } else if (F->Len == 2) {
+ if (Abs) {
+ /* Absolute value */
+ if (Val > 65535) {
+ PError (&F->Pos, ERR_RANGE);
+ }
+ } else {
+ /* PC relative value */
+ if (Val < -32768 || Val > 32767) {
+ PError (&F->Pos, ERR_RANGE);
+ }
+ }
+ }
+
+ /* Convert the fragment into a literal fragment */
+ for (I = 0; I < F->Len; ++I) {
+ F->V.Data [I] = Val & 0xFF;
+ Val >>= 8;
+ }
+ F->Type = FRAG_LITERAL;
+ } else {
+ /* We cannot evaluate the expression now, leave the job for
+ * the linker. However, we are able to check for explicit
+ * byte expressions and we will do so.
+ */
+ if (F->Type == FRAG_EXPR && F->Len == 1 && !IsByteExpr (F->V.Expr)) {
+ PError (&F->Pos, ERR_RANGE);
+ }
+ }
+ }
+ F = F->Next;
+ }
+ S = S->List;
+ }
+}
+
+
+
+void SegDump (void)
+/* Dump the contents of all segments */
+{
+ unsigned X = 0;
+ Segment* S = SegmentList;
+ printf ("\n");
+ while (S) {
+ unsigned I;
+ Fragment* F;
+ int State = -1;
+ printf ("New segment: %s", S->Name);
+ F = S->Root;
+ while (F) {
+ if (F->Type == FRAG_LITERAL) {
+ if (State != 0) {
+ printf ("\n Literal:");
+ X = 15;
+ State = 0;
+ }
+ for (I = 0; I < F->Len; ++I) {
+ printf (" %02X", F->V.Data [I]);
+ X += 3;
+ }
+ } else if (F->Type == FRAG_EXPR || F->Type == FRAG_SEXPR) {
+ State = 1;
+ printf ("\n Expression (%u): ", F->Len);
+ DumpExpr (F->V.Expr);
+ } else if (F->Type == FRAG_FILL) {
+ State = 1;
+ printf ("\n Fill bytes (%u)", F->Len);
+ } else {
+ Internal ("Unknown fragment type: %u", F->Type);
+ }
+ if (X > 65) {
+ State = -1;
+ }
+ F = F->Next;
+ }
+ printf ("\n End PC = $%04X\n", (unsigned)(S->PC & 0xFFFF));
+ S = S->List;
+ }
+ printf ("\n");
+}
+
+
+
+static void WriteOneSeg (Segment* Seg)
+/* Write one segment to the object file */
+{
+ Fragment* Frag;
+ Fragment* F;
+ unsigned long Size;
+
+ /* Write the segment name followed by the byte count in this segment */
+ ObjWriteStr (Seg->Name);
+ ObjWrite32 (Seg->PC);
+ ObjWrite8 (Seg->Align);
+ ObjWrite8 (Seg->SegType);
+
+ /* Now walk through the fragment list for this segment and write the
+ * fragments.
+ */
+ Frag = Seg->Root;
+ while (Frag) {
+
+ /* Write data depending on the type */
+ switch (Frag->Type) {
+
+ case FRAG_LITERAL:
+ /* To make the object file somewhat smaller, write all literal
+ * data of this and the following fragments preceeded by the
+ * length.
+ */
+ F = Frag;
+ Size = 0;
+ while (F && F->Type == FRAG_LITERAL) {
+ Size += F->Len;
+ F = F->Next;
+ }
+ if (Size < 0x100) {
+ ObjWrite8 (FRAG_LITERAL8);
+ ObjWrite8 (Size);
+ } else if (Size < 0x10000) {
+ ObjWrite8 (FRAG_LITERAL16);
+ ObjWrite16 (Size);
+ } else if (Size < 0x1000000) {
+ ObjWrite8 (FRAG_LITERAL24);
+ ObjWrite24 (Size);
+ } else {
+ ObjWrite8 (FRAG_LITERAL32);
+ ObjWrite32 (Size);
+ }
+
+ /* Now write the literal data */
+ F = Frag;
+ while (F && F->Type == FRAG_LITERAL) {
+ ObjWriteData (F->V.Data, F->Len);
+ Frag = F;
+ F = F->Next;
+ }
+ break;
+
+ case FRAG_EXPR:
+ switch (Frag->Len) {
+ case 1: ObjWrite8 (FRAG_EXPR8); break;
+ case 2: ObjWrite8 (FRAG_EXPR16); break;
+ case 3: ObjWrite8 (FRAG_EXPR24); break;
+ case 4: ObjWrite8 (FRAG_EXPR32); break;
+ default: Internal ("Invalid fragment size: %u", Frag->Len);
+ }
+ WriteExpr (Frag->V.Expr);
+ break;
+
+ case FRAG_SEXPR:
+ switch (Frag->Len) {
+ case 1: ObjWrite8 (FRAG_SEXPR8); break;
+ case 2: ObjWrite8 (FRAG_SEXPR16); break;
+ case 3: ObjWrite8 (FRAG_SEXPR24); break;
+ case 4: ObjWrite8 (FRAG_SEXPR32); break;
+ default: Internal ("Invalid fragment size: %u", Frag->Len);
+ }
+ WriteExpr (Frag->V.Expr);
+ break;
+
+ case FRAG_FILL:
+ ObjWrite8 (FRAG_FILL);
+ ObjWrite16 (Frag->Len);
+ break;
+
+ default:
+ Internal ("Invalid fragment type: %u", Frag->Type);
+
+ }
+
+ /* Write the file position of this fragment */
+ ObjWritePos (&Frag->Pos);
+
+ /* Next fragment */
+ Frag = Frag->Next;
+ }
+}
+
+
+
+void WriteSegments (void)
+/* Write the segment data to the object file */
+{
+ Segment* Seg;
+
+ /* Tell the object file module that we're about to start the seg list */
+ ObjStartSegments ();
+
+ /* First thing is segment count */
+ ObjWrite8 (SegmentCount);
+
+ /* Now walk through all segments and write them to the object file */
+ Seg = SegmentList;
+ while (Seg) {
+ /* Write one segment */
+ WriteOneSeg (Seg);
+ /* Next segment */
+ Seg = Seg->List;
+ }
+
+ /* Done writing segments */
+ ObjEndSegments ();
+}
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+static void IncPC (unsigned Value)
+/* Increment the PC counter */
+{
+ ActiveSeg->PC += Value;
+ if (!RelocMode) {
+ AbsPC += Value;
+ }
+}
+
+
+
+static Fragment* NewFragment (unsigned char Type, unsigned short Len)
+/* Create, initialize and return a new fragment. The fragment will be inserted
+ * into the current segment.
+ */
+{
+ Fragment* F;
+
+ /* Create a new fragment */
+ F = Xmalloc (sizeof (*F));
+
+ /* Initialize it */
+ F->List = 0;
+ F->Next = 0;
+ F->LineList = 0;
+ F->Pos = CurPos;
+ F->Len = Len;
+ F->Type = Type;
+
+ /* Insert it into the list of all segments */
+ if (FragList == 0) {
+ FragList = F;
+ } else {
+ FragLast->List = F;
+ }
+ FragLast = F;
+
+ /* Insert it into the current segment */
+ if (ActiveSeg->Root) {
+ ActiveSeg->Last->Next = F;
+ ActiveSeg->Last = F;
+ } else {
+ ActiveSeg->Root = ActiveSeg->Last = F;
+ }
+
+ /* Add this fragment to the current listing line */
+ if (LineCur) {
+ if (LineCur->FragList == 0) {
+ LineCur->FragList = F;
+ /* First fragment - set the PC
+ LineCur->PC = GetPC ();
+ LineCur->Reloc = RelocMode;
+*/
+ } else {
+ LineCur->FragLast->LineList = F;
+ }
+ LineCur->FragLast = F;
+ }
+
+ /* Increment the program counter */
+ IncPC (Len);
+
+ /* And return it */
+ return F;
+}
+
+
+
+void Emit0 (unsigned char OPC)
+/* Emit an instruction with a zero sized operand */
+{
+ /* First fragment, wrong type or out of space, create new one */
+ Fragment* F = NewFragment (FRAG_LITERAL, 1);
+ F->V.Data [0] = OPC;
+}
+
+
+
+void Emit1 (unsigned char OPC, ExprNode* Value)
+/* Emit an instruction with an one byte argument */
+{
+ Emit0 (OPC);
+ EmitByte (Value);
+}
+
+
+
+void Emit2 (unsigned char OPC, ExprNode* Value)
+/* Emit an instruction with a two byte argument */
+{
+ Emit0 (OPC);
+ EmitWord (Value);
+}
+
+
+
+void Emit3 (unsigned char OPC, ExprNode* Expr)
+/* Emit an instruction with a three byte argument */
+{
+ Emit0 (OPC);
+ EmitFarAddr (Expr);
+}
+
+
+
+void Emit3b (unsigned char OPC, ExprNode* Expr, ExprNode* Bank)
+/* Emit an instruction with a three byte argument and separate bank */
+{
+ Emit0 (OPC);
+ EmitWord (Expr);
+ EmitByte (Bank);
+}
+
+
+
+void EmitPCRel (unsigned char OPC, ExprNode* Expr, unsigned Size)
+/* Emit an opcode with a PC relative argument of one or two bytes */
+{
+ Fragment* F;
+ Emit0 (OPC);
+ F = NewFragment (FRAG_SEXPR, Size);
+ F->V.Expr = Expr;
+}
+
+
+
+void EmitData (const unsigned char* Data, unsigned Size)
+/* Emit data into the current segment */
+{
+ /* Create lots of fragments for the data */
+ while (Size) {
+ Fragment* F;
+
+ /* Determine the length of the next fragment */
+ unsigned Len = Size;
+ if (Len > sizeof (F->V.Data)) {
+ Len = sizeof (F->V.Data);
+ }
+
+ /* Create a new fragment */
+ F = NewFragment (FRAG_LITERAL, Len);
+
+ /* Copy the data */
+ memcpy (F->V.Data, Data, Len);
+
+ /* Next chunk */
+ Data += Len;
+ Size -= Len;
+
+ }
+}
+
+
+
+void EmitByte (ExprNode* Expr)
+/* Emit one byte */
+{
+ if (IsConstExpr (Expr)) {
+ /* Constant expression, emit literal byte */
+ long Val = GetExprVal (Expr);
+ FreeExpr (Expr);
+ if ((Val & ~0xFF) != 0) {
+ Error (ERR_RANGE);
+ }
+ Emit0 (Val & 0xFF);
+ } else {
+ /* Create a new fragment */
+ Fragment* F = NewFragment (FRAG_EXPR, 1);
+
+ /* Set the data */
+ F->V.Expr = Expr;
+ }
+}
+
+
+
+void EmitWord (ExprNode* Expr)
+/* Emit one word */
+{
+ if (IsConstExpr (Expr)) {
+ /* Constant expression, emit literal byte */
+ long Val = GetExprVal (Expr);
+ FreeExpr (Expr);
+ if ((Val & ~0xFFFF) != 0) {
+ Error (ERR_RANGE);
+ }
+ Emit0 (Val & 0xFF);
+ Emit0 ((Val >> 8) & 0xFF);
+ } else {
+ /* Create a new fragment */
+ Fragment* F = NewFragment (FRAG_EXPR, 2);
+
+ /* Set the data */
+ F->V.Expr = Expr;
+ }
+}
+
+
+
+void EmitFarAddr (ExprNode* Expr)
+/* Emit a 24 bit expression */
+{
+ if (IsConstExpr (Expr)) {
+ /* Constant expression, emit literal byte */
+ long Val = GetExprVal (Expr);
+ FreeExpr (Expr);
+ if ((Val & ~0xFFFFFF) != 0) {
+ Error (ERR_RANGE);
+ }
+ Emit0 (Val & 0xFF);
+ Emit0 ((Val >> 8) & 0xFF);
+ Emit0 ((Val >> 16) & 0xFF);
+ } else {
+ /* Create a new fragment */
+ Fragment* F = NewFragment (FRAG_EXPR, 3);
+
+ /* Set the data */
+ F->V.Expr = Expr;
+ }
+}
+
+
+
+void EmitDWord (ExprNode* Expr)
+/* Emit one dword */
+{
+ if (IsConstExpr (Expr)) {
+ /* Constant expression, emit literal byte */
+ long Val = GetExprVal (Expr);
+ FreeExpr (Expr);
+ Emit0 (Val & 0xFF);
+ Emit0 ((Val >> 8) & 0xFF);
+ Emit0 ((Val >> 16) & 0xFF);
+ Emit0 ((Val >> 24) & 0xFF);
+ } else {
+ /* Create a new fragment */
+ Fragment* F = NewFragment (FRAG_EXPR, 4);
+
+ /* Set the data */
+ F->V.Expr = Expr;
+ }
+}
+
+
+
+void EmitFill (unsigned long Count)
+/* Emit Count fill bytes */
+{
+ while (Count) {
+ /* Calculate the size of the next chunk */
+ unsigned Chunk = (Count > 0xFFFF)? 0xFFFF : (unsigned) Count;
+ Count -= Chunk;
+
+ /* Emit one chunk */
+ NewFragment (FRAG_FILL, Chunk);
+ }
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* objcode.h */
+/* */
+/* Objectcode management for the ca65 macroassembler */
+/* */
+/* */
+/* */
+/* (C) 1998-2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef OBJCODE_H
+#define OBJCODE_H
+
+
+
+#include "../common/segdefs.h"
+#include "expr.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Are we in absolute mode or in relocatable mode? */
+extern int RelocMode;
+
+
+
+/*****************************************************************************/
+/* Segment management */
+/*****************************************************************************/
+
+
+
+void UseCodeSeg (void);
+/* Use the code segment */
+
+void UseRODataSeg (void);
+/* Use the r/o data segment */
+
+void UseDataSeg (void);
+/* Use the data segment */
+
+void UseBssSeg (void);
+/* Use the BSS segment */
+
+void UseZeropageSeg (void);
+/* Use the zero page segment */
+
+void UseNullSeg (void);
+/* Use the null segment */
+
+void UseSeg (const char* Name, unsigned SegType);
+/* Use the segment with the given name */
+
+unsigned GetSegNum (void);
+/* Get the number of the current segment */
+
+void SegAlign (unsigned Power, int Val);
+/* Align the PC segment to 2^Power. If Val is -1, emit fill fragments (the
+ * actual fill value will be determined by the linker), otherwise use the
+ * given value.
+ */
+
+int IsZPSeg (void);
+/* Return true if the current segment is a zeropage segment */
+
+int IsFarSeg (void);
+/* Return true if the current segment is a far segment */
+
+unsigned GetSegType (unsigned SegNum);
+/* Return the type of the segment with the given number */
+
+unsigned long GetPC (void);
+/* Get the program counter of the current segment */
+
+void SetAbsPC (unsigned long AbsPC);
+/* Set the program counter in absolute mode */
+
+void SegCheck (void);
+/* Check the segments for range and other errors */
+
+void SegDump (void);
+/* Dump the contents of all segments */
+
+void WriteSegments (void);
+/* Write the segment data to the object file */
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void Emit0 (unsigned char OPC);
+/* Emit an instruction with a zero sized operand */
+
+void Emit1 (unsigned char OPC, ExprNode* Value);
+/* Emit an instruction with an one byte argument */
+
+void Emit2 (unsigned char OPC, ExprNode* Value);
+/* Emit an instruction with a two byte argument */
+
+void Emit3 (unsigned char OPC, ExprNode* Expr);
+/* Emit an instruction with a three byte argument */
+
+void Emit3b (unsigned char OPC, ExprNode* Expr, ExprNode* Bank);
+/* Emit an instruction with a three byte argument and separate bank */
+
+void EmitPCRel (unsigned char OPC, ExprNode* Expr, unsigned Size);
+/* Emit an opcode with a PC relative argument of one or two bytes */
+
+void EmitData (const unsigned char* Data, unsigned Size);
+/* Emit data into the current segment */
+
+void EmitByte (ExprNode* Expr);
+/* Emit one byte */
+
+void EmitWord (ExprNode* Expr);
+/* Emit one word */
+
+void EmitFarAddr (ExprNode* Expr);
+/* Emit a 24 bit expression */
+
+void EmitDWord (ExprNode* Expr);
+/* Emit one dword */
+
+void EmitFill (unsigned long Count);
+/* Emit Count fill bytes */
+
+
+
+/* End of objcode.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* objfile.c */
+/* */
+/* Object file writing routines for the ca65 macroassembler */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "../common/objdefs.h"
+
+#include "global.h"
+#include "error.h"
+#include "fname.h"
+#include "mem.h"
+#include "objfile.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* File descriptor */
+static FILE* F = 0;
+
+/* Default extension */
+#define OBJ_EXT ".o"
+
+/* Header structure */
+static ObjHeader Header = {
+ OBJ_MAGIC,
+ OBJ_VERSION
+};
+
+
+
+/*****************************************************************************/
+/* Internally used functions */
+/*****************************************************************************/
+
+
+
+static void ObjWriteError (void)
+/* Called on a write error. Will try to close and remove the file, then
+ * print a fatal error.
+ */
+{
+ /* Remember the error */
+ int Error = errno;
+
+ /* Force a close of the file, ignoring errors */
+ fclose (F);
+
+ /* Try to remove the file, also ignoring errors */
+ remove (OutFile);
+
+ /* Now abort with a fatal error */
+ Fatal (FAT_CANNOT_WRITE_OUTPUT, OutFile, strerror (Error));
+}
+
+
+
+static void ObjWriteHeader (void)
+/* Write the object file header to the current file position */
+{
+ ObjWrite32 (Header.Magic);
+ ObjWrite16 (Header.Version);
+ ObjWrite16 (Header.Flags);
+ ObjWrite32 (Header.OptionOffs);
+ ObjWrite32 (Header.OptionSize);
+ ObjWrite32 (Header.FileOffs);
+ ObjWrite32 (Header.FileSize);
+ ObjWrite32 (Header.SegOffs);
+ ObjWrite32 (Header.SegSize);
+ ObjWrite32 (Header.ImportOffs);
+ ObjWrite32 (Header.ImportSize);
+ ObjWrite32 (Header.ExportOffs);
+ ObjWrite32 (Header.ExportSize);
+ ObjWrite32 (Header.DbgSymOffs);
+ ObjWrite32 (Header.DbgSymSize);
+}
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void ObjOpen (void)
+/* Open the object file for writing, write a dummy header */
+{
+ /* Do we have a name for the output file? */
+ if (OutFile == 0) {
+ /* We don't have an output name explicitly given, construct one from
+ * the name of the input file.
+ */
+ OutFile = MakeFilename (InFile, OBJ_EXT);
+ }
+
+ /* Create the output file */
+ F = fopen (OutFile, "w+b");
+ if (F == 0) {
+ Fatal (FAT_CANNOT_OPEN_OUTPUT, OutFile, strerror (errno));
+ }
+
+ /* Write a dummy header */
+ ObjWriteHeader ();
+}
+
+
+
+void ObjClose (void)
+/* Write an update header and close the object file. */
+{
+ /* Go back to the beginning */
+ if (fseek (F, 0, SEEK_SET) != 0) {
+ ObjWriteError ();
+ }
+
+ /* If we have debug infos, set the flag in the header */
+ if (DbgSyms) {
+ Header.Flags |= OBJ_FLAGS_DBGINFO;
+ }
+
+ /* Write the updated header */
+ ObjWriteHeader ();
+
+ /* Close the file */
+ if (fclose (F) != 0) {
+ ObjWriteError ();
+ }
+}
+
+
+
+void ObjWrite8 (unsigned char V)
+/* Write an 8 bit value to the file */
+{
+ if (putc (V, F) == EOF) {
+ ObjWriteError ();
+ }
+}
+
+
+
+void ObjWrite16 (unsigned V)
+/* Write a 16 bit value to the file */
+{
+ ObjWrite8 (V);
+ ObjWrite8 (V >> 8);
+}
+
+
+
+void ObjWrite24 (unsigned long V)
+/* Write a 24 bit value to the file */
+{
+ ObjWrite8 (V);
+ ObjWrite8 (V >> 8);
+ ObjWrite8 (V >> 16);
+}
+
+
+
+void ObjWrite32 (unsigned long V)
+/* Write a 32 bit value to the file */
+{
+ ObjWrite8 (V);
+ ObjWrite8 (V >> 8);
+ ObjWrite8 (V >> 16);
+ ObjWrite8 (V >> 24);
+}
+
+
+
+void ObjWriteStr (const char* S)
+/* Write a string to the object file */
+{
+ unsigned Len = strlen (S);
+ if (Len > 255) {
+ Internal ("String too long in ObjWriteStr");
+ }
+
+ /* Write the string with a length byte preceeded (this is easier for
+ * the reading routine than the C format since the length is known in
+ * advance).
+ */
+ ObjWrite8 ((unsigned char) Len);
+ ObjWriteData (S, Len);
+}
+
+
+
+void ObjWriteData (const void* Data, unsigned Size)
+/* Write literal data to the file */
+{
+ if (fwrite (Data, 1, Size, F) != Size) {
+ ObjWriteError ();
+ }
+}
+
+
+
+void ObjWritePos (const FilePos* Pos)
+/* Write a file position to the object file */
+{
+ /* Write the line number as 24 bit value to save one byte */
+ ObjWrite24 (Pos->Line);
+ ObjWrite8 (Pos->Col);
+ if (Pos->Name == 0) {
+ /* Position is outside file scope, use the main file instead */
+ ObjWrite8 (0);
+ } else {
+ ObjWrite8 (Pos->Name - 1);
+ }
+}
+
+
+
+void ObjStartOptions (void)
+/* Mark the start of the option section */
+{
+ Header.OptionOffs = ftell (F);
+}
+
+
+
+void ObjEndOptions (void)
+/* Mark the end of the option section */
+{
+ Header.OptionSize = ftell (F) - Header.OptionOffs;
+}
+
+
+
+void ObjStartFiles (void)
+/* Mark the start of the files section */
+{
+ Header.FileOffs = ftell (F);
+}
+
+
+
+void ObjEndFiles (void)
+/* Mark the end of the files section */
+{
+ Header.FileSize = ftell (F) - Header.FileOffs;
+}
+
+
+
+void ObjStartSegments (void)
+/* Mark the start of the segment section */
+{
+ Header.SegOffs = ftell (F);
+}
+
+
+
+void ObjEndSegments (void)
+/* Mark the end of the segment section */
+{
+ Header.SegSize = ftell (F) - Header.SegOffs;
+}
+
+
+
+void ObjStartImports (void)
+/* Mark the start of the import section */
+{
+ Header.ImportOffs = ftell (F);
+}
+
+
+
+void ObjEndImports (void)
+/* Mark the end of the import section */
+{
+ Header.ImportSize = ftell (F) - Header.ImportOffs;
+}
+
+
+
+void ObjStartExports (void)
+/* Mark the start of the export section */
+{
+ Header.ExportOffs = ftell (F);
+}
+
+
+
+void ObjEndExports (void)
+/* Mark the end of the export section */
+{
+ Header.ExportSize = ftell (F) - Header.ExportOffs;
+}
+
+
+
+void ObjStartDbgSyms (void)
+/* Mark the start of the debug symbol section */
+{
+ Header.DbgSymOffs = ftell (F);
+}
+
+
+
+void ObjEndDbgSyms (void)
+/* Mark the end of the debug symbol section */
+{
+ Header.DbgSymSize = ftell (F) - Header.DbgSymOffs;
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* objfile.h */
+/* */
+/* Object file writing routines for the ca65 macroassembler */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef OBJFILE_H
+#define OBJFILE_H
+
+
+
+#include "../common/filepos.h"
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void ObjOpen (void);
+/* Open the object file for writing, write a dummy header */
+
+void ObjClose (void);
+/* Write an update header and close the object file. */
+
+void ObjWrite8 (unsigned char V);
+/* Write an 8 bit value to the file */
+
+void ObjWrite16 (unsigned V);
+/* Write a 16 bit value to the file */
+
+void ObjWrite24 (unsigned long V);
+/* Write a 24 bit value to the file */
+
+void ObjWrite32 (unsigned long V);
+/* Write a 32 bit value to the file */
+
+void ObjWriteStr (const char* S);
+/* Write a string to the object file */
+
+void ObjWriteData (const void* Data, unsigned Size);
+/* Write literal data to the file */
+
+void ObjWritePos (const FilePos* Pos);
+/* Write a file position to the object file */
+
+void ObjStartOptions (void);
+/* Mark the start of the option section */
+
+void ObjEndOptions (void);
+/* Mark the end of the option section */
+
+void ObjStartFiles (void);
+/* Mark the start of the files section */
+
+void ObjEndFiles (void);
+/* Mark the end of the files section */
+
+void ObjStartSegments (void);
+/* Mark the start of the segment section */
+
+void ObjEndSegments (void);
+/* Mark the end of the segment section */
+
+void ObjStartImports (void);
+/* Mark the start of the import section */
+
+void ObjEndImports (void);
+/* Mark the end of the import section */
+
+void ObjStartExports (void);
+/* Mark the start of the export section */
+
+void ObjEndExports (void);
+/* Mark the end of the export section */
+
+void ObjStartDbgSyms (void);
+/* Mark the start of the debug symbol section */
+
+void ObjEndDbgSyms (void);
+/* Mark the end of the debug symbol section */
+
+
+
+/* End of objfile.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* options.c */
+/* */
+/* Object file options for the ca65 macroassembler */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include "../common/optdefs.h"
+
+#include "mem.h"
+#include "error.h"
+#include "objfile.h"
+#include "options.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Option list */
+static Option* OptRoot = 0;
+static Option* OptLast = 0;
+static unsigned OptCount = 0;
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+static Option* NewOption (unsigned char Type)
+/* Create a new option, insert it into the list and return it */
+{
+ Option* Opt;
+
+ /* Allocate memory */
+ Opt = Xmalloc (sizeof (*Opt));
+
+ /* Initialize fields */
+ Opt->Next = 0;
+ Opt->Type = Type;
+ Opt->V.Str = 0;
+
+ /* Insert it into the list */
+ if (OptRoot == 0) {
+ OptRoot = Opt;
+ } else {
+ OptLast->Next = Opt;
+ }
+ OptLast = Opt;
+
+ /* One more option now */
+ ++OptCount;
+
+ /* Return the new struct */
+ return Opt;
+}
+
+
+
+void OptStr (unsigned char Type, const char* Text)
+/* Add a string option */
+{
+ Option* O;
+
+ /* String must have less than 255 bytes */
+ if (strlen (Text) > 255) {
+ Fatal (FAT_STRING_TOO_LONG);
+ }
+ O = NewOption (Type);
+ O->V.Str = StrDup (Text);
+}
+
+
+
+void OptComment (const char* Comment)
+/* Add a comment */
+{
+ OptStr (OPT_COMMENT, Comment);
+}
+
+
+
+void OptAuthor (const char* Author)
+/* Add an author statement */
+{
+ OptStr (OPT_AUTHOR, Author);
+}
+
+
+
+void OptTranslator (const char* Translator)
+/* Add a translator option */
+{
+ OptStr (OPT_TRANSLATOR, Translator);
+}
+
+
+
+void OptCompiler (const char* Compiler)
+/* Add a compiler option */
+{
+ OptStr (OPT_COMPILER, Compiler);
+}
+
+
+
+void OptOS (const char* OS)
+/* Add an operating system option */
+{
+ OptStr (OPT_OS, OS);
+}
+
+
+
+void OptDateTime (unsigned long DateTime)
+/* Add a date/time option */
+{
+ Option* O = NewOption (OPT_DATETIME);
+ O->V.Val = DateTime;
+}
+
+
+
+void WriteOptions (void)
+/* Write the options to the object file */
+{
+ Option* O;
+
+ /* Tell the object file module that we're about to start the options */
+ ObjStartOptions ();
+
+ /* Write the option count */
+ ObjWrite16 (OptCount);
+
+ /* Walk through the list and write the options */
+ O = OptRoot;
+ while (O) {
+
+ /* Write the type of the option */
+ ObjWrite8 (O->Type);
+
+ /* Write the argument */
+ switch (O->Type & OPT_ARGMASK) {
+
+ case OPT_ARGSTR:
+ ObjWriteStr (O->V.Str);
+ break;
+
+ case OPT_ARGNUM:
+ ObjWrite32 (O->V.Val);
+ break;
+
+ default:
+ Internal ("Invalid option type: $%02X", O->Type & 0xFF);
+
+ }
+
+ /* Next option */
+ O = O->Next;
+
+ }
+
+ /* Done writing options */
+ ObjEndOptions ();
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* options.h */
+/* */
+/* Object file options for the ca65 macroassembler */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef OPTIONS_H
+#define OPTIONS_H
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void OptStr (unsigned char Type, const char* Text);
+/* Add a string option */
+
+void OptComment (const char* Comment);
+/* Add a comment */
+
+void OptAuthor (const char* Author);
+/* Add an author statement */
+
+void OptTranslator (const char* Translator);
+/* Add a translator option */
+
+void OptCompiler (const char* Compiler);
+/* Add a compiler option */
+
+void OptOS (const char* OS);
+/* Add an operating system option */
+
+void OptDateTime (unsigned long DateTime);
+/* Add a date/time option */
+
+void WriteOptions (void);
+/* Write the options to the object file */
+
+
+
+/* End of options.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* pseudo.c */
+/* */
+/* Pseudo instructions for the ca65 macroassembler */
+/* */
+/* */
+/* */
+/* (C) 1998-2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "../common/bitops.h"
+
+#include "condasm.h"
+#include "error.h"
+#include "expr.h"
+#include "global.h"
+#include "instr.h"
+#include "listing.h"
+#include "macpack.h"
+#include "macro.h"
+#include "objcode.h"
+#include "options.h"
+#include "scanner.h"
+#include "strexpr.h"
+#include "symtab.h"
+#include "pseudo.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Keyword we're about to handle */
+static char Keyword [sizeof (SVal)+1] = ".";
+
+
+
+/*****************************************************************************/
+/* Forwards */
+/*****************************************************************************/
+
+
+
+static void DoUnexpected (void);
+
+
+
+/*****************************************************************************/
+/* Helper functions */
+/*****************************************************************************/
+
+
+
+static void SetBoolOption (unsigned char* Flag)
+/* Read a on/off/+/- option and set flag accordingly */
+{
+ static const char* Keys[] = {
+ "OFF",
+ "ON",
+ };
+
+ if (Tok == TOK_PLUS) {
+ *Flag = 1;
+ NextTok ();
+ } else if (Tok == TOK_MINUS) {
+ *Flag = 0;
+ NextTok ();
+ } else if (Tok == TOK_IDENT) {
+ /* Map the keyword to a number */
+ switch (GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]))) {
+ case 0: *Flag = 0; NextTok (); break;
+ case 1: *Flag = 1; NextTok (); break;
+ default: ErrorSkip (ERR_ONOFF_EXPECTED); break;
+ }
+ } else if (Tok == TOK_SEP || Tok == TOK_EOF) {
+ /* Without anything assume switch on */
+ *Flag = 1;
+ } else {
+ ErrorSkip (ERR_ONOFF_EXPECTED);
+ }
+}
+
+
+
+static void ExportImport (void (*SymFunc) (const char*, int), int ZP)
+/* Export or import symbols */
+{
+ while (1) {
+ if (Tok != TOK_IDENT) {
+ ErrorSkip (ERR_IDENT_EXPECTED);
+ break;
+ }
+ SymFunc (SVal, ZP);
+ NextTok ();
+ if (Tok == TOK_COMMA) {
+ NextTok ();
+ } else {
+ break;
+ }
+ }
+}
+
+
+
+static long IntArg (long Min, long Max)
+/* Read an integer argument and check a range. Accept the token "unlimited"
+ * and return -1 in this case.
+ */
+{
+ if (Tok == TOK_IDENT && strcmp (SVal, "unlimited") == 0) {
+ NextTok ();
+ return -1;
+ } else {
+ long Val = ConstExpression ();
+ if (Val < Min || Val > Max) {
+ Error (ERR_RANGE);
+ Val = Min;
+ }
+ return Val;
+ }
+}
+
+
+
+/*****************************************************************************/
+/* Handler functions */
+/*****************************************************************************/
+
+
+
+static void DoA16 (void)
+/* Switch the accu to 16 bit mode (assembler only) */
+{
+ if (GetCPU() != CPU_65816) {
+ Error (ERR_816_MODE_ONLY);
+ } else {
+ /* Immidiate mode has two extension bytes */
+ ExtBytes [AMI_IMM_ACCU] = 2;
+ }
+}
+
+
+
+static void DoA8 (void)
+/* Switch the accu to 8 bit mode (assembler only) */
+{
+ if (GetCPU() != CPU_65816) {
+ Error (ERR_816_MODE_ONLY);
+ } else {
+ /* Immidiate mode has one extension byte */
+ ExtBytes [AMI_IMM_ACCU] = 1;
+ }
+}
+
+
+
+static void DoAddr (void)
+/* Define addresses */
+{
+ while (1) {
+ if (GetCPU() == CPU_65816) {
+ EmitWord (ForceWordExpr (Expression ()));
+ } else {
+ /* Do a range check */
+ EmitWord (Expression ());
+ }
+ if (Tok != TOK_COMMA) {
+ break;
+ } else {
+ NextTok ();
+ }
+ }
+}
+
+
+
+static void DoAlign (void)
+/* Align the PC to some boundary */
+{
+ long Val;
+ long Align;
+ unsigned Bit;
+
+ /* Read the alignment value */
+ Align = ConstExpression ();
+ if (Align <= 0 || Align > 0x10000) {
+ ErrorSkip (ERR_RANGE);
+ return;
+ }
+
+ /* Optional value follows */
+ if (Tok == TOK_COMMA) {
+ NextTok ();
+ Val = ConstExpression ();
+ /* We need a byte value here */
+ if (!IsByteRange (Val)) {
+ ErrorSkip (ERR_RANGE);
+ return;
+ }
+ } else {
+ Val = -1;
+ }
+
+ /* Check if the alignment is a power of two */
+ Bit = BitFind (Align);
+ if (Align != (0x01UL << Bit)) {
+ Error (ERR_ALIGN);
+ } else {
+ SegAlign (Bit, (int) Val);
+ }
+}
+
+
+
+static void DoASCIIZ (void)
+/* Define text with a zero terminator */
+{
+ while (1) {
+ if (StringExpression () == 0) {
+ ErrorSkip (ERR_STRCON_EXPECTED);
+ return;
+ }
+ EmitData (SVal, strlen (SVal));
+ NextTok ();
+ if (Tok == TOK_COMMA) {
+ NextTok ();
+ } else {
+ break;
+ }
+ }
+ Emit0 (0);
+}
+
+
+
+static void DoAutoImport (void)
+/* Mark unresolved symbols as imported */
+{
+ SetBoolOption (&AutoImport);
+}
+
+
+
+static void DoBss (void)
+/* Switch to the BSS segment */
+{
+ UseBssSeg ();
+}
+
+
+
+static void DoByte (void)
+/* Define bytes */
+{
+ while (1) {
+ if (StringExpression () != 0) {
+ /* A string */
+ EmitData (SVal, strlen (SVal));
+ NextTok ();
+ } else {
+ EmitByte (Expression ());
+ }
+ if (Tok != TOK_COMMA) {
+ break;
+ } else {
+ NextTok ();
+ /* Do smart handling of dangling comma */
+ if (Tok == TOK_SEP) {
+ Error (ERR_UNEXPECTED_EOL);
+ break;
+ }
+ }
+ }
+}
+
+
+
+static void DoCase (void)
+/* Switch the IgnoreCase option */
+{
+ SetBoolOption (&IgnoreCase);
+ IgnoreCase = !IgnoreCase;
+}
+
+
+
+static void DoCode (void)
+/* Switch to the code segment */
+{
+ UseCodeSeg ();
+}
+
+
+
+static void DoData (void)
+/* Switch to the data segment */
+{
+ UseDataSeg ();
+}
+
+
+
+static void DoDByt (void)
+/* Output double bytes */
+{
+ while (1) {
+ EmitWord (SwapExpr (Expression ()));
+ if (Tok != TOK_COMMA) {
+ break;
+ } else {
+ NextTok ();
+ }
+ }
+}
+
+
+
+static void DoDebugInfo (void)
+/* Switch debug info on or off */
+{
+ SetBoolOption (&DbgSyms);
+}
+
+
+
+static void DoDefine (void)
+/* Define a one line macro */
+{
+ MacDef (MAC_STYLE_DEFINE);
+}
+
+
+
+static void DoDWord (void)
+/* Define dwords */
+{
+ while (1) {
+ EmitDWord (Expression ());
+ if (Tok != TOK_COMMA) {
+ break;
+ } else {
+ NextTok ();
+ }
+ }
+}
+
+
+
+static void DoEnd (void)
+/* End of assembly */
+{
+ ForcedEnd = 1;
+}
+
+
+
+static void DoEndProc (void)
+/* Leave a lexical level */
+{
+ SymLeaveLevel ();
+}
+
+
+
+static void DoError (void)
+/* Use error */
+{
+ if (StringExpression () == 0) {
+ ErrorSkip (ERR_STRCON_EXPECTED);
+ } else {
+ Error (ERR_USER, SVal);
+ SkipUntilSep ();
+ }
+}
+
+
+
+static void DoExitMacro (void)
+/* Exit a macro expansion */
+{
+ if (!InMacExpansion ()) {
+ /* We aren't expanding a macro currently */
+ DoUnexpected ();
+ } else {
+ MacAbort ();
+ }
+}
+
+
+
+static void DoExport (void)
+/* Export a symbol */
+{
+ ExportImport (SymExport, 0);
+}
+
+
+
+static void DoExportZP (void)
+/* Export a zeropage symbol */
+{
+ ExportImport (SymExport, 1);
+}
+
+
+
+static void DoFarAddr (void)
+/* Define far addresses (24 bit) */
+{
+ while (1) {
+ EmitFarAddr (Expression ());
+ if (Tok != TOK_COMMA) {
+ break;
+ } else {
+ NextTok ();
+ }
+ }
+}
+
+
+
+static void DoFeature (void)
+/* Switch the Feature option */
+{
+ int Feature;
+
+ static const char* Keys[] = {
+ "DOLLAR_IS_PC",
+ "LABELS_WITHOUT_COLONS",
+ "LOOSE_STRING_TERM",
+ "AT_IN_IDENTIFIERS",
+ "DOLLAR_IN_IDENTIFIERS",
+ };
+
+ /* Allow a list of comma separated keywords */
+ while (1) {
+
+ /* We expect an identifier */
+ if (Tok != TOK_IDENT) {
+ ErrorSkip (ERR_IDENT_EXPECTED);
+ return;
+ }
+
+ /* Map the keyword to a number */
+ Feature = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
+ if (Feature < 0) {
+ /* Not found */
+ ErrorSkip (ERR_ILLEGAL_FEATURE);
+ return;
+ }
+
+ /* Skip the keyword */
+ NextTok ();
+
+ /* Switch the feature on */
+ switch (Feature) {
+ case 0: DollarIsPC = 1; break;
+ case 1: NoColonLabels = 1; break;
+ case 2: LooseStringTerm = 1; break;
+ case 3: AtInIdents = 1; break;
+ case 4: DollarInIdents = 1; break;
+ default: Internal ("Invalid feature: %d", Feature);
+ }
+
+ /* Allow more than one keyword */
+ if (Tok == TOK_COMMA) {
+ NextTok ();
+ } else {
+ break;
+ }
+ }
+}
+
+
+
+static void DoFileOpt (void)
+/* Insert a file option */
+{
+ long OptNum;
+
+ /* The option type may be given as a keyword or as a number. */
+ if (Tok == TOK_IDENT) {
+
+ /* Option given as keyword */
+ static const char* Keys [] = {
+ "AUTHOR", "COMMENT", "COMPILER"
+ };
+
+ /* Map the option to a number */
+ OptNum = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
+ if (OptNum < 0) {
+ /* Not found */
+ ErrorSkip (ERR_OPTION_KEY_EXPECTED);
+ return;
+ }
+
+ /* Skip the keyword */
+ NextTok ();
+
+ /* Must be followed by a comma */
+ ConsumeComma ();
+
+ /* We accept only string options for now */
+ if (StringExpression () == 0) {
+ ErrorSkip (ERR_STRCON_EXPECTED);
+ return;
+ }
+
+ /* Insert the option */
+ switch (OptNum) {
+
+ case 0:
+ /* Author */
+ OptAuthor (SVal);
+ break;
+
+ case 1:
+ /* Comment */
+ OptComment (SVal);
+ break;
+
+ case 2:
+ /* Compiler */
+ OptCompiler (SVal);
+ break;
+
+ default:
+ Internal ("Invalid OptNum: %l", OptNum);
+
+ }
+
+ /* Done */
+ NextTok ();
+
+ } else {
+
+ /* Option given as number */
+ OptNum = ConstExpression ();
+ if (!IsByteRange (OptNum)) {
+ ErrorSkip (ERR_RANGE);
+ return;
+ }
+
+ /* Must be followed by a comma */
+ ConsumeComma ();
+
+ /* We accept only string options for now */
+ if (StringExpression () == 0) {
+ ErrorSkip (ERR_STRCON_EXPECTED);
+ return;
+ }
+
+ /* Insert the option */
+ OptStr ((unsigned char) OptNum, SVal);
+
+ /* Done */
+ NextTok ();
+ }
+}
+
+
+
+static void DoGlobal (void)
+/* Declare a global symbol */
+{
+ ExportImport (SymGlobal, 0);
+}
+
+
+
+static void DoGlobalZP (void)
+/* Declare a global zeropage symbol */
+{
+ ExportImport (SymGlobal, 1);
+}
+
+
+
+static void DoI16 (void)
+/* Switch the index registers to 16 bit mode (assembler only) */
+{
+ if (GetCPU() != CPU_65816) {
+ Error (ERR_816_MODE_ONLY);
+ } else {
+ /* Immidiate mode has two extension bytes */
+ ExtBytes [AMI_IMM_INDEX] = 2;
+ }
+}
+
+
+
+static void DoI8 (void)
+/* Switch the index registers to 16 bit mode (assembler only) */
+{
+ if (GetCPU() != CPU_65816) {
+ Error (ERR_816_MODE_ONLY);
+ } else {
+ /* Immidiate mode has one extension byte */
+ ExtBytes [AMI_IMM_INDEX] = 1;
+ }
+}
+
+
+
+static void DoImport (void)
+/* Import a symbol */
+{
+ ExportImport (SymImport, 0);
+}
+
+
+
+static void DoImportZP (void)
+/* Import a zero page symbol */
+{
+ ExportImport (SymImport, 1);
+}
+
+
+
+static void DoIncBin (void)
+/* Include a binary file */
+{
+ /* Name must follow */
+ if (StringExpression () == 0) {
+ ErrorSkip (ERR_STRCON_EXPECTED);
+ } else {
+ /* Try to open the file */
+ FILE* F = fopen (SVal, "rb");
+ if (F == 0) {
+ Error (ERR_CANNOT_OPEN_INCLUDE, SVal, strerror (errno));
+ } else {
+ unsigned char Buf [1024];
+ size_t Count;
+ /* Read chunks and insert them into the output */
+ while ((Count = fread (Buf, 1, sizeof (Buf), F)) > 0) {
+ EmitData (Buf, Count);
+ }
+ /* Close the file, ignore errors since it's r/o */
+ (void) fclose (F);
+ }
+ /* Skip the name */
+ NextTok ();
+ }
+}
+
+
+
+static void DoInclude (void)
+/* Include another file */
+{
+ char Name [MAX_STR_LEN+1];
+
+ /* Name must follow */
+ if (StringExpression () == 0) {
+ ErrorSkip (ERR_STRCON_EXPECTED);
+ } else {
+ strcpy (Name, SVal);
+ NextTok ();
+ NewInputFile (Name);
+ }
+}
+
+
+
+static void DoLineCont (void)
+/* Switch the use of line continuations */
+{
+ SetBoolOption (&LineCont);
+}
+
+
+
+static void DoList (void)
+/* Enable/disable the listing */
+{
+ /* Get the setting */
+ unsigned char List;
+ SetBoolOption (&List);
+
+ /* Manage the counter */
+ if (List) {
+ EnableListing ();
+ } else {
+ DisableListing ();
+ }
+}
+
+
+
+static void DoListBytes (void)
+/* Set maximum number of bytes to list for one line */
+{
+ SetListBytes (IntArg (MIN_LIST_BYTES, MAX_LIST_BYTES));
+}
+
+
+
+static void DoLocalChar (void)
+/* Define the character that starts local labels */
+{
+ if (Tok != TOK_CHARCON) {
+ ErrorSkip (ERR_CHARCON_EXPECTED);
+ } else {
+ if (IVal != '@' && IVal != '?') {
+ Error (ERR_ILLEGAL_LOCALSTART);
+ } else {
+ LocalStart = IVal;
+ }
+ NextTok ();
+ }
+}
+
+
+
+static void DoMacPack (void)
+/* Insert a macro package */
+{
+ /* Macro package names */
+ static const char* Keys [] = {
+ "GENERIC",
+ "LONGBRANCH",
+ };
+
+ int Package;
+
+ /* We expect an identifier */
+ if (Tok != TOK_IDENT) {
+ ErrorSkip (ERR_IDENT_EXPECTED);
+ return;
+ }
+
+ /* Map the keyword to a number */
+ Package = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
+ if (Package < 0) {
+ /* Not found */
+ ErrorSkip (ERR_ILLEGAL_MACPACK);
+ return;
+ }
+
+ /* Skip the package name */
+ NextTok ();
+
+ /* Insert the package */
+ InsertMacPack (Package);
+}
+
+
+
+static void DoMacro (void)
+/* Start a macro definition */
+{
+ MacDef (MAC_STYLE_CLASSIC);
+}
+
+
+
+static void DoNull (void)
+/* Switch to the NULL segment */
+{
+ UseNullSeg ();
+}
+
+
+
+static void DoOrg (void)
+/* Start absolute code */
+{
+ long PC = ConstExpression ();
+ if (PC < 0 || PC > 0xFFFF) {
+ Error (ERR_RANGE);
+ return;
+ }
+ SetAbsPC (PC);
+}
+
+
+
+static void DoOut (void)
+/* Output a string */
+{
+ if (StringExpression () == 0) {
+ ErrorSkip (ERR_STRCON_EXPECTED);
+ } else {
+ /* Output the string and be sure to flush the output to keep it in
+ * sync with any error messages if the output is redirected to a file.
+ */
+ printf ("%s\n", SVal);
+ fflush (stdout);
+ NextTok ();
+ }
+}
+
+
+
+static void DoP02 (void)
+/* Switch to 6502 CPU */
+{
+ SetCPU (CPU_6502);
+}
+
+
+
+static void DoPC02 (void)
+/* Switch to 65C02 CPU */
+{
+ SetCPU (CPU_65C02);
+}
+
+
+
+static void DoP816 (void)
+/* Switch to 65816 CPU */
+{
+ SetCPU (CPU_65816);
+}
+
+
+
+static void DoPageLength (void)
+/* Set the page length for the listing */
+{
+ PageLength = IntArg (MIN_PAGE_LEN, MAX_PAGE_LEN);
+}
+
+
+
+static void DoProc (void)
+/* Start a new lexical scope */
+{
+ if (Tok == TOK_IDENT) {
+ /* The new scope has a name */
+ SymDef (SVal, CurrentPC (), IsZPSeg ());
+ NextTok ();
+ }
+ SymEnterLevel ();
+}
+
+
+
+static void DoReloc (void)
+/* Enter relocatable mode */
+{
+ RelocMode = 1;
+}
+
+
+
+static void DoRepeat (void)
+/* Repeat some instruction block */
+{
+ ErrorSkip (ERR_NOT_IMPLEMENTED);
+}
+
+
+
+static void DoRes (void)
+/* Reserve some number of storage bytes */
+{
+ long Count;
+ long Val;
+
+ Count = ConstExpression ();
+ if (Count > 0xFFFF || Count < 0) {
+ ErrorSkip (ERR_RANGE);
+ return;
+ }
+ if (Tok == TOK_COMMA) {
+ NextTok ();
+ Val = ConstExpression ();
+ /* We need a byte value here */
+ if (!IsByteRange (Val)) {
+ ErrorSkip (ERR_RANGE);
+ return;
+ }
+
+ /* Emit constant values */
+ while (Count--) {
+ Emit0 ((unsigned char) Val);
+ }
+
+ } else {
+ /* Emit fill fragments */
+ EmitFill (Count);
+ }
+}
+
+
+
+static void DoROData (void)
+/* Switch to the r/o data segment */
+{
+ UseRODataSeg ();
+}
+
+
+
+static void DoSegment (void)
+/* Switch to another segment */
+{
+ static const char* AttrTab [] = {
+ "ZEROPAGE", "DIRECT",
+ "ABSOLUTE",
+ "FAR", "LONG"
+ };
+ char Name [sizeof (SVal)];
+ int SegType;
+
+ if (StringExpression () == 0) {
+ ErrorSkip (ERR_STRCON_EXPECTED);
+ } else {
+
+ /* Save the name of the segment and skip it */
+ strcpy (Name, SVal);
+ NextTok ();
+
+ /* Check for an optional segment attribute */
+ SegType = SEGTYPE_DEFAULT;
+ if (Tok == TOK_COMMA) {
+ NextTok ();
+ if (Tok != TOK_IDENT) {
+ ErrorSkip (ERR_IDENT_EXPECTED);
+ } else {
+ int Attr = GetSubKey (AttrTab, sizeof (AttrTab) / sizeof (AttrTab [0]));
+ switch (Attr) {
+
+ case 0:
+ case 1:
+ /* Zeropage */
+ SegType = SEGTYPE_ZP;
+ break;
+
+ case 2:
+ /* Absolute */
+ SegType = SEGTYPE_ABS;
+ break;
+
+ case 3:
+ case 4:
+ /* Far */
+ SegType = SEGTYPE_FAR;
+ break;
+
+ default:
+ Error (ERR_ILLEGAL_SEG_ATTR);
+ }
+ NextTok ();
+ }
+ }
+
+ /* Set the segment */
+ UseSeg (Name, SegType);
+ }
+}
+
+
+
+static void DoSmart (void)
+/* Smart mode on/off */
+{
+ SetBoolOption (&SmartMode);
+}
+
+
+
+static void DoSunPlus (void)
+/* Switch to the SUNPLUS CPU */
+{
+ SetCPU (CPU_SUNPLUS);
+}
+
+
+
+static void DoUnexpected (void)
+/* Got an unexpected keyword */
+{
+ Error (ERR_UNEXPECTED, Keyword);
+ SkipUntilSep ();
+}
+
+
+
+static void DoWord (void)
+/* Define words */
+{
+ while (1) {
+ EmitWord (Expression ());
+ if (Tok != TOK_COMMA) {
+ break;
+ } else {
+ NextTok ();
+ }
+ }
+}
+
+
+
+static void DoZeropage (void)
+/* Switch to the zeropage segment */
+{
+ UseZeropageSeg ();
+}
+
+
+
+/*****************************************************************************/
+/* Table data */
+/*****************************************************************************/
+
+
+
+/* Control commands flags */
+enum {
+ ccNone = 0x0000, /* No special flags */
+ ccKeepToken = 0x0001 /* Do not skip the current token */
+};
+
+/* Control command table */
+struct CtrlDesc_ {
+ unsigned Flags; /* Flags for this directive */
+ void (*Handler) (void); /* Command handler */
+};
+typedef struct CtrlDesc_ CtrlDesc;
+
+#define PSEUDO_COUNT (sizeof (CtrlCmdTab) / sizeof (CtrlCmdTab [0]))
+static CtrlDesc CtrlCmdTab [] = {
+ { ccNone, DoA16 },
+ { ccNone, DoA8 },
+ { ccNone, DoAddr }, /* .ADDR */
+ { ccNone, DoAlign },
+ { ccNone, DoASCIIZ },
+ { ccNone, DoAutoImport },
+ { ccNone, DoUnexpected }, /* .BLANK */
+ { ccNone, DoBss },
+ { ccNone, DoByte },
+ { ccNone, DoCase },
+ { ccNone, DoCode },
+ { ccNone, DoUnexpected }, /* .CONST */
+ { ccNone, DoUnexpected }, /* .CPU */
+ { ccNone, DoData },
+ { ccNone, DoDByt },
+ { ccNone, DoDebugInfo },
+ { ccNone, DoDefine },
+ { ccNone, DoUnexpected }, /* .DEFINED */
+ { ccNone, DoDWord },
+ { ccKeepToken, DoConditionals }, /* .ELSE */
+ { ccKeepToken, DoConditionals }, /* .ELSEIF */
+ { ccNone, DoEnd },
+ { ccKeepToken, DoConditionals }, /* .ENDIF */
+ { ccNone, DoUnexpected }, /* .ENDMACRO */
+ { ccNone, DoEndProc },
+ { ccNone, DoUnexpected }, /* .ENDREPEAT */
+ { ccNone, DoError },
+ { ccNone, DoExitMacro },
+ { ccNone, DoExport },
+ { ccNone, DoExportZP },
+ { ccNone, DoFarAddr },
+ { ccNone, DoFeature },
+ { ccNone, DoFileOpt },
+ { ccNone, DoGlobal },
+ { ccNone, DoGlobalZP },
+ { ccNone, DoI16 },
+ { ccNone, DoI8 },
+ { ccKeepToken, DoConditionals }, /* .IF */
+ { ccKeepToken, DoConditionals }, /* .IFBLANK */
+ { ccKeepToken, DoConditionals }, /* .IFCONST */
+ { ccKeepToken, DoConditionals }, /* .IFDEF */
+ { ccKeepToken, DoConditionals }, /* .IFNBLANK */
+ { ccKeepToken, DoConditionals }, /* .IFNCONST */
+ { ccKeepToken, DoConditionals }, /* .IFNDEF */
+ { ccKeepToken, DoConditionals }, /* .IFNREF */
+ { ccKeepToken, DoConditionals }, /* .IFP02 */
+ { ccKeepToken, DoConditionals }, /* .IFP816 */
+ { ccKeepToken, DoConditionals }, /* .IFPC02 */
+ { ccKeepToken, DoConditionals }, /* .IFREF */
+ { ccNone, DoImport },
+ { ccNone, DoImportZP },
+ { ccNone, DoIncBin },
+ { ccNone, DoInclude },
+ { ccNone, DoLineCont },
+ { ccNone, DoList },
+ { ccNone, DoListBytes },
+ { ccNone, DoUnexpected }, /* .LOCAL */
+ { ccNone, DoLocalChar },
+ { ccNone, DoMacPack },
+ { ccNone, DoMacro },
+ { ccNone, DoUnexpected }, /* .MATCH */
+ { ccNone, DoNull },
+ { ccNone, DoOrg },
+ { ccNone, DoOut },
+ { ccNone, DoP02 },
+ { ccNone, DoP816 },
+ { ccNone, DoPageLength },
+ { ccNone, DoUnexpected }, /* .PARAMCOUNT */
+ { ccNone, DoPC02 },
+ { ccNone, DoProc },
+ { ccNone, DoUnexpected }, /* .REFERENCED */
+ { ccNone, DoReloc },
+ { ccNone, DoRepeat },
+ { ccNone, DoRes },
+ { ccNone, DoROData },
+ { ccNone, DoSegment },
+ { ccNone, DoSmart },
+ { ccNone, DoUnexpected }, /* .STRING */
+ { ccNone, DoSunPlus },
+ { ccNone, DoWord },
+ { ccNone, DoUnexpected }, /* .XMATCH */
+ { ccNone, DoZeropage },
+};
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+int TokIsPseudo (unsigned Tok)
+/* Return true if the given token is a pseudo instruction token */
+{
+ return (Tok >= TOK_FIRSTPSEUDO && Tok <= TOK_LASTPSEUDO);
+}
+
+
+
+void HandlePseudo (void)
+/* Handle a pseudo instruction */
+{
+ CtrlDesc* D;
+
+ /* Calculate the index into the table */
+ unsigned Index = Tok - TOK_FIRSTPSEUDO;
+
+ /* Safety check */
+ if (PSEUDO_COUNT != (TOK_LASTPSEUDO - TOK_FIRSTPSEUDO + 1)) {
+ Internal ("Pseudo mismatch: PSEUDO_COUNT = %u, actual count = %u\n",
+ PSEUDO_COUNT, TOK_LASTPSEUDO - TOK_FIRSTPSEUDO + 1);
+ }
+ CHECK (Index < PSEUDO_COUNT);
+
+ /* Get the pseudo intruction descriptor */
+ D = &CtrlCmdTab [Index];
+
+ /* Remember the instruction, then skip it if needed */
+ if ((D->Flags & ccKeepToken) == 0) {
+ strcpy (Keyword+1, SVal);
+ NextTok ();
+ }
+
+ /* Call the handler */
+ D->Handler ();
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* pseudo.h */
+/* */
+/* Pseudo instructions for the ca65 macroassembler */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef PSEUDO_H
+#define PSEUDO_H
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Are we inside a .IF condition that has been evaluated to TRUE? */
+extern unsigned char IfCond;
+
+/* How many .IFs are currently open? */
+extern unsigned OpenIfs;
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+int TokIsPseudo (unsigned Tok);
+/* Return true if the given token is a pseudo instruction token */
+
+void HandlePseudo (void);
+/* Handle a pseudo instruction */
+
+
+
+/* End of pseudo.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* scanner.c */
+/* */
+/* The scanner for the ca65 macroassembler */
+/* */
+/* */
+/* */
+/* (C) 1998-2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#include "condasm.h"
+#include "error.h"
+#include "fname.h"
+#include "global.h"
+#include "instr.h"
+#include "listing.h"
+#include "macro.h"
+#include "mem.h"
+#include "objfile.h"
+#include "scanner.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+enum Token Tok = TOK_NONE; /* Current token */
+int WS; /* Flag: Whitespace before token */
+long IVal; /* Integer token attribute */
+char SVal [MAX_STR_LEN+1]; /* String token attribute */
+
+FilePos CurPos = { 0, 0, 0 }; /* Name and position in current file */
+
+
+
+/* Struct to handle include files. Note: The length of the input line may
+ * not exceed 255+1, since the column is stored in the file position struct
+ * as a character. Increasing this value means changing the FilePos struct,
+ * and the read and write routines in the assembler and linker.
+ */
+typedef struct InputFile_ InputFile;
+struct InputFile_ {
+ FILE* F; /* Input file descriptor */
+ FilePos Pos; /* Position in file */
+ enum Token Tok; /* Last token */
+ int C; /* Last character */
+ char Line[256]; /* The current input line */
+ InputFile* Next; /* Linked list of input files */
+};
+
+/* Struct to handle textual input data */
+typedef struct InputData_ InputData;
+struct InputData_ {
+ const char* Data; /* Pointer to the data */
+ const char* Pos; /* Pointer to current position */
+ int Malloced; /* Memory was malloced */
+ enum Token Tok; /* Last token */
+ int C; /* Last character */
+ InputData* Next; /* Linked list of input data */
+};
+
+/* List of input files */
+static struct {
+ unsigned long MTime; /* Time of last modification */
+ unsigned long Size; /* Size of file */
+ const char* Name; /* Name of file */
+} Files [MAX_INPUT_FILES];
+static unsigned FileCount = 0;
+
+/* Current input variables */
+static InputFile* IFile = 0;
+static InputData* IData = 0;
+static unsigned ICount = 0; /* Count of input files */
+static int C = 0;
+
+/* Force end of assembly */
+int ForcedEnd = 0;
+
+/* List of dot keywords with the corresponding tokens */
+struct DotKeyword {
+ const char* Key; /* MUST be first field */
+ enum Token Tok;
+} DotKeywords [] = {
+ { "A16", TOK_A16 },
+ { "A8", TOK_A8 },
+ { "ADDR", TOK_ADDR },
+ { "ALIGN", TOK_ALIGN },
+ { "AND", TOK_BAND },
+ { "ASCIIZ", TOK_ASCIIZ },
+ { "AUTOIMPORT", TOK_AUTOIMPORT },
+ { "BITAND", TOK_AND },
+ { "BITNOT", TOK_NOT },
+ { "BITOR", TOK_OR },
+ { "BITXOR", TOK_XOR },
+ { "BLANK", TOK_BLANK },
+ { "BSS", TOK_BSS },
+ { "BYTE", TOK_BYTE },
+ { "CASE", TOK_CASE },
+ { "CODE", TOK_CODE },
+ { "CONST", TOK_CONST },
+ { "CPU", TOK_CPU },
+ { "DATA", TOK_DATA },
+ { "DBYT", TOK_DBYT },
+ { "DEBUGINFO", TOK_DEBUGINFO },
+ { "DEF", TOK_DEFINED },
+ { "DEFINE", TOK_DEFINE },
+ { "DEFINED", TOK_DEFINED },
+ { "DWORD", TOK_DWORD },
+ { "ELSE", TOK_ELSE },
+ { "ELSEIF", TOK_ELSEIF },
+ { "END", TOK_END },
+ { "ENDIF", TOK_ENDIF },
+ { "ENDMAC", TOK_ENDMACRO },
+ { "ENDMACRO", TOK_ENDMACRO },
+ { "ENDPROC", TOK_ENDPROC },
+ { "ENDREP", TOK_ENDREP },
+ { "ENDREPEAT", TOK_ENDREP },
+ { "ERROR", TOK_ERROR },
+ { "EXITMAC", TOK_EXITMACRO },
+ { "EXITMACRO", TOK_EXITMACRO },
+ { "EXPORT", TOK_EXPORT },
+ { "EXPORTZP", TOK_EXPORTZP },
+ { "FARADDR", TOK_FARADDR },
+ { "FEATURE", TOK_FEATURE },
+ { "FILEOPT", TOK_FILEOPT },
+ { "FOPT", TOK_FILEOPT },
+ { "GLOBAL", TOK_GLOBAL },
+ { "GLOBALZP", TOK_GLOBALZP },
+ { "I16", TOK_I16 },
+ { "I8", TOK_I8 },
+ { "IF", TOK_IF },
+ { "IFBLANK", TOK_IFBLANK },
+ { "IFCONST", TOK_IFCONST },
+ { "IFDEF", TOK_IFDEF },
+ { "IFNBLANK", TOK_IFNBLANK },
+ { "IFNCONST", TOK_IFNCONST },
+ { "IFNDEF", TOK_IFNDEF },
+ { "IFNREF", TOK_IFNREF },
+ { "IFP02", TOK_IFP02 },
+ { "IFP816", TOK_IFP816 },
+ { "IFPC02", TOK_IFPC02 },
+ { "IFREF", TOK_IFREF },
+ { "IMPORT", TOK_IMPORT },
+ { "IMPORTZP", TOK_IMPORTZP },
+ { "INCBIN", TOK_INCBIN },
+ { "INCLUDE", TOK_INCLUDE },
+ { "LINECONT", TOK_LINECONT },
+ { "LIST", TOK_LIST },
+ { "LISTBYTES", TOK_LISTBYTES },
+ { "LOCAL", TOK_LOCAL },
+ { "LOCALCHAR", TOK_LOCALCHAR },
+ { "MAC", TOK_MACRO },
+ { "MACPACK", TOK_MACPACK },
+ { "MACRO", TOK_MACRO },
+ { "MATCH", TOK_MATCH },
+ { "MOD", TOK_MOD },
+ { "NOT", TOK_BNOT },
+ { "NULL", TOK_NULL },
+ { "OR", TOK_BOR },
+ { "ORG", TOK_ORG },
+ { "OUT", TOK_OUT },
+ { "P02", TOK_P02 },
+ { "P816", TOK_P816 },
+ { "PAGELEN", TOK_PAGELENGTH },
+ { "PAGELENGTH", TOK_PAGELENGTH },
+ { "PARAMCOUNT", TOK_PARAMCOUNT },
+ { "PC02", TOK_PC02 },
+ { "PROC", TOK_PROC },
+ { "REF", TOK_REFERENCED },
+ { "REFERENCED", TOK_REFERENCED },
+ { "RELOC", TOK_RELOC },
+ { "REPEAT", TOK_REPEAT },
+ { "RES", TOK_RES },
+ { "RODATA", TOK_RODATA },
+ { "SEGMENT", TOK_SEGMENT },
+ { "SHL", TOK_SHL },
+ { "SHR", TOK_SHR },
+ { "SMART", TOK_SMART },
+ { "STRING", TOK_STRING },
+ { "SUNPLUS", TOK_SUNPLUS },
+ { "WORD", TOK_WORD },
+ { "XMATCH", TOK_XMATCH },
+ { "XOR", TOK_BXOR },
+ { "ZEROPAGE", TOK_ZEROPAGE },
+};
+
+
+
+/*****************************************************************************/
+/* Forwards */
+/*****************************************************************************/
+
+
+
+static void NextChar (void);
+/* Read the next character from the input file */
+
+
+
+/*****************************************************************************/
+/* Character classification functions */
+/*****************************************************************************/
+
+
+
+static int IsBlank (int C)
+/* Return true if the character is a blank or tab */
+{
+ return (C == ' ' || C == '\t');
+}
+
+
+
+static int IsDigit (int C)
+/* Return true if the character is a digit */
+{
+ return isdigit (C);
+}
+
+
+
+static int IsXDigit (int C)
+/* Return true if the character is a hexadecimal digit */
+{
+ return isxdigit (C);
+}
+
+
+
+static int IsDDigit (int C)
+/* Return true if the character is a dual digit */
+{
+ return (C == '0' || C == '1');
+}
+
+
+
+static int IsIdChar (int C)
+/* Return true if the character is a valid character for an identifier */
+{
+ return isalnum (C) ||
+ (C == '_') ||
+ (C == '@' && AtInIdents) ||
+ (C == '$' && DollarInIdents);
+}
+
+
+
+static int IsIdStart (int C)
+/* Return true if the character may start an identifier */
+{
+ return isalpha (C) || C == '_';
+}
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+const char* GetFileName (unsigned char Name)
+/* Get the name of a file where the name index is known */
+{
+ PRECONDITION (Name <= FileCount);
+ if (Name == 0) {
+ /* Name was defined outside any file scope, use the name of the first
+ * file instead. Errors are then reported with a file position of
+ * line zero in the first file.
+ */
+ if (FileCount == 0) {
+ /* No files defined until now */
+ return "(outside file scope)";
+ } else {
+ return Files [0].Name;
+ }
+ } else {
+ return Files [Name-1].Name;
+ }
+}
+
+
+
+void NewInputFile (const char* Name)
+/* Open a new input file */
+{
+ InputFile* I;
+ FILE* F;
+
+ /* Insert a copy of the filename into the list */
+ if (FileCount >= MAX_INPUT_FILES) {
+ Fatal (FAT_MAX_INPUT_FILES);
+ }
+ Files [FileCount].Name = StrDup (Name);
+
+ /* First try to open the file */
+ F = fopen (Name, "r");
+ if (F == 0) {
+
+ /* Error (fatal error if this is the main file) */
+ if (ICount == 0) {
+ Fatal (FAT_CANNOT_OPEN_INPUT, Name, strerror (errno));
+ } else {
+ Error (ERR_CANNOT_OPEN_INCLUDE, Name, strerror (errno));
+ Xfree (Files [FileCount].Name);
+ }
+
+ } else {
+
+ /* Stat the file and remember the values */
+ struct stat Buf;
+ if (fstat (fileno (F), &Buf) != 0) {
+ Fatal (FAT_CANNOT_STAT_INPUT, Name, strerror (errno));
+ }
+ Files [FileCount].MTime = Buf.st_mtime;
+ Files [FileCount].Size = Buf.st_size;
+ ++FileCount;
+
+ /* Create a new state variable and initialize it */
+ I = Xmalloc (sizeof (*I));
+ I->F = F;
+ I->Pos.Line = 0;
+ I->Pos.Col = 0;
+ I->Pos.Name = FileCount;
+ I->Tok = Tok;
+ I->C = C;
+ I->Line[0] = '\0';
+
+ /* Use the new file */
+ I->Next = IFile;
+ IFile = I;
+ ++ICount;
+
+ /* Prime the pump */
+ NextChar ();
+ }
+}
+
+
+
+void DoneInputFile (void)
+/* Close the current input file */
+{
+ InputFile* I;
+
+ /* Restore the old token */
+ Tok = IFile->Tok;
+ C = IFile->C;
+
+ /* Save a pointer to the current struct, then set it back */
+ I = IFile;
+ IFile = I->Next;
+
+ /* Cleanup the current stuff */
+ fclose (I->F);
+ Xfree (I);
+ --ICount;
+}
+
+
+
+void NewInputData (const char* Data, int Malloced)
+/* Add a chunk of input data to the input stream */
+{
+ InputData* I;
+
+ /* Create a new state variable and initialize it */
+ I = Xmalloc (sizeof (*I));
+ I->Data = Data;
+ I->Pos = Data;
+ I->Malloced = Malloced;
+ I->Tok = Tok;
+ I->C = C;
+
+ /* Use the new data */
+ I->Next = IData;
+ IData = I;
+
+ /* Prime the pump */
+ NextChar ();
+}
+
+
+
+static void DoneInputData (void)
+/* End the current input data stream */
+{
+ InputData* I;
+
+ /* Restore the old token */
+ Tok = IData->Tok;
+ C = IData->C;
+
+ /* Save a pointer to the current struct, then set it back */
+ I = IData;
+ IData = I->Next;
+
+ /* Cleanup the current stuff */
+ if (I->Malloced) {
+ Xfree (I->Data);
+ }
+ Xfree (I);
+}
+
+
+
+static unsigned DigitVal (unsigned char C)
+/* Convert a digit into it's numerical representation */
+{
+ if (IsDigit (C)) {
+ return C - '0';
+ } else {
+ return toupper (C) - 'A' + 10;
+ }
+}
+
+
+
+static void NextChar (void)
+/* Read the next character from the input file */
+{
+ /* If we have an input data structure, read from there */
+ if (IData) {
+
+ C = *IData->Pos++;
+ if (C == '\0') {
+ /* End of input data, will set to last file char */
+ DoneInputData ();
+ }
+
+ } else {
+
+ /* Check for end of line, read the next line if needed */
+ while (IFile->Line [IFile->Pos.Col] == '\0') {
+
+ /* End of current line reached, read next line */
+ if (fgets (IFile->Line, sizeof (IFile->Line), IFile->F) == 0) {
+ /* End of file. Add an empty line to the listing. This is a
+ * small hack needed to keep the PC output in sync.
+ */
+ NewListingLine ("", IFile->Pos.Name, ICount);
+ C = EOF;
+ return;
+ }
+
+ /* One more line */
+ IFile->Pos.Line++;
+ IFile->Pos.Col = 0;
+
+ /* Remember the new line for the listing */
+ NewListingLine (IFile->Line, IFile->Pos.Name, ICount);
+
+ }
+
+ /* Return the next character from the file */
+ C = IFile->Line [IFile->Pos.Col++];
+
+ }
+}
+
+
+
+void UpcaseSVal (void)
+/* Make SVal upper case */
+{
+ unsigned I = 0;
+ while (SVal [I]) {
+ SVal [I] = toupper (SVal [I]);
+ ++I;
+ }
+}
+
+
+
+static int CmpDotKeyword (const void* K1, const void* K2)
+/* Compare function for the dot keyword search */
+{
+ return strcmp (((struct DotKeyword*)K1)->Key, ((struct DotKeyword*)K2)->Key);
+}
+
+
+
+static unsigned char FindDotKeyword (void)
+/* Find the dot keyword in SVal. Return the corresponding token if found,
+ * return TOK_NONE if not found.
+ */
+{
+ static const struct DotKeyword K = { SVal, 0 };
+ struct DotKeyword* R;
+
+ /* If we aren't in ignore case mode, we have to uppercase the keyword */
+ if (!IgnoreCase) {
+ UpcaseSVal ();
+ }
+
+ /* Search for the keyword */
+ R = bsearch (&K, DotKeywords, sizeof (DotKeywords) / sizeof (DotKeywords [0]),
+ sizeof (DotKeywords [0]), CmpDotKeyword);
+ if (R != 0) {
+ return R->Tok;
+ } else {
+ return TOK_NONE;
+ }
+}
+
+
+
+static void ReadIdent (void)
+/* Read an identifier from the current input position into Ident. It is
+ * assumed that the first character has already been checked.
+ */
+{
+ /* Read the identifier */
+ unsigned I = 0;
+ do {
+ if (I < MAX_STR_LEN) {
+ SVal [I++] = C;
+ }
+ NextChar ();
+ } while (IsIdChar (C));
+ SVal [I] = '\0';
+
+ /* If we should ignore case, convert the identifier to upper case */
+ if (IgnoreCase) {
+ UpcaseSVal ();
+ }
+}
+
+
+
+static unsigned ReadStringConst (int StringTerm)
+/* Read a string constant into SVal. Check for maximum string length and all
+ * other stuff. The length of the string is returned.
+ */
+{
+ unsigned I;
+
+ /* Skip the leading string terminator */
+ NextChar ();
+
+ /* Read the string */
+ I = 0;
+ while (1) {
+ if (C == StringTerm) {
+ break;
+ }
+ if (C == '\n' || C == EOF) {
+ Error (ERR_NEWLINE_IN_STRING);
+ break;
+ }
+
+ /* Check for string length, print an error message once */
+ if (I == MAX_STR_LEN) {
+ Error (ERR_STRING_TOO_LONG);
+ } else if (I < MAX_STR_LEN) {
+ SVal [I] = C;
+ }
+ ++I;
+
+ /* Skip the character */
+ NextChar ();
+ }
+
+ /* Skip the trailing terminator */
+ NextChar ();
+
+ /* Terminate the string */
+ if (I >= MAX_STR_LEN) {
+ I = MAX_STR_LEN;
+ }
+ SVal [I] = '\0';
+
+ /* Return the length of the string */
+ return I;
+}
+
+
+
+void NextTok (void)
+/* Read the next raw token from the input stream */
+{
+ /* If we've a forced end of assembly, don't read further */
+ if (ForcedEnd) {
+ Tok = TOK_EOF;
+ return;
+ }
+
+ /* If we're expanding a macro, the tokens come from the macro expansion */
+ if (MacExpand ()) {
+ return;
+ }
+
+Again:
+ /* Skip whitespace, remember if we had some */
+ if ((WS = IsBlank (C)) != 0) {
+ do {
+ NextChar ();
+ } while (IsBlank (C));
+ }
+
+ /* If we're reading from the file, update the location from where the
+ * next token will be read. If we're reading from input data, keep the
+ * current position.
+ */
+ if (IData == 0) {
+ CurPos = IFile->Pos;
+ }
+
+ /* Hex number or PC symbol? */
+ if (C == '$') {
+ NextChar ();
+
+ /* Hex digit must follow or DollarIsPC must be enabled */
+ if (!IsXDigit (C)) {
+ if (DollarIsPC) {
+ Tok = TOK_PC;
+ return;
+ } else {
+ Error (ERR_HEX_DIGIT_EXPECTED);
+ }
+ }
+
+ /* Read the number */
+ IVal = 0;
+ while (IsXDigit (C)) {
+ if (IVal & 0xF0000000) {
+ Error (ERR_NUM_OVERFLOW);
+ IVal = 0;
+ }
+ IVal = (IVal << 4) + DigitVal (C);
+ NextChar ();
+ }
+
+ /* This is an integer constant */
+ Tok = TOK_INTCON;
+ return;
+ }
+
+ /* Dual number? */
+ if (C == '%') {
+ NextChar ();
+
+ /* 0 or 1 must follow */
+ if (!IsDDigit (C)) {
+ Error (ERR_01_EXPECTED);
+ }
+
+ /* Read the number */
+ IVal = 0;
+ while (IsDDigit (C)) {
+ if (IVal & 0x80000000) {
+ Error (ERR_NUM_OVERFLOW);
+ IVal = 0;
+ }
+ IVal = (IVal << 1) + DigitVal (C);
+ NextChar ();
+ }
+
+ /* This is an integer constant */
+ Tok = TOK_INTCON;
+ return;
+ }
+
+ /* Decimal number? */
+ if (IsDigit (C)) {
+
+ /* Read the number */
+ IVal = 0;
+ while (IsDigit (C)) {
+ if (IVal > (0xFFFFFFFF / 10)) {
+ Error (ERR_NUM_OVERFLOW);
+ IVal = 0;
+ }
+ IVal = (IVal * 10) + DigitVal (C);
+ NextChar ();
+ }
+
+ /* This is an integer constant */
+ Tok = TOK_INTCON;
+ return;
+ }
+
+ /* Control command? */
+ if (C == '.') {
+
+ NextChar ();
+
+ if (!IsIdStart (C)) {
+ Error (ERR_PSEUDO_EXPECTED);
+ /* Try to read an identifier */
+ goto Again;
+ }
+
+ /* Read the identifier */
+ ReadIdent ();
+
+ /* Search the keyword */
+ Tok = FindDotKeyword ();
+ if (Tok == TOK_NONE) {
+ /* Not found */
+ Error (ERR_PSEUDO_EXPECTED);
+ goto Again;
+ }
+ return;
+ }
+
+ /* Local symbol? */
+ if (C == LocalStart) {
+
+ /* Read the identifier */
+ ReadIdent ();
+
+ /* Start character alone is not enough */
+ if (SVal [1] == '\0') {
+ Error (ERR_IDENT_EXPECTED);
+ goto Again;
+ }
+
+ /* An identifier */
+ Tok = TOK_IDENT;
+ return;
+ }
+
+
+ /* Identifier or keyword? */
+ if (IsIdStart (C)) {
+
+ /* Read the identifier */
+ ReadIdent ();
+
+ /* Check for special names */
+ if (SVal [1] == '\0') {
+ switch (toupper (SVal [0])) {
+
+ case 'A':
+ Tok = TOK_A;
+ return;
+
+ case 'X':
+ Tok = TOK_X;
+ return;
+
+ case 'Y':
+ Tok = TOK_Y;
+ return;
+
+ case 'S':
+ Tok = TOK_S;
+ return;
+
+ default:
+ Tok = TOK_IDENT;
+ return;
+ }
+ }
+
+ /* Search for an opcode */
+ IVal = FindInstruction (SVal);
+ if (IVal >= 0) {
+ /* This is a mnemonic */
+ Tok = TOK_MNEMO;
+ } else if (IsDefine (SVal)) {
+ /* This is a define style macro - expand it */
+ MacExpandStart ();
+ if (!MacExpand ()) {
+ goto Again;
+ }
+ } else {
+ /* An identifier */
+ Tok = TOK_IDENT;
+ }
+ return;
+ }
+
+ /* Ok, let's do the switch */
+CharAgain:
+ switch (C) {
+
+ case '+':
+ NextChar ();
+ Tok = TOK_PLUS;
+ return;
+
+ case '-':
+ NextChar ();
+ Tok = TOK_MINUS;
+ return;
+
+ case '/':
+ NextChar ();
+ Tok = TOK_DIV;
+ return;
+
+ case '*':
+ NextChar ();
+ Tok = TOK_MUL;
+ return;
+
+ case '^':
+ NextChar ();
+ Tok = TOK_XOR;
+ return;
+
+ case '&':
+ NextChar ();
+ if (C == '&') {
+ NextChar ();
+ Tok = TOK_BAND;
+ } else {
+ Tok = TOK_AND;
+ }
+ return;
+
+ case '|':
+ NextChar ();
+ if (C == '|') {
+ NextChar ();
+ Tok = TOK_BOR;
+ } else {
+ Tok = TOK_OR;
+ }
+ return;
+
+ case ':':
+ NextChar ();
+ switch (C) {
+
+ case ':':
+ NextChar ();
+ Tok = TOK_NAMESPACE;
+ break;
+
+ case '-':
+ IVal = 0;
+ do {
+ --IVal;
+ NextChar ();
+ } while (C == '-');
+ Tok = TOK_ULABEL;
+ break;
+
+ case '+':
+ IVal = 0;
+ do {
+ ++IVal;
+ NextChar ();
+ } while (C == '+');
+ Tok = TOK_ULABEL;
+ break;
+
+ default:
+ Tok = TOK_COLON;
+ break;
+ }
+ return;
+
+ case ',':
+ NextChar ();
+ Tok = TOK_COMMA;
+ return;
+
+ case ';':
+ NextChar ();
+ while (C != '\n' && C != EOF) {
+ NextChar ();
+ }
+ goto CharAgain;
+
+ case '#':
+ NextChar ();
+ Tok = TOK_HASH;
+ return;
+
+ case '(':
+ NextChar ();
+ Tok = TOK_LPAREN;
+ return;
+
+ case ')':
+ NextChar ();
+ Tok = TOK_RPAREN;
+ return;
+
+ case '[':
+ NextChar ();
+ Tok = TOK_LBRACK;
+ return;
+
+ case ']':
+ NextChar ();
+ Tok = TOK_RBRACK;
+ return;
+
+ case '<':
+ NextChar ();
+ if (C == '=') {
+ NextChar ();
+ Tok = TOK_LE;
+ } else if (C == '<') {
+ NextChar ();
+ Tok = TOK_SHL;
+ } else if (C == '>') {
+ NextChar ();
+ Tok = TOK_NE;
+ } else {
+ Tok = TOK_LT;
+ }
+ return;
+
+ case '=':
+ NextChar ();
+ Tok = TOK_EQ;
+ return;
+
+ case '!':
+ NextChar ();
+ Tok = TOK_BNOT;
+ return;
+
+ case '>':
+ NextChar ();
+ if (C == '=') {
+ NextChar ();
+ Tok = TOK_GE;
+ } else if (C == '>') {
+ NextChar ();
+ Tok = TOK_SHR;
+ } else {
+ Tok = TOK_GT;
+ }
+ return;
+
+ case '~':
+ NextChar ();
+ Tok = TOK_NOT;
+ return;
+
+ case '\'':
+ /* Hack: If we allow ' as terminating character for strings, read
+ * the following stuff as a string, and check for a one character
+ * string later.
+ */
+ if (LooseStringTerm) {
+ if (ReadStringConst ('\'') == 1) {
+ IVal = SVal[0];
+ Tok = TOK_CHARCON;
+ } else {
+ Tok = TOK_STRCON;
+ }
+ } else {
+ /* Always a character constant */
+ NextChar ();
+ if (C == '\n' || C == EOF) {
+ Error (ERR_ILLEGAL_CHARCON);
+ goto CharAgain;
+ }
+ IVal = C;
+ Tok = TOK_CHARCON;
+ NextChar ();
+ if (C != '\'') {
+ Error (ERR_ILLEGAL_CHARCON);
+ } else {
+ NextChar ();
+ }
+ }
+ return;
+
+ case '\"':
+ ReadStringConst ('\"');
+ Tok = TOK_STRCON;
+ return;
+
+ case '\\':
+ /* Line continuation? */
+ if (LineCont) {
+ NextChar ();
+ if (C == '\n') {
+ /* Handle as white space */
+ NextChar ();
+ C = ' ';
+ goto Again;
+ }
+ }
+ break;
+
+ case '\n':
+ NextChar ();
+ Tok = TOK_SEP;
+ return;
+
+ case EOF:
+ /* Check if we have any open .IFs in this file */
+ CheckOpenIfs ();
+
+ /* If this was an include file, then close it and handle like a
+ * separator. Do not close the main file, but return EOF.
+ */
+ if (ICount > 1) {
+ DoneInputFile ();
+ } else {
+ Tok = TOK_EOF;
+ }
+ return;
+
+ }
+
+ /* If we go here, we could not identify the current character. Skip it
+ * and try again.
+ */
+ Error (ERR_INVALID_CHAR, C & 0xFF);
+ NextChar ();
+ goto Again;
+}
+
+
+
+void Consume (enum Token Expected, unsigned ErrMsg)
+/* Consume Expected, print an error if we don't find it */
+{
+ if (Tok == Expected) {
+ NextTok ();
+ } else {
+ Error (ErrMsg);
+ }
+}
+
+
+
+void ConsumeSep (void)
+/* Consume a separator token */
+{
+ /* Accept an EOF as separator */
+ if (Tok != TOK_EOF) {
+ if (Tok != TOK_SEP) {
+ Error (ERR_TOO_MANY_CHARS);
+ SkipUntilSep ();
+ } else {
+ NextTok ();
+ }
+ }
+}
+
+
+
+void ConsumeLParen (void)
+/* Consume a left paren */
+{
+ Consume (TOK_LPAREN, ERR_LPAREN_EXPECTED);
+}
+
+
+
+void ConsumeRParen (void)
+/* Consume a right paren */
+{
+ Consume (TOK_RPAREN, ERR_RPAREN_EXPECTED);
+}
+
+
+
+void ConsumeComma (void)
+/* Consume a comma */
+{
+ Consume (TOK_COMMA, ERR_COMMA_EXPECTED);
+}
+
+
+
+void SkipUntilSep (void)
+/* Skip tokens until we reach a line separator */
+{
+ while (Tok != TOK_SEP && Tok != TOK_EOF) {
+ NextTok ();
+ }
+}
+
+
+
+int TokHasSVal (enum Token Tok)
+/* Return true if the given token has an attached SVal */
+{
+ return (Tok == TOK_IDENT || Tok == TOK_STRCON);
+}
+
+
+
+int TokHasIVal (enum Token Tok)
+/* Return true if the given token has an attached IVal */
+{
+ return (Tok == TOK_INTCON || Tok == TOK_CHARCON || Tok == TOK_MNEMO);
+}
+
+
+
+int GetSubKey (const char** Keys, unsigned Count)
+/* Search for a subkey in a table of keywords. The current token must be an
+ * identifier and all keys must be in upper case. The identifier will be
+ * uppercased in the process. The function returns the index of the keyword,
+ * or -1 if the keyword was not found.
+ */
+{
+ unsigned I;
+
+ /* Must have an identifier */
+ PRECONDITION (Tok == TOK_IDENT);
+
+ /* If we aren't in ignore case mode, we have to uppercase the identifier */
+ if (!IgnoreCase) {
+ UpcaseSVal ();
+ }
+
+ /* Do a linear search (a binary search is not worth the effort) */
+ for (I = 0; I < Count; ++I) {
+ if (strcmp (SVal, Keys [I]) == 0) {
+ /* Found it */
+ return I;
+ }
+ }
+
+ /* Not found */
+ return -1;
+}
+
+
+
+void WriteFiles (void)
+/* Write the list of input files to the object file */
+{
+ unsigned I;
+
+ /* Tell the obj file module that we're about to start the file list */
+ ObjStartFiles ();
+
+ /* Write the file count */
+ ObjWrite8 (FileCount);
+
+ /* Write the file data */
+ for (I = 0; I < FileCount; ++I) {
+ ObjWrite32 (Files [I].MTime);
+ ObjWrite32 (Files [I].Size);
+ ObjWriteStr (Files [I].Name);
+ }
+
+ /* Done writing files */
+ ObjEndFiles ();
+}
+
+
+
+void InitScanner (const char* InFile)
+/* Initialize the scanner, open the given input file */
+{
+ /* Open the input file */
+ NewInputFile (InFile);
+}
+
+
+
+void DoneScanner (void)
+/* Release scanner resources */
+{
+ DoneInputFile ();
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* scanner.h */
+/* */
+/* The scanner for the ca65 macroassembler */
+/* */
+/* */
+/* */
+/* (C) 1998-2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef SCANNER_H
+#define SCANNER_H
+
+
+
+#include "../common/filepos.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Tokens */
+enum Token {
+ TOK_NONE, /* Start value, invalid */
+ TOK_EOF, /* End of input file */
+ TOK_SEP, /* Separator (usually newline) */
+ TOK_IDENT, /* An identifier */
+ TOK_MNEMO, /* A mnemonic */
+
+ TOK_INTCON, /* Integer constant */
+ TOK_CHARCON, /* Character constant */
+ TOK_STRCON, /* String constant */
+
+ TOK_A, /* A)ccu */
+ TOK_X, /* X register */
+ TOK_Y, /* Y register */
+ TOK_S, /* S register */
+
+ TOK_ULABEL, /* :++ or :-- */
+
+ TOK_EQ, /* = */
+ TOK_NE, /* <> */
+ TOK_LT, /* < */
+ TOK_GT, /* > */
+ TOK_LE, /* <= */
+ TOK_GE, /* >= */
+
+ TOK_BAND, /* .and */
+ TOK_BOR, /* .or */
+ TOK_BXOR, /* .xor */
+ TOK_BNOT, /* .not */
+
+ TOK_PLUS, /* + */
+ TOK_MINUS, /* - */
+ TOK_MUL, /* * */
+ TOK_STAR = TOK_MUL, /* Alias */
+ TOK_DIV, /* / */
+ TOK_MOD, /* ! */
+ TOK_OR, /* | */
+ TOK_XOR, /* ^ */
+ TOK_AND, /* & */
+ TOK_SHL, /* << */
+ TOK_SHR, /* >> */
+ TOK_NOT, /* ~ */
+
+ TOK_PC, /* $ if enabled */
+ TOK_NAMESPACE, /* :: */
+ TOK_DOT, /* . */
+ TOK_COMMA, /* , */
+ TOK_HASH, /* # */
+ TOK_COLON, /* : */
+ TOK_LPAREN, /* ( */
+ TOK_RPAREN, /* ) */
+ TOK_LBRACK, /* [ */
+ TOK_RBRACK, /* ] */
+
+ TOK_MACPARAM, /* Macro parameter, not generated by scanner */
+
+ /* The next ones are tokens for the pseudo instructions. Keep together! */
+ TOK_FIRSTPSEUDO,
+ TOK_A16 = TOK_FIRSTPSEUDO,
+ TOK_A8,
+ TOK_ADDR,
+ TOK_ALIGN,
+ TOK_ASCIIZ,
+ TOK_AUTOIMPORT,
+ TOK_BLANK,
+ TOK_BSS,
+ TOK_BYTE,
+ TOK_CASE,
+ TOK_CODE,
+ TOK_CONST,
+ TOK_CPU,
+ TOK_DATA,
+ TOK_DBYT,
+ TOK_DEBUGINFO,
+ TOK_DEFINE,
+ TOK_DEFINED,
+ TOK_DWORD,
+ TOK_ELSE,
+ TOK_ELSEIF,
+ TOK_END,
+ TOK_ENDIF,
+ TOK_ENDMACRO,
+ TOK_ENDPROC,
+ TOK_ENDREP,
+ TOK_ERROR,
+ TOK_EXITMACRO,
+ TOK_EXPORT,
+ TOK_EXPORTZP,
+ TOK_FARADDR,
+ TOK_FEATURE,
+ TOK_FILEOPT,
+ TOK_GLOBAL,
+ TOK_GLOBALZP,
+ TOK_I16,
+ TOK_I8,
+ TOK_IF,
+ TOK_IFBLANK,
+ TOK_IFCONST,
+ TOK_IFDEF,
+ TOK_IFNBLANK,
+ TOK_IFNCONST,
+ TOK_IFNDEF,
+ TOK_IFNREF,
+ TOK_IFP02,
+ TOK_IFP816,
+ TOK_IFPC02,
+ TOK_IFREF,
+ TOK_IMPORT,
+ TOK_IMPORTZP,
+ TOK_INCBIN,
+ TOK_INCLUDE,
+ TOK_LINECONT,
+ TOK_LIST,
+ TOK_LISTBYTES,
+ TOK_LOCAL,
+ TOK_LOCALCHAR,
+ TOK_MACPACK,
+ TOK_MACRO,
+ TOK_MATCH,
+ TOK_NULL,
+ TOK_ORG,
+ TOK_OUT,
+ TOK_P02,
+ TOK_P816,
+ TOK_PAGELENGTH,
+ TOK_PARAMCOUNT,
+ TOK_PC02,
+ TOK_PROC,
+ TOK_REFERENCED,
+ TOK_RELOC,
+ TOK_REPEAT,
+ TOK_RES,
+ TOK_RODATA,
+ TOK_SEGMENT,
+ TOK_SMART,
+ TOK_STRING,
+ TOK_SUNPLUS,
+ TOK_WORD,
+ TOK_XMATCH,
+ TOK_ZEROPAGE,
+ TOK_LASTPSEUDO = TOK_ZEROPAGE,
+
+ TOK_COUNT /* Count of tokens */
+};
+
+
+
+/* Scanner variables */
+#define MAX_INPUT_FILES 254 /* No more than this files total */
+#define MAX_STR_LEN 255 /* Maximum length of any string */
+extern enum Token Tok; /* Current token */
+extern int WS; /* Flag: Whitespace before token */
+extern long IVal; /* Integer token attribute */
+extern char SVal [MAX_STR_LEN+1]; /* String token attribute */
+
+extern FilePos CurPos; /* Name and position in file */
+extern int ForcedEnd; /* Force end of assembly */
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+const char* GetFileName (unsigned char Name);
+/* Get the name of a file where the name index is known */
+
+void NewInputFile (const char* Name);
+/* Open a new input file */
+
+void DoneInputFile (void);
+/* Close the current input file */
+
+void NewInputData (const char* Data, int Malloced);
+/* Add a chunk of input data to the input stream */
+
+void UpcaseSVal (void);
+/* Make SVal upper case */
+
+void NextTok (void);
+/* Read the next token from the input stream */
+
+void Consume (enum Token Expected, unsigned ErrMsg);
+/* Consume Token, print an error if we don't find it */
+
+void ConsumeSep (void);
+/* Consume a separator token */
+
+void ConsumeLParen (void);
+/* Consume a left paren */
+
+void ConsumeRParen (void);
+/* Consume a right paren */
+
+void ConsumeComma (void);
+/* Consume a comma */
+
+void SkipUntilSep (void);
+/* Skip tokens until we reach a line separator */
+
+int TokHasSVal (enum Token Tok);
+/* Return true if the given token has an attached SVal */
+
+int TokHasIVal (enum Token Tok);
+/* Return true if the given token has an attached IVal */
+
+int GetSubKey (const char** Keys, unsigned Count);
+/* Search for a subkey in a table of keywords. The current token must be an
+ * identifier and all keys must be in upper case. The identifier will be
+ * uppercased in the process. The function returns the index of the keyword,
+ * or -1 if the keyword was not found.
+ */
+
+void WriteFiles (void);
+/* Write the list of input files to the object file */
+
+void InitScanner (const char* InFile);
+/* Initialize the scanner, open the given input file */
+
+void DoneScanner (void);
+/* Release scanner resources */
+
+
+
+/* End of scanner.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* strexpr.c */
+/* */
+/* String expressions for the ca65 macroassembler */
+/* */
+/* */
+/* */
+/* (C) 2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+
+#include "error.h"
+#include "expr.h"
+#include "scanner.h"
+#include "strexpr.h"
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+const char* StringExpression (void)
+/* Evaluate a string expression. If there are no errors, the function will
+ * place the string into the token attribute buffer SVal and the token will
+ * be TOK_STRCON. A pointer to the buffer is returned.
+ * If there was an error, a NULL pointer is returned.
+ */
+{
+ char Buf [sizeof (SVal)];
+
+ /* Check for a string constant or a function that returns a string */
+ switch (Tok) {
+
+ case TOK_STRING:
+ NextTok ();
+ ConsumeLParen ();
+ if (Tok == TOK_IDENT) {
+ /* Save the identifier, then skip it */
+ strcpy (Buf, SVal);
+ NextTok ();
+ } else {
+ /* Numeric expression */
+ long Val = ConstExpression ();
+ sprintf (Buf, "%ld", Val);
+ }
+ if (Tok != TOK_RPAREN) {
+ Error (ERR_RPAREN_EXPECTED);
+ }
+ /* Overwrite the token, do not skip it! */
+ strcpy (SVal, Buf);
+ Tok = TOK_STRCON;
+ break;
+
+ case TOK_STRCON:
+ /* We already have a string */
+ break;
+
+ default:
+ /* Error - no string constant */
+ return 0;
+ }
+
+ /* Return a pointer to the buffer */
+ return SVal;
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* strexpr.h */
+/* */
+/* String expressions for the ca65 macroassembler */
+/* */
+/* */
+/* */
+/* (C) 2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef STREXPR_H
+#define STREXPR_H
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+const char* StringExpression (void);
+/* Evaluate a string expression. If there are no errors, the function will
+ * place the string into the token attribute buffer SVal and the token will
+ * be TOK_STRCON. A pointer to the buffer is returned.
+ * If there was an error, a NULL pointer is returned.
+ */
+
+
+
+/* End of strexpr.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* symentry.h */
+/* */
+/* Symbol table entry forward for the ca65 macroassembler */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef SYMENTRY_H
+#define SYMENTRY_H
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Forward declaration for struct SymEntry */
+typedef struct SymEntry_ SymEntry;
+
+
+
+/* End of symentry.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* symtab.c */
+/* */
+/* Symbol table for the ca65 macroassembler */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <string.h>
+
+#include "../common/symdefs.h"
+#include "../common/hashstr.h"
+
+#include "global.h"
+#include "error.h"
+#include "mem.h"
+#include "expr.h"
+#include "objfile.h"
+#include "symtab.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Bits for the Flags value in SymEntry */
+#define SF_USER 0x0001 /* User bit */
+#define SF_TRAMPOLINE 0x0002 /* Trampoline entry */
+#define SF_EXPORT 0x0004 /* Export this symbol */
+#define SF_IMPORT 0x0008 /* Import this symbol */
+#define SF_GLOBAL 0x0010 /* Global symbol */
+#define SF_ZP 0x0020 /* Declared as zeropage symbol */
+#define SF_ABS 0x0040 /* Declared as absolute symbol */
+#define SF_INDEXED 0x0800 /* Index is valid */
+#define SF_CONST 0x1000 /* The symbol has a constant value */
+#define SF_MULTDEF 0x2000 /* Multiply defined symbol */
+#define SF_DEFINED 0x4000 /* Defined */
+#define SF_REFERENCED 0x8000 /* Referenced */
+
+/* Combined stuff */
+#define SF_UNDEFMASK (SF_REFERENCED | SF_DEFINED | SF_IMPORT)
+#define SF_UNDEFVAL (SF_REFERENCED)
+#define SF_IMPMASK (SF_TRAMPOLINE | SF_IMPORT | SF_REFERENCED)
+#define SF_IMPVAL (SF_IMPORT | SF_REFERENCED)
+#define SF_EXPMASK (SF_TRAMPOLINE | SF_EXPORT)
+#define SF_EXPVAL (SF_EXPORT)
+#define SF_DBGINFOMASK (SF_TRAMPOLINE | SF_DEFINED | SF_EXPORT | SF_IMPORT)
+#define SF_DBGINFOVAL (SF_DEFINED)
+
+
+
+/* Structure of a symbol table entry */
+struct SymEntry_ {
+ SymEntry* Left; /* Lexically smaller entry */
+ SymEntry* Right; /* Lexically larger entry */
+ SymEntry* List; /* List of all entries */
+ SymEntry* Locals; /* Root of subtree for local symbols */
+ struct SymTable_* SymTab; /* Table this symbol is in, 0 for locals */
+ FilePos Pos; /* File position for this symbol */
+ unsigned Flags; /* Symbol flags */
+ unsigned Index; /* Index of import/export entries */
+ union {
+ struct ExprNode_* Expr; /* Expression if CONST not set */
+ long Val; /* Value (if CONST set) */
+ SymEntry* Sym; /* Symbol (if trampoline entry) */
+ } V;
+ char Name [1]; /* Dynamic allocation */
+};
+
+
+
+/* Definitions for the hash table */
+#define MAIN_HASHTAB_SIZE 213
+#define SUB_HASHTAB_SIZE 53
+typedef struct SymTable_ SymTable;
+struct SymTable_ {
+ unsigned TableSlots; /* Number of hash table slots */
+ unsigned TableEntries; /* Number of entries in the table */
+ SymTable* BackLink; /* Link to enclosing scope if any */
+ SymEntry* Table [1]; /* Dynamic allocation */
+};
+
+
+
+/* Symbol table variables */
+static SymEntry* SymList = 0; /* List of all symbol table entries */
+static SymEntry* SymLast = 0; /* Pointer to last defined symbol */
+static SymTable* SymTab = 0; /* Pointer to current symbol table */
+static SymTable* RootTab = 0; /* Root symbol table */
+static unsigned ImportCount = 0;/* Counter for import symbols */
+static unsigned ExportCount = 0;/* Counter for export symbols */
+
+
+
+/*****************************************************************************/
+/* Internally used functions */
+/*****************************************************************************/
+
+
+
+static int IsLocal (const char* Name)
+/* Return true if Name is the name of a local symbol */
+{
+ return (*Name == LocalStart);
+}
+
+
+
+static SymEntry* NewSymEntry (const char* Name)
+/* Allocate a symbol table entry, initialize and return it */
+{
+ SymEntry* S;
+ unsigned Len;
+
+ /* Get the length of the name */
+ Len = strlen (Name);
+
+ /* Allocate memory */
+ S = Xmalloc (sizeof (SymEntry) + Len);
+
+ /* Initialize the entry */
+ S->Left = 0;
+ S->Right = 0;
+ S->Locals = 0;
+ S->SymTab = 0;
+ S->Flags = 0;
+ S->V.Expr = 0;
+ S->Pos = CurPos;
+ memcpy (S->Name, Name, Len+1);
+
+ /* Insert it into the list of all entries */
+ S->List = SymList;
+ SymList = S;
+
+ /* Return the initialized entry */
+ return S;
+}
+
+
+
+static SymTable* NewSymTable (unsigned Size)
+/* Allocate a symbol table on the heap and return it */
+{
+ SymTable* S;
+
+ /* Allocate memory */
+ S = Xmalloc (sizeof (SymTable) + (Size-1) * sizeof (SymEntry*));
+
+ /* Set variables and clear hash table entries */
+ S->TableSlots = Size;
+ S->TableEntries = 0;
+ S->BackLink = 0;
+ while (Size--) {
+ S->Table [Size] = 0;
+ }
+
+ /* Return the prepared struct */
+ return S;
+}
+
+
+
+static int SearchSymTab (SymEntry* T, const char* Name, SymEntry** E)
+/* Search in the given table for a name (Hash is the hash value of Name and
+ * is given as parameter so that it will not get calculated twice if we search
+ * in more than one table). If we find the symbol, the function will return 0
+ * and put the entry pointer into E. If we did not find the symbol, and the
+ * tree is empty, E is set to NULL. If the tree is not empty, E will be set to
+ * the last entry, and the result of the function is <0 if the entry should
+ * be inserted on the left side, and >0 if it should get inserted on the right
+ * side.
+ */
+{
+ int Cmp;
+
+ /* Is there a tree? */
+ if (T == 0) {
+ *E = 0;
+ return 1;
+ }
+
+ /* We have a table, search it */
+ while (1) {
+ /* Choose next entry */
+ Cmp = strcmp (Name, T->Name);
+ if (Cmp < 0 && T->Left) {
+ T = T->Left;
+ } else if (Cmp > 0 && T->Right) {
+ T = T->Right;
+ } else {
+ /* Found or end of search */
+ break;
+ }
+ }
+
+ /* Return the search result */
+ *E = T;
+ return Cmp;
+}
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+static SymEntry* SymFind (SymTable* Tab, const char* Name, int AllocNew)
+/* Find a new symbol table entry in the given table. If AllocNew is given and
+ * the entry is not found, create a new one. Return the entry found, or the
+ * new entry created, or - in case AllocNew is zero - return 0.
+ */
+{
+ SymEntry* S;
+ int Cmp;
+ unsigned Hash;
+
+ if (IsLocal (Name)) {
+
+ /* Local symbol, get the table */
+ if (!SymLast) {
+ /* No last global, so there's no local table */
+ Error (ERR_ILLEGAL_LOCAL_USE);
+ if (AllocNew) {
+ return NewSymEntry (Name);
+ } else {
+ return 0;
+ }
+ }
+
+ /* Search for the symbol if we have a table */
+ Cmp = SearchSymTab (SymLast->Locals, Name, &S);
+
+ /* If we found an entry, return it */
+ if (Cmp == 0) {
+ return S;
+ }
+
+ if (AllocNew) {
+
+ /* Otherwise create a new entry, insert and return it */
+ SymEntry* N = NewSymEntry (Name);
+ if (S == 0) {
+ SymLast->Locals = N;
+ } else if (Cmp < 0) {
+ S->Left = N;
+ } else {
+ S->Right = N;
+ }
+ return N;
+ }
+
+ } else {
+
+ /* Global symbol: Get the hash value for the name */
+ Hash = HashStr (Name) % Tab->TableSlots;
+
+ /* Search for the entry */
+ Cmp = SearchSymTab (Tab->Table [Hash], Name, &S);
+
+ /* If we found an entry, return it */
+ if (Cmp == 0) {
+ /* Check for a trampoline entry, in this case return the real
+ * symbol.
+ */
+ if (S->Flags & SF_TRAMPOLINE) {
+ return S->V.Sym;
+ } else {
+ return S;
+ }
+ }
+
+ if (AllocNew) {
+
+ /* Otherwise create a new entry, insert and return it */
+ SymEntry* N = NewSymEntry (Name);
+ if (S == 0) {
+ Tab->Table [Hash] = N;
+ } else if (Cmp < 0) {
+ S->Left = N;
+ } else {
+ S->Right = N;
+ }
+ N->SymTab = Tab;
+ ++Tab->TableEntries;
+ return N;
+
+ }
+ }
+
+ /* We did not find the entry and AllocNew is false. */
+ return 0;
+}
+
+
+
+static SymEntry* SymFindAny (SymTable* Tab, const char* Name)
+/* Find a symbol in any table */
+{
+ SymEntry* Sym;
+ do {
+ /* Search in the current table */
+ Sym = SymFind (Tab, Name, 0);
+ if (Sym) {
+ /* Found, return it */
+ return Sym;
+ } else {
+ /* Not found, search in the backlink, if we have one */
+ Tab = Tab->BackLink;
+ }
+ } while (Sym == 0 && Tab != 0);
+
+ /* Not found */
+ return 0;
+}
+
+
+
+static SymEntry* SymRefInternal (SymTable* Table, const char* Name)
+/* Search for the symbol in the given table and return it */
+{
+ SymEntry* S;
+
+ /* Try to find the symbol, create a new one if the symbol does not exist */
+ S = SymFind (Table, Name, 1);
+
+ /* Mark the symbol as referenced */
+ S->Flags |= SF_REFERENCED;
+
+ /* Return it */
+ return S;
+}
+
+
+
+void SymEnterLevel (void)
+/* Enter a new lexical level */
+{
+ if (RootTab == 0) {
+ /* Create the main symbol table */
+ RootTab = SymTab = NewSymTable (MAIN_HASHTAB_SIZE);
+ } else {
+ /* Create a local symbol table */
+ SymTable* LocalSyms;
+ LocalSyms = NewSymTable (SUB_HASHTAB_SIZE);
+ LocalSyms->BackLink = SymTab;
+ SymTab = LocalSyms;
+ }
+}
+
+
+
+void SymLeaveLevel (void)
+/* Leave the current lexical level */
+{
+ SymTab = SymTab->BackLink;
+}
+
+
+
+void SymDef (const char* Name, ExprNode* Expr, int ZP)
+/* Define a new symbol */
+{
+ SymEntry* S;
+
+ /* Do we have such a symbol? */
+ S = SymFind (SymTab, Name, 1);
+ if (S->Flags & SF_IMPORT) {
+ /* Defined symbol is marked as imported external symbol */
+ Error (ERR_SYM_ALREADY_IMPORT);
+ return;
+ }
+ if (S->Flags & SF_DEFINED) {
+ /* Multiple definition */
+ Error (ERR_SYM_ALREADY_DEFINED, Name);
+ S->Flags |= SF_MULTDEF;
+ return;
+ }
+
+ /* Set the symbol data */
+ if (IsConstExpr (Expr)) {
+ /* Expression is const, store the value */
+ S->Flags |= SF_CONST;
+ S->V.Val = GetExprVal (Expr);
+ FreeExpr (Expr);
+ } else {
+ /* Not const, store the expression */
+ S->V.Expr = Expr;
+ }
+ S->Flags |= SF_DEFINED;
+ if (ZP) {
+ S->Flags |= SF_ZP;
+ }
+
+ /* If the symbol is a ZP symbol, check if the value is in correct range */
+ if (S->Flags & SF_ZP) {
+ /* Already marked as ZP symbol by some means */
+ if (!IsByteExpr (Expr)) {
+ Error (ERR_RANGE);
+ }
+ }
+
+ /* If this is not a local symbol, remember it as the last global one */
+ if (!IsLocal (Name)) {
+ SymLast = S;
+ }
+}
+
+
+
+SymEntry* SymRef (const char* Name)
+/* Search for the symbol and return it */
+{
+ /* Reference the symbol in the current table */
+ return SymRefInternal (SymTab, Name);
+}
+
+
+
+SymEntry* SymRefGlobal (const char* Name)
+/* Search for the symbol in the global namespace and return it */
+{
+ /* Reference the symbol in the current table */
+ return SymRefInternal (RootTab, Name);
+}
+
+
+
+void SymImport (const char* Name, int ZP)
+/* Mark the given symbol as an imported symbol */
+{
+ SymEntry* S;
+
+ /* Don't accept local symbols */
+ if (IsLocal (Name)) {
+ Error (ERR_ILLEGAL_LOCAL_USE);
+ return;
+ }
+
+ /* Do we have such a symbol? */
+ S = SymFind (SymTab, Name, 1);
+ if (S->Flags & SF_DEFINED) {
+ Error (ERR_SYM_ALREADY_DEFINED, Name);
+ S->Flags |= SF_MULTDEF;
+ return;
+ }
+ if (S->Flags & SF_EXPORT) {
+ /* The symbol is already marked as exported symbol */
+ Error (ERR_SYM_ALREADY_EXPORT);
+ return;
+ }
+
+ /* If the symbol is marked as global, check the symbol size, then do
+ * silently remove the global flag
+ */
+ if (S->Flags & SF_GLOBAL) {
+ if ((ZP != 0) != ((S->Flags & SF_ZP) != 0)) {
+ Error (ERR_SYM_REDECL_MISMATCH);
+ }
+ S->Flags &= ~SF_GLOBAL;
+ }
+
+ /* Set the symbol data */
+ S->Flags |= SF_IMPORT;
+ if (ZP) {
+ S->Flags |= SF_ZP;
+ }
+}
+
+
+
+void SymExport (const char* Name, int ZP)
+/* Mark the given symbol as an exported symbol */
+{
+ SymEntry* S;
+
+ /* Don't accept local symbols */
+ if (IsLocal (Name)) {
+ Error (ERR_ILLEGAL_LOCAL_USE);
+ return;
+ }
+
+ /* Do we have such a symbol? */
+ S = SymFind (SymTab, Name, 1);
+ if (S->Flags & SF_IMPORT) {
+ /* The symbol is already marked as imported external symbol */
+ Error (ERR_SYM_ALREADY_IMPORT);
+ return;
+ }
+
+ /* If the symbol is marked as global, check the symbol size, then do
+ * silently remove the global flag
+ */
+ if (S->Flags & SF_GLOBAL) {
+ if ((ZP != 0) != ((S->Flags & SF_ZP) != 0)) {
+ Error (ERR_SYM_REDECL_MISMATCH);
+ }
+ S->Flags &= ~SF_GLOBAL;
+ }
+
+ /* Set the symbol data */
+ S->Flags |= SF_EXPORT | SF_REFERENCED;
+ if (ZP) {
+ S->Flags |= SF_ZP;
+ }
+}
+
+
+
+void SymGlobal (const char* Name, int ZP)
+/* Mark the given symbol as a global symbol, that is, as a symbol that is
+ * either imported or exported.
+ */
+{
+ SymEntry* S;
+
+ /* Don't accept local symbols */
+ if (IsLocal (Name)) {
+ Error (ERR_ILLEGAL_LOCAL_USE);
+ return;
+ }
+
+ /* Search for this symbol, create a new entry if needed */
+ S = SymFind (SymTab, Name, 1);
+
+ /* If the symbol is already marked as import or export, check the
+ * size of the definition, then bail out. */
+ if (S->Flags & SF_IMPORT || S->Flags & SF_EXPORT) {
+ if ((ZP != 0) != ((S->Flags & SF_ZP) != 0)) {
+ Error (ERR_SYM_REDECL_MISMATCH);
+ }
+ return;
+ }
+
+ /* Mark the symbol */
+ S->Flags |= SF_GLOBAL;
+ if (ZP) {
+ S->Flags |= SF_ZP;
+ }
+}
+
+
+
+int SymIsDef (const char* Name)
+/* Return true if the given symbol is already defined */
+{
+ SymEntry* S = SymFindAny (SymTab, Name);
+ return S != 0 && (S->Flags & (SF_DEFINED | SF_IMPORT)) != 0;
+}
+
+
+
+int SymIsRef (const char* Name)
+/* Return true if the given symbol has been referenced */
+{
+ SymEntry* S = SymFindAny (SymTab, Name);
+ return S != 0 && (S->Flags & SF_REFERENCED) != 0;
+}
+
+
+
+int SymIsConst (SymEntry* S)
+/* Return true if the given symbol has a constant value */
+{
+ /* Resolve trampoline entries */
+ if (S->Flags & SF_TRAMPOLINE) {
+ S = S->V.Sym;
+ }
+
+ /* Check for constness */
+ if (S->Flags & SF_CONST) {
+ return 1;
+ } else if ((S->Flags & SF_DEFINED) && IsConstExpr (S->V.Expr)) {
+ /* Constant expression, remember the value */
+ ExprNode* Expr = S->V.Expr;
+ S->Flags |= SF_CONST;
+ S->V.Val = GetExprVal (Expr);
+ FreeExpr (Expr);
+ return 1;
+ }
+ return 0;
+}
+
+
+
+int SymIsZP (SymEntry* S)
+/* Return true if the symbol is explicitly marked as zeropage symbol */
+{
+ /* Resolve trampoline entries */
+ if (S->Flags & SF_TRAMPOLINE) {
+ S = S->V.Sym;
+ }
+
+ /* If the symbol is not a global symbol, was not defined before, check the
+ * enclosing scope for a symbol with the same name, and return the ZP
+ * attribute of this symbol if we find one.
+ */
+ if (!IsLocal (S->Name) &&
+ (S->Flags & (SF_ZP | SF_ABS | SF_DEFINED | SF_IMPORT)) == 0 &&
+ S->SymTab->BackLink != 0) {
+
+ /* Try to find a symbol with the same name in the enclosing scope */
+ SymEntry* E = SymFindAny (S->SymTab->BackLink, S->Name);
+
+ /* If we found one, use the ZP flag */
+ if (E && (E->Flags & SF_ZP) != 0) {
+ S->Flags |= SF_ZP;
+ }
+ }
+
+ /* Check the ZP flag */
+ return (S->Flags & SF_ZP) != 0;
+}
+
+
+
+int SymIsImport (SymEntry* S)
+/* Return true if the given symbol is marked as import */
+{
+ /* Resolve trampoline entries */
+ if (S->Flags & SF_TRAMPOLINE) {
+ S = S->V.Sym;
+ }
+
+ /* Check the import flag */
+ return (S->Flags & SF_IMPORT) != 0;
+}
+
+
+
+int SymHasExpr (SymEntry* S)
+/* Return true if the given symbol has an associated expression */
+{
+ /* Resolve trampoline entries */
+ if (S->Flags & SF_TRAMPOLINE) {
+ S = S->V.Sym;
+ }
+
+ /* Check the expression */
+ return ((S->Flags & SF_DEFINED) != 0 &&
+ (S->Flags & SF_IMPORT) == 0 &&
+ (S->Flags & SF_CONST) == 0);
+}
+
+
+
+void SymFinalize (SymEntry* S)
+/* Finalize a symbol expression if there is one */
+{
+ /* Resolve trampoline entries */
+ if (S->Flags & SF_TRAMPOLINE) {
+ S = S->V.Sym;
+ }
+
+ /* Check if we have an expression */
+ if (SymHasExpr (S)) {
+ S->V.Expr = FinalizeExpr (S->V.Expr);
+ }
+}
+
+
+
+void SymMarkUser (SymEntry* S)
+/* Set a user mark on the specified symbol */
+{
+ /* Resolve trampoline entries */
+ if (S->Flags & SF_TRAMPOLINE) {
+ S = S->V.Sym;
+ }
+
+ /* Set the bit */
+ S->Flags |= SF_USER;
+}
+
+
+
+void SymUnmarkUser (SymEntry* S)
+/* Remove a user mark from the specified symbol */
+{
+ /* Resolve trampoline entries */
+ if (S->Flags & SF_TRAMPOLINE) {
+ S = S->V.Sym;
+ }
+
+ /* Reset the bit */
+ S->Flags &= ~SF_USER;
+}
+
+
+
+int SymHasUserMark (SymEntry* S)
+/* Return the state of the user mark for the specified symbol */
+{
+ /* Resolve trampoline entries */
+ if (S->Flags & SF_TRAMPOLINE) {
+ S = S->V.Sym;
+ }
+
+ /* Check the bit */
+ return (S->Flags & SF_USER) != 0;
+}
+
+
+
+long GetSymVal (SymEntry* S)
+/* Return the symbol value */
+{
+ /* Resolve trampoline entries */
+ if (S->Flags & SF_TRAMPOLINE) {
+ S = S->V.Sym;
+ }
+
+ PRECONDITION ((S->Flags & SF_DEFINED) != 0 && (S->Flags & SF_CONST) != 0);
+ return S->V.Val;
+}
+
+
+
+ExprNode* GetSymExpr (SymEntry* S)
+/* Get the expression for a non-const symbol */
+{
+ /* Resolve trampoline entries */
+ if (S->Flags & SF_TRAMPOLINE) {
+ S = S->V.Sym;
+ }
+
+ PRECONDITION (S != 0 && (S->Flags & SF_CONST) == 0);
+ return S->V.Expr;
+}
+
+
+
+const char* GetSymName (SymEntry* S)
+/* Return the name of the symbol */
+{
+ /* Resolve trampoline entries */
+ if (S->Flags & SF_TRAMPOLINE) {
+ S = S->V.Sym;
+ }
+ return S->Name;
+}
+
+
+
+unsigned GetSymIndex (SymEntry* S)
+/* Return the symbol index for the given symbol */
+{
+ /* Resolve trampoline entries */
+ if (S->Flags & SF_TRAMPOLINE) {
+ S = S->V.Sym;
+ }
+ PRECONDITION (S != 0 && (S->Flags & SF_INDEXED));
+ return S->Index;
+}
+
+
+
+const FilePos* GetSymPos (SymEntry* S)
+/* Return the position of first occurence in the source for the given symbol */
+{
+ /* Resolve trampoline entries */
+ if (S->Flags & SF_TRAMPOLINE) {
+ S = S->V.Sym;
+ }
+ PRECONDITION (S != 0);
+ return &S->Pos;
+}
+
+
+
+static void SymCheckUndefined (SymEntry* S)
+/* Handle an undefined symbol */
+{
+ /* Undefined symbol. It may be...
+ *
+ * - An undefined symbol in a nested lexical level. In this
+ * case, search for the symbol in the higher levels and
+ * make the entry a trampoline entry if we find one.
+ *
+ * - If the symbol is not found, it is a real undefined symbol.
+ * If the AutoImport flag is set, make it an import. If the
+ * AutoImport flag is not set, it's an error.
+ */
+ SymEntry* Sym = 0;
+ if (S->SymTab) {
+ /* It's a global symbol, get the higher level table */
+ SymTable* Tab = S->SymTab->BackLink;
+ while (Tab) {
+ Sym = SymFindAny (Tab, S->Name);
+ if (Sym) {
+ if (Sym->Flags & (SF_DEFINED | SF_IMPORT)) {
+ /* We've found a symbol in a higher level that is
+ * either defined in the source, or an import.
+ */
+ break;
+ } else {
+ /* The symbol found is undefined itself. Look further */
+ Tab = Sym->SymTab->BackLink;
+ }
+ } else {
+ /* No symbol found */
+ break;
+ }
+ }
+ }
+ if (Sym) {
+ /* We found the symbol in a higher level. Make S a trampoline
+ * symbol. Beware: We have to transfer the symbol attributes to
+ * the real symbol and check for any conflicts.
+ */
+ S->Flags |= SF_TRAMPOLINE;
+ S->V.Sym = Sym;
+
+ /* Transfer the flags. Note: S may not be imported, since in that
+ * case it wouldn't be undefined.
+ */
+ if (S->Flags & SF_EXPORT) {
+ if (Sym->Flags & SF_IMPORT) {
+ /* The symbol is already marked as imported external symbol */
+ PError (&S->Pos, ERR_SYM_ALREADY_IMPORT);
+ }
+ Sym->Flags |= S->Flags & (SF_EXPORT | SF_ZP);
+ }
+
+ /* Transfer the referenced flag */
+ Sym->Flags |= (S->Flags & SF_REFERENCED);
+
+ } else {
+ /* The symbol is definitely undefined */
+ if (S->Flags & SF_EXPORT) {
+ /* We will not auto-import an export */
+ PError (&S->Pos, ERR_EXPORT_UNDEFINED, S->Name);
+ } else {
+ if (AutoImport) {
+ /* Mark as import, will be indexed later */
+ S->Flags |= SF_IMPORT;
+ } else {
+ /* Error */
+ PError (&S->Pos, ERR_SYM_UNDEFINED, S->Name);
+ }
+ }
+ }
+}
+
+
+
+void SymCheck (void)
+/* Run through all symbols and check for anomalies and errors */
+{
+ SymEntry* S;
+
+ /* Check for open lexical levels */
+ if (SymTab->BackLink != 0) {
+ Error (ERR_OPEN_PROC);
+ }
+
+ /* First pass: Walk through all symbols, checking for undefined's and
+ * changing them to trampoline symbols or make them imports.
+ */
+ S = SymList;
+ while (S) {
+ /* If the symbol is marked as global, mark it as export, if it is
+ * already defined, otherwise mark it as import.
+ */
+ if (S->Flags & SF_GLOBAL) {
+ S->Flags &= ~SF_GLOBAL;
+ if (S->Flags & SF_DEFINED) {
+ S->Flags |= SF_EXPORT;
+ } else {
+ S->Flags |= SF_IMPORT;
+ }
+ }
+
+ /* Handle undefined symbols */
+ if ((S->Flags & SF_UNDEFMASK) == SF_UNDEFVAL) {
+ /* This is an undefined symbol. Handle it. */
+ SymCheckUndefined (S);
+ }
+
+ /* Next symbol */
+ S = S->List;
+ }
+
+ /* Second pass: Walk again through the symbols. Ignore undefined's, since
+ * we handled them in the last pass, and ignore trampoline symbols, since
+ * we handled them in the last pass, too.
+ */
+ S = SymList;
+ while (S) {
+ if ((S->Flags & SF_TRAMPOLINE) == 0 &&
+ (S->Flags & SF_UNDEFMASK) != SF_UNDEFVAL) {
+ if ((S->Flags & SF_DEFINED) != 0 && (S->Flags & SF_REFERENCED) == 0) {
+ /* Symbol was defined but never referenced */
+ PWarning (&S->Pos, WARN_SYM_NOT_REFERENCED, S->Name);
+ }
+ if (S->Flags & SF_IMPORT) {
+ if ((S->Flags & SF_REFERENCED) == 0) {
+ /* Imported symbol is not referenced */
+ PWarning (&S->Pos, WARN_IMPORT_NOT_REFERENCED, S->Name);
+ } else {
+ /* Give the import an index, count imports */
+ S->Index = ImportCount++;
+ S->Flags |= SF_INDEXED;
+ }
+ }
+ if (S->Flags & SF_EXPORT) {
+ /* Give the export an index, count exports */
+ S->Index = ExportCount++;
+ S->Flags |= SF_INDEXED;
+ }
+ }
+
+ /* Next symbol */
+ S = S->List;
+ }
+}
+
+
+
+void SymDump (FILE* F)
+/* Dump the symbol table */
+{
+ SymEntry* S = SymList;
+
+ while (S) {
+ /* Ignore trampoline symbols */
+ if ((S->Flags & SF_TRAMPOLINE) != 0) {
+ printf ("%-24s %s %s %s %s %s\n",
+ S->Name,
+ (S->Flags & SF_DEFINED)? "DEF" : "---",
+ (S->Flags & SF_REFERENCED)? "REF" : "---",
+ (S->Flags & SF_IMPORT)? "IMP" : "---",
+ (S->Flags & SF_EXPORT)? "EXP" : "---",
+ (S->Flags & SF_ZP)? "ZP" : "--");
+ }
+ /* Next symbol */
+ S = S->List;
+ }
+}
+
+
+
+void WriteImports (void)
+/* Write the imports list to the object file */
+{
+ SymEntry* S;
+
+ /* Tell the object file module that we're about to start the imports */
+ ObjStartImports ();
+
+ /* Write the import count to the list */
+ ObjWrite16 (ImportCount);
+
+ /* Walk throught list and write all imports to the file */
+ S = SymList;
+ while (S) {
+ if ((S->Flags & SF_IMPMASK) == SF_IMPVAL) {
+ if (S->Flags & SF_ZP) {
+ ObjWrite8 (IMP_ZP);
+ } else {
+ ObjWrite8 (IMP_ABS);
+ }
+ ObjWriteStr (S->Name);
+ ObjWritePos (&S->Pos);
+ }
+ S = S->List;
+ }
+
+ /* Done writing imports */
+ ObjEndImports ();
+}
+
+
+
+void WriteExports (void)
+/* Write the exports list to the object file */
+{
+ SymEntry* S;
+
+ /* Tell the object file module that we're about to start the exports */
+ ObjStartExports ();
+
+ /* Write the export count to the list */
+ ObjWrite16 (ExportCount);
+
+ /* Walk throught list and write all exports to the file */
+ S = SymList;
+ while (S) {
+ if ((S->Flags & SF_EXPMASK) == SF_EXPVAL) {
+ unsigned char ExprMask;
+
+ /* Finalize an associated expression if we have one */
+ SymFinalize (S);
+
+ /* Check if the symbol is const */
+ ExprMask = (SymIsConst (S))? EXP_CONST : EXP_EXPR;
+
+ /* Write the type */
+ if (S->Flags & SF_ZP) {
+ ObjWrite8 (EXP_ZP | ExprMask);
+ } else {
+ ObjWrite8 (EXP_ABS | ExprMask);
+ }
+ ObjWriteStr (S->Name);
+ if (ExprMask == EXP_CONST) {
+ /* Constant value */
+ ObjWrite32 (S->V.Val);
+ } else {
+ /* Expression involved */
+ WriteExpr (S->V.Expr);
+ }
+ ObjWritePos (&S->Pos);
+ }
+ S = S->List;
+ }
+
+ /* Done writing exports */
+ ObjEndExports ();
+}
+
+
+
+void WriteDbgSyms (void)
+/* Write a list of all symbols to the object file */
+{
+ unsigned Count;
+ SymEntry* S;
+
+ /* Tell the object file module that we're about to start the debug info */
+ ObjStartDbgSyms ();
+
+ /* Check if debug info is requested */
+ if (DbgSyms) {
+
+ /* Walk through the list and count the symbols */
+ Count = 0;
+ S = SymList;
+ while (S) {
+ if ((S->Flags & SF_DBGINFOMASK) == SF_DBGINFOVAL) {
+ ++Count;
+ }
+ S = S->List;
+ }
+
+ /* Safety check */
+ if (Count > 0xFFFF) {
+ Fatal (FAT_TOO_MANY_SYMBOLS);
+ }
+
+ /* Write the symbol count to the list */
+ ObjWrite16 (Count);
+
+ /* Walk through list and write all symbols to the file */
+ S = SymList;
+ while (S) {
+ if ((S->Flags & SF_DBGINFOMASK) == SF_DBGINFOVAL) {
+ unsigned char ExprMask;
+
+ /* Finalize an associated expression if we have one */
+ SymFinalize (S);
+
+ /* Check if the symbol is const */
+ ExprMask = (SymIsConst (S))? EXP_CONST : EXP_EXPR;
+
+ /* Write the type */
+ if (S->Flags & SF_ZP) {
+ ObjWrite8 (EXP_ZP | ExprMask);
+ } else {
+ ObjWrite8 (EXP_ABS | ExprMask);
+ }
+ ObjWriteStr (S->Name);
+ if (ExprMask == EXP_CONST) {
+ /* Constant value */
+ ObjWrite32 (S->V.Val);
+ } else {
+ /* Expression involved */
+ WriteExpr (S->V.Expr);
+ }
+ ObjWritePos (&S->Pos);
+ }
+ S = S->List;
+ }
+
+ } else {
+
+ /* No debug symbols */
+ ObjWrite16 (0);
+
+ }
+
+ /* Done writing debug symbols */
+ ObjEndDbgSyms ();
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* symtab.h */
+/* */
+/* Symbol table for the ca65 macroassembler */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef SYMTAB_H
+#define SYMTAB_H
+
+
+
+#include <stdio.h>
+
+#include "../common/exprdefs.h"
+
+#include "symentry.h"
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void SymEnterLevel (void);
+/* Enter a new lexical level */
+
+void SymLeaveLevel (void);
+/* Leave the current lexical level */
+
+void SymDef (const char* Name, ExprNode* Expr, int ZP);
+/* Define a new symbol */
+
+SymEntry* SymRef (const char* Name);
+/* Search for the symbol and return it */
+
+SymEntry* SymRefGlobal (const char* Name);
+/* Search for the symbol in the global namespace and return it */
+
+int SymIsDef (const char* Name);
+/* Return true if the given symbol is already defined */
+
+int SymIsRef (const char* Name);
+/* Return true if the given symbol has been referenced */
+
+void SymImport (const char* Name, int ZP);
+/* Mark the given symbol as an imported symbol */
+
+void SymExport (const char* Name, int ZP);
+/* Mark the given symbol as an exported symbol */
+
+void SymGlobal (const char* Name, int ZP);
+/* Mark the given symbol as a global symbol, that is, as a symbol that is
+ * either imported or exported.
+ */
+
+int SymIsConst (SymEntry* Sym);
+/* Return true if the given symbol has a constant value */
+
+int SymIsZP (SymEntry* Sym);
+/* Return true if the symbol is explicitly marked as zeropage symbol */
+
+int SymIsImport (SymEntry* Sym);
+/* Return true if the given symbol is marked as import */
+
+int SymHasExpr (SymEntry* Sym);
+/* Return true if the given symbol has an associated expression */
+
+void SymMarkUser (SymEntry* Sym);
+/* Set a user mark on the specified symbol */
+
+void SymUnmarkUser (SymEntry* Sym);
+/* Remove a user mark from the specified symbol */
+
+int SymHasUserMark (SymEntry* Sym);
+/* Return the state of the user mark for the specified symbol */
+
+long GetSymVal (SymEntry* Sym);
+/* Return the symbol value */
+
+ExprNode* GetSymExpr (SymEntry* Sym);
+/* Get the expression for a non-const symbol */
+
+const char* GetSymName (SymEntry* Sym);
+/* Return the name of the symbol */
+
+unsigned GetSymIndex (SymEntry* Sym);
+/* Return the symbol index for the given symbol */
+
+const FilePos* GetSymPos (SymEntry* Sym);
+/* Return the position of first occurence in the source for the given symbol */
+
+void SymCheck (void);
+/* Run through all symbols and check for anomalies and errors */
+
+void SymDump (FILE* F);
+/* Dump the symbol table */
+
+void WriteImports (void);
+/* Write the imports list to the object file */
+
+void WriteExports (void);
+/* Write the exports list to the object file */
+
+void WriteDbgSyms (void);
+/* Write a list of all symbols to the object file */
+
+
+
+/* End of symtab.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* toknode.c */
+/* */
+/* Token list node for the ca65 macroassembler */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <string.h>
+
+#include "mem.h"
+#include "scanner.h"
+#include "toknode.h"
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+TokNode* NewTokNode (void)
+/* Create and return a token node with the current token value */
+{
+ TokNode* T;
+
+ /* Allocate memory */
+ unsigned Len = TokHasSVal (Tok)? strlen (SVal) : 0;
+ T = Xmalloc (sizeof (TokNode) + Len);
+
+ /* Initialize the token contents */
+ T->Next = 0;
+ T->Tok = Tok;
+ T->WS = WS;
+ T->IVal = IVal;
+ memcpy (T->SVal, SVal, Len);
+ T->SVal [Len] = '\0';
+
+ /* Return the node */
+ return T;
+}
+
+
+
+void FreeTokNode (TokNode* T)
+/* Free the given token node */
+{
+ Xfree (T);
+}
+
+
+
+void TokSet (TokNode* T)
+/* Set the scanner token from the given token node */
+{
+ /* Set the values */
+ Tok = T->Tok;
+ WS = T->WS;
+ IVal = T->IVal;
+ strcpy (SVal, T->SVal);
+}
+
+
+
+enum TC TokCmp (const TokNode* T)
+/* Compare the token given as parameter against the current token */
+{
+ if (T->Tok != Tok) {
+ /* Different token */
+ return tcDifferent;
+ }
+
+ /* If the token has string attribute, check it */
+ if (TokHasSVal (T->Tok)) {
+ if (strcmp (T->SVal, SVal) != 0) {
+ return tcSameToken;
+ }
+ } else if (TokHasIVal (T->Tok)) {
+ if (T->IVal != IVal) {
+ return tcSameToken;
+ }
+ }
+
+ /* Tokens are identical */
+ return tcIdentical;
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* toknode.h */
+/* */
+/* Token list node for the ca65 macroassembler */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef TOKNODE_H
+#define TOKNODE_H
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Struct holding a token */
+typedef struct TokNode_ TokNode;
+struct TokNode_ {
+ TokNode* Next; /* For single linked list */
+ enum Token Tok; /* Token value */
+ int WS; /* Whitespace before token? */
+ long IVal; /* Integer token attribute */
+ char SVal [1]; /* String attribute, dyn. allocated */
+};
+
+
+
+/* Return codes for TokCmp - higher numeric code means better match */
+enum TC {
+ tcDifferent, /* Different tokents */
+ tcSameToken, /* Same token, different attribute */
+ tcIdentical /* Identical (token + attribute) */
+};
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+TokNode* NewTokNode (void);
+/* Create and return a token node with the current token value */
+
+void FreeTokNode (TokNode* T);
+/* Free the given token node */
+
+void TokSet (TokNode* T);
+/* Set the scanner token from the given token node */
+
+enum TC TokCmp (const TokNode* T);
+/* Compare the token given as parameter against the current token */
+
+
+
+/* End of toknode.h */
+
+#endif
+
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* ulabel.c */
+/* */
+/* Unnamed labels for the ca65 macroassembler */
+/* */
+/* */
+/* */
+/* (C) 2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include "../common/filepos.h"
+
+#include "error.h"
+#include "expr.h"
+#include "mem.h"
+#include "scanner.h"
+#include "ulabel.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Struct that describes an unnamed label */
+typedef struct ULabel_ ULabel;
+struct ULabel_ {
+ ULabel* Prev; /* Pointer to previous node in list */
+ ULabel* Next; /* Pointer to next node in list */
+ FilePos Pos; /* Position of the label in the source */
+ ExprNode* Val; /* The label value - may be NULL */
+};
+
+/* List management */
+static ULabel* ULabRoot = 0; /* Root of the list */
+static ULabel* ULabLast = 0; /* Last ULabel */
+static ULabel* ULabLastDef = 0; /* Last defined ULabel */
+static unsigned ULabCount = 0; /* Number of labels */
+static unsigned ULabDefCount = 0; /* Number of defined labels */
+static ULabel** ULabList = 0; /* Array with pointers to all labels */
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+static ULabel* NewULabel (ExprNode* Val)
+/* Create a new ULabel and insert it into the list. The function will move
+ * ULabelLast, but not ULabelLastDef. The created label structure is returned.
+ */
+{
+ /* Allocate memory for the ULabel structure */
+ ULabel* L = Xmalloc (sizeof (ULabel));
+
+ /* Initialize the fields */
+ L->Pos = CurPos;
+ L->Val = Val;
+
+ /* Insert the label into the list */
+ L->Next = 0;
+ if (ULabRoot == 0) {
+ /* First label */
+ L->Prev = 0;
+ ULabRoot = L;
+ } else {
+ ULabLast->Next = L;
+ L->Prev = ULabLast;
+ }
+ ULabLast = L;
+
+ /* One label more */
+ ++ULabCount;
+
+ /* Return the created label */
+ return L;
+}
+
+
+
+ExprNode* ULabRef (int Which)
+/* Get an unnamed label. If Which is negative, it is a backreference (a
+ * reference to an already defined label), and the function will return a
+ * segment relative expression. If Which is positive, it is a forward ref,
+ * and the function will return a expression node for an unnamed label that
+ * must be resolved later.
+ */
+{
+ ULabel* L;
+
+ /* Which can never be 0 */
+ PRECONDITION (Which != 0);
+
+ /* Which is never really big (usually -3..+3), so a linear search is
+ * the best we can do here.
+ */
+ L = ULabLastDef;
+ if (Which < 0) {
+ /* Backward reference */
+ while (Which < -1 && L != 0) {
+ L = L->Prev;
+ ++Which;
+ }
+ if (L == 0) {
+ /* Label does not exist */
+ Error (ERR_UNDEFINED_LABEL);
+ /* We must return something valid */
+ return CurrentPC();
+ } else {
+ /* Return a copy of the label value */
+ return CloneExpr (L->Val);
+ }
+ } else {
+ /* Forward reference. Create labels as needed */
+ unsigned LabelNum = ULabDefCount + Which - 1;
+ while (Which > 0) {
+ if (L->Next == 0) {
+ NewULabel (0);
+ }
+ L = L->Next;
+ --Which;
+ }
+ /* Return an unnamed label expression */
+ return ULabelExpr (LabelNum);
+ }
+}
+
+
+
+void ULabDef (void)
+/* Define an unnamed label at the current PC */
+{
+ /* Create a new label if needed, or use an existing one */
+ if (ULabLastDef == 0 || ULabLastDef->Next == 0) {
+ /* The last label is also the last defined label, we need a new one */
+ ULabLastDef = NewULabel (CurrentPC ());
+ } else {
+ /* We do already have the label, but it's undefined until now */
+ ULabLastDef = ULabLastDef->Next;
+ ULabLastDef->Val = CurrentPC ();
+ ULabLastDef->Pos = CurPos;
+ }
+ ++ULabDefCount;
+}
+
+
+
+int ULabCanResolve (void)
+/* Return true if we can resolve arbitrary ULabels. */
+{
+ /* We can resolve labels if we have built the necessary access array */
+ return (ULabList != 0);
+}
+
+
+
+ExprNode* ULabResolve (unsigned Index)
+/* Return a valid expression for the unnamed label with the given index. This
+ * is used to resolve unnamed labels when assembly is done, so it is an error
+ * if a label is still undefined in this phase.
+ */
+{
+ ULabel* L;
+
+ /* Must be in resolve phase and the index must be valid */
+ CHECK (ULabList != 0 && Index < ULabCount);
+
+ /* Get the label */
+ L = ULabList [Index];
+
+ /* If the label is open (not defined), return some valid value */
+ if (L->Val == 0) {
+ return LiteralExpr (0);
+ } else {
+ return CloneExpr (L->Val);
+ }
+}
+
+
+
+void ULabCheck (void)
+/* Run through all unnamed labels and check for anomalies and errors */
+{
+ ULabel* L;
+
+ /* Check if there are undefined labels */
+ if (ULabLastDef) {
+ L = ULabLastDef->Next;
+ while (L) {
+ PError (&L->Pos, ERR_UNDEFINED_LABEL);
+ L = L->Next;
+ }
+ }
+
+ /* Create an array that holds pointers to all labels. This allows us to
+ * access the labels quickly by index in the resolver phase at the end of
+ * the assembly.
+ */
+ if (ULabCount) {
+ unsigned I = 0;
+ ULabList = Xmalloc (ULabCount * sizeof (ULabel*));
+ L = ULabRoot;
+ while (L) {
+ ULabList[I] = L;
+ ++I;
+ L = L->Next;
+ }
+ CHECK (I == ULabCount);
+ }
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* ulabel.h */
+/* */
+/* Unnamed labels for the ca65 macroassembler */
+/* */
+/* */
+/* */
+/* (C) 2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef ULABEL_H
+#define ULABEL_H
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+ExprNode* ULabRef (int Which);
+/* Get an unnamed label. If Which is negative, it is a backreference (a
+ * reference to an already defined label), and the function will return a
+ * segment relative expression. If Which is positive, it is a forward ref,
+ * and the function will return a expression node for an unnamed label that
+ * must be resolved later.
+ */
+
+void ULabDef (void);
+/* Define an unnamed label at the current PC */
+
+int ULabCanResolve (void);
+/* Return true if we can resolve arbitrary ULabels. */
+
+ExprNode* ULabResolve (unsigned Index);
+/* Return a valid expression for the unnamed label with the given index. This
+ * is used to resolve unnamed labels when assembly is done, so it is an error
+ * if a label is still undefined in this phase.
+ */
+
+void ULabCheck (void);
+/* Run through all unnamed labels and check for anomalies and errors */
+
+
+
+/* End of ulabel.h */
+
+#endif
+
+
+
--- /dev/null
+.depend
+.kdbgrc.cc65
+cc65
+*.com
+*.map
+xopt
+predent
+postdent
+code-gen.m65
+glb.m65
+cc64
+error.m65
+expr1.m65
+expr2.m65
+save
+expr3.m65
+function.m65
+globlvar.m65
+io.m65
+lexer.m65
+main.m65
+optab1.m65
+optab2.m65
+optimize.m65
+preproc.m65
+rwords.m65
+stmt1.m65
+stmt2.m65
+symtab.m65
--- /dev/null
+/*****************************************************************************/
+/* */
+/* anonname.c */
+/* */
+/* Create names for anonymous variables/types */
+/* */
+/* */
+/* */
+/* (C) 2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+
+#include "anonname.h"
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+char* AnonName (char* Buf, const char* Spec)
+/* Get a name for an anonymous variable or type. The given buffer is expected
+ * to be IDENTSIZE characters long. A pointer to the buffer is returned.
+ */
+{
+ static unsigned ACount = 0;
+ sprintf (Buf, "$anon-%s-%04X", Spec, ++ACount);
+ return Buf;
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* anonname.h */
+/* */
+/* Create names for anonymous variables/types */
+/* */
+/* */
+/* */
+/* (C) 2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef ANONNAME_H
+#define ANONNAME_H
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+char* AnonName (char* Buf, const char* Spec);
+/* Get a name for an anonymous variable or type. The given buffer is expected
+ * to be IDENTSIZE characters long. A pointer to the buffer is returned.
+ */
+
+
+
+/* End of anonname.h */
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* asmcode.c */
+/* */
+/* Assembler output code handling for the cc65 C compiler */
+/* */
+/* */
+/* */
+/* (C) 2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include "asmline.h"
+#include "check.h"
+#include "global.h"
+#include "asmcode.h"
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void AddCodeLine (const char* Format, ...)
+/* Add a new line of code to the output */
+{
+ va_list ap;
+ va_start (ap, Format);
+ NewCodeLine (Format, ap);
+ va_end (ap);
+}
+
+
+
+void AddCodeHint (const char* Hint)
+/* Add an optimizer hint */
+{
+ AddCodeLine ("+%s", Hint);
+}
+
+
+
+void AddEmptyLine (void)
+/* Add an empty line for formatting purposes */
+{
+ AddCodeLine ("");
+}
+
+
+
+CodeMark GetCodePos (void)
+/* Get a marker pointing to the current output position */
+{
+ /* This function should never be called without any code output */
+ CHECK (LastLine != 0);
+
+ return LastLine;
+}
+
+
+
+void RemoveCode (CodeMark M)
+/* Remove all code after the given code marker */
+{
+ while (LastLine != M) {
+ FreeCodeLine (LastLine);
+ }
+}
+
+
+
+void WriteOutput (FILE* F)
+/* Write the final output to a file */
+{
+ Line* L = FirstLine;
+ while (L) {
+ /* Don't write optimizer hints if not requested to do so */
+ if (L->Line[0] == '+') {
+ if (Debug) {
+ fprintf (F, ";%s\n", L->Line);
+ }
+ } else {
+ fprintf (F, "%s\n", L->Line);
+ }
+ L = L->Next;
+ }
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* asmcode.h */
+/* */
+/* Assembler output code handling for the cc65 C compiler */
+/* */
+/* */
+/* */
+/* (C) 2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef ASMCODE_H
+#define ASMCODE_H
+
+
+
+#include <stdio.h>
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Marker for an assembler code position */
+typedef struct Line_* CodeMark;
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void AddCodeLine (const char* Format, ...);
+/* Add a new line of code to the output */
+
+void AddCodeHint (const char* Hint);
+/* Add an optimizer hint */
+
+void AddEmptyLine (void);
+/* Add an empty line for formatting purposes */
+
+CodeMark GetCodePos (void);
+/* Get a marker pointing to the current output position */
+
+void RemoveCode (CodeMark M);
+/* Remove all code after the given code marker */
+
+void WriteOutput (FILE* F);
+/* Write the final output to a file */
+
+
+
+/* End of asmcode.h */
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* asmlabel.c */
+/* */
+/* Generate assembler code labels */
+/* */
+/* */
+/* */
+/* (C) 2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include "asmlabel.h"
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+unsigned GetLabel (void)
+/* Get an unused label. Will never return zero. */
+{
+ /* Number to generate unique labels */
+ static unsigned NextLabel = 0;
+ return ++NextLabel;
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* asmlabel.h */
+/* */
+/* Generate assembler code labels */
+/* */
+/* */
+/* */
+/* (C) 2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef ASMLABEL_H
+#define ASMLABEL_H
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+unsigned GetLabel (void);
+/* Get an unused assembler label. Will never return zero. */
+
+
+
+/* End of asmlabel.h */
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* asmline.h */
+/* */
+/* Internal assembler line structure */
+/* */
+/* */
+/* */
+/* (C) 2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+
+#include "error.h"
+#include "mem.h"
+#include "asmline.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Number used to index lines */
+static unsigned long LineIndex = 0;
+
+/* The line list */
+Line* FirstLine = 0; /* Pointer to first line */
+Line* LastLine = 0; /* Pointer to last line */
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+static Line* NewLine (const char* Format, va_list ap)
+/* Interal routine to create a new line from the given text */
+{
+ char Buf [8192];
+ int OVF;
+ unsigned Len;
+ Line* L;
+
+
+ /* Make a string from the given format and arguments */
+#if defined(__WATCOMC__)
+ OVF = (_vbprintf (Buf, sizeof (Buf), Format, ap) >= sizeof (S));
+#else
+ /* Assume gcc running on a Unix OS */
+ OVF = (vsnprintf (Buf, sizeof (Buf), Format, ap) < 0);
+#endif
+ if (OVF) {
+ Internal ("String size overflow");
+ }
+
+ /* Get the length of the line */
+ Len = strlen (Buf);
+
+ /* Allocate memory */
+ L = xmalloc (sizeof (Line) + Len);
+
+ /* Partially initialize the struct (the remaining fields are initialized
+ * by the caller).
+ */
+ L->Flags = 0;
+ L->Size = 0;
+ L->Len = Len;
+ memcpy (L->Line, Buf, Len+1);
+
+ /* Return the new line */
+ return L;
+}
+
+
+
+Line* NewCodeLine (const char* Format, va_list ap)
+/* Create a new code line and return it */
+{
+ /* Create a new line struct */
+ Line* L = NewLine (Format, ap);
+
+ /* Initialize struct fields */
+ L->Index = LineIndex++;
+
+ /* Insert the line into the list */
+ if (FirstLine == 0) {
+ /* The list is empty */
+ L->Next = L->Prev = 0;
+ FirstLine = LastLine = L;
+ } else {
+ /* There are entries in the list, add the new one at the end */
+ LastLine->Next = L;
+ L->Prev = LastLine;
+ L->Next = 0;
+ LastLine = L;
+ }
+
+ /* Return the new line */
+ return L;
+}
+
+
+
+Line* NewCodeLineAfter (Line* LineBefore, const char* Format, va_list ap)
+/* Create a new line, insert it after L and return it. */
+{
+ /* Create a new line struct */
+ Line* L = NewLine (Format, ap);
+
+ /* Initialize struct fields. We use the same index for the inserted line
+ * as for its predecessor, since we cannot create new numbers on the
+ * fly and the index is only used to determine sort order.
+ */
+ L->Index = LineBefore->Index;
+
+ /* Insert the line after its predecessor */
+ L->Next = LineBefore->Next;
+ LineBefore->Next = L;
+ L->Prev = LineBefore;
+ if (L->Next) {
+ L->Next->Prev = L;
+ } else {
+ /* This is the last line */
+ LastLine = L;
+ }
+
+ /* Return the new line */
+ return L;
+}
+
+
+
+void FreeCodeLine (Line* L)
+/* Remove a line from the list and free it */
+{
+ /* Unlink the line */
+ if (L->Prev == 0) {
+ /* No line before this one */
+ FirstLine = L->Next;
+ } else {
+ L->Prev->Next = L->Next;
+ }
+ if (L->Next == 0) {
+ /* No line after this one */
+ LastLine = L->Prev;
+ } else {
+ L->Next->Prev = L->Prev;
+ }
+
+ /* Free the struct */
+ xfree (L);
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* asmline.h */
+/* */
+/* Internal assembler line structure */
+/* */
+/* */
+/* */
+/* (C) 2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef ASMLINE_H
+#define ASMLINE_H
+
+
+
+#include <stdarg.h>
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Structure that contains one line */
+typedef struct Line_ Line;
+struct Line_ {
+ Line* Next; /* Next line on double linked list */
+ Line* Prev; /* Revious line in list */
+ unsigned Flags; /* Flags for this line */
+ unsigned long Index; /* Index of this line */
+ unsigned Size; /* Size of this code */
+ unsigned Len; /* Length of the line */
+ char Line [1]; /* The line itself */
+};
+
+/* The line list */
+extern Line* FirstLine; /* Pointer to first line */
+extern Line* LastLine; /* Pointer to last line */
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+Line* NewCodeLine (const char* Format, va_list ap);
+/* Create a new code line and return it */
+
+Line* NewCodeLineAfter (Line* LineBefore, const char* Format, va_list ap);
+/* Create a new line, insert it after L and return it. */
+
+void FreeCodeLine (Line* L);
+/* Remove a line from the list and free it */
+
+
+
+/* End of asmline.h */
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* check.c */
+/* */
+/* Assert macros for the cc65 C compiler */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <stdlib.h>
+
+#include "error.h"
+#include "check.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Predefined messages */
+const char* _MsgInternalError = "Internal error: ";
+const char* _MsgAbstractCall = "Call to abstract method";
+const char* _MsgPrecondition = "Precondition violated: ";
+const char* _MsgCheckFailed = "Check failed: ";
+const char* _MsgProgramAborted = "Program aborted: ";
+
+
+
+static void _CheckFailed (const char* msg, const char* cond,
+ int code, const char* file, unsigned line);
+
+void (*CheckFailed) (const char* Msg, const char* Cond, int Code,
+ const char* File, unsigned Line) = _CheckFailed;
+/* Function pointer that is called from check if the condition code is true. */
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+static void _CheckFailed (const char* Msg, const char* Cond,
+ int Code, const char* File, unsigned Line)
+{
+ /* Log the error */
+ if (Code) {
+ Internal ("%s%s (= %d), file `%s', line %u", Msg, Cond, Code, File, Line);
+ } else {
+ Internal ("%s%s, file `%s', line %u", Msg, Cond, File, Line);
+ }
+
+ /* Use abort() to create a core for debugging */
+ abort ();
+}
+
+
+
+void Check (const char* Msg, const char* Cond, int Code,
+ const char* File, unsigned Line)
+/* This function is called from all check macros (see below). It checks,
+ * wether the given Code is true (!= 0). If so, it calls the CheckFailed
+ * vector with the given strings. If not, it simply returns.
+ */
+{
+ if (Code != 0) {
+ CheckFailed (Msg, Cond, Code, File, Line);
+ }
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* check.h */
+/* */
+/* Assert macros for the cc65 C compiler */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef CHECK_H
+#define CHECK_H
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+extern const char* _MsgInternalError; /* "Internal error: " */
+extern const char* _MsgPrecondition; /* "Precondition violated: " */
+extern const char* _MsgCheckFailed; /* "Check failed: " */
+extern const char* _MsgProgramAborted; /* "Program aborted: " */
+
+
+
+extern void (*CheckFailed) (const char* Msg, const char* Cond,
+ int Code, const char* File, unsigned Line);
+/* Function pointer that is called from check if the condition code is true. */
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void Check (const char* Msg, const char* Cond, int Code,
+ const char* File, unsigned Line);
+/* This function is called from all check macros (see below). It checks,
+ * wether the given Code is true (!= 0). If so, it calls the CheckFailed
+ * vector with the given strings. If not, it simply returns.
+ */
+
+
+
+#define FAIL(s) CheckFailed (_MsgInternalError, s, 0, __FILE__, __LINE__)
+/* Fail macro. Is used if something evil happens, calls checkfailed directly. */
+
+#define ABORT(s) CheckFailed (_MsgProgramAborted, s, 0, __FILE__, __LINE__)
+/* Use this one instead of FAIL if there is no internal program error but an
+ * error condition that is caused by the user or operating system (FAIL and
+ * ABORT are essentially the same but the message differs).
+ */
+
+#define PRECONDITION(c) Check (_MsgPrecondition, #c, !(c), __FILE__, __LINE__)
+
+#define CHECK(c) Check (_MsgCheckFailed, #c, !(c), __FILE__, __LINE__)
+
+#define ZCHECK(c) Check (_MsgCheckFailed, #c, c, __FILE__, __LINE__)
+
+
+
+/* End of check.h */
+#endif
+
+
+
--- /dev/null
+/*
+ * codegen.c
+ *
+ * Ullrich von Bassewitz, 08.06.1998
+ */
+
+
+
+#include <stdio.h>
+#include <string.h>
+
+#include "../common/version.h"
+
+#include "asmcode.h"
+#include "asmlabel.h"
+#include "check.h"
+#include "error.h"
+#include "global.h"
+#include "io.h"
+#include "litpool.h"
+#include "mem.h"
+#include "optimize.h"
+#include "util.h"
+#include "codegen.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Compiler relative stk ptr */
+int oursp = 0;
+
+/* Current segment */
+static enum { SEG_CODE, SEG_RODATA, SEG_DATA, SEG_BSS } CurSeg = SEG_CODE;
+
+/* Segment names */
+static char* SegmentNames [4];
+static char* SegmentHints [4] = {
+ "seg:code", "seg:rodata", "seg:data", "seg:bss"
+};
+
+
+/*****************************************************************************/
+/* Helpers */
+/*****************************************************************************/
+
+
+
+static void typeerror (unsigned type)
+/* Print an error message about an invalid operand type */
+{
+ Internal ("Invalid type in CF flags: %04X, type = %u", type, type & CF_TYPE);
+}
+
+
+
+static void CheckLocalOffs (unsigned Offs)
+/* Check the offset into the stack for 8bit range */
+{
+ if (Offs >= 256) {
+ /* Too many local vars */
+ AddCodeLine (";*** Too many locals");
+ Error (ERR_TOO_MANY_LOCALS);
+ }
+}
+
+
+
+static char* GetLabelName (unsigned flags, unsigned long label, unsigned offs)
+{
+ static char lbuf [128]; /* Label name */
+
+ /* Create the correct label name */
+ switch (flags & CF_ADDRMASK) {
+
+ case CF_STATIC:
+ /* Static memory cell */
+ sprintf (lbuf, "L%04X+%u", (unsigned)(label & 0xFFFF), offs);
+ break;
+
+ case CF_EXTERNAL:
+ /* External label */
+ sprintf (lbuf, "_%s+%u", (char*) label, offs);
+ break;
+
+ case CF_ABSOLUTE:
+ /* Absolute address */
+ sprintf (lbuf, "$%04X", (unsigned)((label+offs) & 0xFFFF));
+ break;
+
+ case CF_REGVAR:
+ /* Variable in register bank */
+ sprintf (lbuf, "regbank+%u", (unsigned)((label+offs) & 0xFFFF));
+ break;
+
+ default:
+ Internal ("Invalid address flags");
+ }
+
+ /* Return a pointer to the static buffer */
+ return lbuf;
+}
+
+
+
+/*****************************************************************************/
+/* Pre- and postamble */
+/*****************************************************************************/
+
+
+
+void g_preamble (void)
+/* Generate the assembler code preamble */
+{
+ AddCodeLine ("; File generated by cc65 v %u.%u.%u", VER_MAJOR, VER_MINOR, VER_PATCH);
+ AddEmptyLine ();
+
+ /* Insert some object file options */
+ AddCodeLine (".fopt\t\tcompiler,\"cc65 v %u.%u.%u\"", VER_MAJOR, VER_MINOR, VER_PATCH);
+ AddEmptyLine ();
+
+ /* Allow auto import for runtime library routines */
+ AddCodeLine (".autoimport\ton");
+
+ /* Switch the assembler into case sensible mode */
+ AddCodeLine (".case\t\ton");
+
+ /* Tell the assembler if we want to generate debug info */
+ AddCodeLine (".debuginfo\t%s", (DebugInfo != 0)? "on" : "off");
+
+ /* Import the stack pointer for direct auto variable access */
+ AddCodeLine (".importzp\tsp, sreg, regsave, regbank, tmp1, ptr1");
+
+ /* Define long branch macros */
+ AddCodeLine (".macpack\tlongbranch");
+ AddEmptyLine ();
+
+ /* Define the ldax macro */
+ AddCodeLine (".macro ldax Value");
+ AddCodeLine (" lda #<(Value)");
+ AddCodeLine (" ldx #>(Value)");
+ AddCodeLine (".endmacro");
+ AddEmptyLine ();
+
+ /* Define the default names for the segments */
+ SegmentNames [SEG_CODE] = xstrdup ("CODE");
+ SegmentNames [SEG_RODATA] = xstrdup ("RODATA");
+ SegmentNames [SEG_DATA] = xstrdup ("DATA");
+ SegmentNames [SEG_BSS] = xstrdup ("BSS");
+
+ /* Tell the optimizer that this is the end of the preamble */
+ AddCodeHint ("end_of_preamble");
+}
+
+
+
+void g_postamble (void)
+/* Generate assembler code postamble */
+{
+ /* Tell the optimizer that this is the start of the postamble */
+ AddCodeHint ("start_of_postamble");
+}
+
+
+
+/*****************************************************************************/
+/* Segment support */
+/*****************************************************************************/
+
+
+
+static void UseSeg (unsigned NewSeg)
+/* Switch to a specific segment */
+{
+ if (CurSeg != NewSeg) {
+ CurSeg = NewSeg;
+ AddCodeLine (".segment\t\"%s\"", SegmentNames [CurSeg]);
+ AddCodeHint (SegmentHints [CurSeg]);
+ }
+}
+
+
+
+void g_usecode (void)
+/* Switch to the code segment */
+{
+ UseSeg (SEG_CODE);
+}
+
+
+
+void g_userodata (void)
+/* Switch to the read only data segment */
+{
+ UseSeg (SEG_RODATA);
+}
+
+
+
+void g_usedata (void)
+/* Switch to the data segment */
+{
+ UseSeg (SEG_DATA);
+}
+
+
+
+void g_usebss (void)
+/* Switch to the bss segment */
+{
+ UseSeg (SEG_BSS);
+}
+
+
+
+void SegName (unsigned Seg, const char* Name)
+/* Set the name of a segment */
+{
+ /* Free the old name and set a new one */
+ xfree (SegmentNames [Seg]);
+ SegmentNames [Seg] = xstrdup (Name);
+
+ /* If the new segment is the current segment, emit a segment directive
+ * with the new name.
+ */
+ if (Seg == CurSeg) {
+ CurSeg = -1; /* Invalidate */
+ UseSeg (Seg);
+ }
+}
+
+
+
+void g_codename (const char* Name)
+/* Set the name of the CODE segment */
+{
+ SegName (SEG_CODE, Name);
+}
+
+
+
+void g_rodataname (const char* Name)
+/* Set the name of the RODATA segment */
+{
+ SegName (SEG_RODATA, Name);
+}
+
+
+
+void g_dataname (const char* Name)
+/* Set the name of the DATA segment */
+{
+ SegName (SEG_DATA, Name);
+}
+
+
+
+void g_bssname (const char* Name)
+/* Set the name of the BSS segment */
+{
+ SegName (SEG_BSS, Name);
+}
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+unsigned sizeofarg (unsigned flags)
+/* Return the size of a function argument type that is encoded in flags */
+{
+ switch (flags & CF_TYPE) {
+
+ case CF_CHAR:
+ return (flags & CF_FORCECHAR)? 1 : 2;
+
+ case CF_INT:
+ return 2;
+
+ case CF_LONG:
+ return 4;
+
+ default:
+ typeerror (flags);
+ /* NOTREACHED */
+ return 2;
+ }
+}
+
+
+
+int pop (unsigned flags)
+/* Pop an argument of the given size */
+{
+ return oursp += sizeofarg (flags);
+}
+
+
+
+int push (unsigned flags)
+/* Push an argument of the given size */
+{
+ return oursp -= sizeofarg (flags);
+}
+
+
+
+static unsigned MakeByteOffs (unsigned Flags, unsigned Offs)
+/* The value in Offs is an offset to an address in a/x. Make sure, an object
+ * of the type given in Flags can be loaded or stored into this address by
+ * adding part of the offset to the address in ax, so that the remaining
+ * offset fits into an index register. Return the remaining offset.
+ */
+{
+ /* If the offset is too large for a byte register, add the high byte
+ * of the offset to the primary. Beware: We need a special correction
+ * if the offset in the low byte will overflow in the operation.
+ */
+ unsigned O = Offs & ~0xFFU;
+ if ((Offs & 0xFF) > 256 - sizeofarg (Flags)) {
+ /* We need to add the low byte also */
+ O += Offs & 0xFF;
+ }
+
+ /* Do the correction if we need one */
+ if (O != 0) {
+ g_inc (CF_INT | CF_CONST, O);
+ Offs -= O;
+ }
+
+ /* Return the new offset */
+ return Offs;
+}
+
+
+
+/*****************************************************************************/
+/* Functions handling local labels */
+/*****************************************************************************/
+
+
+
+void g_defloclabel (unsigned label)
+/* Define a local label */
+{
+ AddCodeLine ("L%04X:", label & 0xFFFF);
+}
+
+
+
+/*****************************************************************************/
+/* Functions handling global labels */
+/*****************************************************************************/
+
+
+
+void g_defgloblabel (const char* Name)
+/* Define a global label with the given name */
+{
+ AddCodeLine ("_%s:", Name);
+}
+
+
+
+void g_defexport (const char* Name, int ZP)
+/* Export the given label */
+{
+ if (ZP) {
+ AddCodeLine ("\t.exportzp\t_%s", Name);
+ } else {
+ AddCodeLine ("\t.export\t\t_%s", Name);
+ }
+}
+
+
+
+void g_defimport (const char* Name, int ZP)
+/* Import the given label */
+{
+ if (ZP) {
+ AddCodeLine ("\t.importzp\t_%s", Name);
+ } else {
+ AddCodeLine ("\t.import\t\t_%s", Name);
+ }
+}
+
+
+
+/*****************************************************************************/
+/* Load functions for various registers */
+/*****************************************************************************/
+
+
+
+static void ldaconst (unsigned val)
+/* Load a with a constant */
+{
+ AddCodeLine ("\tlda\t#$%02X", val & 0xFF);
+}
+
+
+
+static void ldxconst (unsigned val)
+/* Load x with a constant */
+{
+ AddCodeLine ("\tldx\t#$%02X", val & 0xFF);
+}
+
+
+
+static void ldyconst (unsigned val)
+/* Load y with a constant */
+{
+ AddCodeLine ("\tldy\t#$%02X", val & 0xFF);
+}
+
+
+
+/*****************************************************************************/
+/* Function entry and exit */
+/*****************************************************************************/
+
+
+
+/* Remember the argument size of a function. The variable is set by g_enter
+ * and used by g_leave. If the functions gets its argument size by the caller
+ * (variable param list or function without prototype), g_enter will set the
+ * value to -1.
+ */
+static int funcargs;
+
+
+void g_enter (unsigned flags, const char* Name, unsigned argsize)
+/* Function prologue */
+{
+ g_defgloblabel (Name); /* Define function name as label */
+ if ((flags & CF_FIXARGC) != 0) {
+ /* Just remember the argument size for the leave */
+ funcargs = argsize;
+ } else {
+ funcargs = -1;
+ AddCodeLine ("\tjsr\tenter");
+ }
+}
+
+
+
+void g_leave (int flags, int val)
+/* Function epilogue */
+{
+ int k;
+ char buf [40];
+
+ /* How many bytes of locals do we have to drop? */
+ k = -oursp;
+
+ /* If we didn't have a variable argument list, don't call leave */
+ if (funcargs >= 0) {
+
+ /* Load a function return code if needed */
+ if ((flags & CF_CONST) != 0) {
+ g_getimmed (flags, val, 0);
+ }
+
+ /* Drop stackframe or leave with rts */
+ k += funcargs;
+ if (k == 0) {
+ AddCodeLine ("\trts");
+ } else if (k <= 8) {
+ AddCodeLine ("\tjmp\tincsp%d", k);
+ } else {
+ CheckLocalOffs (k);
+ ldyconst (k);
+ AddCodeLine ("\tjmp\taddysp");
+ }
+
+ } else {
+
+ strcpy (buf, "\tjmp\tleave");
+ if (k) {
+ /* We've a stack frame to drop */
+ ldyconst (k);
+ strcat (buf, "y");
+ }
+ if (flags & CF_CONST) {
+ if ((flags & CF_TYPE) != CF_LONG) {
+ /* Constant int sized value given for return code */
+ if (val == 0) {
+ /* Special case: return 0 */
+ strcat (buf, "00");
+ } else if (((val >> 8) & 0xFF) == 0) {
+ /* Special case: constant with high byte zero */
+ ldaconst (val); /* Load low byte */
+ strcat (buf, "0");
+ } else {
+ /* Others: arbitrary constant value */
+ g_getimmed (flags, val, 0); /* Load value */
+ }
+ } else {
+ /* Constant long value: No shortcut possible */
+ g_getimmed (flags, val, 0);
+ }
+ }
+
+ /* Output the jump */
+ AddCodeLine (buf);
+ }
+
+ /* Add an empty line after a function to make the code more readable */
+ AddEmptyLine ();
+}
+
+
+
+/*****************************************************************************/
+/* Register variables */
+/*****************************************************************************/
+
+
+
+void g_save_regvars (int RegOffs, unsigned Bytes)
+/* Save register variables */
+{
+ /* Don't loop for up to two bytes */
+ if (Bytes == 1) {
+
+ AddCodeLine ("\tlda\tregbank%+d", RegOffs);
+ AddCodeLine ("\tjsr\tpusha");
+
+ } else if (Bytes == 2) {
+
+ AddCodeLine ("\tlda\tregbank%+d", RegOffs);
+ AddCodeLine ("\tldx\tregbank%+d", RegOffs+1);
+ AddCodeLine ("\tjsr\tpushax");
+
+ } else {
+
+ /* More than two bytes - loop */
+ unsigned Label = GetLabel ();
+ g_space (Bytes);
+ ldyconst (Bytes - 1);
+ ldxconst (Bytes);
+ g_defloclabel (Label);
+ AddCodeLine ("\tlda\tregbank%+d,x", RegOffs-1);
+ AddCodeLine ("\tsta\t(sp),y");
+ AddCodeLine ("\tdey");
+ AddCodeLine ("\tdex");
+ AddCodeLine ("\tbne\tL%04X", Label);
+
+ }
+
+ /* We pushed stuff, correct the stack pointer */
+ oursp -= Bytes;
+}
+
+
+
+void g_restore_regvars (int StackOffs, int RegOffs, unsigned Bytes)
+/* Restore register variables */
+{
+ /* Calculate the actual stack offset and check it */
+ StackOffs -= oursp;
+ CheckLocalOffs (StackOffs);
+
+ /* Don't loop for up to two bytes */
+ if (Bytes == 1) {
+
+ ldyconst (StackOffs);
+ AddCodeLine ("\tlda\t(sp),y");
+ AddCodeLine ("\tsta\tregbank%+d", RegOffs);
+
+ } else if (Bytes == 2) {
+
+ ldyconst (StackOffs);
+ AddCodeLine ("\tlda\t(sp),y");
+ AddCodeLine ("\tsta\tregbank%+d", RegOffs);
+ AddCodeLine ("\tiny");
+ AddCodeLine ("\tlda\t(sp),y");
+ AddCodeLine ("\tsta\tregbank%+d", RegOffs+1);
+
+ } else {
+
+ /* More than two bytes - loop */
+ unsigned Label = GetLabel ();
+ ldyconst (StackOffs+Bytes-1);
+ ldxconst (Bytes);
+ g_defloclabel (Label);
+ AddCodeLine ("\tlda\t(sp),y");
+ AddCodeLine ("\tsta\tregbank%+d,x", RegOffs-1);
+ AddCodeLine ("\tdey");
+ AddCodeLine ("\tdex");
+ AddCodeLine ("\tbne\tL%04X", Label);
+
+ }
+}
+
+
+
+/*****************************************************************************/
+/* Fetching memory cells */
+/*****************************************************************************/
+
+
+
+void g_getimmed (unsigned flags, unsigned long val, unsigned offs)
+/* Load a constant into the primary register */
+{
+ if ((flags & CF_CONST) != 0) {
+
+ /* Numeric constant */
+ switch (flags & CF_TYPE) {
+
+ case CF_CHAR:
+ if ((flags & CF_FORCECHAR) != 0) {
+ ldaconst (val);
+ break;
+ }
+ /* FALL THROUGH */
+ case CF_INT:
+ ldxconst ((val >> 8) & 0xFF);
+ ldaconst (val & 0xFF);
+ break;
+
+ case CF_LONG:
+ if (val < 0x100) {
+ AddCodeLine ("\tldx\t#$00");
+ AddCodeLine ("\tstx\tsreg+1");
+ AddCodeLine ("\tstx\tsreg");
+ AddCodeLine ("\tlda\t#$%02X", (unsigned char) val);
+ } else if ((val & 0xFFFF00FF) == 0) {
+ AddCodeLine ("\tlda\t#$00");
+ AddCodeLine ("\tsta\tsreg+1");
+ AddCodeLine ("\tsta\tsreg");
+ AddCodeLine ("\tldx\t#$%02X", (unsigned char) (val >> 8));
+ } else if ((val & 0xFFFF0000) == 0 && FavourSize == 0) {
+ AddCodeLine ("\tlda\t#$00");
+ AddCodeLine ("\tsta\tsreg+1");
+ AddCodeLine ("\tsta\tsreg");
+ AddCodeLine ("\tlda\t#$%02X", (unsigned char) val);
+ AddCodeLine ("\tldx\t#$%02X", (unsigned char) (val >> 8));
+ } else if ((val & 0xFFFFFF00) == 0xFFFFFF00) {
+ AddCodeLine ("\tldx\t#$FF");
+ AddCodeLine ("\tstx\tsreg+1");
+ AddCodeLine ("\tstx\tsreg");
+ if ((val & 0xFF) == 0xFF) {
+ AddCodeLine ("\ttxa");
+ } else {
+ AddCodeLine ("\tlda\t#$%02X", (unsigned char) val);
+ }
+ } else if ((val & 0xFFFF00FF) == 0xFFFF00FF) {
+ AddCodeLine ("\tlda\t#$FF");
+ AddCodeLine ("\tsta\tsreg+1");
+ AddCodeLine ("\tsta\tsreg");
+ AddCodeLine ("\tldx\t#$%02X", (unsigned char) (val >> 8));
+ } else {
+ /* Call a subroutine that will load following value */
+ AddCodeLine ("\tjsr\tldeax");
+ AddCodeLine ("\t.dword\t$%08lX", val & 0xFFFFFFFF);
+ }
+ break;
+
+ default:
+ typeerror (flags);
+ break;
+
+ }
+
+ } else {
+
+ /* Some sort of label */
+ const char* Label = GetLabelName (flags, val, offs);
+
+ /* Load the address into the primary */
+ AddCodeLine ("\tldax\t%s", Label);
+
+ }
+}
+
+
+
+void g_getstatic (unsigned flags, unsigned long label, unsigned offs)
+/* Fetch an static memory cell into the primary register */
+{
+ /* Create the correct label name */
+ char* lbuf = GetLabelName (flags, label, offs);
+
+ /* Check the size and generate the correct load operation */
+ switch (flags & CF_TYPE) {
+
+ case CF_CHAR:
+ if ((flags & CF_FORCECHAR) || (flags & CF_TEST)) {
+ AddCodeLine ("\tlda\t%s", lbuf); /* load A from the label */
+ } else {
+ ldxconst (0);
+ AddCodeLine ("\tlda\t%s", lbuf); /* load A from the label */
+ if (!(flags & CF_UNSIGNED)) {
+ /* Must sign extend */
+ AddCodeLine ("\tbpl\t*+3");
+ AddCodeLine ("\tdex");
+ AddCodeHint ("x:!"); /* X is invalid now */
+ }
+ }
+ break;
+
+ case CF_INT:
+ AddCodeLine ("\tlda\t%s", lbuf);
+ if (flags & CF_TEST) {
+ AddCodeLine ("\tora\t%s+1", lbuf);
+ } else {
+ AddCodeLine ("\tldx\t%s+1", lbuf);
+ }
+ break;
+
+ case CF_LONG:
+ if (flags & CF_TEST) {
+ AddCodeLine ("\tlda\t%s+3", lbuf);
+ AddCodeLine ("\tora\t%s+2", lbuf);
+ AddCodeLine ("\tora\t%s+1", lbuf);
+ AddCodeLine ("\tora\t%s+0", lbuf);
+ } else {
+ AddCodeLine ("\tlda\t%s+3", lbuf);
+ AddCodeLine ("\tsta\tsreg+1");
+ AddCodeLine ("\tlda\t%s+2", lbuf);
+ AddCodeLine ("\tsta\tsreg");
+ AddCodeLine ("\tldx\t%s+1", lbuf);
+ AddCodeLine ("\tlda\t%s", lbuf);
+ }
+ break;
+
+ default:
+ typeerror (flags);
+
+ }
+}
+
+
+
+void g_getlocal (unsigned flags, int offs)
+/* Fetch specified local object (local var). */
+{
+ offs -= oursp;
+ CheckLocalOffs (offs);
+ switch (flags & CF_TYPE) {
+
+ case CF_CHAR:
+ if ((flags & CF_FORCECHAR) || (flags & CF_TEST)) {
+ ldyconst (offs);
+ AddCodeLine ("\tlda\t(sp),y");
+ } else {
+ if (offs == 0) {
+ AddCodeLine ("\tldx\t#$00");
+ AddCodeLine ("\tlda\t(sp,x)");
+ } else {
+ ldyconst (offs);
+ AddCodeLine ("\tldx\t#$00");
+ AddCodeLine ("\tlda\t(sp),y");
+ }
+ if ((flags & CF_UNSIGNED) == 0) {
+ AddCodeLine ("\tbpl\t*+3");
+ AddCodeLine ("\tdex");
+ AddCodeHint ("x:!"); /* X is invalid now */
+ }
+ }
+ break;
+
+ case CF_INT:
+ CheckLocalOffs (offs + 1);
+ if (flags & CF_TEST) {
+ ldyconst (offs + 1);
+ AddCodeLine ("\tlda\t(sp),y");
+ AddCodeLine ("\tdey");
+ AddCodeLine ("\tora\t(sp),y");
+ } else {
+ if (FavourSize) {
+ if (offs) {
+ ldyconst (offs+1);
+ AddCodeLine ("\tjsr\tldaxysp");
+ } else {
+ AddCodeLine ("\tjsr\tldax0sp");
+ }
+ } else {
+ ldyconst (offs + 1);
+ AddCodeLine ("\tlda\t(sp),y");
+ AddCodeLine ("\ttax");
+ AddCodeLine ("\tdey");
+ AddCodeLine ("\tlda\t(sp),y");
+ }
+ }
+ break;
+
+ case CF_LONG:
+ if (offs) {
+ ldyconst (offs+3);
+ AddCodeLine ("\tjsr\tldeaxysp");
+ } else {
+ AddCodeLine ("\tjsr\tldeax0sp");
+ }
+ break;
+
+ default:
+ typeerror (flags);
+ }
+}
+
+
+
+void g_getind (unsigned flags, unsigned offs)
+/* Fetch the specified object type indirect through the primary register
+ * into the primary register
+ */
+{
+ /* If the offset is greater than 255, add the part that is > 255 to
+ * the primary. This way we get an easy addition and use the low byte
+ * as the offset
+ */
+ offs = MakeByteOffs (flags, offs);
+
+ /* Handle the indirect fetch */
+ switch (flags & CF_TYPE) {
+
+ case CF_CHAR:
+ /* Character sized */
+ if (offs) {
+ ldyconst (offs);
+ if (flags & CF_UNSIGNED) {
+ AddCodeLine ("\tjsr\tldauidx");
+ } else {
+ AddCodeLine ("\tjsr\tldaidx");
+ }
+ } else {
+ if (flags & CF_UNSIGNED) {
+ if (FavourSize) {
+ AddCodeLine ("\tjsr\tldaui");
+ } else {
+ AddCodeLine ("\tsta\tptr1");
+ AddCodeLine ("\tstx\tptr1+1");
+ AddCodeLine ("\tldx\t#$00");
+ AddCodeLine ("\tlda\t(ptr1,x)");
+ }
+ } else {
+ AddCodeLine ("\tjsr\tldai");
+ }
+ }
+ break;
+
+ case CF_INT:
+ if (flags & CF_TEST) {
+ ldyconst (offs);
+ AddCodeLine ("\tsta\tptr1");
+ AddCodeLine ("\tstx\tptr1+1");
+ AddCodeLine ("\tlda\t(ptr1),y");
+ AddCodeLine ("\tiny");
+ AddCodeLine ("\tora\t(ptr1),y");
+ } else {
+ if (offs == 0) {
+ AddCodeLine ("\tjsr\tldaxi");
+ } else {
+ ldyconst (offs+1);
+ AddCodeLine ("\tjsr\tldaxidx");
+ }
+ }
+ break;
+
+ case CF_LONG:
+ if (offs == 0) {
+ AddCodeLine ("\tjsr\tldeaxi");
+ } else {
+ ldyconst (offs+3);
+ AddCodeLine ("\tjsr\tldeaxidx");
+ }
+ if (flags & CF_TEST) {
+ AddCodeLine ("\tjsr\ttsteax");
+ }
+ break;
+
+ default:
+ typeerror (flags);
+
+ }
+}
+
+
+
+void g_leasp (int offs)
+/* Fetch the address of the specified symbol into the primary register */
+{
+ /* Calculate the offset relative to sp */
+ offs -= oursp;
+
+ /* For value 0 we do direct code */
+ if (offs == 0) {
+ AddCodeLine ("\tlda\tsp");
+ AddCodeLine ("\tldx\tsp+1");
+ } else {
+ if (FavourSize) {
+ ldyconst (offs); /* Load Y with offset value */
+ AddCodeLine ("\tjsr\tleaysp"); /* Load effective address */
+ } else {
+ ldaconst (offs);
+ AddCodeLine ("\tclc");
+ AddCodeLine ("\tldx\tsp+1");
+ AddCodeLine ("\tadc\tsp");
+ AddCodeLine ("\tbcc\t*+3");
+ AddCodeLine ("\tinx");
+ AddCodeHint ("x:!"); /* Invalidate X */
+ }
+ }
+}
+
+
+
+/*****************************************************************************/
+/* Store into memory */
+/*****************************************************************************/
+
+
+
+void g_putstatic (unsigned flags, unsigned long label, unsigned offs)
+/* Store the primary register into the specified static memory cell */
+{
+ /* Create the correct label name */
+ char* lbuf = GetLabelName (flags, label, offs);
+
+ /* Check the size and generate the correct store operation */
+ switch (flags & CF_TYPE) {
+
+ case CF_CHAR:
+ AddCodeLine ("\tsta\t%s", lbuf);
+ break;
+
+ case CF_INT:
+ AddCodeLine ("\tsta\t%s", lbuf);
+ AddCodeLine ("\tstx\t%s+1", lbuf);
+ break;
+
+ case CF_LONG:
+ AddCodeLine ("\tsta\t%s", lbuf);
+ AddCodeLine ("\tstx\t%s+1", lbuf);
+ AddCodeLine ("\tldy\tsreg");
+ AddCodeLine ("\tsty\t%s+2", lbuf);
+ AddCodeLine ("\tldy\tsreg+1");
+ AddCodeLine ("\tsty\t%s+3", lbuf);
+ break;
+
+ default:
+ typeerror (flags);
+
+ }
+}
+
+
+
+void g_putlocal (unsigned flags, int offs)
+/* Put data into local object. */
+{
+ offs -= oursp;
+ CheckLocalOffs (offs);
+ switch (flags & CF_TYPE) {
+
+ case CF_CHAR:
+ ldyconst (offs);
+ AddCodeLine ("\tsta\t(sp),y");
+ break;
+
+ case CF_INT:
+ if (offs) {
+ ldyconst (offs);
+ AddCodeLine ("\tjsr\tstaxysp");
+ } else {
+ AddCodeLine ("\tjsr\tstax0sp");
+ }
+ break;
+
+ case CF_LONG:
+ if (offs) {
+ ldyconst (offs);
+ AddCodeLine ("\tjsr\tsteaxysp");
+ } else {
+ AddCodeLine ("\tjsr\tsteax0sp");
+ }
+ break;
+
+ default:
+ typeerror (flags);
+
+ }
+}
+
+
+
+void g_putind (unsigned flags, unsigned offs)
+/* Store the specified object type in the primary register at the address
+ * on the top of the stack
+ */
+{
+ /* We cannot currently handle more than byte sized offsets */
+ if (offs > 256 - sizeofarg (flags)) {
+ Internal ("g_putind: Large offsets not implemented");
+ }
+
+ /* Check the size and determine operation */
+ switch (flags & CF_TYPE) {
+
+ case CF_CHAR:
+ if (offs) {
+ ldyconst (offs);
+ AddCodeLine ("\tjsr\tstaspidx");
+ } else {
+ AddCodeLine ("\tjsr\tstaspp");
+ }
+ break;
+
+ case CF_INT:
+ if (offs) {
+ ldyconst (offs);
+ AddCodeLine ("\tjsr\tstaxspidx");
+ } else {
+ AddCodeLine ("\tjsr\tstaxspp");
+ }
+ break;
+
+ case CF_LONG:
+ if (offs) {
+ ldyconst (offs);
+ AddCodeLine ("\tjsr\tsteaxspidx");
+ } else {
+ AddCodeLine ("\tjsr\tsteaxspp");
+ }
+ break;
+
+ default:
+ typeerror (flags);
+
+ }
+
+ /* Pop the argument which is always a pointer */
+ pop (CF_PTR);
+}
+
+
+
+/*****************************************************************************/
+/* type conversion and similiar stuff */
+/*****************************************************************************/
+
+
+
+void g_toslong (unsigned flags)
+/* Make sure, the value on TOS is a long. Convert if necessary */
+{
+ switch (flags & CF_TYPE) {
+
+ case CF_CHAR:
+ case CF_INT:
+ if (flags & CF_UNSIGNED) {
+ AddCodeLine ("\tjsr\ttosulong");
+ } else {
+ AddCodeLine ("\tjsr\ttoslong");
+ }
+ push (CF_INT);
+ break;
+
+ case CF_LONG:
+ break;
+
+ default:
+ typeerror (flags);
+ }
+}
+
+
+
+void g_tosint (unsigned flags)
+/* Make sure, the value on TOS is an int. Convert if necessary */
+{
+ switch (flags & CF_TYPE) {
+
+ case CF_CHAR:
+ case CF_INT:
+ break;
+
+ case CF_LONG:
+ AddCodeLine ("\tjsr\ttosint");
+ pop (CF_INT);
+ break;
+
+ default:
+ typeerror (flags);
+ }
+}
+
+
+
+void g_reglong (unsigned flags)
+/* Make sure, the value in the primary register a long. Convert if necessary */
+{
+ switch (flags & CF_TYPE) {
+
+ case CF_CHAR:
+ case CF_INT:
+ if (flags & CF_UNSIGNED) {
+ if (FavourSize) {
+ AddCodeLine ("\tjsr\taxulong");
+ } else {
+ ldyconst (0);
+ AddCodeLine ("\tsty\tsreg");
+ AddCodeLine ("\tsty\tsreg+1");
+ }
+ } else {
+ AddCodeLine ("\tjsr\taxlong");
+ }
+ break;
+
+ case CF_LONG:
+ break;
+
+ default:
+ typeerror (flags);
+ }
+}
+
+
+
+unsigned g_typeadjust (unsigned lhs, unsigned rhs)
+/* Adjust the integer operands before doing a binary operation. lhs is a flags
+ * value, that corresponds to the value on TOS, rhs corresponds to the value
+ * in (e)ax. The return value is the the flags value for the resulting type.
+ */
+{
+ unsigned ltype, rtype;
+ unsigned result;
+
+ /* Get the type spec from the flags */
+ ltype = lhs & CF_TYPE;
+ rtype = rhs & CF_TYPE;
+
+ /* Check if a conversion is needed */
+ if (ltype == CF_LONG && rtype != CF_LONG && (rhs & CF_CONST) == 0) {
+ /* We must promote the primary register to long */
+ g_reglong (rhs);
+ /* Get the new rhs type */
+ rhs = (rhs & ~CF_TYPE) | CF_LONG;
+ rtype = CF_LONG;
+ } else if (ltype != CF_LONG && (lhs & CF_CONST) == 0 && rtype == CF_LONG) {
+ /* We must promote the lhs to long */
+ if (lhs & CF_REG) {
+ g_reglong (lhs);
+ } else {
+ g_toslong (lhs);
+ }
+ /* Get the new rhs type */
+ lhs = (lhs & ~CF_TYPE) | CF_LONG;
+ ltype = CF_LONG;
+ }
+
+ /* Determine the result type for the operation:
+ * - The result is const if both operands are const.
+ * - The result is unsigned if one of the operands is unsigned.
+ * - The result is long if one of the operands is long.
+ * - Otherwise the result is int sized.
+ */
+ result = (lhs & CF_CONST) & (rhs & CF_CONST);
+ result |= (lhs & CF_UNSIGNED) | (rhs & CF_UNSIGNED);
+ if (rtype == CF_LONG || ltype == CF_LONG) {
+ result |= CF_LONG;
+ } else {
+ result |= CF_INT;
+ }
+ return result;
+}
+
+
+
+unsigned g_typecast (unsigned lhs, unsigned rhs)
+/* Cast the value in the primary register to the operand size that is flagged
+ * by the lhs value. Return the result value.
+ */
+{
+ unsigned ltype, rtype;
+
+ /* Get the type spec from the flags */
+ ltype = lhs & CF_TYPE;
+ rtype = rhs & CF_TYPE;
+
+ /* Check if a conversion is needed */
+ if (ltype == CF_LONG && rtype != CF_LONG && (rhs & CF_CONST) == 0) {
+ /* We must promote the primary register to long */
+ g_reglong (rhs);
+ }
+
+ /* Do not need any other action. If the left type is int, and the primary
+ * register is long, it will be automagically truncated. If the right hand
+ * side is const, it is not located in the primary register and handled by
+ * the expression parser code.
+ */
+
+ /* Result is const if the right hand side was const */
+ lhs |= (rhs & CF_CONST);
+
+ /* The resulting type is that of the left hand side (that's why you called
+ * this function :-)
+ */
+ return lhs;
+}
+
+
+
+void g_scale (unsigned flags, long val)
+/* Scale the value in the primary register by the given value. If val is positive,
+ * scale up, is val is negative, scale down. This function is used to scale
+ * the operands or results of pointer arithmetic by the size of the type, the
+ * pointer points to.
+ */
+{
+ int p2;
+
+ /* Value may not be zero */
+ if (val == 0) {
+ Internal ("Data type has no size");
+ } else if (val > 0) {
+
+ /* Scale up */
+ if ((p2 = powerof2 (val)) > 0 && p2 <= 3) {
+
+ /* Factor is 2, 4 or 8, use special function */
+ switch (flags & CF_TYPE) {
+
+ case CF_CHAR:
+ if (flags & CF_FORCECHAR) {
+ while (p2--) {
+ AddCodeLine ("\tasl\ta");
+ }
+ break;
+ }
+ /* FALLTHROUGH */
+
+ case CF_INT:
+ if (FavourSize || p2 >= 3) {
+ if (flags & CF_UNSIGNED) {
+ AddCodeLine ("\tjsr\tshlax%d", p2);
+ } else {
+ AddCodeLine ("\tjsr\taslax%d", p2);
+ }
+ } else {
+ AddCodeLine ("\tstx\ttmp1");
+ while (p2--) {
+ AddCodeLine ("\tasl\ta");
+ AddCodeLine ("\trol\ttmp1");
+ }
+ AddCodeLine ("\tldx\ttmp1");
+ }
+ break;
+
+ case CF_LONG:
+ if (flags & CF_UNSIGNED) {
+ AddCodeLine ("\tjsr\tshleax%d", p2);
+ } else {
+ AddCodeLine ("\tjsr\tasleax%d", p2);
+ }
+ break;
+
+ default:
+ typeerror (flags);
+
+ }
+
+ } else if (val != 1) {
+
+ /* Use a multiplication instead */
+ g_mul (flags | CF_CONST, val);
+
+ }
+
+ } else {
+
+ /* Scale down */
+ val = -val;
+ if ((p2 = powerof2 (val)) > 0 && p2 <= 3) {
+
+ /* Factor is 2, 4 or 8, use special function */
+ switch (flags & CF_TYPE) {
+
+ case CF_CHAR:
+ if (flags & CF_FORCECHAR) {
+ if (flags & CF_UNSIGNED) {
+ while (p2--) {
+ AddCodeLine ("\tlsr\ta");
+ }
+ break;
+ } else if (p2 <= 2) {
+ AddCodeLine ("\tcmp\t#$80");
+ AddCodeLine ("\tror\ta");
+ break;
+ }
+ }
+ /* FALLTHROUGH */
+
+ case CF_INT:
+ if (flags & CF_UNSIGNED) {
+ if (FavourSize || p2 >= 3) {
+ AddCodeLine ("\tjsr\tlsrax%d", p2);
+ } else {
+ AddCodeLine ("\tstx\ttmp1");
+ while (p2--) {
+ AddCodeLine ("\tlsr\ttmp1");
+ AddCodeLine ("\tror\ta");
+ }
+ AddCodeLine ("\tldx\ttmp1");
+ }
+ } else {
+ if (FavourSize || p2 >= 3) {
+ AddCodeLine ("\tjsr\tasrax%d", p2);
+ } else {
+ AddCodeLine ("\tstx\ttmp1");
+ while (p2--) {
+ AddCodeLine ("\tcpx\t#$80");
+ AddCodeLine ("\tror\ttmp1");
+ AddCodeLine ("\tror\ta");
+ }
+ AddCodeLine ("\tldx\ttmp1");
+ }
+ }
+ break;
+
+ case CF_LONG:
+ if (flags & CF_UNSIGNED) {
+ AddCodeLine ("\tjsr\tlsreax%d", p2);
+ } else {
+ AddCodeLine ("\tjsr\tasreax%d", p2);
+ }
+ break;
+
+ default:
+ typeerror (flags);
+
+ }
+
+ } else if (val != 1) {
+
+ /* Use a division instead */
+ g_div (flags | CF_CONST, val);
+
+ }
+ }
+}
+
+
+
+/*****************************************************************************/
+/* Adds and subs of variables fix a fixed address */
+/*****************************************************************************/
+
+
+
+void g_addlocal (unsigned flags, int offs)
+/* Add a local variable to ax */
+{
+ /* Correct the offset and check it */
+ offs -= oursp;
+ CheckLocalOffs (offs);
+
+ switch (flags & CF_TYPE) {
+
+ case CF_CHAR:
+ AddCodeLine ("\tldy\t#$%02X", offs & 0xFF);
+ AddCodeLine ("\tclc");
+ AddCodeLine ("\tadc\t(sp),y");
+ AddCodeLine ("\tbcc\t*+3");
+ AddCodeLine ("\tinx");
+ AddCodeHint ("x:!");
+ break;
+
+ case CF_INT:
+ AddCodeLine ("\tldy\t#$%02X", offs & 0xFF);
+ AddCodeLine ("\tclc");
+ AddCodeLine ("\tadc\t(sp),y");
+ AddCodeLine ("\tpha");
+ AddCodeLine ("\ttxa");
+ AddCodeLine ("\tiny");
+ AddCodeLine ("\tadc\t(sp),y");
+ AddCodeLine ("\ttax");
+ AddCodeLine ("\tpla");
+ break;
+
+ case CF_LONG:
+ /* Do it the old way */
+ g_push (flags, 0);
+ g_getlocal (flags, offs);
+ g_add (flags, 0);
+ break;
+
+ default:
+ typeerror (flags);
+
+ }
+}
+
+
+
+void g_addstatic (unsigned flags, unsigned long label, unsigned offs)
+/* Add a static variable to ax */
+{
+ /* Create the correct label name */
+ char* lbuf = GetLabelName (flags, label, offs);
+
+ switch (flags & CF_TYPE) {
+
+ case CF_CHAR:
+ AddCodeLine ("\tclc");
+ AddCodeLine ("\tadc\t%s", lbuf);
+ AddCodeLine ("\tbcc\t*+3");
+ AddCodeLine ("\tinx");
+ AddCodeHint ("x:!");
+ break;
+
+ case CF_INT:
+ AddCodeLine ("\tclc");
+ AddCodeLine ("\tadc\t%s", lbuf);
+ AddCodeLine ("\ttay");
+ AddCodeLine ("\ttxa");
+ AddCodeLine ("\tadc\t%s+1", lbuf);
+ AddCodeLine ("\ttax");
+ AddCodeLine ("\ttya");
+ break;
+
+ case CF_LONG:
+ /* Do it the old way */
+ g_push (flags, 0);
+ g_getstatic (flags, label, offs);
+ g_add (flags, 0);
+ break;
+
+ default:
+ typeerror (flags);
+
+ }
+}
+
+
+
+/*****************************************************************************/
+/* Compares of ax with a variable with fixed address */
+/*****************************************************************************/
+
+
+
+void g_cmplocal (unsigned flags, int offs)
+/* Compare a local variable to ax */
+{
+ Internal ("g_cmplocal not implemented");
+}
+
+
+
+void g_cmpstatic (unsigned flags, unsigned label, unsigned offs)
+/* Compare a static variable to ax */
+{
+ Internal ("g_cmpstatic not implemented");
+}
+
+
+
+/*****************************************************************************/
+/* Special op= functions */
+/*****************************************************************************/
+
+
+
+void g_addeqstatic (unsigned flags, unsigned long label, unsigned offs,
+ unsigned long val)
+/* Emit += for a static variable */
+{
+ /* Create the correct label name */
+ char* lbuf = GetLabelName (flags, label, offs);
+
+ /* Check the size and determine operation */
+ switch (flags & CF_TYPE) {
+
+ case CF_CHAR:
+ if (flags & CF_FORCECHAR) {
+ AddCodeLine ("\tldx\t#$00");
+ if (flags & CF_CONST) {
+ if (val == 1) {
+ AddCodeLine ("\tinc\t%s", lbuf);
+ AddCodeLine ("\tlda\t%s", lbuf);
+ } else {
+ AddCodeLine ("\tlda\t#$%02X", val & 0xFF);
+ AddCodeLine ("\tclc");
+ AddCodeLine ("\tadc\t%s", lbuf);
+ AddCodeLine ("\tsta\t%s", lbuf);
+ }
+ } else {
+ AddCodeLine ("\tclc");
+ AddCodeLine ("\tadc\t%s", lbuf);
+ AddCodeLine ("\tsta\t%s", lbuf);
+ }
+ if ((flags & CF_UNSIGNED) == 0) {
+ AddCodeLine ("\tbpl\t*+3");
+ AddCodeLine ("\tdex");
+ AddCodeHint ("x:!"); /* Invalidate X */
+ }
+ break;
+ }
+ /* FALLTHROUGH */
+
+ case CF_INT:
+ if (flags & CF_CONST) {
+ if (val == 1) {
+ label = GetLabel ();
+ AddCodeLine ("\tinc\t%s", lbuf);
+ AddCodeLine ("\tbne\tL%04X", label);
+ AddCodeLine ("\tinc\t%s+1", lbuf);
+ g_defloclabel (label);
+ AddCodeLine ("\tlda\t%s", lbuf); /* Hmmm... */
+ AddCodeLine ("\tldx\t%s+1", lbuf);
+ } else {
+ AddCodeLine ("\tlda\t#$%02X", val & 0xFF);
+ AddCodeLine ("\tclc");
+ AddCodeLine ("\tadc\t%s", lbuf);
+ AddCodeLine ("\tsta\t%s", lbuf);
+ if (val < 0x100) {
+ label = GetLabel ();
+ AddCodeLine ("\tbcc\tL%04X", label);
+ AddCodeLine ("\tinc\t%s+1", lbuf);
+ g_defloclabel (label);
+ AddCodeLine ("\tldx\t%s+1", lbuf);
+ } else {
+ AddCodeLine ("\tlda\t#$%02X", (val >> 8) & 0xFF);
+ AddCodeLine ("\tadc\t%s+1", lbuf);
+ AddCodeLine ("\tsta\t%s+1", lbuf);
+ AddCodeLine ("\ttax");
+ AddCodeLine ("\tlda\t%s", lbuf);
+ }
+ }
+ } else {
+ AddCodeLine ("\tclc");
+ AddCodeLine ("\tadc\t%s", lbuf);
+ AddCodeLine ("\tsta\t%s", lbuf);
+ AddCodeLine ("\ttxa");
+ AddCodeLine ("\tadc\t%s+1", lbuf);
+ AddCodeLine ("\tsta\t%s+1", lbuf);
+ AddCodeLine ("\ttax");
+ AddCodeLine ("\tlda\t%s", lbuf);
+ }
+ break;
+
+ case CF_LONG:
+ if (flags & CF_CONST) {
+ if (val < 0x100) {
+ AddCodeLine ("\tldy\t#<(%s)", lbuf);
+ AddCodeLine ("\tsty\tptr1");
+ AddCodeLine ("\tldy\t#>(%s+1)", lbuf);
+ if (val == 1) {
+ AddCodeLine ("\tjsr\tladdeq1");
+ } else {
+ AddCodeLine ("\tlda\t#$%02X", val & 0xFF);
+ AddCodeLine ("\tjsr\tladdeqa");
+ }
+ } else {
+ g_getstatic (flags, label, offs);
+ g_inc (flags, val);
+ g_putstatic (flags, label, offs);
+ }
+ } else {
+ AddCodeLine ("\tldy\t#<(%s)", lbuf);
+ AddCodeLine ("\tsty\tptr1");
+ AddCodeLine ("\tldy\t#>(%s+1)", lbuf);
+ AddCodeLine ("\tjsr\tladdeq");
+ }
+ break;
+
+ default:
+ typeerror (flags);
+ }
+}
+
+
+
+void g_addeqlocal (unsigned flags, int offs, unsigned long val)
+/* Emit += for a local variable */
+{
+ /* Calculate the true offset, check it, load it into Y */
+ offs -= oursp;
+ CheckLocalOffs (offs);
+
+ /* Check the size and determine operation */
+ switch (flags & CF_TYPE) {
+
+ case CF_CHAR:
+ if (flags & CF_FORCECHAR) {
+ if (offs == 0) {
+ AddCodeLine ("\tldx\t#$00");
+ if (flags & CF_CONST) {
+ AddCodeLine ("\tclc");
+ AddCodeLine ("\tlda\t#$%02X", val & 0xFF);
+ AddCodeLine ("\tadc\t(sp,x)");
+ AddCodeLine ("\tsta\t(sp,x)");
+ } else {
+ AddCodeLine ("\tclc");
+ AddCodeLine ("\tadc\t(sp,x)");
+ AddCodeLine ("\tsta\t(sp,x)");
+ }
+ } else {
+ ldyconst (offs);
+ AddCodeLine ("\tldx\t#$00");
+ if (flags & CF_CONST) {
+ AddCodeLine ("\tclc");
+ AddCodeLine ("\tlda\t#$%02X", val & 0xFF);
+ AddCodeLine ("\tadc\t(sp),y");
+ AddCodeLine ("\tsta\t(sp),y");
+ } else {
+ AddCodeLine ("\tclc");
+ AddCodeLine ("\tadc\t(sp),y");
+ AddCodeLine ("\tsta\t(sp),y");
+ }
+ }
+ if ((flags & CF_UNSIGNED) == 0) {
+ AddCodeLine ("\tbpl\t*+3");
+ AddCodeLine ("\tdex");
+ AddCodeHint ("x:!"); /* Invalidate X */
+ }
+ break;
+ }
+ /* FALLTHROUGH */
+
+ case CF_INT:
+ if (flags & CF_CONST) {
+ g_getimmed (flags, val, 0);
+ }
+ if (offs == 0) {
+ AddCodeLine ("\tjsr\taddeq0sp");
+ } else {
+ ldyconst (offs);
+ AddCodeLine ("\tjsr\taddeqysp");
+ }
+ break;
+
+ case CF_LONG:
+ if (flags & CF_CONST) {
+ g_getimmed (flags, val, 0);
+ }
+ if (offs == 0) {
+ AddCodeLine ("\tjsr\tladdeq0sp");
+ } else {
+ ldyconst (offs);
+ AddCodeLine ("\tjsr\tladdeqysp");
+ }
+ break;
+
+ default:
+ typeerror (flags);
+ }
+}
+
+
+
+void g_addeqind (unsigned flags, unsigned offs, unsigned long val)
+/* Emit += for the location with address in ax */
+{
+ /* If the offset is too large for a byte register, add the high byte
+ * of the offset to the primary. Beware: We need a special correction
+ * if the offset in the low byte will overflow in the operation.
+ */
+ offs = MakeByteOffs (flags, offs);
+
+ /* Check the size and determine operation */
+ switch (flags & CF_TYPE) {
+
+ case CF_CHAR:
+ AddCodeLine ("\tsta\tptr1");
+ AddCodeLine ("\tstx\tptr1+1");
+ if (offs == 0) {
+ AddCodeLine ("\tldx\t#$00");
+ AddCodeLine ("\tlda\t#$%02X", val & 0xFF);
+ AddCodeLine ("\tclc");
+ AddCodeLine ("\tadc\t(ptr1,x)");
+ AddCodeLine ("\tsta\t(ptr1,x)");
+ } else {
+ AddCodeLine ("\tldy\t#$%02X", offs);
+ AddCodeLine ("\tldx\t#$00");
+ AddCodeLine ("\tlda\t#$%02X", val & 0xFF);
+ AddCodeLine ("\tclc");
+ AddCodeLine ("\tadc\t(ptr1),y");
+ AddCodeLine ("\tsta\t(ptr1),y");
+ }
+ break;
+
+ case CF_INT:
+ if (!FavourSize) {
+ /* Lots of code, use only if size is not important */
+ AddCodeLine ("\tsta\tptr1");
+ AddCodeLine ("\tstx\tptr1+1");
+ AddCodeLine ("\tldy\t#$%02X", offs);
+ AddCodeLine ("\tlda\t#$%02X", val & 0xFF);
+ AddCodeLine ("\tclc");
+ AddCodeLine ("\tadc\t(ptr1),y");
+ AddCodeLine ("\tsta\t(ptr1),y");
+ AddCodeLine ("\tpha");
+ AddCodeLine ("\tiny");
+ AddCodeLine ("\tlda\t#$%02X", (val >> 8) & 0xFF);
+ AddCodeLine ("\tadc\t(ptr1),y");
+ AddCodeLine ("\tsta\t(ptr1),y");
+ AddCodeLine ("\ttax");
+ AddCodeLine ("\tpla");
+ break;
+ }
+ /* FALL THROUGH */
+
+ case CF_LONG:
+ AddCodeLine ("\tjsr\tpushax"); /* Push the address */
+ push (flags); /* Correct the internal sp */
+ g_getind (flags, offs); /* Fetch the value */
+ g_inc (flags, val); /* Increment value in primary */
+ g_putind (flags, offs); /* Store the value back */
+ break;
+
+ default:
+ typeerror (flags);
+ }
+}
+
+
+
+void g_subeqstatic (unsigned flags, unsigned long label, unsigned offs,
+ unsigned long val)
+/* Emit -= for a static variable */
+{
+ /* Create the correct label name */
+ char* lbuf = GetLabelName (flags, label, offs);
+
+ /* Check the size and determine operation */
+ switch (flags & CF_TYPE) {
+
+ case CF_CHAR:
+ if (flags & CF_FORCECHAR) {
+ AddCodeLine ("\tldx\t#$00");
+ if (flags & CF_CONST) {
+ if (val == 1) {
+ AddCodeLine ("\tdec\t%s", lbuf);
+ AddCodeLine ("\tlda\t%s", lbuf);
+ } else {
+ AddCodeLine ("\tsec");
+ AddCodeLine ("\tlda\t%s", lbuf);
+ AddCodeLine ("\tsbc\t#$%02X", val & 0xFF);
+ AddCodeLine ("\tsta\t%s", lbuf);
+ }
+ } else {
+ AddCodeLine ("\tsec");
+ AddCodeLine ("\tsta\ttmp1");
+ AddCodeLine ("\tlda\t%s", lbuf);
+ AddCodeLine ("\tsbc\ttmp1");
+ AddCodeLine ("\tsta\t%s", lbuf);
+ }
+ if ((flags & CF_UNSIGNED) == 0) {
+ AddCodeLine ("\tbpl\t*+3");
+ AddCodeLine ("\tdex");
+ AddCodeHint ("x:!"); /* Invalidate X */
+ }
+ break;
+ }
+ /* FALLTHROUGH */
+
+ case CF_INT:
+ AddCodeLine ("\tsec");
+ if (flags & CF_CONST) {
+ AddCodeLine ("\tlda\t%s", lbuf);
+ AddCodeLine ("\tsbc\t#$%02X", val & 0xFF);
+ AddCodeLine ("\tsta\t%s", lbuf);
+ if (val < 0x100) {
+ label = GetLabel ();
+ AddCodeLine ("\tbcs\tL%04X", label);
+ AddCodeLine ("\tdec\t%s+1", lbuf);
+ g_defloclabel (label);
+ AddCodeLine ("\tldx\t%s+1", lbuf);
+ } else {
+ AddCodeLine ("\tlda\t%s+1", lbuf);
+ AddCodeLine ("\tsbc\t#$%02X", (val >> 8) & 0xFF);
+ AddCodeLine ("\tsta\t%s+1", lbuf);
+ AddCodeLine ("\ttax");
+ AddCodeLine ("\tlda\t%s", lbuf);
+ }
+ } else {
+ AddCodeLine ("\tsta\ttmp1");
+ AddCodeLine ("\tlda\t%s", lbuf);
+ AddCodeLine ("\tsbc\ttmp1");
+ AddCodeLine ("\tsta\t%s", lbuf);
+ AddCodeLine ("\tstx\ttmp1");
+ AddCodeLine ("\tlda\t%s+1", lbuf);
+ AddCodeLine ("\tsbc\ttmp1");
+ AddCodeLine ("\tsta\t%s+1", lbuf);
+ AddCodeLine ("\ttax");
+ AddCodeLine ("\tlda\t%s", lbuf);
+ }
+ break;
+
+ case CF_LONG:
+ if (flags & CF_CONST) {
+ if (val < 0x100) {
+ AddCodeLine ("\tldy\t#<(%s)", lbuf);
+ AddCodeLine ("\tsty\tptr1");
+ AddCodeLine ("\tldy\t#>(%s+1)", lbuf);
+ if (val == 1) {
+ AddCodeLine ("\tjsr\tlsubeq1");
+ } else {
+ AddCodeLine ("\tlda\t#$%02X", val & 0xFF);
+ AddCodeLine ("\tjsr\tlsubeqa");
+ }
+ } else {
+ g_getstatic (flags, label, offs);
+ g_dec (flags, val);
+ g_putstatic (flags, label, offs);
+ }
+ } else {
+ AddCodeLine ("\tldy\t#<(%s)", lbuf);
+ AddCodeLine ("\tsty\tptr1");
+ AddCodeLine ("\tldy\t#>(%s+1)", lbuf);
+ AddCodeLine ("\tjsr\tlsubeq");
+ }
+ break;
+
+ default:
+ typeerror (flags);
+ }
+}
+
+
+
+void g_subeqlocal (unsigned flags, int offs, unsigned long val)
+/* Emit -= for a local variable */
+{
+ /* Calculate the true offset, check it, load it into Y */
+ offs -= oursp;
+ CheckLocalOffs (offs);
+
+ /* Check the size and determine operation */
+ switch (flags & CF_TYPE) {
+
+ case CF_CHAR:
+ if (flags & CF_FORCECHAR) {
+ ldyconst (offs);
+ AddCodeLine ("\tldx\t#$00");
+ AddCodeLine ("\tsec");
+ if (flags & CF_CONST) {
+ AddCodeLine ("\tlda\t(sp),y");
+ AddCodeLine ("\tsbc\t#$%02X", val & 0xFF);
+ } else {
+ AddCodeLine ("\tsta\ttmp1");
+ AddCodeLine ("\tlda\t(sp),y");
+ AddCodeLine ("\tsbc\ttmp1");
+ }
+ AddCodeLine ("\tsta\t(sp),y");
+ if ((flags & CF_UNSIGNED) == 0) {
+ AddCodeLine ("\tbpl\t*+3");
+ AddCodeLine ("\tdex");
+ AddCodeHint ("x:!"); /* Invalidate X */
+ }
+ break;
+ }
+ /* FALLTHROUGH */
+
+ case CF_INT:
+ if (flags & CF_CONST) {
+ g_getimmed (flags, val, 0);
+ }
+ if (offs == 0) {
+ AddCodeLine ("\tjsr\tsubeq0sp");
+ } else {
+ ldyconst (offs);
+ AddCodeLine ("\tjsr\tsubeqysp");
+ }
+ break;
+
+ case CF_LONG:
+ if (flags & CF_CONST) {
+ g_getimmed (flags, val, 0);
+ }
+ if (offs == 0) {
+ AddCodeLine ("\tjsr\tlsubeq0sp");
+ } else {
+ ldyconst (offs);
+ AddCodeLine ("\tjsr\tlsubeqysp");
+ }
+ break;
+
+ default:
+ typeerror (flags);
+ }
+}
+
+
+
+void g_subeqind (unsigned flags, unsigned offs, unsigned long val)
+/* Emit -= for the location with address in ax */
+{
+ /* If the offset is too large for a byte register, add the high byte
+ * of the offset to the primary. Beware: We need a special correction
+ * if the offset in the low byte will overflow in the operation.
+ */
+ offs = MakeByteOffs (flags, offs);
+
+ /* Check the size and determine operation */
+ switch (flags & CF_TYPE) {
+
+ case CF_CHAR:
+ AddCodeLine ("\tsta\tptr1");
+ AddCodeLine ("\tstx\tptr1+1");
+ if (offs == 0) {
+ AddCodeLine ("\tldx\t#$00");
+ AddCodeLine ("\tlda\t(ptr1,x)");
+ AddCodeLine ("\tsec");
+ AddCodeLine ("\tsbc\t#$%02X", val & 0xFF);
+ AddCodeLine ("\tsta\t(ptr1,x)");
+ } else {
+ AddCodeLine ("\tldy\t#$%02X", offs);
+ AddCodeLine ("\tldx\t#$00");
+ AddCodeLine ("\tlda\t(ptr1),y");
+ AddCodeLine ("\tsec");
+ AddCodeLine ("\tsbc\t#$%02X", val & 0xFF);
+ AddCodeLine ("\tsta\t(ptr1),y");
+ }
+ break;
+
+ case CF_INT:
+ if (!FavourSize) {
+ /* Lots of code, use only if size is not important */
+ AddCodeLine ("\tsta\tptr1");
+ AddCodeLine ("\tstx\tptr1+1");
+ AddCodeLine ("\tldy\t#$%02X", offs);
+ AddCodeLine ("\tlda\t(ptr1),y");
+ AddCodeLine ("\tsec");
+ AddCodeLine ("\tsbc\t#$%02X", val & 0xFF);
+ AddCodeLine ("\tsta\t(ptr1),y");
+ AddCodeLine ("\tpha");
+ AddCodeLine ("\tiny");
+ AddCodeLine ("\tlda\t(ptr1),y");
+ AddCodeLine ("\tsbc\t#$%02X", (val >> 8) & 0xFF);
+ AddCodeLine ("\tsta\t(ptr1),y");
+ AddCodeLine ("\ttax");
+ AddCodeLine ("\tpla");
+ break;
+ }
+ /* FALL THROUGH */
+
+ case CF_LONG:
+ AddCodeLine ("\tjsr\tpushax"); /* Push the address */
+ push (flags); /* Correct the internal sp */
+ g_getind (flags, offs); /* Fetch the value */
+ g_dec (flags, val); /* Increment value in primary */
+ g_putind (flags, offs); /* Store the value back */
+ break;
+
+ default:
+ typeerror (flags);
+ }
+}
+
+
+
+/*****************************************************************************/
+/* Add a variable address to the value in ax */
+/*****************************************************************************/
+
+
+
+void g_addaddr_local (unsigned flags, int offs)
+/* Add the address of a local variable to ax */
+{
+ /* Add the offset */
+ offs -= oursp;
+ if (offs != 0) {
+ /* We cannot address more then 256 bytes of locals anyway */
+ CheckLocalOffs (offs);
+ AddCodeLine ("\tclc");
+ AddCodeLine ("\tadc\t#$%02X", offs & 0xFF);
+ AddCodeLine ("\tbcc\t*+4"); /* Do also skip the CLC insn below */
+ AddCodeLine ("\tinx");
+ AddCodeHint ("x:!"); /* Invalidate X */
+ }
+
+ /* Add the current stackpointer value */
+ AddCodeLine ("\tclc");
+ AddCodeLine ("\tadc\tsp");
+ AddCodeLine ("\ttay");
+ AddCodeLine ("\ttxa");
+ AddCodeLine ("\tadc\tsp+1");
+ AddCodeLine ("\ttax");
+ AddCodeLine ("\ttya");
+}
+
+
+
+void g_addaddr_static (unsigned flags, unsigned long label, unsigned offs)
+/* Add the address of a static variable to ax */
+{
+ /* Create the correct label name */
+ char* lbuf = GetLabelName (flags, label, offs);
+
+ /* Add the address to the current ax value */
+ AddCodeLine ("\tclc");
+ AddCodeLine ("\tadc\t#<(%s)", lbuf);
+ AddCodeLine ("\ttay");
+ AddCodeLine ("\ttxa");
+ AddCodeLine ("\tadc\t#>(%s)", lbuf);
+ AddCodeLine ("\ttax");
+ AddCodeLine ("\ttya");
+}
+
+
+
+/*****************************************************************************/
+/* */
+/*****************************************************************************/
+
+
+
+void g_save (unsigned flags)
+/* Copy primary register to hold register. */
+{
+ /* Check the size and determine operation */
+ switch (flags & CF_TYPE) {
+
+ case CF_CHAR:
+ if (flags & CF_FORCECHAR) {
+ AddCodeLine ("\tpha");
+ break;
+ }
+ /* FALLTHROUGH */
+
+ case CF_INT:
+ AddCodeLine ("\tsta\tregsave");
+ AddCodeLine ("\tstx\tregsave+1");
+ break;
+
+ case CF_LONG:
+ AddCodeLine ("\tjsr\tsaveeax");
+ break;
+
+ default:
+ typeerror (flags);
+ }
+}
+
+
+
+void g_restore (unsigned flags)
+/* Copy hold register to P. */
+{
+ /* Check the size and determine operation */
+ switch (flags & CF_TYPE) {
+
+ case CF_CHAR:
+ if (flags & CF_FORCECHAR) {
+ AddCodeLine ("\tpla");
+ break;
+ }
+ /* FALLTHROUGH */
+
+ case CF_INT:
+ AddCodeLine ("\tlda\tregsave");
+ AddCodeLine ("\tldx\tregsave+1");
+ break;
+
+ case CF_LONG:
+ AddCodeLine ("\tjsr\tresteax");
+ break;
+
+ default:
+ typeerror (flags);
+ }
+}
+
+
+
+void g_cmp (unsigned flags, unsigned long val)
+/* Immidiate compare. The primary register will not be changed, Z flag
+ * will be set.
+ */
+{
+ /* Check the size and determine operation */
+ switch (flags & CF_TYPE) {
+
+ case CF_CHAR:
+ if (flags & CF_FORCECHAR) {
+ AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
+ break;
+ }
+ /* FALLTHROUGH */
+
+ case CF_INT:
+ AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
+ AddCodeLine ("\tbne\t*+4");
+ AddCodeLine ("\tcpx\t#$%02X", (val >> 8) & 0xFF);
+ break;
+
+ case CF_LONG:
+ Internal ("g_cmp: Long compares not implemented");
+ break;
+
+ default:
+ typeerror (flags);
+ }
+}
+
+
+
+static void oper (unsigned flags, unsigned long val, char** subs)
+/* Encode a binary operation. subs is a pointer to four groups of three
+ * strings:
+ * 0-2 --> Operate on ints
+ * 3-5 --> Operate on unsigneds
+ * 6-8 --> Operate on longs
+ * 9-11 --> Operate on unsigned longs
+ *
+ * The first subroutine names in each string group is used to encode an
+ * operation with a zero constant, the second to encode an operation with
+ * a 8 bit constant, and the third is used in all other cases.
+ */
+{
+ unsigned offs;
+
+ /* Determine the offset into the array */
+ offs = (flags & CF_UNSIGNED)? 3 : 0;
+ switch (flags & CF_TYPE) {
+ case CF_CHAR:
+ case CF_INT:
+ break;
+
+ case CF_LONG:
+ offs += 6;
+ break;
+
+ default:
+ typeerror (flags);
+ }
+
+ /* Encode the operation */
+ if (flags & CF_CONST) {
+ /* Constant value given */
+ if (val == 0 && subs [offs+0]) {
+ /* Special case: constant with value zero */
+ AddCodeLine ("\tjsr\t%s", subs [offs+0]);
+ } else if (val < 0x100 && subs [offs+1]) {
+ /* Special case: constant with high byte zero */
+ ldaconst (val); /* Load low byte */
+ AddCodeLine ("\tjsr\t%s", subs [offs+1]);
+ } else {
+ /* Others: arbitrary constant value */
+ g_getimmed (flags, val, 0); /* Load value */
+ AddCodeLine ("\tjsr\t%s", subs [offs+2]);
+ }
+ } else {
+ /* Value not constant (is already in (e)ax) */
+ AddCodeLine ("\tjsr\t%s", subs [offs+2]);
+ }
+
+ /* The operation will pop it's argument */
+ pop (flags);
+}
+
+
+
+void g_test (unsigned flags)
+/* Force a test to set cond codes right */
+{
+ switch (flags & CF_TYPE) {
+
+ case CF_CHAR:
+ if (flags & CF_FORCECHAR) {
+ AddCodeLine ("\ttax");
+ break;
+ }
+ /* FALLTHROUGH */
+
+ case CF_INT:
+ AddCodeLine ("\tstx\ttmp1");
+ AddCodeLine ("\tora\ttmp1");
+ break;
+
+ case CF_LONG:
+ if (flags & CF_UNSIGNED) {
+ AddCodeLine ("\tjsr\tutsteax");
+ } else {
+ AddCodeLine ("\tjsr\ttsteax");
+ }
+ break;
+
+ default:
+ typeerror (flags);
+
+ }
+}
+
+
+
+void g_push (unsigned flags, unsigned long val)
+/* Push the primary register or a constant value onto the stack */
+{
+ unsigned char hi;
+
+ if (flags & CF_CONST && (flags & CF_TYPE) != CF_LONG) {
+
+ /* We have a constant 8 or 16 bit value */
+ if ((flags & CF_TYPE) == CF_CHAR && (flags & CF_FORCECHAR)) {
+
+ /* Handle as 8 bit value */
+ if (FavourSize && val <= 2) {
+ AddCodeLine ("\tjsr\tpushc%d", (int) val);
+ } else {
+ ldaconst (val);
+ AddCodeLine ("\tjsr\tpusha");
+ }
+
+ } else {
+
+ /* Handle as 16 bit value */
+ hi = val >> 8;
+ if (val <= 7) {
+ AddCodeLine ("\tjsr\tpush%u", val);
+ } else if (hi == 0 || hi == 0xFF) {
+ /* Use special function */
+ ldaconst (val);
+ AddCodeLine ("\tjsr\t%s", (hi == 0)? "pusha0" : "pushaFF");
+ } else {
+ /* Long way ... */
+ g_getimmed (flags, val, 0);
+ AddCodeLine ("\tjsr\tpushax");
+ }
+ }
+
+ } else {
+
+ /* Value is not 16 bit or not constant */
+ if (flags & CF_CONST) {
+ /* Constant 32 bit value, load into eax */
+ g_getimmed (flags, val, 0);
+ }
+
+ /* Push the primary register */
+ switch (flags & CF_TYPE) {
+
+ case CF_CHAR:
+ if (flags & CF_FORCECHAR) {
+ /* Handle as char */
+ AddCodeLine ("\tjsr\tpusha");
+ break;
+ }
+ /* FALL THROUGH */
+ case CF_INT:
+ AddCodeLine ("\tjsr\tpushax");
+ break;
+
+ case CF_LONG:
+ AddCodeLine ("\tjsr\tpusheax");
+ break;
+
+ default:
+ typeerror (flags);
+
+ }
+
+ }
+
+ /* Adjust the stack offset */
+ push (flags);
+}
+
+
+
+void g_swap (unsigned flags)
+/* Swap the primary register and the top of the stack. flags give the type
+ * of *both* values (must have same size).
+ */
+{
+ switch (flags & CF_TYPE) {
+
+ case CF_CHAR:
+ case CF_INT:
+ AddCodeLine ("\tjsr\tswapstk");
+ break;
+
+ case CF_LONG:
+ AddCodeLine ("\tjsr\tswapestk");
+ break;
+
+ default:
+ typeerror (flags);
+
+ }
+}
+
+
+
+void g_call (unsigned flags, char* lbl, unsigned argsize)
+/* Call the specified subroutine name */
+{
+ if ((flags & CF_FIXARGC) == 0) {
+ /* Pass arg count */
+ ldyconst (argsize);
+ }
+ AddCodeLine ("\tjsr\t_%s", lbl);
+ oursp += argsize; /* callee pops args */
+}
+
+
+
+void g_callind (unsigned flags, unsigned argsize)
+/* Call subroutine with address in AX */
+{
+ if ((flags & CF_FIXARGC) == 0) {
+ /* Pass arg count */
+ ldyconst (argsize);
+ }
+ AddCodeLine ("\tjsr\tcallax"); /* do the call */
+ oursp += argsize; /* callee pops args */
+}
+
+
+
+void g_jump (unsigned label)
+/* Jump to specified internal label number */
+{
+ AddCodeLine ("\tjmp\tL%04X", label);
+}
+
+
+
+void g_switch (unsigned flags)
+/* Output switch statement preample */
+{
+ switch (flags & CF_TYPE) {
+
+ case CF_CHAR:
+ case CF_INT:
+ AddCodeLine ("\tjsr\tswitch");
+ break;
+
+ case CF_LONG:
+ AddCodeLine ("\tjsr\tlswitch");
+ break;
+
+ default:
+ typeerror (flags);
+
+ }
+}
+
+
+
+void g_case (unsigned flags, unsigned label, unsigned long val)
+/* Create table code for one case selector */
+{
+ switch (flags & CF_TYPE) {
+
+ case CF_CHAR:
+ case CF_INT:
+ AddCodeLine ("\t.word\t$%04X, L%04X", val & 0xFFFF, label & 0xFFFF);
+ break;
+
+ case CF_LONG:
+ AddCodeLine ("\t.dword\t$%08X", val);
+ AddCodeLine ("\t.word\tL%04X", label & 0xFFFF);
+ break;
+
+ default:
+ typeerror (flags);
+
+ }
+}
+
+
+
+void g_truejump (unsigned flags, unsigned label)
+/* Jump to label if zero flag clear */
+{
+ if (flags & CF_SHORT) {
+ AddCodeLine ("\tbne\tL%04X", label);
+ } else {
+ AddCodeLine ("\tjne\tL%04X", label);
+ }
+}
+
+
+
+void g_falsejump (unsigned flags, unsigned label)
+/* Jump to label if zero flag set */
+{
+ if (flags & CF_SHORT) {
+ AddCodeLine ("\tbeq\tL%04X", label);
+ } else {
+ AddCodeLine ("\tjeq\tL%04X", label);
+ }
+}
+
+
+
+static void mod_internal (int k, char* verb1, char* verb2)
+{
+ if (k <= 8) {
+ AddCodeLine ("\tjsr\t%ssp%c", verb1, k + '0');
+ } else {
+ CheckLocalOffs (k);
+ ldyconst (k);
+ AddCodeLine ("\tjsr\t%ssp", verb2);
+ }
+}
+
+
+
+void g_space (int space)
+/* Create or drop space on the stack */
+{
+ if (space < 0) {
+ mod_internal (-space, "inc", "addy");
+ } else if (space > 0) {
+ mod_internal (space, "dec", "suby");
+ }
+}
+
+
+
+void g_add (unsigned flags, unsigned long val)
+/* Primary = TOS + Primary */
+{
+ static char* ops [12] = {
+ 0, "tosadda0", "tosaddax",
+ 0, "tosadda0", "tosaddax",
+ 0, 0, "tosaddeax",
+ 0, 0, "tosaddeax",
+ };
+
+ if (flags & CF_CONST) {
+ flags &= ~CF_FORCECHAR; // Handle chars as ints
+ g_push (flags & ~CF_CONST, 0);
+ }
+ oper (flags, val, ops);
+}
+
+
+
+void g_sub (unsigned flags, unsigned long val)
+/* Primary = TOS - Primary */
+{
+ static char* ops [12] = {
+ 0, "tossuba0", "tossubax",
+ 0, "tossuba0", "tossubax",
+ 0, 0, "tossubeax",
+ 0, 0, "tossubeax",
+ };
+
+ if (flags & CF_CONST) {
+ flags &= ~CF_FORCECHAR; // Handle chars as ints
+ g_push (flags & ~CF_CONST, 0);
+ }
+ oper (flags, val, ops);
+}
+
+
+
+void g_rsub (unsigned flags, unsigned long val)
+/* Primary = Primary - TOS */
+{
+ static char* ops [12] = {
+ 0, "tosrsuba0", "tosrsubax",
+ 0, "tosrsuba0", "tosrsubax",
+ 0, 0, "tosrsubeax",
+ 0, 0, "tosrsubeax",
+ };
+ oper (flags, val, ops);
+}
+
+
+
+void g_mul (unsigned flags, unsigned long val)
+/* Primary = TOS * Primary */
+{
+ static char* ops [12] = {
+ 0, "tosmula0", "tosmulax",
+ 0, "tosumula0", "tosumulax",
+ 0, 0, "tosmuleax",
+ 0, 0, "tosumuleax",
+ };
+
+ int p2;
+
+ /* Do strength reduction if the value is constant and a power of two */
+ if (flags & CF_CONST && (p2 = powerof2 (val)) >= 0) {
+ /* Generate a shift instead */
+ g_asl (flags, p2);
+ return;
+ }
+
+ /* If the right hand side is const, the lhs is not on stack but still
+ * in the primary register.
+ */
+ if (flags & CF_CONST) {
+
+ switch (flags & CF_TYPE) {
+
+ case CF_CHAR:
+ if (flags & CF_FORCECHAR) {
+ /* Handle some special cases */
+ switch (val) {
+
+ case 3:
+ AddCodeLine ("\tsta\ttmp1");
+ AddCodeLine ("\tasl\ta");
+ AddCodeLine ("\tclc");
+ AddCodeLine ("\tadc\ttmp1");
+ return;
+
+ case 5:
+ AddCodeLine ("\tsta\ttmp1");
+ AddCodeLine ("\tasl\ta");
+ AddCodeLine ("\tasl\ta");
+ AddCodeLine ("\tclc");
+ AddCodeLine ("\tadc\ttmp1");
+ return;
+
+ case 10:
+ AddCodeLine ("\tsta\ttmp1");
+ AddCodeLine ("\tasl\ta");
+ AddCodeLine ("\tasl\ta");
+ AddCodeLine ("\tclc");
+ AddCodeLine ("\tadc\ttmp1");
+ AddCodeLine ("\tasl\ta");
+ return;
+ }
+ }
+ /* FALLTHROUGH */
+
+ case CF_INT:
+ break;
+
+ case CF_LONG:
+ break;
+
+ default:
+ typeerror (flags);
+ }
+
+ /* If we go here, we didn't emit code. Push the lhs on stack and fall
+ * into the normal, non-optimized stuff.
+ */
+ flags &= ~CF_FORCECHAR; // Handle chars as ints
+ g_push (flags & ~CF_CONST, 0);
+
+ }
+
+ /* Use long way over the stack */
+ oper (flags, val, ops);
+}
+
+
+
+void g_div (unsigned flags, unsigned long val)
+/* Primary = TOS / Primary */
+{
+ static char* ops [12] = {
+ 0, "tosdiva0", "tosdivax",
+ 0, "tosudiva0", "tosudivax",
+ 0, 0, "tosdiveax",
+ 0, 0, "tosudiveax",
+ };
+
+ /* Do strength reduction if the value is constant and a power of two */
+ int p2;
+ if ((flags & CF_CONST) && (p2 = powerof2 (val)) >= 0) {
+ /* Generate a shift instead */
+ g_asr (flags, p2);
+ } else {
+ /* Generate a division */
+ if (flags & CF_CONST) {
+ /* lhs is not on stack */
+ flags &= ~CF_FORCECHAR; // Handle chars as ints
+ g_push (flags & ~CF_CONST, 0);
+ }
+ oper (flags, val, ops);
+ }
+}
+
+
+
+void g_mod (unsigned flags, unsigned long val)
+/* Primary = TOS % Primary */
+{
+ static char* ops [12] = {
+ 0, "tosmoda0", "tosmodax",
+ 0, "tosumoda0", "tosumodax",
+ 0, 0, "tosmodeax",
+ 0, 0, "tosumodeax",
+ };
+ int p2;
+
+ /* Check if we can do some cost reduction */
+ if ((flags & CF_CONST) && (flags & CF_UNSIGNED) && val != 0xFFFFFFFF && (p2 = powerof2 (val)) >= 0) {
+ /* We can do that with an AND operation */
+ g_and (flags, val - 1);
+ } else {
+ /* Do it the hard way... */
+ if (flags & CF_CONST) {
+ /* lhs is not on stack */
+ flags &= ~CF_FORCECHAR; // Handle chars as ints
+ g_push (flags & ~CF_CONST, 0);
+ }
+ oper (flags, val, ops);
+ }
+}
+
+
+
+void g_or (unsigned flags, unsigned long val)
+/* Primary = TOS | Primary */
+{
+ static char* ops [12] = {
+ 0, "tosora0", "tosorax",
+ 0, "tosora0", "tosorax",
+ 0, 0, "tosoreax",
+ 0, 0, "tosoreax",
+ };
+
+ /* If the right hand side is const, the lhs is not on stack but still
+ * in the primary register.
+ */
+ if (flags & CF_CONST) {
+
+ switch (flags & CF_TYPE) {
+
+ case CF_CHAR:
+ if (flags & CF_FORCECHAR) {
+ if ((val & 0xFF) != 0xFF) {
+ AddCodeLine ("\tora\t#$%02X", val & 0xFF);
+ }
+ return;
+ }
+ /* FALLTHROUGH */
+
+ case CF_INT:
+ if (val <= 0xFF) {
+ AddCodeLine ("\tora\t#$%02X", val & 0xFF);
+ return;
+ }
+ break;
+
+ case CF_LONG:
+ if (val <= 0xFF) {
+ AddCodeLine ("\tora\t#$%02X", val & 0xFF);
+ return;
+ }
+ break;
+
+ default:
+ typeerror (flags);
+ }
+
+ /* If we go here, we didn't emit code. Push the lhs on stack and fall
+ * into the normal, non-optimized stuff.
+ */
+ g_push (flags & ~CF_CONST, 0);
+
+ }
+
+ /* Use long way over the stack */
+ oper (flags, val, ops);
+}
+
+
+
+void g_xor (unsigned flags, unsigned long val)
+/* Primary = TOS ^ Primary */
+{
+ static char* ops [12] = {
+ 0, "tosxora0", "tosxorax",
+ 0, "tosxora0", "tosxorax",
+ 0, 0, "tosxoreax",
+ 0, 0, "tosxoreax",
+ };
+
+
+ /* If the right hand side is const, the lhs is not on stack but still
+ * in the primary register.
+ */
+ if (flags & CF_CONST) {
+
+ switch (flags & CF_TYPE) {
+
+ case CF_CHAR:
+ if (flags & CF_FORCECHAR) {
+ if ((val & 0xFF) != 0) {
+ AddCodeLine ("\teor\t#$%02X", val & 0xFF);
+ }
+ return;
+ }
+ /* FALLTHROUGH */
+
+ case CF_INT:
+ if (val <= 0xFF) {
+ if (val != 0) {
+ AddCodeLine ("\teor\t#$%02X", val);
+ }
+ return;
+ } else if ((val & 0xFF) == 0) {
+ AddCodeLine ("\tpha");
+ AddCodeLine ("\ttxa");
+ AddCodeLine ("\teor\t#$%02X", (val >> 8) & 0xFF);
+ AddCodeLine ("\ttax");
+ AddCodeLine ("\tpla");
+ return;
+ }
+ break;
+
+ case CF_LONG:
+ if (val <= 0xFF) {
+ if (val != 0) {
+ AddCodeLine ("\teor\t#$%02X", val & 0xFF);
+ }
+ return;
+ }
+ break;
+
+ default:
+ typeerror (flags);
+ }
+
+ /* If we go here, we didn't emit code. Push the lhs on stack and fall
+ * into the normal, non-optimized stuff.
+ */
+ g_push (flags & ~CF_CONST, 0);
+
+ }
+
+ /* Use long way over the stack */
+ oper (flags, val, ops);
+}
+
+
+
+void g_and (unsigned flags, unsigned long val)
+/* Primary = TOS & Primary */
+{
+ static char* ops [12] = {
+ 0, "tosanda0", "tosandax",
+ 0, "tosanda0", "tosandax",
+ 0, 0, "tosandeax",
+ 0, 0, "tosandeax",
+ };
+
+ /* If the right hand side is const, the lhs is not on stack but still
+ * in the primary register.
+ */
+ if (flags & CF_CONST) {
+
+ switch (flags & CF_TYPE) {
+
+ case CF_CHAR:
+ if (flags & CF_FORCECHAR) {
+ AddCodeLine ("\tand\t#$%02X", val & 0xFF);
+ return;
+ }
+ /* FALLTHROUGH */
+ case CF_INT:
+ if ((val & 0xFFFF) != 0xFFFF) {
+ if (val <= 0xFF) {
+ ldxconst (0);
+ if (val == 0) {
+ ldaconst (0);
+ } else if (val != 0xFF) {
+ AddCodeLine ("\tand\t#$%02X", val & 0xFF);
+ }
+ } else if ((val & 0xFF00) == 0xFF00) {
+ AddCodeLine ("\tand\t#$%02X", val & 0xFF);
+ } else if ((val & 0x00FF) == 0x0000) {
+ AddCodeLine ("\ttxa");
+ AddCodeLine ("\tand\t#$%02X", (val >> 8) & 0xFF);
+ AddCodeLine ("\ttax");
+ ldaconst (0);
+ } else {
+ AddCodeLine ("\ttay");
+ AddCodeLine ("\ttxa");
+ AddCodeLine ("\tand\t#$%02X", (val >> 8) & 0xFF);
+ AddCodeLine ("\ttax");
+ AddCodeLine ("\ttya");
+ if ((val & 0x00FF) != 0x00FF) {
+ AddCodeLine ("\tand\t#$%02X", val & 0xFF);
+ }
+ }
+ }
+ return;
+
+ case CF_LONG:
+ if (val <= 0xFF) {
+ ldxconst (0);
+ AddCodeLine ("\tstx\tsreg+1");
+ AddCodeLine ("\tstx\tsreg");
+ if ((val & 0xFF) != 0xFF) {
+ AddCodeLine ("\tand\t#$%02X", val & 0xFF);
+ }
+ return;
+ } else if (val == 0xFF00) {
+ ldaconst (0);
+ AddCodeLine ("\tsta\tsreg+1");
+ AddCodeLine ("\tsta\tsreg");
+ return;
+ }
+ break;
+
+ default:
+ typeerror (flags);
+ }
+
+ /* If we go here, we didn't emit code. Push the lhs on stack and fall
+ * into the normal, non-optimized stuff.
+ */
+ g_push (flags & ~CF_CONST, 0);
+
+ }
+
+ /* Use long way over the stack */
+ oper (flags, val, ops);
+}
+
+
+
+void g_asr (unsigned flags, unsigned long val)
+/* Primary = TOS >> Primary */
+{
+ static char* ops [12] = {
+ 0, "tosasra0", "tosasrax",
+ 0, "tosshra0", "tosshrax",
+ 0, 0, "tosasreax",
+ 0, 0, "tosshreax",
+ };
+
+ /* If the right hand side is const, the lhs is not on stack but still
+ * in the primary register.
+ */
+ if (flags & CF_CONST) {
+
+ switch (flags & CF_TYPE) {
+
+ case CF_CHAR:
+ case CF_INT:
+ if (val >= 1 && val <= 3) {
+ if (flags & CF_UNSIGNED) {
+ AddCodeLine ("\tjsr\tshrax%ld", val);
+ } else {
+ AddCodeLine ("\tjsr\tasrax%ld", val);
+ }
+ return;
+ } else if (val == 8 && (flags & CF_UNSIGNED)) {
+ AddCodeLine ("\ttxa");
+ ldxconst (0);
+ return;
+ }
+ break;
+
+ case CF_LONG:
+ if (val >= 1 && val <= 3) {
+ if (flags & CF_UNSIGNED) {
+ AddCodeLine ("\tjsr\tshreax%ld", val);
+ } else {
+ AddCodeLine ("\tjsr\tasreax%ld", val);
+ }
+ return;
+ } else if (val == 8 && (flags & CF_UNSIGNED)) {
+ AddCodeLine ("\ttxa");
+ AddCodeLine ("\tldx\tsreg");
+ AddCodeLine ("\tldy\tsreg+1");
+ AddCodeLine ("\tsty\tsreg");
+ AddCodeLine ("\tldy\t#$00");
+ AddCodeLine ("\tsty\tsreg+1");
+ return;
+ } else if (val == 16) {
+ AddCodeLine ("\tldy\t#$00");
+ AddCodeLine ("\tldx\tsreg+1");
+ if ((flags & CF_UNSIGNED) == 0) {
+ AddCodeLine ("\tbpl\t*+3");
+ AddCodeLine ("\tdey");
+ AddCodeHint ("y:!");
+ }
+ AddCodeLine ("\tlda\tsreg");
+ AddCodeLine ("\tsty\tsreg+1");
+ AddCodeLine ("\tsty\tsreg");
+ return;
+ }
+ break;
+
+ default:
+ typeerror (flags);
+ }
+
+ /* If we go here, we didn't emit code. Push the lhs on stack and fall
+ * into the normal, non-optimized stuff.
+ */
+ g_push (flags & ~CF_CONST, 0);
+
+ }
+
+ /* Use long way over the stack */
+ oper (flags, val, ops);
+}
+
+
+
+void g_asl (unsigned flags, unsigned long val)
+/* Primary = TOS << Primary */
+{
+ static char* ops [12] = {
+ 0, "tosasla0", "tosaslax",
+ 0, "tosshla0", "tosshlax",
+ 0, 0, "tosasleax",
+ 0, 0, "tosshleax",
+ };
+
+
+ /* If the right hand side is const, the lhs is not on stack but still
+ * in the primary register.
+ */
+ if (flags & CF_CONST) {
+
+ switch (flags & CF_TYPE) {
+
+ case CF_CHAR:
+ case CF_INT:
+ if (val >= 1 && val <= 3) {
+ if (flags & CF_UNSIGNED) {
+ AddCodeLine ("\tjsr\tshlax%ld", val);
+ } else {
+ AddCodeLine ("\tjsr\taslax%ld", val);
+ }
+ return;
+ } else if (val == 8) {
+ AddCodeLine ("\ttax");
+ AddCodeLine ("\tlda\t#$00");
+ return;
+ }
+ break;
+
+ case CF_LONG:
+ if (val >= 1 && val <= 3) {
+ if (flags & CF_UNSIGNED) {
+ AddCodeLine ("\tjsr\tshleax%ld", val);
+ } else {
+ AddCodeLine ("\tjsr\tasleax%ld", val);
+ }
+ return;
+ } else if (val == 8) {
+ AddCodeLine ("\tldy\tsreg");
+ AddCodeLine ("\tsty\tsreg+1");
+ AddCodeLine ("\tstx\tsreg");
+ AddCodeLine ("\ttax");
+ AddCodeLine ("\tlda\t#$00");
+ return;
+ } else if (val == 16) {
+ AddCodeLine ("\tstx\tsreg+1");
+ AddCodeLine ("\tsta\tsreg");
+ AddCodeLine ("\tlda\t#$00");
+ AddCodeLine ("\ttax");
+ return;
+ }
+ break;
+
+ default:
+ typeerror (flags);
+ }
+
+ /* If we go here, we didn't emit code. Push the lhs on stack and fall
+ * into the normal, non-optimized stuff.
+ */
+ g_push (flags & ~CF_CONST, 0);
+
+ }
+
+ /* Use long way over the stack */
+ oper (flags, val, ops);
+}
+
+
+
+void g_neg (unsigned flags)
+/* Primary = -Primary */
+{
+ switch (flags & CF_TYPE) {
+
+ case CF_CHAR:
+ case CF_INT:
+ AddCodeLine ("\tjsr\tnegax");
+ break;
+
+ case CF_LONG:
+ AddCodeLine ("\tjsr\tnegeax");
+ break;
+
+ default:
+ typeerror (flags);
+ }
+}
+
+
+
+void g_bneg (unsigned flags)
+/* Primary = !Primary */
+{
+ switch (flags & CF_TYPE) {
+
+ case CF_CHAR:
+ AddCodeLine ("\tjsr\tbnega");
+ break;
+
+ case CF_INT:
+ AddCodeLine ("\tjsr\tbnegax");
+ break;
+
+ case CF_LONG:
+ AddCodeLine ("\tjsr\tbnegeax");
+ break;
+
+ default:
+ typeerror (flags);
+ }
+}
+
+
+
+void g_com (unsigned flags)
+/* Primary = ~Primary */
+{
+ switch (flags & CF_TYPE) {
+
+ case CF_CHAR:
+ case CF_INT:
+ AddCodeLine ("\tjsr\tcomplax");
+ break;
+
+ case CF_LONG:
+ AddCodeLine ("\tjsr\tcompleax");
+ break;
+
+ default:
+ typeerror (flags);
+ }
+}
+
+
+
+void g_inc (unsigned flags, unsigned long val)
+/* Increment the primary register by a given number */
+{
+ /* Don't inc by zero */
+ if (val == 0) {
+ return;
+ }
+
+ /* Generate code for the supported types */
+ flags &= ~CF_CONST;
+ switch (flags & CF_TYPE) {
+
+ case CF_CHAR:
+ if (flags & CF_FORCECHAR) {
+ AddCodeLine ("\tclc");
+ AddCodeLine ("\tadc\t#$%02X", val & 0xFF);
+ break;
+ }
+ /* FALLTHROUGH */
+
+ case CF_INT:
+ if (FavourSize) {
+ /* Use jsr calls */
+ if (val <= 8) {
+ AddCodeLine ("\tjsr\tincax%u", val);
+ } else if (val <= 255) {
+ ldyconst (val);
+ AddCodeLine ("\tjsr\tincaxy");
+ } else {
+ g_add (flags | CF_CONST, val);
+ }
+ } else {
+ /* Inline the code */
+ if (val < 0x300) {
+ if ((val & 0xFF) != 0) {
+ AddCodeLine ("\tclc");
+ AddCodeLine ("\tadc\t#$%02X", (unsigned char) val);
+ AddCodeLine ("\tbcc\t*+3");
+ AddCodeLine ("\tinx");
+ /* Tell the optimizer that the X register may be invalid */
+ AddCodeHint ("x:!");
+ }
+ if (val >= 0x100) {
+ AddCodeLine ("\tinx");
+ }
+ if (val >= 0x200) {
+ AddCodeLine ("\tinx");
+ }
+ } else {
+ AddCodeLine ("\tclc");
+ if ((val & 0xFF) != 0) {
+ AddCodeLine ("\tadc\t#$%02X", (unsigned char) val);
+ /* Tell the optimizer that the X register may be invalid */
+ AddCodeHint ("x:!");
+ }
+ AddCodeLine ("\tpha");
+ AddCodeLine ("\ttxa");
+ AddCodeLine ("\tadc\t#$%02X", (unsigned char) (val >> 8));
+ AddCodeLine ("\ttax");
+ AddCodeLine ("\tpla");
+ }
+ }
+ break;
+
+ case CF_LONG:
+ if (val <= 255) {
+ ldyconst (val);
+ AddCodeLine ("\tjsr\tinceaxy");
+ } else {
+ g_add (flags | CF_CONST, val);
+ }
+ break;
+
+ default:
+ typeerror (flags);
+
+ }
+}
+
+
+
+void g_dec (unsigned flags, unsigned long val)
+/* Decrement the primary register by a given number */
+{
+ /* Generate code for the supported types */
+ flags &= ~CF_CONST;
+ switch (flags & CF_TYPE) {
+
+ case CF_CHAR:
+ if (flags & CF_FORCECHAR) {
+ AddCodeLine ("\tsec");
+ AddCodeLine ("\tsbc\t#$%02X", val & 0xFF);
+ break;
+ }
+ /* FALLTHROUGH */
+
+ case CF_INT:
+ if (val <= 2) {
+ AddCodeLine ("\tjsr\tdecax%d", (int) val);
+ } else if (val <= 255) {
+ ldyconst (val);
+ AddCodeLine ("\tjsr\tdecaxy");
+ } else {
+ g_sub (flags | CF_CONST, val);
+ }
+ break;
+
+ case CF_LONG:
+ if (val <= 255) {
+ ldyconst (val);
+ AddCodeLine ("\tjsr\tdeceaxy");
+ } else {
+ g_sub (flags | CF_CONST, val);
+ }
+ break;
+
+ default:
+ typeerror (flags);
+
+ }
+}
+
+
+
+/*
+ * Following are the conditional operators. They compare the TOS against
+ * the primary and put a literal 1 in the primary if the condition is
+ * true, otherwise they clear the primary register
+ */
+
+
+
+void g_eq (unsigned flags, unsigned long val)
+/* Test for equal */
+{
+ static char* ops [12] = {
+ "toseq00", "toseqa0", "toseqax",
+ "toseq00", "toseqa0", "toseqax",
+ 0, 0, "toseqeax",
+ 0, 0, "toseqeax",
+ };
+
+ /* If the right hand side is const, the lhs is not on stack but still
+ * in the primary register.
+ */
+ if (flags & CF_CONST) {
+
+ switch (flags & CF_TYPE) {
+
+ case CF_CHAR:
+ if (flags & CF_FORCECHAR) {
+ AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
+ AddCodeLine ("\tjsr\tbooleq");
+ return;
+ }
+ /* FALLTHROUGH */
+
+ case CF_INT:
+ AddCodeLine ("\tcpx\t#$%02X", (val >> 8) & 0xFF);
+ AddCodeLine ("\tbne\t*+4");
+ AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
+ AddCodeLine ("\tjsr\tbooleq");
+ return;
+
+ case CF_LONG:
+ break;
+
+ default:
+ typeerror (flags);
+ }
+
+ /* If we go here, we didn't emit code. Push the lhs on stack and fall
+ * into the normal, non-optimized stuff.
+ */
+ g_push (flags & ~CF_CONST, 0);
+
+ }
+
+ /* Use long way over the stack */
+ oper (flags, val, ops);
+}
+
+
+
+void g_ne (unsigned flags, unsigned long val)
+/* Test for not equal */
+{
+ static char* ops [12] = {
+ "tosne00", "tosnea0", "tosneax",
+ "tosne00", "tosnea0", "tosneax",
+ 0, 0, "tosneeax",
+ 0, 0, "tosneeax",
+ };
+
+
+ /* If the right hand side is const, the lhs is not on stack but still
+ * in the primary register.
+ */
+ if (flags & CF_CONST) {
+
+ switch (flags & CF_TYPE) {
+
+ case CF_CHAR:
+ if (flags & CF_FORCECHAR) {
+ AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
+ AddCodeLine ("\tjsr\tboolne");
+ return;
+ }
+ /* FALLTHROUGH */
+
+ case CF_INT:
+ AddCodeLine ("\tcpx\t#$%02X", (val >> 8) & 0xFF);
+ AddCodeLine ("\tbne\t*+4");
+ AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
+ AddCodeLine ("\tjsr\tboolne");
+ return;
+
+ case CF_LONG:
+ break;
+
+ default:
+ typeerror (flags);
+ }
+
+ /* If we go here, we didn't emit code. Push the lhs on stack and fall
+ * into the normal, non-optimized stuff.
+ */
+ g_push (flags & ~CF_CONST, 0);
+
+ }
+
+ /* Use long way over the stack */
+ oper (flags, val, ops);
+}
+
+
+
+void g_lt (unsigned flags, unsigned long val)
+/* Test for less than */
+{
+ static char* ops [12] = {
+ "toslt00", "toslta0", "tosltax",
+ "tosult00", "tosulta0", "tosultax",
+ 0, 0, "toslteax",
+ 0, 0, "tosulteax",
+ };
+
+ /* If the right hand side is const, the lhs is not on stack but still
+ * in the primary register.
+ */
+ if (flags & CF_CONST) {
+
+ /* Give a warning in some special cases */
+ if ((flags & CF_UNSIGNED) && val == 0) {
+ Warning (WARN_COND_NEVER_TRUE);
+ }
+
+ /* Look at the type */
+ switch (flags & CF_TYPE) {
+
+ case CF_CHAR:
+ if (flags & CF_FORCECHAR) {
+ AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
+ if (flags & CF_UNSIGNED) {
+ AddCodeLine ("\tjsr\tboolult");
+ } else {
+ AddCodeLine ("\tjsr\tboollt");
+ }
+ return;
+ }
+ /* FALLTHROUGH */
+
+ case CF_INT:
+ if ((flags & CF_UNSIGNED) == 0 && val == 0) {
+ /* If we have a signed compare against zero, we only need to
+ * test the high byte.
+ */
+ AddCodeLine ("\ttxa");
+ AddCodeLine ("\tjsr\tboollt");
+ return;
+ }
+ /* Direct code only for unsigned data types */
+ if (flags & CF_UNSIGNED) {
+ AddCodeLine ("\tcpx\t#$%02X", (val >> 8) & 0xFF);
+ AddCodeLine ("\tbne\t*+4");
+ AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
+ AddCodeLine ("\tjsr\tboolult");
+ return;
+ }
+ break;
+
+ case CF_LONG:
+ break;
+
+ default:
+ typeerror (flags);
+ }
+
+ /* If we go here, we didn't emit code. Push the lhs on stack and fall
+ * into the normal, non-optimized stuff.
+ */
+ g_push (flags & ~CF_CONST, 0);
+
+ }
+
+ /* Use long way over the stack */
+ oper (flags, val, ops);
+}
+
+
+
+void g_le (unsigned flags, unsigned long val)
+/* Test for less than or equal to */
+{
+ static char* ops [12] = {
+ "tosle00", "toslea0", "tosleax",
+ "tosule00", "tosulea0", "tosuleax",
+ 0, 0, "tosleeax",
+ 0, 0, "tosuleeax",
+ };
+
+
+ /* If the right hand side is const, the lhs is not on stack but still
+ * in the primary register.
+ */
+ if (flags & CF_CONST) {
+
+ /* Look at the type */
+ switch (flags & CF_TYPE) {
+
+ case CF_CHAR:
+ if (flags & CF_FORCECHAR) {
+ AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
+ if (flags & CF_UNSIGNED) {
+ AddCodeLine ("\tjsr\tboolule");
+ } else {
+ AddCodeLine ("\tjsr\tboolle");
+ }
+ return;
+ }
+ /* FALLTHROUGH */
+
+ case CF_INT:
+ if (flags & CF_UNSIGNED) {
+ AddCodeLine ("\tcpx\t#$%02X", (val >> 8) & 0xFF);
+ AddCodeLine ("\tbne\t*+4");
+ AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
+ AddCodeLine ("\tjsr\tboolule");
+ return;
+ }
+ break;
+
+ case CF_LONG:
+ break;
+
+ default:
+ typeerror (flags);
+ }
+
+ /* If we go here, we didn't emit code. Push the lhs on stack and fall
+ * into the normal, non-optimized stuff.
+ */
+ g_push (flags & ~CF_CONST, 0);
+
+ }
+
+ /* Use long way over the stack */
+ oper (flags, val, ops);
+}
+
+
+
+void g_gt (unsigned flags, unsigned long val)
+/* Test for greater than */
+{
+ static char* ops [12] = {
+ "tosgt00", "tosgta0", "tosgtax",
+ "tosugt00", "tosugta0", "tosugtax",
+ 0, 0, "tosgteax",
+ 0, 0, "tosugteax",
+ };
+
+
+ /* If the right hand side is const, the lhs is not on stack but still
+ * in the primary register.
+ */
+ if (flags & CF_CONST) {
+
+ /* Look at the type */
+ switch (flags & CF_TYPE) {
+
+ case CF_CHAR:
+ if (flags & CF_FORCECHAR) {
+ AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
+ if (flags & CF_UNSIGNED) {
+ /* If we have a compare > 0, we will replace it by
+ * != 0 here, since both are identical but the latter
+ * is easier to optimize.
+ */
+ if (val & 0xFF) {
+ AddCodeLine ("\tjsr\tboolugt");
+ } else {
+ AddCodeLine ("\tjsr\tboolne");
+ }
+ } else {
+ AddCodeLine ("\tjsr\tboolgt");
+ }
+ return;
+ }
+ /* FALLTHROUGH */
+
+ case CF_INT:
+ if (flags & CF_UNSIGNED) {
+ /* If we have a compare > 0, we will replace it by
+ * != 0 here, since both are identical but the latter
+ * is easier to optimize.
+ */
+ if ((val & 0xFFFF) == 0) {
+ AddCodeLine ("\tstx\ttmp1");
+ AddCodeLine ("\tora\ttmp1");
+ AddCodeLine ("\tjsr\tboolne");
+ } else {
+ AddCodeLine ("\tcpx\t#$%02X", (val >> 8) & 0xFF);
+ AddCodeLine ("\tbne\t*+4");
+ AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
+ AddCodeLine ("\tjsr\tboolugt");
+ }
+ return;
+ }
+ break;
+
+ case CF_LONG:
+ break;
+
+ default:
+ typeerror (flags);
+ }
+
+ /* If we go here, we didn't emit code. Push the lhs on stack and fall
+ * into the normal, non-optimized stuff.
+ */
+ g_push (flags & ~CF_CONST, 0);
+
+ }
+
+ /* Use long way over the stack */
+ oper (flags, val, ops);
+}
+
+
+
+void g_ge (unsigned flags, unsigned long val)
+/* Test for greater than or equal to */
+{
+ static char* ops [12] = {
+ "tosge00", "tosgea0", "tosgeax",
+ "tosuge00", "tosugea0", "tosugeax",
+ 0, 0, "tosgeeax",
+ 0, 0, "tosugeeax",
+ };
+
+
+ /* If the right hand side is const, the lhs is not on stack but still
+ * in the primary register.
+ */
+ if (flags & CF_CONST) {
+
+ /* Give a warning in some special cases */
+ if ((flags & CF_UNSIGNED) && val == 0) {
+ Warning (WARN_COND_ALWAYS_TRUE);
+ }
+
+ /* Look at the type */
+ switch (flags & CF_TYPE) {
+
+ case CF_CHAR:
+ if (flags & CF_FORCECHAR) {
+ AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
+ if (flags & CF_UNSIGNED) {
+ AddCodeLine ("\tjsr\tbooluge");
+ } else {
+ AddCodeLine ("\tjsr\tboolge");
+ }
+ return;
+ }
+ /* FALLTHROUGH */
+
+ case CF_INT:
+ if (flags & CF_UNSIGNED) {
+ AddCodeLine ("\tcpx\t#$%02X", (val >> 8) & 0xFF);
+ AddCodeLine ("\tbne\t*+4");
+ AddCodeLine ("\tcmp\t#$%02X", val & 0xFF);
+ AddCodeLine ("\tjsr\tbooluge");
+ return;
+ }
+ break;
+
+ case CF_LONG:
+ break;
+
+ default:
+ typeerror (flags);
+ }
+
+ /* If we go here, we didn't emit code. Push the lhs on stack and fall
+ * into the normal, non-optimized stuff.
+ */
+ g_push (flags & ~CF_CONST, 0);
+
+ }
+
+ /* Use long way over the stack */
+ oper (flags, val, ops);
+}
+
+
+
+/*****************************************************************************/
+/* Allocating static storage */
+/*****************************************************************************/
+
+
+
+void g_res (unsigned n)
+/* reserve static storage, n bytes */
+{
+ AddCodeLine ("\t.res\t%u", n);
+}
+
+
+
+void g_defdata (unsigned flags, unsigned long val, unsigned offs)
+/* Define data with the size given in flags */
+{
+ if (flags & CF_CONST) {
+
+ /* Numeric constant */
+ switch (flags & CF_TYPE) {
+
+ case CF_CHAR:
+ AddCodeLine ("\t.byte\t$%02lX", val & 0xFF);
+ break;
+
+ case CF_INT:
+ AddCodeLine ("\t.word\t$%04lX", val & 0xFFFF);
+ break;
+
+ case CF_LONG:
+ AddCodeLine ("\t.dword\t$%08lX", val & 0xFFFFFFFF);
+ break;
+
+ default:
+ typeerror (flags);
+ break;
+
+ }
+
+ } else {
+
+ /* Create the correct label name */
+ const char* Label = GetLabelName (flags, val, offs);
+
+ /* Labels are always 16 bit */
+ AddCodeLine ("\t.word\t%s", Label);
+
+ }
+}
+
+
+
+void g_defbytes (const unsigned char* Bytes, unsigned Count)
+/* output a row of bytes as a constant */
+{
+ unsigned Chunk;
+ char Buf [128];
+ char* B;
+
+ /* Output the stuff */
+ while (Count) {
+
+ /* How many go into this line? */
+ if ((Chunk = Count) > 16) {
+ Chunk = 16;
+ }
+ Count -= Chunk;
+
+ /* Output one line */
+ strcpy (Buf, "\t.byte\t");
+ B = Buf + 7;
+ do {
+ B += sprintf (B, "$%02X", *Bytes++ & 0xFF);
+ if (--Chunk) {
+ *B++ = ',';
+ }
+ } while (Chunk);
+
+ /* Output the line */
+ AddCodeLine (Buf);
+ }
+}
+
+
+
+void g_zerobytes (unsigned n)
+/* Output n bytes of data initialized with zero */
+{
+ AddCodeLine ("\t.res\t%u", n);
+}
+
+
+
+/*****************************************************************************/
+/* Inlined known functions */
+/*****************************************************************************/
+
+
+
+void g_strlen (unsigned flags, unsigned long val, unsigned offs)
+/* Inline the strlen() function */
+{
+ /* We need a label in both cases */
+ unsigned label = GetLabel ();
+
+ /* Two different encodings */
+ if (flags & CF_CONST) {
+
+ /* The address of the string is constant. Create the correct label name */
+ char* lbuf = GetLabelName (flags, val, offs);
+
+ /* Generate the strlen code */
+ AddCodeLine ("\tldy\t#$FF");
+ g_defloclabel (label);
+ AddCodeLine ("\tiny");
+ AddCodeLine ("\tlda\t%s,y", lbuf);
+ AddCodeLine ("\tbne\tL%04X", label);
+ AddCodeLine ("\ttya");
+ AddCodeLine ("\tldx\t#$00");
+
+ } else {
+
+ /* Address not constant but in primary */
+ if (FavourSize) {
+ /* This is too much code, so call strlen instead of inlining */
+ AddCodeLine ("\tjsr\t_strlen");
+ } else {
+ /* Inline the function */
+ AddCodeLine ("\tsta\tptr1");
+ AddCodeLine ("\tstx\tptr1+1");
+ AddCodeLine ("\tldy\t#$FF");
+ g_defloclabel (label);
+ AddCodeLine ("\tiny");
+ AddCodeLine ("\tlda\t(ptr1),y");
+ AddCodeLine ("\tbne\tL%04X", label);
+ AddCodeLine ("\ttya");
+ AddCodeLine ("\tldx\t#$00");
+ }
+ }
+}
+
+
+
--- /dev/null
+/*
+ * codegen.h
+ *
+ * Ullrich von Bassewitz, 04.06.1998
+ */
+
+
+
+#ifndef CODEGEN_H
+#define CODEGEN_H
+
+
+
+/*****************************************************************************/
+/* data */
+/*****************************************************************************/
+
+
+
+/* Code generator flags.
+ * Note: The type flags are designed so that a smaller type may override a
+ * larger one by or'ing it into the existing one.
+ */
+#define CF_NONE 0x0000 /* No special flags */
+
+#define CF_TYPE 0x000F /* Mask for operand type */
+#define CF_CHAR 0x0003 /* Operation on characters */
+#define CF_INT 0x0001 /* Operation on ints */
+#define CF_PTR CF_INT /* Alias for readability */
+#define CF_LONG 0x0000 /* Operation on longs */
+
+#define CF_UNSIGNED 0x0010 /* Value is unsigned */
+#define CF_CONST 0x0020 /* Constant value available */
+#define CF_CONSTADDR 0x0040 /* Constant address value available */
+#define CF_TEST 0x0080 /* Test value */
+#define CF_FIXARGC 0x0100 /* Function has fixed arg count */
+#define CF_FORCECHAR 0x0200 /* Handle chars as chars, not ints */
+#define CF_SHORT 0x0400 /* Use short addressing */
+#define CF_REG 0x0800 /* Value is in primary register */
+
+/* Type of static address */
+#define CF_ADDRMASK 0xF000 /* Type of address */
+#define CF_STATIC 0x0000 /* Static local */
+#define CF_EXTERNAL 0x1000 /* Static external */
+#define CF_ABSOLUTE 0x2000 /* Numeric absolute address */
+#define CF_LOCAL 0x4000 /* Auto variable */
+#define CF_REGVAR 0x8000 /* Register variable */
+
+
+
+/* Compiler relative stackpointer */
+extern int oursp;
+
+
+
+/*****************************************************************************/
+/* Pre- and postamble */
+/*****************************************************************************/
+
+
+
+void g_preamble (void);
+/* Generate the assembler code preamble */
+
+void g_postamble (void);
+/* Generate assembler code postamble */
+
+
+
+/*****************************************************************************/
+/* Segment support */
+/*****************************************************************************/
+
+
+
+void g_usecode (void);
+/* Switch to the code segment */
+
+void g_userodata (void);
+/* Switch to the read only data segment */
+
+void g_usedata (void);
+/* Switch to the data segment */
+
+void g_usebss (void);
+/* Switch to the bss segment */
+
+void g_codename (const char* Name);
+/* Set the name of the CODE segment */
+
+void g_rodataname (const char* Name);
+/* Set the name of the RODATA segment */
+
+void g_dataname (const char* Name);
+/* Set the name of the DATA segment */
+
+void g_bssname (const char* Name);
+/* Set the name of the BSS segment */
+
+
+
+/*****************************************************************************/
+/* Functions handling local labels */
+/*****************************************************************************/
+
+
+
+void g_defloclabel (unsigned label);
+/* Define a local label */
+
+
+
+/*****************************************************************************/
+/* Functions handling global labels */
+/*****************************************************************************/
+
+
+
+void g_defgloblabel (const char* Name);
+/* Define a global label with the given name */
+
+void g_defexport (const char* Name, int ZP);
+/* Export the given label */
+
+void g_defimport (const char* Name, int ZP);
+/* Import the given label */
+
+
+
+/*****************************************************************************/
+/* stack */
+/*****************************************************************************/
+
+
+
+int pop (unsigned flags);
+/* Pop an argument of the given size */
+
+int push (unsigned flags);
+/* Push an argument of the given size */
+
+unsigned sizeofarg (unsigned flags);
+/* Return the size of a function argument type that is encoded in flags */
+
+
+
+/*****************************************************************************/
+/* type conversion and similiar stuff */
+/*****************************************************************************/
+
+
+
+void g_toslong (unsigned flags);
+/* Make sure, the value on TOS is a long. Convert if necessary */
+
+void g_tosint (unsigned flags);
+/* Make sure, the value on TOS is an int. Convert if necessary */
+
+void g_reglong (unsigned flags);
+/* Make sure, the value in the primary register a long. Convert if necessary */
+
+unsigned g_typeadjust (unsigned lhs, unsigned rhs);
+/* Adjust the integer operands before doing a binary operation. lhs is a flags
+ * value, that corresponds to the value on TOS, rhs corresponds to the value
+ * in (e)ax. The return value is the the flags value for the resulting type.
+ */
+
+unsigned g_typecast (unsigned lhs, unsigned rhs);
+/* Cast the value in the primary register to the operand size that is flagged
+ * by the lhs value. Return the result value.
+ */
+
+void g_scale (unsigned flags, long val);
+/* Scale the value in the primary register by the given value. If val is positive,
+ * scale up, is val is negative, scale down. This function is used to scale
+ * the operands or results of pointer arithmetic by the size of the type, the
+ * pointer points to.
+ */
+
+
+
+/*****************************************************************************/
+/* Function entry and exit */
+/*****************************************************************************/
+
+
+
+void g_enter (unsigned flags, const char* Name, unsigned argsize);
+/* Function prologue */
+
+void g_leave (int flags, int val);
+/* Function epilogue */
+
+
+
+/*****************************************************************************/
+/* Register variables */
+/*****************************************************************************/
+
+
+
+void g_save_regvars (int RegOffs, unsigned Bytes);
+/* Save register variables */
+
+void g_restore_regvars (int StackOffs, int RegOffs, unsigned Bytes);
+/* Restore register variables */
+
+
+
+/*****************************************************************************/
+/* Fetching memory cells */
+/*****************************************************************************/
+
+
+
+void g_getimmed (unsigned flags, unsigned long val, unsigned offs);
+void g_getstatic (unsigned flags, unsigned long label, unsigned offs);
+void g_getlocal (unsigned flags, int offs);
+void g_getind (unsigned flags, unsigned offs);
+void g_leasp (int offs);
+
+
+
+/*****************************************************************************/
+/* Store into memory */
+/*****************************************************************************/
+
+
+
+void g_putstatic (unsigned flags, unsigned long label, unsigned offs);
+/* Store the primary register into the specified static memory cell */
+
+void g_putlocal (unsigned flags, int offs);
+/* Put data into local object. */
+
+void g_putind (unsigned flags, unsigned offs);
+/* Store the specified object type in the primary register at the address
+ * on the top of the stack
+ */
+
+
+
+/*****************************************************************************/
+/* Adds and subs of variables fix a fixed address */
+/*****************************************************************************/
+
+
+
+void g_addlocal (unsigned flags, int offs);
+/* Add a local variable to ax */
+
+void g_addstatic (unsigned flags, unsigned long label, unsigned offs);
+/* Add a static variable to ax */
+
+
+
+/*****************************************************************************/
+/* Compares of ax with a variable with fixed address */
+/*****************************************************************************/
+
+
+
+void g_cmplocal (unsigned flags, int offs);
+/* Compare a local variable to ax */
+
+void g_cmpstatic (unsigned flags, unsigned label, unsigned offs);
+/* Compare a static variable to ax */
+
+
+
+/*****************************************************************************/
+/* Special op= functions */
+/*****************************************************************************/
+
+
+
+void g_addeqstatic (unsigned flags, unsigned long label, unsigned offs,
+ unsigned long val);
+/* Emit += for a static variable */
+
+void g_addeqlocal (unsigned flags, int offs, unsigned long val);
+/* Emit += for a local variable */
+
+void g_addeqind (unsigned flags, unsigned offs, unsigned long val);
+/* Emit += for the location with address in ax */
+
+void g_subeqstatic (unsigned flags, unsigned long label, unsigned offs,
+ unsigned long val);
+/* Emit -= for a static variable */
+
+void g_subeqlocal (unsigned flags, int offs, unsigned long val);
+/* Emit -= for a local variable */
+
+void g_subeqind (unsigned flags, unsigned offs, unsigned long val);
+/* Emit -= for the location with address in ax */
+
+
+
+/*****************************************************************************/
+/* Add a variable address to the value in ax */
+/*****************************************************************************/
+
+
+
+void g_addaddr_local (unsigned flags, int offs);
+/* Add the address of a local variable to ax */
+
+void g_addaddr_static (unsigned flags, unsigned long label, unsigned offs);
+/* Add the address of a static variable to ax */
+
+
+
+/*****************************************************************************/
+/* */
+/*****************************************************************************/
+
+
+
+void g_save (unsigned flags);
+void g_restore (unsigned flags);
+
+void g_cmp (unsigned flags, unsigned long val);
+/* Immidiate compare. The primary register will not be changed, Z flag
+ * will be set.
+ */
+
+void g_test (unsigned flags);
+void g_push (unsigned flags, unsigned long val);
+void g_swap (unsigned flags);
+void g_call (unsigned flags, char *lbl, unsigned argsize);
+void g_callind (unsigned flags, unsigned argsize);
+void g_jump (unsigned label);
+void g_switch (unsigned flags);
+
+void g_case (unsigned flags, unsigned label, unsigned long val);
+/* Create table code for one case selector */
+
+void g_truejump (unsigned flags, unsigned label);
+/* Jump to label if zero flag clear */
+
+void g_falsejump (unsigned flags, unsigned label);
+/* Jump to label if zero flag set */
+
+void g_space (int space);
+/* Create or drop space on the stack */
+
+void g_add (unsigned flags, unsigned long val);
+void g_sub (unsigned flags, unsigned long val);
+void g_rsub (unsigned flags, unsigned long val);
+void g_mul (unsigned flags, unsigned long val);
+void g_div (unsigned flags, unsigned long val);
+void g_mod (unsigned flags, unsigned long val);
+void g_or (unsigned flags, unsigned long val);
+void g_xor (unsigned flags, unsigned long val);
+void g_and (unsigned flags, unsigned long val);
+void g_asr (unsigned flags, unsigned long val);
+void g_asl (unsigned flags, unsigned long val);
+void g_neg (unsigned flags);
+void g_bneg (unsigned flags);
+void g_com (unsigned flags);
+void g_inc (unsigned flags, unsigned long n);
+void g_dec (unsigned flags, unsigned long n);
+void g_eq (unsigned flags, unsigned long val);
+void g_ne (unsigned flags, unsigned long val);
+void g_lt (unsigned flags, unsigned long val);
+void g_le (unsigned flags, unsigned long val);
+void g_gt (unsigned flags, unsigned long val);
+void g_ge (unsigned flags, unsigned long val);
+void g_makebool (unsigned flags);
+void outdat (int n);
+void g_res (unsigned n);
+
+void g_defdata (unsigned flags, unsigned long val, unsigned offs);
+/* Define data with the size given in flags */
+
+void g_defbytes (const unsigned char *bytes, unsigned count);
+void g_zerobytes (unsigned n);
+
+
+
+/*****************************************************************************/
+/* Inlined known functions */
+/*****************************************************************************/
+
+
+
+void g_strlen (unsigned flags, unsigned long val, unsigned offs);
+/* Inline the strlen() function */
+
+
+
+/* End of codegen.h */
+#endif
+
+
--- /dev/null
+-*- Mode: Text -*-
+
+ This is the copyright notice for RA65, LINK65, LIBR65, and other
+Atari 8-bit programs. Said programs are Copyright 1989, by John R.
+Dunning. All rights reserved, with the following exceptions:
+
+ Anyone may copy or redistribute these programs, provided that:
+
+1: You don't charge anything for the copy. It is permissable to
+ charge a nominal fee for media, etc.
+
+2: All source code and documentation for the programs is made
+ available as part of the distribution.
+
+3: This copyright notice is preserved verbatim, and included in
+ the distribution.
+
+ You are allowed to modify these programs, and redistribute the
+modified versions, provided that the modifications are clearly noted.
+
+ There is NO WARRANTY with this software, it comes as is, and is
+distributed in the hope that it may be useful.
+
+ This copyright notice applies to any program which contains
+this text, or the refers to this file.
+
+ This copyright notice is based on the one published by the Free
+Software Foundation, sometimes known as the GNU project. The idea
+is the same as theirs, ie the software is free, and is intended to
+stay that way. Everybody has the right to copy, modify, and re-
+distribute this software. Nobody has the right to prevent anyone
+else from copying, modifying or redistributing it.
--- /dev/null
+/*****************************************************************************/
+/* */
+/* ctrans.c */
+/* */
+/* Character set translation for the cc65 C compiler */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include "global.h"
+#include "ctrans.h"
+
+
+
+/*****************************************************************************/
+/* data */
+/*****************************************************************************/
+
+
+
+static unsigned char CTNone [256] = {
+ /* No system - no translation */
+ 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
+ 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
+ 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
+ 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,
+ 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
+ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F,
+ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
+ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
+ 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,
+ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
+ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,
+ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
+ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF
+};
+
+static unsigned char CTAtari [256] = {
+ /* ASCII -> ATASCII */
+ 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x7E,0x08,0x7F,0x9B,0x0B,0x7D,0x0D,0x0E,0x0F,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
+ 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
+ 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
+ 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,
+ 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
+ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F,
+ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
+ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
+ 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,
+ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
+ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,
+ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
+ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF
+};
+
+static unsigned char CTPET [256] = {
+ /* ASCII -> PETSCII */
+ 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x14,0x09,0x0D,0x11,0x93,0x0A,0x0E,0x0F,
+ 0x10,0x0B,0x12,0x13,0x08,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
+ 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
+ 0x40,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
+ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0x5B,0x5C,0x5D,0x5E,0x5F,
+ 0xC0,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
+ 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0xDB,0xDC,0xDD,0xDE,0xDF,
+ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
+ 0x90,0x91,0x92,0x0C,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
+ 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,
+ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
+ 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
+ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F,
+ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
+ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF
+};
+
+static unsigned char* CTab [TGT_COUNT] = {
+ CTNone, /* No system */
+ CTAtari, /* Atari */
+ CTPET, /* C64 */
+ CTPET, /* C128 */
+ CTPET, /* ACE */
+ CTPET, /* Plus/4 */
+ CTPET, /* CBM610 */
+ CTPET, /* PET */
+ CTNone, /* NES */
+ CTNone, /* Apple2 */
+ CTPET, /* GEOS */
+};
+
+
+
+/*****************************************************************************/
+/* code */
+/*****************************************************************************/
+
+
+
+int ctrans (unsigned char C)
+/* Translate a character from source charset into target charset */
+{
+ /* Translate for the given system */
+ return CTab [Target][C];
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* ctrans.h */
+/* */
+/* Character set translation for the cc65 C compiler */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef CTRANS_H
+#define CTRANS_H
+
+
+
+/*****************************************************************************/
+/* code */
+/*****************************************************************************/
+
+
+
+int ctrans (unsigned char c);
+/* Translate a character from source charset into target charset */
+
+
+
+/* End of ctrans.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* datatype.c */
+/* */
+/* Type string handling for the cc65 C compiler */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <string.h>
+
+#include "check.h"
+#include "codegen.h"
+#include "datatype.h"
+#include "error.h"
+#include "funcdesc.h"
+#include "global.h"
+#include "mem.h"
+#include "util.h"
+#include "symtab.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Predefined type strings */
+type type_int [] = { T_INT, T_END };
+type type_uint [] = { T_UINT, T_END };
+type type_long [] = { T_LONG, T_END };
+type type_ulong [] = { T_ULONG, T_END };
+type type_void [] = { T_VOID, T_END };
+type type_pschar [] = { T_PTR, T_CHAR, T_END };
+type type_puchar [] = { T_PTR, T_UCHAR, T_END };
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+unsigned TypeLen (const type* T)
+/* Return the length of the type string */
+{
+ const type* Start = T;
+ while (*T) {
+ ++T;
+ }
+ return T - Start;
+}
+
+
+
+int TypeCmp (const type* T1, const type* T2)
+/* Compare two type strings */
+{
+ int A, B, D;
+ do {
+ A = *T1++;
+ B = *T2++;
+ D = A - B;
+ } while (D == 0 && A != 0);
+ return D;
+}
+
+
+
+type* TypeCpy (type* Dest, const type* Src)
+/* Copy a type string */
+{
+ type T;
+ type* Orig = Dest;
+ do {
+ T = *Src++;
+ *Dest++ = T;
+ } while (T);
+ return Orig;
+}
+
+
+
+type* TypeCat (type* Dest, const type* Src)
+/* Append Src */
+{
+ TypeCpy (Dest + TypeLen (Dest), Src);
+ return Dest;
+}
+
+
+
+type* TypeDup (const type* T)
+/* Create a copy of the given type on the heap */
+{
+ unsigned Len = (TypeLen (T) + 1) * sizeof (type);
+ return memcpy (xmalloc (Len), T, Len);
+}
+
+
+
+type* TypeAlloc (unsigned Len)
+/* Allocate memory for a type string of length Len. Len *must* include the
+ * trailing T_END.
+ */
+{
+ return xmalloc (Len * sizeof (type));
+}
+
+
+
+void TypeFree (type* T)
+/* Free a type string */
+{
+ xfree (T);
+}
+
+
+
+type GetDefaultChar (void)
+/* Return the default char type (signed/unsigned) depending on the settings */
+{
+ return SignedChars? T_CHAR : T_UCHAR;
+}
+
+
+
+type* GetCharArrayType (unsigned Len)
+/* Return the type for a char array of the given length */
+{
+ /* Allocate memory for the type string */
+ type* T = TypeAlloc (1 + DECODE_SIZE + 2);
+
+ /* Fill the type string */
+ T [0] = T_ARRAY;
+ T [DECODE_SIZE+1] = GetDefaultChar();
+ T [DECODE_SIZE+2] = T_END;
+
+ /* Encode the length in the type string */
+ Encode (T+1, Len);
+
+ /* Return the new type */
+ return T;
+}
+
+
+
+type* GetImplicitFuncType (void)
+/* Return a type string for an inplicitly declared function */
+{
+ /* Get a new function descriptor */
+ FuncDesc* F = NewFuncDesc ();
+
+ /* Allocate memory for the type string */
+ type* T = TypeAlloc (1 + DECODE_SIZE + 2);
+
+ /* Prepare the function descriptor */
+ F->Flags = FD_IMPLICIT | FD_ELLIPSIS;
+ F->SymTab = &EmptySymTab;
+ F->StructTab = &EmptySymTab;
+ F->EnumTab = &EmptySymTab;
+
+ /* Fill the type string */
+ T [0] = T_FUNC;
+ T [DECODE_SIZE+1] = T_INT;
+ T [DECODE_SIZE+2] = T_END;
+
+ /* Encode the function descriptor into the type string */
+ EncodePtr (T+1, F);
+
+ /* Return the new type */
+ return T;
+}
+
+
+
+void PrintType (FILE* F, const type* tarray)
+/* Output translation of type array. */
+{
+ const type* p;
+
+ for (p = tarray; *p != T_END; ++p) {
+ if (*p & T_UNSIGNED) {
+ fprintf (F, "unsigned ");
+ }
+ switch (*p) {
+ case T_VOID:
+ fprintf (F, "void\n");
+ break;
+ case T_CHAR:
+ case T_UCHAR:
+ fprintf (F, "char\n");
+ break;
+ case T_INT:
+ case T_UINT:
+ fprintf (F, "int\n");
+ break;
+ case T_SHORT:
+ case T_USHORT:
+ fprintf (F, "short\n");
+ break;
+ case T_LONG:
+ case T_ULONG:
+ fprintf (F, "long\n");
+ break;
+ case T_FLOAT:
+ fprintf (F, "float\n");
+ break;
+ case T_DOUBLE:
+ fprintf (F, "double\n");
+ break;
+ case T_PTR:
+ fprintf (F, "pointer to ");
+ break;
+ case T_ARRAY:
+ fprintf (F, "array[%lu] of ", Decode (p + 1));
+ p += DECODE_SIZE;
+ break;
+ case T_STRUCT:
+ fprintf (F, "struct %s\n", ((SymEntry*) Decode (p + 1))->Name);
+ p += DECODE_SIZE;
+ break;
+ case T_UNION:
+ fprintf (F, "union %s\n", ((SymEntry*) Decode (p + 1))->Name);
+ p += DECODE_SIZE;
+ break;
+ case T_FUNC:
+ fprintf (F, "function returning ");
+ p += DECODE_SIZE;
+ break;
+ default:
+ fprintf (F, "unknown type: %04X\n", *p);
+ }
+ }
+}
+
+
+
+void PrintRawType (FILE* F, const type* Type)
+/* Print a type string in raw format (for debugging) */
+{
+ while (*Type != T_END) {
+ fprintf (F, "%04X ", *Type++);
+ }
+ fprintf (F, "\n");
+}
+
+
+
+void Encode (type* Type, unsigned long Val)
+/* Encode p[0] and p[1] so that neither p[0] nore p[1] is zero */
+{
+ int I;
+ for (I = 0; I < DECODE_SIZE; ++I) {
+ *Type++ = ((type) Val) | 0x8000;
+ Val >>= 15;
+ }
+}
+
+
+
+void EncodePtr (type* Type, void* P)
+/* Encode a pointer into a type array */
+{
+ Encode (Type, (unsigned long) P);
+}
+
+
+
+unsigned long Decode (const type* Type)
+/* Decode */
+{
+ int I;
+ unsigned long Val = 0;
+ for (I = DECODE_SIZE-1; I >= 0; I--) {
+ Val <<= 15;
+ Val |= (Type[I] & 0x7FFF);
+ }
+ return Val;
+}
+
+
+
+void* DecodePtr (const type* Type)
+/* Decode a pointer from a type array */
+{
+ return (void*) Decode (Type);
+}
+
+
+
+int HasEncode (const type* Type)
+/* Return true if the given type has encoded data */
+{
+ return IsStruct (Type) || IsArray (Type) || IsFunc (Type);
+}
+
+
+
+void CopyEncode (const type* Source, type* Target)
+/* Copy encoded data from Source to Target */
+{
+ memcpy (Target, Source, DECODE_SIZE * sizeof (type));
+}
+
+
+
+unsigned SizeOf (const type* tarray)
+/* Compute size of object represented by type array. */
+{
+ SymEntry* Entry;
+
+ switch (*tarray) {
+
+ case T_VOID:
+ return 0;
+
+ case T_CHAR:
+ case T_UCHAR:
+ return 1;
+
+ case T_INT:
+ case T_UINT:
+ case T_SHORT:
+ case T_USHORT:
+ case T_PTR:
+ case T_ENUM:
+ return 2;
+
+ case T_LONG:
+ case T_ULONG:
+ return 4;
+
+ case T_ARRAY:
+ return (Decode (tarray + 1) * SizeOf (tarray + DECODE_SIZE + 1));
+
+ case T_STRUCT:
+ case T_UNION:
+ Entry = DecodePtr (tarray+1);
+ return Entry->V.S.Size;
+
+ default:
+ Internal ("Unknown type: %04X", *tarray);
+ return 0;
+
+ }
+}
+
+
+
+unsigned PSizeOf (const type* tptr)
+/* Compute size of pointer object. */
+{
+ /* We are expecting a pointer expression */
+ CHECK (*tptr & T_POINTER);
+
+ /* Skip the pointer or array token itself */
+ if (*tptr == T_ARRAY) {
+ return SizeOf (tptr + DECODE_SIZE + 1);
+ } else {
+ return SizeOf (tptr + 1);
+ }
+}
+
+
+
+unsigned TypeOf (const type* Type)
+/* Get the code generator base type of the object */
+{
+ FuncDesc* F;
+
+ switch (*Type) {
+
+ case T_CHAR:
+ return CF_CHAR;
+
+ case T_UCHAR:
+ return CF_CHAR | CF_UNSIGNED;
+
+ case T_SHORT:
+ case T_INT:
+ case T_ENUM:
+ return CF_INT;
+
+ case T_USHORT:
+ case T_UINT:
+ case T_PTR:
+ case T_ARRAY:
+ return CF_INT | CF_UNSIGNED;
+
+ case T_LONG:
+ return CF_LONG;
+
+ case T_ULONG:
+ return CF_LONG | CF_UNSIGNED;
+
+ case T_FUNC:
+ F = DecodePtr (Type+1);
+ return (F->Flags & FD_ELLIPSIS)? 0 : CF_FIXARGC;
+
+ case T_STRUCT:
+ case T_UNION:
+ /* Address of ... */
+ return CF_INT | CF_UNSIGNED;
+
+ default:
+ Error (ERR_ILLEGAL_TYPE);
+ return CF_INT;
+ }
+}
+
+
+
+type* Indirect (type* Type)
+/* Do one indirection for the given type, that is, return the type where the
+ * given type points to.
+ */
+{
+ /* We are expecting a pointer expression */
+ CHECK (Type[0] & T_POINTER);
+
+ /* Skip the pointer or array token itself */
+ if (Type[0] == T_ARRAY) {
+ return Type + DECODE_SIZE + 1;
+ } else {
+ return Type + 1;
+ }
+}
+
+
+
+int IsVoid (const type* Type)
+/* Return true if this is a void type */
+{
+ return (Type[0] == T_VOID && Type[1] == T_END);
+}
+
+
+
+int IsPtr (const type* Type)
+/* Return true if this is a pointer type */
+{
+ return (Type[0] & T_POINTER) != 0;
+}
+
+
+
+int IsChar (const type* Type)
+/* Return true if this is a character type */
+{
+ return (Type[0] == T_CHAR || Type[0] == T_UCHAR) && Type[1] == T_END;
+}
+
+
+
+int IsInt (const type* Type)
+/* Return true if this is an integer type */
+{
+ return (Type[0] & T_INTEGER) != 0;
+}
+
+
+
+int IsLong (const type* Type)
+/* Return true if this is a long type (signed or unsigned) */
+{
+ return (Type[0] & T_LONG) == T_LONG;
+}
+
+
+
+int IsUnsigned (const type* Type)
+/* Return true if this is an unsigned type */
+{
+ return (Type[0] & T_UNSIGNED) != 0;
+}
+
+
+
+int IsStruct (const type* Type)
+/* Return true if this is a struct type */
+{
+ return (Type[0] == T_STRUCT || Type[0] == T_UNION);
+}
+
+
+
+int IsFunc (const type* Type)
+/* Return true if this is a function type */
+{
+ return (Type[0] == T_FUNC);
+}
+
+
+
+int IsFastCallFunc (const type* Type)
+/* Return true if this is a function type with __fastcall__ calling conventions */
+{
+ FuncDesc* F;
+ CHECK (*Type == T_FUNC);
+ F = DecodePtr (Type+1);
+ return (F->Flags & FD_FASTCALL) != 0;
+}
+
+
+
+int IsFuncPtr (const type* Type)
+/* Return true if this is a function pointer */
+{
+ return (Type[0] == T_PTR && Type[1] == T_FUNC);
+}
+
+
+
+int IsArray (const type* Type)
+/* Return true if this is an array type */
+{
+ return (Type[0] == T_ARRAY);
+}
+
+
+
+struct FuncDesc* GetFuncDesc (const type* Type)
+/* Get the FuncDesc pointer from a function or pointer-to-function type */
+{
+ if (Type[0] == T_PTR) {
+ /* Pointer to function */
+ ++Type;
+ }
+
+ /* Be sure it's a function type */
+ CHECK (Type[0] == T_FUNC);
+
+ /* Decode the function descriptor and return it */
+ return DecodePtr (Type+1);
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* datatype.h */
+/* */
+/* Type string handling for the cc65 C compiler */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef DATATYPE_H
+#define DATATYPE_H
+
+
+
+#include <stdio.h>
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Data types */
+#define T_END 0x0000
+#define T_CHAR 0x0011
+#define T_INT 0x0012
+#define T_SHORT 0x0013
+#define T_LONG 0x0014
+#define T_ENUM 0x0015
+#define T_UCHAR 0x0019
+#define T_UINT 0x001A
+#define T_USHORT 0x001B
+#define T_ULONG 0x001C
+
+#define T_FLOAT 0x0025
+#define T_DOUBLE 0x0026
+
+#define T_VOID 0x0001 /* void parameter list */
+#define T_FUNC 0x0002 /* Function */
+
+#define T_UNSIGNED 0x0008 /* Class */
+#define T_INTEGER 0x0010 /* Class */
+#define T_REAL 0x0020 /* Class */
+#define T_POINTER 0x0040 /* Class */
+#define T_PTR 0x0049
+#define T_ARRAY 0x004A
+#define T_STRUCT 0x0080
+#define T_UNION 0x0081
+#define T_SMASK 0x003F
+
+
+
+/* Forward for a symbol entry */
+struct SymEntry;
+
+/* Type entry */
+typedef unsigned short type;
+
+/* Maximum length of a type string */
+#define MAXTYPELEN 30
+
+/* type elements needed for Encode/Decode */
+#define DECODE_SIZE 5
+
+/* Predefined type strings */
+extern type type_int [];
+extern type type_uint [];
+extern type type_long [];
+extern type type_ulong [];
+extern type type_void [];
+extern type type_pschar [];
+extern type type_puchar [];
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+unsigned TypeLen (const type* Type);
+/* Return the length of the type string */
+
+int TypeCmp (const type* T1, const type* T2);
+/* Compare two type strings */
+
+type* TypeCpy (type* Dest, const type* Src);
+/* Copy a type string */
+
+type* TypeCat (type* Dest, const type* Src);
+/* Append Src */
+
+type* TypeDup (const type* Type);
+/* Create a copy of the given type on the heap */
+
+type* TypeAlloc (unsigned Len);
+/* Allocate memory for a type string of length Len. Len *must* include the
+ * trailing T_END.
+ */
+
+void TypeFree (type* Type);
+/* Free a type string */
+
+type GetDefaultChar (void);
+/* Return the default char type (signed/unsigned) depending on the settings */
+
+type* GetCharArrayType (unsigned Len);
+/* Return the type for a char array of the given length */
+
+type* GetImplicitFuncType (void);
+/* Return a type string for an inplicitly declared function */
+
+void PrintType (FILE* F, const type* Type);
+/* Output translation of type array. */
+
+void PrintRawType (FILE* F, const type* Type);
+/* Print a type string in raw format (for debugging) */
+
+void Encode (type* Type, unsigned long Val);
+/* Encode an unsigned long into a type array */
+
+void EncodePtr (type* Type, void* P);
+/* Encode a pointer into a type array */
+
+unsigned long Decode (const type* Type);
+/* Decode an unsigned long from a type array */
+
+void* DecodePtr (const type* Type);
+/* Decode a pointer from a type array */
+
+int HasEncode (const type* Type);
+/* Return true if the given type has encoded data */
+
+void CopyEncode (const type* Source, type* Target);
+/* Copy encoded data from Source to Target */
+
+unsigned SizeOf (const type* Type);
+/* Compute size of object represented by type array. */
+
+unsigned PSizeOf (const type* Type);
+/* Compute size of pointer object. */
+
+unsigned TypeOf (const type* Type);
+/* Get the code generator base type of the object */
+
+type* Indirect (type* Type);
+/* Do one indirection for the given type, that is, return the type where the
+ * given type points to.
+ */
+
+int IsVoid (const type* Type);
+/* Return true if this is a void type */
+
+int IsPtr (const type* Type);
+/* Return true if this is a pointer type */
+
+int IsChar (const type* Type);
+/* Return true if this is a character type */
+
+int IsInt (const type* Type);
+/* Return true if this is an integer type */
+
+int IsLong (const type* Type);
+/* Return true if this is a long type (signed or unsigned) */
+
+int IsUnsigned (const type* Type);
+/* Return true if this is an unsigned type */
+
+int IsStruct (const type* Type);
+/* Return true if this is a struct type */
+
+int IsFunc (const type* Type);
+/* Return true if this is a function type */
+
+int IsFastCallFunc (const type* Type);
+/* Return true if this is a function type with __fastcall__ calling conventions */
+
+int IsFuncPtr (const type* Type);
+/* Return true if this is a function pointer */
+
+int IsArray (const type* Type);
+/* Return true if this is an array type */
+
+struct FuncDesc* GetFuncDesc (const type* Type);
+/* Get the FuncDesc pointer from a function or pointer-to-function type */
+
+
+
+/* End of datatype.h */
+
+#endif
+
+
+
--- /dev/null
+/*
+ * declare.c
+ *
+ * Ullrich von Bassewitz, 20.06.1998
+ */
+
+
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "anonname.h"
+#include "codegen.h"
+#include "datatype.h"
+#include "error.h"
+#include "expr.h"
+#include "funcdesc.h"
+#include "function.h"
+#include "global.h"
+#include "litpool.h"
+#include "mem.h"
+#include "pragma.h"
+#include "scanner.h"
+#include "symtab.h"
+#include "declare.h"
+
+
+
+/*****************************************************************************/
+/* Forwards */
+/*****************************************************************************/
+
+
+
+static void ParseTypeSpec (DeclSpec* D, int Default);
+/* Parse a type specificier */
+
+
+
+/*****************************************************************************/
+/* internal functions */
+/*****************************************************************************/
+
+
+
+static void optional_modifiers (void)
+/* Eat optional "const" or "volatile" tokens */
+{
+ while (curtok == CONST || curtok == VOLATILE) {
+ /* Skip it */
+ gettok ();
+ }
+}
+
+
+
+static void optionalint (void)
+/* Eat an optional "int" token */
+{
+ if (curtok == INT) {
+ /* Skip it */
+ gettok ();
+ }
+}
+
+
+
+static void optionalsigned (void)
+/* Eat an optional "signed" token */
+{
+ if (curtok == SIGNED) {
+ /* Skip it */
+ gettok ();
+ }
+}
+
+
+
+static void InitDeclSpec (DeclSpec* D)
+/* Initialize the DeclSpec struct for use */
+{
+ D->StorageClass = 0;
+ D->Type[0] = T_END;
+ D->Flags = 0;
+}
+
+
+
+static void InitDeclaration (Declaration* D)
+/* Initialize the Declaration struct for use */
+{
+ D->Ident[0] = '\0';
+ D->Type[0] = T_END;
+ D->T = D->Type;
+}
+
+
+
+static void ParseStorageClass (DeclSpec* D, unsigned DefStorage)
+/* Parse a storage class */
+{
+ /* Assume we're using an explicit storage class */
+ D->Flags &= ~DS_DEF_STORAGE;
+
+ /* Check the storage class given */
+ switch (curtok) {
+
+ case EXTERN:
+ D->StorageClass = SC_EXTERN | SC_STATIC;
+ gettok ();
+ break;
+
+ case STATIC:
+ D->StorageClass = SC_STATIC;
+ gettok ();
+ break;
+
+ case REGISTER:
+ D->StorageClass = SC_REGISTER | SC_STATIC;
+ gettok ();
+ break;
+
+ case AUTO:
+ D->StorageClass = SC_AUTO;
+ gettok ();
+ break;
+
+ case TYPEDEF:
+ D->StorageClass = SC_TYPEDEF;
+ gettok ();
+ break;
+
+ default:
+ /* No storage class given, use default */
+ D->Flags |= DS_DEF_STORAGE;
+ D->StorageClass = DefStorage;
+ break;
+ }
+}
+
+
+
+static void ParseEnumDecl (void)
+/* Process an enum declaration . */
+{
+ int EnumVal;
+ ident Ident;
+
+ /* Accept forward definitions */
+ if (curtok != LCURLY) {
+ return;
+ }
+
+ /* Skip the opening curly brace */
+ gettok ();
+
+ /* Read the enum tags */
+ EnumVal = 0;
+ while (curtok != RCURLY) {
+
+ /* We expect an identifier */
+ if (curtok != IDENT) {
+ Error (ERR_IDENT_EXPECTED);
+ continue;
+ }
+
+ /* Remember the identifier and skip it */
+ strcpy (Ident, CurTok.Ident);
+ gettok ();
+
+ /* Check for an assigned value */
+ if (curtok == ASGN) {
+ struct expent lval;
+ gettok ();
+ constexpr (&lval);
+ EnumVal = lval.e_const;
+ }
+
+ /* Add an entry to the symbol table */
+ AddEnumSym (Ident, EnumVal++);
+
+ /* Check for end of definition */
+ if (curtok != COMMA)
+ break;
+ gettok ();
+ }
+ ConsumeRCurly ();
+}
+
+
+
+static SymEntry* ParseStructDecl (const char* Name, type StructType)
+/* Parse a struct/union declaration. */
+{
+
+ unsigned Size;
+ unsigned Offs;
+ SymTable* FieldTab;
+ SymEntry* Entry;
+
+
+ if (curtok != LCURLY) {
+ /* Just a forward declaration. Try to find a struct with the given
+ * name. If there is none, insert a forward declaration into the
+ * current lexical level.
+ */
+ Entry = FindStructSym (Name);
+ if (Entry == 0 || Entry->Flags != SC_STRUCT) {
+ Entry = AddStructSym (Name, 0, 0);
+ }
+ return Entry;
+ }
+
+ /* Add a forward declaration for the struct in the current lexical level */
+ Entry = AddStructSym (Name, 0, 0);
+
+ /* Skip the curly brace */
+ gettok ();
+
+ /* Enter a new lexical level for the struct */
+ EnterStructLevel ();
+
+ /* Parse struct fields */
+ Size = 0;
+ while (curtok != RCURLY) {
+
+ /* Get the type of the entry */
+ DeclSpec Spec;
+ InitDeclSpec (&Spec);
+ ParseTypeSpec (&Spec, -1);
+
+ /* Read fields with this type */
+ while (1) {
+
+ /* Get type and name of the struct field */
+ Declaration Decl;
+ ParseDecl (&Spec, &Decl, 0);
+
+ /* Add a field entry to the table */
+ AddLocalSym (Decl.Ident, Decl.Type, SC_SFLD, (StructType == T_STRUCT)? Size : 0);
+
+ /* Calculate offset of next field/size of the union */
+ Offs = SizeOf (Decl.Type);
+ if (StructType == T_STRUCT) {
+ Size += Offs;
+ } else {
+ if (Offs > Size) {
+ Size = Offs;
+ }
+ }
+
+ if (curtok != COMMA)
+ break;
+ gettok ();
+ }
+ ConsumeSemi ();
+ }
+
+ /* Skip the closing brace */
+ gettok ();
+
+ /* Remember the symbol table and leave the struct level */
+ FieldTab = GetSymTab ();
+ LeaveStructLevel ();
+
+ /* Make a real entry from the forward decl and return it */
+ return AddStructSym (Name, Size, FieldTab);
+}
+
+
+
+static void ParseTypeSpec (DeclSpec* D, int Default)
+/* Parse a type specificier */
+{
+ ident Ident;
+ SymEntry* Entry;
+ type StructType;
+
+ /* Assume have an explicit type */
+ D->Flags &= ~DS_DEF_TYPE;
+
+ /* Skip const or volatile modifiers if needed */
+ optional_modifiers ();
+
+ /* Look at the data type */
+ switch (curtok) {
+
+ case VOID:
+ gettok ();
+ D->Type[0] = T_VOID;
+ D->Type[1] = T_END;
+ break;
+
+ case CHAR:
+ gettok ();
+ D->Type[0] = GetDefaultChar();
+ D->Type[1] = T_END;
+ break;
+
+ case LONG:
+ gettok ();
+ if (curtok == UNSIGNED) {
+ gettok ();
+ optionalint ();
+ D->Type[0] = T_ULONG;
+ D->Type[1] = T_END;
+ } else {
+ optionalsigned ();
+ optionalint ();
+ D->Type[0] = T_LONG;
+ D->Type[1] = T_END;
+ }
+ break;
+
+ case SHORT:
+ gettok ();
+ if (curtok == UNSIGNED) {
+ gettok ();
+ optionalint ();
+ D->Type[0] = T_USHORT;
+ D->Type[1] = T_END;
+ } else {
+ optionalsigned ();
+ optionalint ();
+ D->Type[0] = T_SHORT;
+ D->Type[1] = T_END;
+ }
+ break;
+
+ case INT:
+ gettok ();
+ D->Type[0] = T_INT;
+ D->Type[1] = T_END;
+ break;
+
+ case SIGNED:
+ gettok ();
+ switch (curtok) {
+
+ case CHAR:
+ gettok ();
+ D->Type[0] = T_CHAR;
+ D->Type[1] = T_END;
+ break;
+
+ case SHORT:
+ gettok ();
+ optionalint ();
+ D->Type[0] = T_SHORT;
+ D->Type[1] = T_END;
+ break;
+
+ case LONG:
+ gettok ();
+ optionalint ();
+ D->Type[0] = T_LONG;
+ D->Type[1] = T_END;
+ break;
+
+ case INT:
+ gettok ();
+ /* FALL THROUGH */
+
+ default:
+ D->Type[0] = T_INT;
+ D->Type[1] = T_END;
+ break;
+ }
+ break;
+
+ case UNSIGNED:
+ gettok ();
+ switch (curtok) {
+
+ case CHAR:
+ gettok ();
+ D->Type[0] = T_UCHAR;
+ D->Type[1] = T_END;
+ break;
+
+ case SHORT:
+ gettok ();
+ optionalint ();
+ D->Type[0] = T_USHORT;
+ D->Type[1] = T_END;
+ break;
+
+ case LONG:
+ gettok ();
+ optionalint ();
+ D->Type[0] = T_ULONG;
+ D->Type[1] = T_END;
+ break;
+
+ case INT:
+ gettok ();
+ /* FALL THROUGH */
+
+ default:
+ D->Type[0] = T_UINT;
+ D->Type[1] = T_END;
+ break;
+ }
+ break;
+
+ case STRUCT:
+ case UNION:
+ StructType = (curtok == STRUCT)? T_STRUCT : T_UNION;
+ gettok ();
+ if (curtok == IDENT) {
+ strcpy (Ident, CurTok.Ident);
+ gettok ();
+ } else {
+ AnonName (Ident, (StructType == T_STRUCT)? "struct" : "union");
+ }
+ /* Declare the struct in the current scope */
+ Entry = ParseStructDecl (Ident, StructType);
+ /* Encode the struct entry into the type */
+ D->Type[0] = StructType;
+ EncodePtr (D->Type+1, Entry);
+ D->Type[DECODE_SIZE+1] = T_END;
+ break;
+
+ case ENUM:
+ gettok ();
+ if (curtok != LCURLY) {
+ /* Named enum */
+ Consume (IDENT, ERR_IDENT_EXPECTED);
+ }
+ ParseEnumDecl ();
+ D->Type[0] = T_INT;
+ D->Type[1] = T_END;
+ break;
+
+ case IDENT:
+ Entry = FindSym (CurTok.Ident);
+ if (Entry && IsTypeDef (Entry)) {
+ /* It's a typedef */
+ gettok ();
+ TypeCpy (D->Type, Entry->Type);
+ break;
+ }
+ /* FALL THROUGH */
+
+ default:
+ if (Default < 0) {
+ Error (ERR_TYPE_EXPECTED);
+ D->Type[0] = T_INT;
+ D->Type[1] = T_END;
+ } else {
+ D->Flags |= DS_DEF_TYPE;
+ D->Type[0] = (type) Default;
+ D->Type[1] = T_END;
+ }
+ break;
+ }
+}
+
+
+
+static FuncDesc* ParseFuncDecl (void)
+/* Parse the argument list of a function. */
+{
+ unsigned UnnamedCount = 0;
+ unsigned Offs;
+ SymEntry* Sym;
+ type* Type;
+
+ /* Create a new function descriptor */
+ FuncDesc* F = NewFuncDesc ();
+
+ /* Enter a new lexical level */
+ EnterFunctionLevel ();
+
+ /* Check for an empty or void parameter list */
+ if (curtok == RPAREN) {
+ /* Parameter list is empty */
+ F->Flags |= (FD_EMPTY | FD_ELLIPSIS);
+ } else if (curtok == VOID && nxttok == RPAREN) {
+ /* Parameter list declared as void */
+ gettok ();
+ F->Flags |= FD_VOID_PARAM;
+ }
+
+ /* Parse params */
+ while (curtok != RPAREN) {
+
+ DeclSpec Spec;
+ Declaration Decl;
+
+ /* Allow an ellipsis as last parameter */
+ if (curtok == ELLIPSIS) {
+ gettok ();
+ F->Flags |= FD_ELLIPSIS;
+ break;
+ }
+
+ /* Read the declaration specifier */
+ ParseDeclSpec (&Spec, SC_AUTO, T_INT);
+
+ /* We accept only auto and register as storage class specifiers, but
+ * we ignore all this and use auto.
+ */
+ if ((Spec.StorageClass & SC_AUTO) == 0 &&
+ (Spec.StorageClass & SC_REGISTER) == 0) {
+ Error (ERR_ILLEGAL_STORAGE_CLASS);
+ }
+ Spec.StorageClass = SC_AUTO | SC_PARAM | SC_DEF;
+
+ /* Allow parameters without a name, but remember if we had some to
+ * eventually print an error message later.
+ */
+ ParseDecl (&Spec, &Decl, DM_ACCEPT_IDENT);
+ if (Decl.Ident[0] == '\0') {
+
+ /* Unnamed symbol. Generate a name that is not user accessible,
+ * then handle the symbol normal.
+ */
+ AnonName (Decl.Ident, "param");
+ ++UnnamedCount;
+
+ /* Clear defined bit on nonames */
+ Spec.StorageClass &= ~SC_DEF;
+ }
+
+ /* If the parameter is an array, convert it to a pointer */
+ Type = Decl.Type;
+ if (IsArray (Type)) {
+ Type += DECODE_SIZE;
+ Type[0] = T_PTR;
+ }
+
+ /* Create a symbol table entry */
+ AddLocalSym (Decl.Ident, Type, Spec.StorageClass, 0);
+
+ /* Count arguments */
+ ++F->ParamCount;
+ F->ParamSize += SizeOf (Type);
+
+ /* Check for more parameters */
+ if (curtok == COMMA) {
+ gettok ();
+ } else {
+ break;
+ }
+ }
+
+ /* Skip right paren. We must explicitly check for one here, since some of
+ * the breaks above bail out without checking.
+ */
+ ConsumeRParen ();
+
+ /* Assign offsets. If the function has a variable parameter list,
+ * there's one additional byte (the arg size).
+ */
+ Offs = (F->Flags & FD_ELLIPSIS)? 1 : 0;
+ Sym = GetSymTab()->SymTail;
+ while (Sym) {
+ Sym->V.Offs = Offs;
+ Offs += SizeOf (Sym->Type);
+ Sym = Sym->PrevSym;
+ }
+
+ /* Check if this is a function definition */
+ if (curtok == LCURLY) {
+ /* Print an error if in strict ANSI mode and we have unnamed
+ * parameters.
+ */
+ if (ANSI && UnnamedCount > 0) {
+ Error (ERR_MISSING_PARAM_NAME);
+ }
+ }
+
+ /* Leave the lexical level remembering the symbol tables */
+ RememberFunctionLevel (F);
+
+ /* Return the function descriptor */
+ return F;
+}
+
+
+
+static void Decl (Declaration* D, unsigned Mode)
+/* Recursively process declarators. Build a type array in reverse order. */
+{
+ if (curtok == STAR) {
+ gettok ();
+ /* Allow optional const or volatile modifiers */
+ optional_modifiers ();
+ Decl (D, Mode);
+ *D->T++ = T_PTR;
+ return;
+ } else if (curtok == LPAREN) {
+ gettok ();
+ Decl (D, Mode);
+ ConsumeRParen ();
+ } else if (curtok == FASTCALL) {
+ /* Remember the current type pointer */
+ type* T = D->T;
+ /* Skip the fastcall token */
+ gettok ();
+ /* Parse the function */
+ Decl (D, Mode);
+ /* Set the fastcall flag */
+ if (!IsFunc (T)) {
+ Error (ERR_ILLEGAL_MODIFIER);
+ } else {
+ FuncDesc* F = DecodePtr (T+1);
+ F->Flags |= FD_FASTCALL;
+ }
+ return;
+ } else {
+ /* Things depend on Mode now:
+ * - Mode == DM_NEED_IDENT means:
+ * we *must* have a type and a variable identifer.
+ * - Mode == DM_NO_IDENT means:
+ * we must have a type but no variable identifer
+ * (if there is one, it's not read).
+ * - Mode == DM_ACCEPT_IDENT means:
+ * we *may* have an identifier. If there is an identifier,
+ * it is read, but it is no error, if there is none.
+ */
+ if (Mode == DM_NO_IDENT) {
+ D->Ident[0] = '\0';
+ } else if (curtok == IDENT) {
+ strcpy (D->Ident, CurTok.Ident);
+ gettok ();
+ } else {
+ if (Mode == DM_NEED_IDENT) {
+ Error (ERR_IDENT_EXPECTED);
+ }
+ D->Ident[0] = '\0';
+ return;
+ }
+ }
+
+ while (curtok == LBRACK || curtok == LPAREN) {
+ if (curtok == LPAREN) {
+ /* Function declaration */
+ FuncDesc* F;
+ gettok ();
+ /* Parse the function declaration */
+ F = ParseFuncDecl ();
+ *D->T++ = T_FUNC;
+ EncodePtr (D->T, F);
+ D->T += DECODE_SIZE;
+ } else {
+ /* Array declaration */
+ unsigned long Size = 0;
+ gettok ();
+ /* Read the size if it is given */
+ if (curtok != RBRACK) {
+ struct expent lval;
+ constexpr (&lval);
+ Size = lval.e_const;
+ }
+ ConsumeRBrack ();
+ *D->T++ = T_ARRAY;
+ Encode (D->T, Size);
+ D->T += DECODE_SIZE;
+ }
+ }
+}
+
+
+
+/*****************************************************************************/
+/* code */
+/*****************************************************************************/
+
+
+
+type* ParseType (type* Type)
+/* Parse a complete type specification */
+{
+ DeclSpec Spec;
+ Declaration Decl;
+
+ /* Get a type without a default */
+ InitDeclSpec (&Spec);
+ ParseTypeSpec (&Spec, -1);
+
+ /* Parse additional declarators */
+ InitDeclaration (&Decl);
+ ParseDecl (&Spec, &Decl, DM_NO_IDENT);
+
+ /* Copy the type to the target buffer */
+ TypeCpy (Type, Decl.Type);
+
+ /* Return a pointer to the target buffer */
+ return Type;
+}
+
+
+
+void ParseDecl (const DeclSpec* Spec, Declaration* D, unsigned Mode)
+/* Parse a variable, type or function declaration */
+{
+ /* Initialize the Declaration struct */
+ InitDeclaration (D);
+
+ /* Get additional declarators and the identifier */
+ Decl (D, Mode);
+
+ /* Add the base type. */
+ TypeCpy (D->T, Spec->Type);
+
+ /* Check the size of the generated type */
+ if (!IsFunc (D->Type) && SizeOf (D->Type) >= 0x10000) {
+ Error (ERR_ILLEGAL_SIZE);
+ }
+}
+
+
+
+void ParseDeclSpec (DeclSpec* D, unsigned DefStorage, int DefType)
+/* Parse a declaration specification */
+{
+ /* Initialize the DeclSpec struct */
+ InitDeclSpec (D);
+
+ /* First, get the storage class specifier for this declaration */
+ ParseStorageClass (D, DefStorage);
+
+ /* Parse the type specifiers */
+ ParseTypeSpec (D, DefType);
+}
+
+
+
+static void ParseVoidInit (void)
+/* Parse an initialization of a void variable (special cc65 extension) */
+{
+ struct expent lval;
+
+ /* Allow an arbitrary list of values */
+ ConsumeLCurly ();
+ do {
+ constexpr (&lval);
+ switch (lval.e_tptr[0]) {
+
+ case T_CHAR:
+ case T_UCHAR:
+ if ((lval.e_flags & E_MCTYPE) == E_TCONST) {
+ /* Make it byte sized */
+ lval.e_const &= 0xFF;
+ }
+ DefineData (&lval);
+ break;
+
+ case T_SHORT:
+ case T_USHORT:
+ case T_INT:
+ case T_UINT:
+ case T_PTR:
+ case T_ARRAY:
+ if ((lval.e_flags & E_MCTYPE) == E_TCONST) {
+ /* Make it word sized */
+ lval.e_const &= 0xFFFF;
+ }
+ DefineData (&lval);
+ break;
+
+ case T_LONG:
+ case T_ULONG:
+ DefineData (&lval);
+ break;
+
+ default:
+ Error (ERR_ILLEGAL_TYPE);
+ break;
+
+ }
+
+ if (curtok != COMMA) {
+ break;
+ }
+ gettok ();
+
+ } while (curtok != RCURLY);
+
+ ConsumeRCurly ();
+}
+
+
+
+static void ParseStructInit (type* Type)
+/* Parse initialization of a struct or union */
+{
+ SymEntry* Entry;
+ SymTable* Tab;
+
+ /* Consume the opening curly brace */
+ ConsumeLCurly ();
+
+ /* Get a pointer to the struct entry from the type */
+ Entry = (SymEntry*) Decode (Type + 1);
+
+ /* Check if this struct definition has a field table. If it doesn't, it
+ * is an incomplete definition.
+ */
+ Tab = Entry->V.S.SymTab;
+ if (Tab == 0) {
+ Error (ERR_INIT_INCOMPLETE_TYPE);
+ /* Returning here will cause lots of errors, but recovery is difficult */
+ return;
+ }
+
+ /* Get a pointer to the list of symbols */
+ Entry = Tab->SymHead;
+ while (curtok != RCURLY) {
+ if (Entry == NULL) {
+ Error (ERR_TOO_MANY_INITIALIZERS);
+ return;
+ }
+ ParseInit (Entry->Type);
+ Entry = Entry->NextSym;
+ if (curtok != COMMA)
+ break;
+ gettok ();
+ }
+
+ /* Consume the closing curly brace */
+ ConsumeRCurly ();
+
+ /* If there are struct fields left, reserve additional storage */
+ while (Entry) {
+ g_zerobytes (SizeOf (Entry->Type));
+ Entry = Entry->NextSym;
+ }
+}
+
+
+
+
+
+void ParseInit (type *tptr)
+/* Parse initialization of variables */
+{
+ int count;
+ struct expent lval;
+ type* t;
+ const char* str;
+ int sz;
+
+ switch (*tptr) {
+
+ case T_CHAR:
+ case T_UCHAR:
+ constexpr (&lval);
+ if ((lval.e_flags & E_MCTYPE) == E_TCONST) {
+ /* Make it byte sized */
+ lval.e_const &= 0xFF;
+ }
+ assignadjust (tptr, &lval);
+ DefineData (&lval);
+ break;
+
+ case T_SHORT:
+ case T_USHORT:
+ case T_INT:
+ case T_UINT:
+ case T_PTR:
+ constexpr (&lval);
+ if ((lval.e_flags & E_MCTYPE) == E_TCONST) {
+ /* Make it word sized */
+ lval.e_const &= 0xFFFF;
+ }
+ assignadjust (tptr, &lval);
+ DefineData (&lval);
+ break;
+
+ case T_LONG:
+ case T_ULONG:
+ constexpr (&lval);
+ if ((lval.e_flags & E_MCTYPE) == E_TCONST) {
+ /* Make it long sized */
+ lval.e_const &= 0xFFFFFFFF;
+ }
+ assignadjust (tptr, &lval);
+ DefineData (&lval);
+ break;
+
+ case T_ARRAY:
+ sz = Decode (tptr + 1);
+ t = tptr + DECODE_SIZE + 1;
+ if ((t [0] == T_CHAR || t [0] == T_UCHAR) && curtok == SCONST) {
+ str = GetLiteral (curval);
+ count = strlen (str) + 1;
+ TranslateLiteralPool (curval); /* Translate into target charset */
+ g_defbytes (str, count);
+ ResetLiteralOffs (curval); /* Remove string from pool */
+ gettok ();
+ } else {
+ ConsumeLCurly ();
+ count = 0;
+ while (curtok != RCURLY) {
+ ParseInit (tptr + DECODE_SIZE + 1);
+ ++count;
+ if (curtok != COMMA)
+ break;
+ gettok ();
+ }
+ ConsumeRCurly ();
+ }
+ if (sz == 0) {
+ Encode (tptr + 1, count);
+ } else if (count < sz) {
+ g_zerobytes ((sz - count) * SizeOf (tptr + DECODE_SIZE + 1));
+ } else if (count > sz) {
+ Error (ERR_TOO_MANY_INITIALIZERS);
+ }
+ break;
+
+ case T_STRUCT:
+ case T_UNION:
+ ParseStructInit (tptr);
+ break;
+
+ case T_VOID:
+ if (!ANSI) {
+ /* Special cc65 extension in non ANSI mode */
+ ParseVoidInit ();
+ break;
+ }
+ /* FALLTHROUGH */
+
+ default:
+ Error (ERR_ILLEGAL_TYPE);
+ break;
+
+ }
+}
+
+
+
--- /dev/null
+/*
+ * declare.h
+ *
+ * Ullrich von Bassewitz, 20.06.1998
+ */
+
+
+
+#ifndef DECLARE_H
+#define DECLARE_H
+
+
+
+#include "scanner.h"
+#include "symtab.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Masks for the Flags field in DeclSpec */
+#define DS_DEF_STORAGE 0x0001U /* Default storage class used */
+#define DS_DEF_TYPE 0x0002U /* Default type used */
+
+/* Result of ParseDeclSpec */
+typedef struct DeclSpec DeclSpec;
+struct DeclSpec {
+ unsigned StorageClass; /* One of the SC_xxx flags */
+ type Type [MAXTYPELEN]; /* Type of the declaration spec */
+ unsigned Flags; /* Bitmapped flags */
+};
+
+/* Result of ParseDecl */
+typedef struct Declaration Declaration;
+struct Declaration {
+ ident Ident; /* The identifier if any, else empty */
+ type Type [MAXTYPELEN]; /* The type */
+
+ /* Working variables */
+ type* T; /* Used to build Type */
+};
+
+/* Modes for ParseDecl */
+#define DM_NEED_IDENT 0U /* We must have an identifier */
+#define DM_NO_IDENT 1U /* We won't read an identifier */
+#define DM_ACCEPT_IDENT 2U /* We will accept an id if there is one */
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+type* ParseType (type* Type);
+/* Parse a complete type specification */
+
+void ParseDecl (const DeclSpec* Spec, Declaration* D, unsigned Mode);
+/* Parse a variable, type or function declaration */
+
+void ParseDeclSpec (DeclSpec* D, unsigned DefStorage, int DefType);
+/* Parse a declaration specification */
+
+void ParseInit (type* tptr);
+/* Parse initialization of variables */
+
+
+
+/* End of declare.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* error.c */
+/* */
+/* Error handling for the cc65 C compiler */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "global.h"
+#include "io.h"
+#include "scanner.h"
+#include "stmt.h"
+#include "error.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+static char* WarnMsg [WARN_COUNT-1] = {
+ "Unreachable code",
+ "Condition is never true",
+ "Condition is always true",
+ "Converting pointer to integer without a cast",
+ "Converting integer to pointer without a cast",
+ "Function call without a prototype",
+ "Unknown #pragma",
+ "No case labels",
+ "Function must be extern",
+ "Parameter `%s' is never used",
+ "`%s' is defined but never used",
+ "Constant is long",
+ "`/*' found inside a comment",
+};
+
+
+
+/* Error messages sorted by ErrTypes */
+static char* ErrMsg [ERR_COUNT-1] = {
+ "Invalid character (%u)",
+ "Unexpected newline",
+ "End-of-file reached in comment starting at line %u",
+ "Syntax error",
+ "`\"' expected",
+ "`:' expected",
+ "`;' expected",
+ "`(' expected",
+ "`)' expected",
+ "`[' expected",
+ "`]' expected",
+ "`{' expected",
+ "`}' expected",
+ "Identifier expected",
+ "Type expected",
+ "Incompatible types",
+ "Incompatible pointer types",
+ "Too many arguments in function call",
+ "Too few arguments in function call",
+ "Macro argument count mismatch",
+ "Duplicate macro parameter: %s",
+ "Variable identifier expected",
+ "Integer expression expected",
+ "Constant expression expected",
+ "No active loop",
+ "`\"' or `<' expected",
+ "Missing terminator or name too long",
+ "Include file `%s' not found",
+ "Open failure on include file `%s'",
+ "Invalid #error directive",
+ "#error: %s",
+ "Unexpected `#endif'",
+ "Unexpected `#else'",
+ "`#endif' expected",
+ "Compiler directive expected",
+ "Symbol `%s' defined more than once",
+ "String literal expected",
+ "`while' expected",
+ "Function must return a value",
+ "Function cannot return a value",
+ "Unexpected `continue'",
+ "Undefined symbol: `%s'",
+ "Undefined label: `%s'",
+ "Include nesting too deep",
+ "Too many local variables",
+ "Too many initializers",
+ "Cannot initialize incomplete type",
+ "Cannot subscript",
+ "Operation not allowed on these types",
+ "Struct expected",
+ "Struct/union has no field named `%s'",
+ "Struct pointer expected",
+ "lvalue expected",
+ "Expression expected",
+ "Preprocessor expression expected",
+ "Illegal type",
+ "Illegal function call",
+ "Illegal indirection",
+ "Illegal address",
+ "Illegal macro call",
+ "Illegal hex digit",
+ "Illegal character constant",
+ "Illegal modifier",
+ "Illegal storage class",
+ "Division by zero",
+ "Modulo operation with zero",
+ "Range error",
+ "Symbol is already different kind",
+ "Too many lexical levels",
+ "Parameter name omitted",
+ "Old style function decl used as prototype",
+ "Declaration for parameter `%s' but no such parameter",
+ "Cannot take address of a register variable",
+ "Illegal size of data type",
+ "__fastcall__ is not allowed for C functions",
+ "Variable has unknown size",
+};
+
+
+
+static char* FatMsg [FAT_COUNT-1] = {
+ "Too many errors",
+ "Cannot open output file: %s",
+ "Cannot write to output file (disk full?)",
+ "Cannot open input file: %s",
+ "Out of memory",
+ "Stack overflow",
+ "Stack empty",
+ "Out of string space",
+ "Too many case labels",
+};
+
+
+
+/* Count of errors/warnings */
+unsigned ErrorCount = 0;
+unsigned WarningCount = 0;
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void Warning (unsigned WarnNum, ...)
+/* Print warning message. */
+{
+ va_list ap;
+
+ if (!NoWarn) {
+ fprintf (stderr, "%s(%u): Warning #%u: ", fin, curpos, WarnNum);
+
+ va_start (ap, WarnNum);
+ vfprintf (stderr, WarnMsg [WarnNum-1], ap);
+ va_end (ap);
+ fprintf (stderr, "\n");
+
+ if (Verbose) {
+ fprintf (stderr, "Line: %s\n", line);
+ }
+ }
+ ++ WarningCount;
+}
+
+
+
+void PPWarning (unsigned WarnNum, ...)
+/* Print warning message. For use within the preprocessor. */
+{
+ va_list ap;
+
+ if (!NoWarn) {
+ fprintf (stderr, "%s(%u): Warning #%u: ", fin, ln, WarnNum);
+
+ va_start (ap, WarnNum);
+ vfprintf (stderr, WarnMsg [WarnNum-1], ap);
+ va_end (ap);
+ fprintf (stderr, "\n");
+ }
+ ++WarningCount;
+}
+
+
+
+void Error (unsigned ErrNum, ...)
+/* Print an error message */
+{
+ va_list ap;
+
+ fprintf (stderr, "%s(%u): Error #%u: ", fin, curpos, ErrNum);
+
+ va_start (ap, ErrNum);
+ vfprintf (stderr, ErrMsg [ErrNum-1], ap);
+ va_end (ap);
+ fprintf (stderr, "\n");
+
+ if (Verbose) {
+ fprintf (stderr, "Line: %s\n", line);
+ }
+ ++ErrorCount;
+ if (ErrorCount > 10) {
+ Fatal (FAT_TOO_MANY_ERRORS);
+ }
+}
+
+
+
+void PPError (unsigned ErrNum, ...)
+/* Print an error message. For use within the preprocessor. */
+{
+ va_list ap;
+
+ fprintf (stderr, "%s(%u): Error #%u: ", fin, ln, ErrNum);
+
+ va_start (ap, ErrNum);
+ vfprintf (stderr, ErrMsg [ErrNum-1], ap);
+ va_end (ap);
+ fprintf (stderr, "\n");
+
+ ++ErrorCount;
+ if (ErrorCount > 10) {
+ Fatal (FAT_TOO_MANY_ERRORS);
+ }
+}
+
+
+
+void Fatal (unsigned FatNum, ...)
+/* Print a message about a fatal error and die */
+{
+ va_list ap;
+
+ fprintf (stderr, "%s(%u): Fatal #%u: ", fin, curpos, FatNum);
+
+ va_start (ap, FatNum);
+ vfprintf (stderr, FatMsg [FatNum-1], ap);
+ va_end (ap);
+ fprintf (stderr, "\n");
+
+ if (Verbose) {
+ fprintf (stderr, "Line: %s\n", line);
+ }
+ exit (EXIT_FAILURE);
+}
+
+
+
+void Internal (char* Format, ...)
+/* Print a message about an internal compiler error and die. */
+{
+ va_list ap;
+
+ fprintf (stderr, "%s(%u): Internal compiler error:\n", fin, curpos);
+
+ va_start (ap, Format);
+ vfprintf (stderr, Format, ap);
+ va_end (ap);
+ fprintf (stderr, "\nLine: %s\n", line);
+
+ /* Use abort to create a core dump */
+ abort ();
+}
+
+
+
+void ErrorReport (void)
+/* Report errors (called at end of compile) */
+{
+ if (ErrorCount == 0 && Verbose) {
+ printf ("No errors.\n");
+ }
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* error.h */
+/* */
+/* Error handling for the cc65 C compiler */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef ERROR_H
+#define ERROR_H
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Warning numbers */
+enum Warnings {
+ WARN_NONE, /* No warning */
+ WARN_UNREACHABLE_CODE,
+ WARN_COND_NEVER_TRUE,
+ WARN_COND_ALWAYS_TRUE,
+ WARN_PTR_TO_INT_CONV,
+ WARN_INT_TO_PTR_CONV,
+ WARN_FUNC_WITHOUT_PROTO,
+ WARN_UNKNOWN_PRAGMA,
+ WARN_NO_CASE_LABELS,
+ WARN_FUNC_MUST_BE_EXTERN,
+ WARN_UNUSED_PARM,
+ WARN_UNUSED_ITEM,
+ WARN_CONSTANT_IS_LONG,
+ WARN_NESTED_COMMENT,
+ WARN_COUNT /* Warning count */
+};
+
+/* Error numbers */
+enum Errors {
+ ERR_NONE, /* No error */
+ ERR_INVALID_CHAR,
+ ERR_UNEXPECTED_NEWLINE,
+ ERR_EOF_IN_COMMENT,
+ ERR_SYNTAX,
+ ERR_QUOTE_EXPECTED,
+ ERR_COLON_EXPECTED,
+ ERR_SEMICOLON_EXPECTED,
+ ERR_LPAREN_EXPECTED,
+ ERR_RPAREN_EXPECTED,
+ ERR_LBRACK_EXPECTED,
+ ERR_RBRACK_EXPECTED,
+ ERR_LCURLY_EXPECTED,
+ ERR_RCURLY_EXPECTED,
+ ERR_IDENT_EXPECTED,
+ ERR_TYPE_EXPECTED,
+ ERR_INCOMPATIBLE_TYPES,
+ ERR_INCOMPATIBLE_POINTERS,
+ ERR_TOO_MANY_FUNC_ARGS,
+ ERR_TOO_FEW_FUNC_ARGS,
+ ERR_MACRO_ARGCOUNT,
+ ERR_DUPLICATE_MACRO_ARG,
+ ERR_VAR_IDENT_EXPECTED,
+ ERR_INT_EXPR_EXPECTED,
+ ERR_CONST_EXPR_EXPECTED,
+ ERR_NO_ACTIVE_LOOP,
+ ERR_INCLUDE_LTERM_EXPECTED,
+ ERR_INCLUDE_RTERM_EXPECTED,
+ ERR_INCLUDE_NOT_FOUND,
+ ERR_INCLUDE_OPEN_FAILURE,
+ ERR_INVALID_USER_ERROR,
+ ERR_USER_ERROR,
+ ERR_UNEXPECTED_CPP_ENDIF,
+ ERR_UNEXPECTED_CPP_ELSE,
+ ERR_CPP_ENDIF_EXPECTED,
+ ERR_CPP_DIRECTIVE_EXPECTED,
+ ERR_MULTIPLE_DEFINITION,
+ ERR_STRLIT_EXPECTED,
+ ERR_WHILE_EXPECTED,
+ ERR_MUST_RETURN_VALUE,
+ ERR_CANNOT_RETURN_VALUE,
+ ERR_UNEXPECTED_CONTINUE,
+ ERR_UNDEFINED_SYMBOL,
+ ERR_UNDEFINED_LABEL,
+ ERR_INCLUDE_NESTING,
+ ERR_TOO_MANY_LOCALS,
+ ERR_TOO_MANY_INITIALIZERS,
+ ERR_INIT_INCOMPLETE_TYPE,
+ ERR_CANNOT_SUBSCRIPT,
+ ERR_OP_NOT_ALLOWED,
+ ERR_STRUCT_EXPECTED,
+ ERR_STRUCT_FIELD_MISMATCH,
+ ERR_STRUCT_PTR_EXPECTED,
+ ERR_LVALUE_EXPECTED,
+ ERR_EXPR_EXPECTED,
+ ERR_CPP_EXPR_EXPECTED,
+ ERR_ILLEGAL_TYPE,
+ ERR_ILLEGAL_FUNC_CALL,
+ ERR_ILLEGAL_INDIRECT,
+ ERR_ILLEGAL_ADDRESS,
+ ERR_ILLEGAL_MACRO_CALL,
+ ERR_ILLEGAL_HEX_DIGIT,
+ ERR_ILLEGAL_CHARCONST,
+ ERR_ILLEGAL_MODIFIER,
+ ERR_ILLEGAL_STORAGE_CLASS,
+ ERR_DIV_BY_ZERO,
+ ERR_MOD_BY_ZERO,
+ ERR_RANGE,
+ ERR_SYMBOL_KIND,
+ ERR_LEVEL_NESTING,
+ ERR_MISSING_PARAM_NAME,
+ ERR_OLD_STYLE_PROTO,
+ ERR_PARAM_DECL,
+ ERR_CANNOT_TAKE_ADDR_OF_REG,
+ ERR_ILLEGAL_SIZE,
+ ERR_FASTCALL,
+ ERR_UNKNOWN_SIZE,
+ ERR_COUNT /* Error count */
+};
+
+/* Fatal errors */
+enum Fatals {
+ FAT_NONE,
+ FAT_TOO_MANY_ERRORS,
+ FAT_CANNOT_OPEN_OUTPUT,
+ FAT_CANNOT_WRITE_OUTPUT,
+ FAT_CANNOT_OPEN_INPUT,
+ FAT_OUT_OF_MEMORY,
+ FAT_STACK_OVERFLOW,
+ FAT_STACK_EMPTY,
+ FAT_OUT_OF_STRSPACE,
+ FAT_TOO_MANY_CASE_LABELS,
+ FAT_COUNT /* Fatal error count */
+};
+
+
+
+/* Count of errors/warnings */
+extern unsigned ErrorCount;
+extern unsigned WarningCount;
+
+
+
+/*****************************************************************************/
+/* code */
+/*****************************************************************************/
+
+
+
+void Warning (unsigned WarnNum, ...);
+/* Print warning message. */
+
+void PPWarning (unsigned WarnNum, ...);
+/* Print warning message. For use within the preprocessor. */
+
+void Error (unsigned ErrNum, ...);
+/* Print an error message */
+
+void PPError (unsigned ErrNum, ...);
+/* Print an error message. For use within the preprocessor. */
+
+void Fatal (unsigned FatNum, ...);
+/* Print a message about a fatal error and die */
+
+void Internal (char* Format, ...);
+/* Print a message about an internal compiler error and die. */
+
+void ErrorReport (void);
+/* Report errors (called at end of compile) */
+
+
+
+/* End of error.h */
+#endif
+
+
+
+
+
--- /dev/null
+/*
+ * expr.c
+ *
+ * Ullrich von Bassewitz, 21.06.1998
+ */
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "asmcode.h"
+#include "asmlabel.h"
+#include "check.h"
+#include "codegen.h"
+#include "datatype.h"
+#include "declare.h"
+#include "error.h"
+#include "funcdesc.h"
+#include "function.h"
+#include "global.h"
+#include "io.h"
+#include "litpool.h"
+#include "macrotab.h"
+#include "mem.h"
+#include "preproc.h"
+#include "scanner.h"
+#include "stdfunc.h"
+#include "symtab.h"
+#include "expr.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Generator attributes */
+#define GEN_NOPUSH 0x01 /* Don't push lhs */
+
+/* Map a generator function and its attributes to a token */
+typedef struct {
+ unsigned char Tok; /* Token to map to */
+ unsigned char Flags; /* Flags for generator function */
+ void (*Func) (unsigned, unsigned long); /* Generator func */
+} GenDesc;
+
+/* Descriptors for the operations */
+static GenDesc GenMUL = { STAR, GEN_NOPUSH, g_mul };
+static GenDesc GenDIV = { DIV, GEN_NOPUSH, g_div };
+static GenDesc GenMOD = { MOD, GEN_NOPUSH, g_mod };
+static GenDesc GenASL = { ASL, GEN_NOPUSH, g_asl };
+static GenDesc GenASR = { ASR, GEN_NOPUSH, g_asr };
+static GenDesc GenLT = { LT, GEN_NOPUSH, g_lt };
+static GenDesc GenLE = { LE, GEN_NOPUSH, g_le };
+static GenDesc GenGE = { GE, GEN_NOPUSH, g_ge };
+static GenDesc GenGT = { GT, GEN_NOPUSH, g_gt };
+static GenDesc GenEQ = { EQ, GEN_NOPUSH, g_eq };
+static GenDesc GenNE = { NE, GEN_NOPUSH, g_ne };
+static GenDesc GenAND = { AMP, GEN_NOPUSH, g_and };
+static GenDesc GenXOR = { XOR, GEN_NOPUSH, g_xor };
+static GenDesc GenOR = { BAR, GEN_NOPUSH, g_or };
+static GenDesc GenPASGN = { PASGN, GEN_NOPUSH, g_add };
+static GenDesc GenSASGN = { SASGN, GEN_NOPUSH, g_sub };
+static GenDesc GenMASGN = { MASGN, GEN_NOPUSH, g_mul };
+static GenDesc GenDASGN = { DASGN, GEN_NOPUSH, g_div };
+static GenDesc GenMOASGN = { MOASGN, GEN_NOPUSH, g_mod };
+static GenDesc GenSLASGN = { SLASGN, GEN_NOPUSH, g_asl };
+static GenDesc GenSRASGN = { SRASGN, GEN_NOPUSH, g_asr };
+static GenDesc GenAASGN = { AASGN, GEN_NOPUSH, g_and };
+static GenDesc GenXOASGN = { XOASGN, GEN_NOPUSH, g_xor };
+static GenDesc GenOASGN = { OASGN, GEN_NOPUSH, g_or };
+
+
+
+/*****************************************************************************/
+/* Function forwards */
+/*****************************************************************************/
+
+
+
+static int hie10 (struct expent* lval);
+/* Handle ++, --, !, unary - etc. */
+
+
+
+/*****************************************************************************/
+/* Helper functions */
+/*****************************************************************************/
+
+
+
+static unsigned GlobalModeFlags (unsigned flags)
+/* Return the addressing mode flags for the variable with the given flags */
+{
+ flags &= E_MCTYPE;
+ if (flags == E_TGLAB) {
+ /* External linkage */
+ return CF_EXTERNAL;
+ } else if (flags == E_TREGISTER) {
+ /* Register variable */
+ return CF_REGVAR;
+ } else {
+ /* Static */
+ return CF_STATIC;
+ }
+}
+
+
+
+static int IsNullPtr (struct expent* lval)
+/* Return true if this is the NULL pointer constant */
+{
+ return (IsInt (lval->e_tptr) && /* Is it an int? */
+ lval->e_flags == E_MCONST && /* Is it constant? */
+ lval->e_const == 0); /* And is it's value zero? */
+}
+
+
+
+static type* promoteint (type* lhst, type* rhst)
+/* In an expression with two ints, return the type of the result */
+{
+ /* Rules for integer types:
+ * - If one of the values is a long, the result is long.
+ * - If one of the values is unsigned, the result is also unsigned.
+ * - Otherwise the result is an int.
+ */
+ if (IsLong (lhst) || IsLong (rhst)) {
+ if (IsUnsigned (lhst) || IsUnsigned (rhst)) {
+ return type_ulong;
+ } else {
+ return type_long;
+ }
+ } else {
+ if (IsUnsigned (lhst) || IsUnsigned (rhst)) {
+ return type_uint;
+ } else {
+ return type_int;
+ }
+ }
+}
+
+
+
+static unsigned typeadjust (struct expent* lhs, struct expent* rhs, int NoPush)
+/* Adjust the two values for a binary operation. lhs is expected on stack or
+ * to be constant, rhs is expected to be in the primary register or constant.
+ * The function will put the type of the result into lhs and return the
+ * code generator flags for the operation.
+ * If NoPush is given, it is assumed that the operation does not expect the lhs
+ * to be on stack, and that lhs is in a register instead.
+ * Beware: The function does only accept int types.
+ */
+{
+ unsigned ltype, rtype;
+ unsigned flags;
+
+ /* Get the type strings */
+ type* lhst = lhs->e_tptr;
+ type* rhst = rhs->e_tptr;
+
+ /* Generate type adjustment code if needed */
+ ltype = TypeOf (lhst);
+ if (lhs->e_flags == E_MCONST) {
+ ltype |= CF_CONST;
+ }
+ if (NoPush) {
+ /* Value is in primary register*/
+ ltype |= CF_REG;
+ }
+ rtype = TypeOf (rhst);
+ if (rhs->e_flags == E_MCONST) {
+ rtype |= CF_CONST;
+ }
+ flags = g_typeadjust (ltype, rtype);
+
+ /* Set the type of the result */
+ lhs->e_tptr = promoteint (lhst, rhst);
+
+ /* Return the code generator flags */
+ return flags;
+}
+
+
+
+unsigned assignadjust (type* lhst, struct expent* rhs)
+/* Adjust the type of the right hand expression so that it can be assigned to
+ * the type on the left hand side. This function is used for assignment and
+ * for converting parameters in a function call. It returns the code generator
+ * flags for the operation. The type string of the right hand side will be
+ * set to the type of the left hand side.
+ */
+{
+ /* Get the type of the right hand side */
+ type* rhst = rhs->e_tptr;
+
+ /* After calling this function, rhs will have the type of the lhs */
+ rhs->e_tptr = lhst;
+
+ /* First, do some type checking */
+ if (IsVoid (lhst) || IsVoid (rhst)) {
+ /* If one of the sides are of type void, output a more apropriate
+ * error message.
+ */
+ Error (ERR_ILLEGAL_TYPE);
+ } else if (IsInt (lhst)) {
+ if (IsPtr (rhst)) {
+ /* Pointer -> int conversion */
+ Warning (WARN_PTR_TO_INT_CONV);
+ } else if (!IsInt (rhst)) {
+ Error (ERR_INCOMPATIBLE_TYPES);
+ } else {
+ /* Adjust the int types. To avoid manipulation of TOS mark lhs
+ * as const.
+ */
+ unsigned flags = TypeOf (rhst);
+ if (rhs->e_flags & E_MCONST) {
+ flags |= CF_CONST;
+ }
+ return g_typeadjust (TypeOf (lhst) | CF_CONST, flags);
+ }
+ } else if (IsPtr (lhst)) {
+ if (IsPtr (rhst)) {
+ /* Pointer to pointer assignment is valid, if:
+ * - both point to the same types, or
+ * - the rhs pointer is a void pointer, or
+ * - the lhs pointer is a void pointer.
+ */
+ type* left = Indirect (lhst);
+ type* right = Indirect (rhst);
+ if (!EqualTypes (left, right) && *left != T_VOID && *right != T_VOID) {
+ Error (ERR_INCOMPATIBLE_POINTERS);
+ }
+ } else if (IsInt (rhst)) {
+ /* Int to pointer assignment is valid only for constant zero */
+ if ((rhs->e_flags & E_MCONST) == 0 || rhs->e_const != 0) {
+ Warning (WARN_INT_TO_PTR_CONV);
+ }
+ } else if (IsFuncPtr (lhst) && IsFunc(rhst)) {
+ /* Assignment of function to function pointer is allowed, provided
+ * that both functions have the same parameter list.
+ */
+ if (!EqualTypes(Indirect (lhst), rhst)) {
+ Error (ERR_INCOMPATIBLE_TYPES);
+ }
+ } else {
+ Error (ERR_INCOMPATIBLE_TYPES);
+ }
+ } else {
+ Error (ERR_INCOMPATIBLE_TYPES);
+ }
+
+ /* Return an int value in all cases where the operands are not both ints */
+ return CF_INT;
+}
+
+
+
+void DefineData (struct expent* lval)
+/* Output a data definition for the given expression */
+{
+ unsigned flags = lval->e_flags;
+
+ switch (flags & E_MCTYPE) {
+
+ case E_TCONST:
+ /* Number */
+ g_defdata (TypeOf (lval->e_tptr) | CF_CONST, lval->e_const, 0);
+ break;
+
+ case E_TREGISTER:
+ /* Register variable. Taking the address is usually not
+ * allowed.
+ */
+ if (!AllowRegVarAddr) {
+ Error (ERR_CANNOT_TAKE_ADDR_OF_REG);
+ }
+ /* FALLTHROUGH */
+
+ case E_TGLAB:
+ case E_TLLAB:
+ /* Local or global symbol */
+ g_defdata (GlobalModeFlags (flags), lval->e_name, lval->e_const);
+ break;
+
+ case E_TLIT:
+ /* a literal of some kind */
+ g_defdata (CF_STATIC, LiteralLabel, lval->e_const);
+ break;
+
+ default:
+ Internal ("Unknown constant type: %04X", flags);
+ }
+}
+
+
+
+static void lconst (unsigned flags, struct expent* lval)
+/* Load primary reg with some constant value. */
+{
+ switch (lval->e_flags & E_MCTYPE) {
+
+ case E_TLOFFS:
+ g_leasp (lval->e_const);
+ break;
+
+ case E_TCONST:
+ /* Number constant */
+ g_getimmed (flags | TypeOf (lval->e_tptr) | CF_CONST, lval->e_const, 0);
+ break;
+
+ case E_TREGISTER:
+ /* Register variable. Taking the address is usually not
+ * allowed.
+ */
+ if (!AllowRegVarAddr) {
+ Error (ERR_CANNOT_TAKE_ADDR_OF_REG);
+ }
+ /* FALLTHROUGH */
+
+ case E_TGLAB:
+ case E_TLLAB:
+ /* Local or global symbol, load address */
+ flags |= GlobalModeFlags (lval->e_flags);
+ flags &= ~CF_CONST;
+ g_getimmed (flags, lval->e_name, lval->e_const);
+ break;
+
+ case E_TLIT:
+ /* Literal string */
+ g_getimmed (CF_STATIC, LiteralLabel, lval->e_const);
+ break;
+
+ default:
+ Internal ("Unknown constant type: %04X", lval->e_flags);
+ }
+}
+
+
+
+static int kcalc (int tok, long val1, long val2)
+/* Calculate an operation with left and right operand constant. */
+{
+ switch (tok) {
+ case EQ:
+ return (val1 == val2);
+ case NE:
+ return (val1 != val2);
+ case LT:
+ return (val1 < val2);
+ case LE:
+ return (val1 <= val2);
+ case GE:
+ return (val1 >= val2);
+ case GT:
+ return (val1 > val2);
+ case BAR:
+ return (val1 | val2);
+ case XOR:
+ return (val1 ^ val2);
+ case AMP:
+ return (val1 & val2);
+ case ASR:
+ return (val1 >> val2);
+ case ASL:
+ return (val1 << val2);
+ case STAR:
+ return (val1 * val2);
+ case DIV:
+ if (val2 == 0) {
+ Error (ERR_DIV_BY_ZERO);
+ return 0x7FFFFFFF;
+ }
+ return (val1 / val2);
+ case MOD:
+ if (val2 == 0) {
+ Error (ERR_MOD_BY_ZERO);
+ return 0;
+ }
+ return (val1 % val2);
+ default:
+ Internal ("kcalc: got token 0x%X\n", tok);
+ return 0;
+ }
+}
+
+
+
+static GenDesc* FindGen (int Tok, GenDesc** Table)
+{
+ GenDesc* G;
+ while ((G = *Table) != 0) {
+ if (G->Tok == Tok) {
+ return G;
+ }
+ ++Table;
+ }
+ return 0;
+}
+
+
+
+static int istypeexpr (void)
+/* Return true if some sort of variable or type is waiting (helper for cast
+ * and sizeof() in hie10).
+ */
+{
+ SymEntry* Entry;
+
+ return curtok == LPAREN && (
+ (nxttok >= FIRSTTYPE && nxttok <= LASTTYPE) ||
+ (nxttok == CONST) ||
+ (nxttok == IDENT &&
+ (Entry = FindSym (NextTok.Ident)) != 0 &&
+ IsTypeDef (Entry))
+ );
+}
+
+
+
+static void PushAddr (struct expent* lval)
+/* If the expression contains an address that was somehow evaluated,
+ * push this address on the stack. This is a helper function for all
+ * sorts of implicit or explicit assignment functions where the lvalue
+ * must be saved if it's not constant, before evaluating the rhs.
+ */
+{
+ /* Get the address on stack if needed */
+ if (lval->e_flags != E_MREG && (lval->e_flags & E_MEXPR)) {
+ /* Push the address (always a pointer) */
+ g_push (CF_PTR, 0);
+ }
+}
+
+
+
+/*****************************************************************************/
+/* code */
+/*****************************************************************************/
+
+
+
+void exprhs (unsigned flags, int k, struct expent *lval)
+/* Put the result of an expression into the primary register */
+{
+ int f;
+
+ f = lval->e_flags;
+ if (k) {
+ /* Dereferenced lvalue */
+ flags |= TypeOf (lval->e_tptr);
+ if (lval->e_test & E_FORCETEST) {
+ flags |= CF_TEST;
+ lval->e_test &= ~E_FORCETEST;
+ }
+ if (f & E_MGLOBAL) { /* ref to globalvar */
+ /* Generate code */
+ flags |= GlobalModeFlags (f);
+ g_getstatic (flags, lval->e_name, lval->e_const);
+ } else if (f & E_MLOCAL) {
+ /* ref to localvar */
+ g_getlocal (flags, lval->e_const);
+ } else if (f & E_MCONST) {
+ /* ref to absolute address */
+ g_getstatic (flags | CF_ABSOLUTE, lval->e_const, 0);
+ } else if (f == E_MEOFFS) {
+ g_getind (flags, lval->e_const);
+ } else if (f != E_MREG) {
+ g_getind (flags, 0);
+ }
+ } else if (f == E_MEOFFS) {
+ /* reference not storable */
+ flags |= TypeOf (lval->e_tptr);
+ g_inc (flags | CF_CONST, lval->e_const);
+ } else if ((f & E_MEXPR) == 0) {
+ /* Constant of some sort, load it into the primary */
+ lconst (flags, lval);
+ }
+ if (lval->e_test & E_FORCETEST) { /* we testing this value? */
+ /* debug... */
+ AddCodeHint ("forcetest");
+ flags |= TypeOf (lval->e_tptr);
+ g_test (flags); /* yes, force a test */
+ lval->e_test &= ~E_FORCETEST;
+ }
+}
+
+
+static void callfunction (struct expent* lval)
+/* Perform a function call. Called from hie11, this routine will
+ * either call the named function, or if the supplied ptr is zero,
+ * will call the contents of P.
+ */
+{
+ struct expent lval2;
+ FuncDesc* Func; /* Function descriptor */
+ int Ellipsis; /* True if we have an open param list */
+ SymEntry* Param; /* Current formal parameter */
+ unsigned ParamCount; /* Actual parameter count */
+ unsigned ParamSize; /* Number of parameter bytes */
+ unsigned Flags;
+ unsigned CFlags;
+ CodeMark Mark;
+
+
+ /* Get a pointer to the function descriptor from the type string */
+ Func = GetFuncDesc (lval->e_tptr);
+
+ /* Initialize vars to keep gcc silent */
+ Param = 0;
+ Mark = 0;
+
+ /* Check if this is a function pointer. If so, save it. If not, check for
+ * special known library functions that may be inlined.
+ */
+ if (lval->e_flags & E_MEXPR) {
+ /* Function pointer is in primary register, save it */
+ Mark = GetCodePos ();
+ g_save (CF_PTR);
+ } else if (InlineStdFuncs && IsStdFunc ((const char*) lval->e_name)) {
+ /* Inline this function */
+ HandleStdFunc (lval);
+ return;
+ }
+
+ /* Parse the actual parameter list */
+ ParamSize = 0;
+ ParamCount = 0;
+ Ellipsis = 0;
+ while (curtok != RPAREN) {
+
+ /* Add a hint for the optimizer */
+ AddCodeHint ("param:start");
+
+ /* Count arguments */
+ ++ParamCount;
+
+ /* Fetch the pointer to the next argument, check for too many args */
+ if (ParamCount <= Func->ParamCount) {
+ if (ParamCount == 1) {
+ /* First argument */
+ Param = Func->SymTab->SymHead;
+ } else {
+ /* Next argument */
+ Param = Param->NextSym;
+ CHECK ((Param->Flags & SC_PARAM) != 0);
+ }
+ } else if (!Ellipsis) {
+ /* Too many arguments. Do we have an open param list? */
+ if ((Func->Flags & FD_ELLIPSIS) == 0) {
+ /* End of param list reached, no ellipsis */
+ Error (ERR_TOO_MANY_FUNC_ARGS);
+ }
+ /* Assume an ellipsis even in case of errors to avoid an error
+ * message for each other argument.
+ */
+ Ellipsis = 1;
+ }
+
+ /* Do some optimization: If we have a constant value to push,
+ * use a special function that may optimize.
+ */
+ CFlags = CF_NONE;
+ if (!Ellipsis && SizeOf (Param->Type) == 1) {
+ CFlags = CF_FORCECHAR;
+ }
+ Flags = 0;
+ if (evalexpr (CFlags, hie1, &lval2) == 0) {
+ /* A constant value */
+ Flags |= CF_CONST;
+ }
+
+ /* If we don't have an argument spec, accept anything, otherwise
+ * convert the actual argument to the type needed.
+ */
+ if (!Ellipsis) {
+ /* Promote the argument if needed */
+ assignadjust (Param->Type, &lval2);
+ /* If we have a prototype, chars may be pushed as chars */
+ Flags |= CF_FORCECHAR;
+ }
+
+ /* Use the type of the argument for the push */
+ Flags |= TypeOf (lval2.e_tptr);
+
+ /* If this is a fastcall function, don't push the last argument */
+ if (ParamCount == Func->ParamCount && (Func->Flags & FD_FASTCALL) != 0) {
+ /* Just load the argument into the primary. This is only needed if
+ * we have a constant argument, otherwise the value is already in
+ * the primary.
+ */
+ if (Flags & CF_CONST) {
+ exprhs (CF_FORCECHAR, 0, &lval2);
+ }
+ } else {
+ /* Push the argument, count the argument size */
+ g_push (Flags, lval2.e_const);
+ ParamSize += sizeofarg (Flags);
+ }
+
+ /* Add an optimizer hint */
+ AddCodeHint ("param:end");
+
+ /* Check for end of argument list */
+ if (curtok != COMMA) {
+ break;
+ }
+ gettok ();
+ }
+
+ /* We need the closing bracket here */
+ ConsumeRParen ();
+
+ /* Check if we had enough parameters */
+ if (ParamCount < Func->ParamCount) {
+ Error (ERR_TOO_FEW_FUNC_ARGS);
+ }
+
+ /* */
+ if (lval->e_flags & E_MEXPR) {
+ /* Function called via pointer: Restore it and call function */
+ if (ParamSize != 0) {
+ g_restore (CF_PTR);
+ } else {
+ /* We had no parameters - remove save code */
+ RemoveCode (Mark);
+ }
+ g_callind (TypeOf (lval->e_tptr), ParamSize);
+ } else {
+ g_call (TypeOf (lval->e_tptr), (char*) lval->e_name, ParamSize);
+ }
+}
+
+
+
+void doasm (void)
+/* This function parses ASM statements. The syntax of the ASM directive
+ * looks like the one defined for C++ (C has no ASM directive), that is,
+ * a string literal in parenthesis.
+ */
+{
+ /* Skip the ASM */
+ gettok ();
+
+ /* Need left parenthesis */
+ ConsumeLParen ();
+
+ /* String literal */
+ if (curtok != SCONST) {
+ Error (ERR_STRLIT_EXPECTED);
+ } else {
+ /* Write the string directly into the output, followed by a newline */
+ AddCodeLine (GetLiteral (curval));
+
+ /* Reset the string pointer, effectivly clearing the string from the
+ * string table. Since we're working with one token lookahead, this
+ * will fail if the next token is also a string token, but that's a
+ * syntax error anyway, because we expect a right paren.
+ */
+ ResetLiteralOffs (curval);
+ }
+
+ /* Skip the string token */
+ gettok ();
+
+ /* Closing paren needed */
+ ConsumeRParen ();
+}
+
+
+
+static int primary (struct expent* lval)
+/* This is the lowest level of the expression parser. */
+{
+ int k;
+
+ /* not a test at all, yet */
+ lval->e_test = 0;
+
+ /* Character and integer constants. */
+ if (curtok == ICONST || curtok == CCONST) {
+ lval->e_flags = E_MCONST | E_TCONST;
+ lval->e_tptr = curtype;
+ lval->e_const = curval;
+ gettok ();
+ return 0;
+ }
+
+ /* Process parenthesized subexpression by calling the whole parser
+ * recursively.
+ */
+ if (curtok == LPAREN) {
+ gettok ();
+ memset (lval, 0, sizeof (*lval)); /* Remove any attributes */
+ k = hie0 (lval);
+ ConsumeRParen ();
+ return k;
+ }
+
+ /* All others may only be used if the expression evaluation is not called
+ * recursively by the preprocessor.
+ */
+ if (Preprocessing) {
+ /* Illegal expression in PP mode */
+ Error (ERR_CPP_EXPR_EXPECTED);
+ lval->e_flags = E_MCONST;
+ lval->e_tptr = type_int;
+ return 0;
+ }
+
+ /* Identifier? */
+ if (curtok == IDENT) {
+
+ SymEntry* Sym;
+ ident Ident;
+
+ /* Get a pointer to the symbol table entry */
+ Sym = FindSym (CurTok.Ident);
+
+ /* Is the symbol known? */
+ if (Sym) {
+
+ /* We found the symbol - skip the name token */
+ gettok ();
+
+ /* The expression type is the symbol type */
+ lval->e_tptr = Sym->Type;
+
+ /* Check for illegal symbol types */
+ if ((Sym->Flags & SC_LABEL) == SC_LABEL) {
+ /* Cannot use labels in expressions */
+ Error (ERR_SYMBOL_KIND);
+ return 1;
+ } else if (Sym->Flags & SC_TYPE) {
+ /* Cannot use type symbols */
+ Error (ERR_VAR_IDENT_EXPECTED);
+ /* Assume an int type to make lval valid */
+ lval->e_flags = E_MLOCAL | E_TLOFFS;
+ lval->e_tptr = type_int;
+ lval->e_const = 0;
+ return 0;
+ }
+
+ /* Check for legal symbol types */
+ if ((Sym->Flags & SC_ENUM) == SC_ENUM) {
+ lval->e_flags = E_MCONST;
+ lval->e_const = Sym->V.EnumVal;
+ return 0;
+ } else if ((Sym->Flags & SC_FUNC) == SC_FUNC) {
+ /* Function */
+ lval->e_flags = E_MGLOBAL | E_MCONST | E_TGLAB;
+ lval->e_name = (unsigned long) Sym->Name;
+ lval->e_const = 0;
+ } else if ((Sym->Flags & SC_AUTO) == SC_AUTO) {
+ /* Local variable */
+ lval->e_flags = E_MLOCAL | E_TLOFFS;
+ lval->e_const = Sym->V.Offs;
+ } else if ((Sym->Flags & SC_STATIC) == SC_STATIC) {
+ /* Static variable */
+ if (Sym->Flags & (SC_EXTERN | SC_STORAGE)) {
+ lval->e_flags = E_MGLOBAL | E_MCONST | E_TGLAB;
+ lval->e_name = (unsigned long) Sym->Name;
+ } else {
+ lval->e_flags = E_MGLOBAL | E_MCONST | E_TLLAB;
+ lval->e_name = Sym->V.Label;
+ }
+ lval->e_const = 0;
+ } else if ((Sym->Flags & SC_REGISTER) == SC_REGISTER) {
+ /* Register variable, zero page based */
+ lval->e_flags = E_MGLOBAL | E_MCONST | E_TREGISTER;
+ lval->e_name = Sym->V.Offs;
+ lval->e_const = 0;
+ } else {
+ /* Local static variable */
+ lval->e_flags = E_MGLOBAL | E_MCONST | E_TLLAB;
+ lval->e_name = Sym->V.Offs;
+ lval->e_const = 0;
+ }
+
+ /* The symbol is referenced now */
+ Sym->Flags |= SC_REF;
+ if (IsFunc (lval->e_tptr) || IsArray (lval->e_tptr)) {
+ return 0;
+ }
+ return 1;
+ }
+
+ /* We did not find the symbol. Remember the name, then skip it */
+ strcpy (Ident, CurTok.Ident);
+ gettok ();
+
+ /* IDENT is either an auto-declared function or an undefined variable. */
+ if (curtok == LPAREN) {
+ /* Declare a function returning int. For that purpose, prepare a
+ * function signature for a function having an empty param list
+ * and returning int.
+ */
+ Warning (WARN_FUNC_WITHOUT_PROTO);
+ Sym = AddGlobalSym (Ident, GetImplicitFuncType(), SC_EXTERN | SC_REF);
+ lval->e_tptr = Sym->Type;
+ lval->e_flags = E_MGLOBAL | E_MCONST | E_TGLAB;
+ lval->e_name = (unsigned long) Sym->Name;
+ lval->e_const = 0;
+ return 0;
+
+ } else {
+
+ /* Undeclared Variable */
+ Sym = AddLocalSym (Ident, type_int, SC_AUTO | SC_REF, 0);
+ lval->e_flags = E_MLOCAL | E_TLOFFS;
+ lval->e_tptr = type_int;
+ lval->e_const = 0;
+ Error (ERR_UNDEFINED_SYMBOL, Ident);
+ return 1;
+
+ }
+ }
+
+ /* String literal? */
+ if (curtok == SCONST) {
+ lval->e_flags = E_MCONST | E_TLIT;
+ lval->e_const = curval;
+ lval->e_tptr = GetCharArrayType (strlen (GetLiteral (curval)));
+ gettok ();
+ return 0;
+ }
+
+ /* ASM statement? */
+ if (curtok == ASM) {
+ doasm ();
+ lval->e_tptr = type_void;
+ lval->e_flags = E_MEXPR;
+ lval->e_const = 0;
+ return 0;
+ }
+
+ /* __AX__ and __EAX__ pseudo values? */
+ if (curtok == AX || curtok == EAX) {
+ lval->e_tptr = (curtok == AX)? type_uint : type_ulong;
+ lval->e_flags = E_MREG;
+ lval->e_test &= ~E_CC;
+ lval->e_const = 0;
+ gettok ();
+ return 1; /* May be used as lvalue */
+ }
+
+ /* Illegal primary. */
+ Error (ERR_EXPR_EXPECTED);
+ lval->e_flags = E_MCONST;
+ lval->e_tptr = type_int;
+ return 0;
+}
+
+
+
+static int arrayref (int k, struct expent* lval)
+/* Handle an array reference */
+{
+ unsigned lflags;
+ unsigned rflags;
+ int ConstBaseAddr;
+ int ConstSubAddr;
+ int l;
+ struct expent lval2;
+ CodeMark Mark1;
+ CodeMark Mark2;
+ type* tptr1;
+ type* tptr2;
+
+
+ /* Skip the bracket */
+ gettok ();
+
+ /* Get the type of left side */
+ tptr1 = lval->e_tptr;
+
+ /* We can apply a special treatment for arrays that have a const base
+ * address. This is true for most arrays and will produce a lot better
+ * code. Check if this is a const base address.
+ */
+ lflags = lval->e_flags & ~E_MCTYPE;
+ ConstBaseAddr = (lflags == E_MCONST) || /* Constant numeric address */
+ (lflags & E_MGLOBAL) != 0 || /* Static array, or ... */
+ lflags == E_MLOCAL; /* Local array */
+
+ /* If we have a constant base, we delay the address fetch */
+ Mark1 = GetCodePos ();
+ Mark2 = 0; /* Silence gcc */
+ if (!ConstBaseAddr) {
+ /* Get a pointer to the array into the primary */
+ exprhs (CF_NONE, k, lval);
+
+ /* Get the array pointer on stack. Do not push more than 16
+ * bit, even if this value is greater, since we cannot handle
+ * other than 16bit stuff when doing indexing.
+ */
+ Mark2 = GetCodePos ();
+ g_push (CF_PTR, 0);
+ }
+
+ /* TOS now contains ptr to array elements. Get the subscript. */
+ l = hie0 (&lval2);
+ if (l == 0 && lval2.e_flags == E_MCONST) {
+
+ /* The array subscript is a constant - remove value from stack */
+ if (!ConstBaseAddr) {
+ RemoveCode (Mark2);
+ pop (CF_PTR);
+ } else {
+ /* Get an array pointer into the primary */
+ exprhs (CF_NONE, k, lval);
+ }
+
+ if (IsPtr (tptr1)) {
+
+ /* Scale the subscript value according to element size */
+ lval2.e_const *= PSizeOf (tptr1);
+
+ /* Remove code for lhs load */
+ RemoveCode (Mark1);
+
+ /* Handle constant base array on stack. Be sure NOT to
+ * handle pointers the same way, this won't work.
+ */
+ if (IsArray (tptr1) &&
+ ((lval->e_flags & ~E_MCTYPE) == E_MCONST ||
+ (lval->e_flags & ~E_MCTYPE) == E_MLOCAL ||
+ (lval->e_flags & E_MGLOBAL) != 0 ||
+ (lval->e_flags == E_MEOFFS))) {
+ lval->e_const += lval2.e_const;
+
+ } else {
+ /* Pointer - load into primary and remember offset */
+ if ((lval->e_flags & E_MEXPR) == 0 || k != 0) {
+ exprhs (CF_NONE, k, lval);
+ }
+ lval->e_const = lval2.e_const;
+ lval->e_flags = E_MEOFFS;
+ }
+
+ /* Result is of element type */
+ lval->e_tptr = Indirect (tptr1);
+
+ /* Done */
+ goto end_array;
+
+ } else if ((tptr2 = lval2.e_tptr) [0] & T_POINTER) {
+ /* Subscript is pointer, get element type */
+ lval2.e_tptr = Indirect (tptr2);
+
+ /* Scale the rhs value in the primary register */
+ g_scale (TypeOf (tptr1), SizeOf (lval2.e_tptr));
+ /* */
+ lval->e_tptr = lval2.e_tptr;
+ } else {
+ Error (ERR_CANNOT_SUBSCRIPT);
+ }
+
+ /* Add the subscript. Since arrays are indexed by integers,
+ * we will ignore the true type of the subscript here and
+ * use always an int.
+ */
+ g_inc (CF_INT | CF_CONST, lval2.e_const);
+
+ } else {
+
+ /* Array subscript is not constant. Load it into the primary */
+ Mark2 = GetCodePos ();
+ exprhs (CF_NONE, l, &lval2);
+
+ tptr2 = lval2.e_tptr;
+ if (IsPtr (tptr1)) {
+
+ /* Get the element type */
+ lval->e_tptr = Indirect (tptr1);
+
+ /* Indexing is based on int's, so we will just use the integer
+ * portion of the index (which is in (e)ax, so there's no further
+ * action required).
+ */
+ g_scale (CF_INT, SizeOf (lval->e_tptr));
+
+ } else if (IsPtr (tptr2)) {
+
+ /* Get the element type */
+ lval2.e_tptr = Indirect (tptr2);
+
+ /* Get the int value on top. If we go here, we're sure,
+ * both values are 16 bit (the first one was truncated
+ * if necessary and the second one is a pointer).
+ * Note: If ConstBaseAddr is true, we don't have a value on
+ * stack, so to "swap" both, just push the subscript.
+ */
+ if (ConstBaseAddr) {
+ g_push (CF_INT, 0);
+ exprhs (CF_NONE, k, lval);
+ ConstBaseAddr = 0;
+ } else {
+ g_swap (CF_INT);
+ }
+
+ /* Scale it */
+ g_scale (TypeOf (tptr1), SizeOf (lval2.e_tptr));
+ lval->e_tptr = lval2.e_tptr;
+ } else {
+ Error (ERR_CANNOT_SUBSCRIPT);
+ }
+
+ /* The offset is now in the primary register. It didn't have a
+ * constant base address for the lhs, the lhs address is already
+ * on stack, and we must add the offset. If the base address was
+ * constant, we call special functions to add the address to the
+ * offset value.
+ */
+ if (!ConstBaseAddr) {
+ /* Add the subscript. Both values are int sized. */
+ g_add (CF_INT, 0);
+ } else {
+
+ /* If the subscript has itself a constant address, it is often
+ * a better idea to reverse again the order of the evaluation.
+ * This will generate better code if the subscript is a byte
+ * sized variable. But beware: This is only possible if the
+ * subscript was not scaled, that is, if this was a byte array
+ * or pointer.
+ */
+ rflags = lval2.e_flags & ~E_MCTYPE;
+ ConstSubAddr = (rflags == E_MCONST) || /* Constant numeric address */
+ (rflags & E_MGLOBAL) != 0 || /* Static array, or ... */
+ rflags == E_MLOCAL; /* Local array */
+
+ if (ConstSubAddr && SizeOf (lval->e_tptr) == 1) {
+
+ type* SavedType;
+
+ /* Reverse the order of evaluation */
+ unsigned flags = (SizeOf (lval2.e_tptr) == 1)? CF_CHAR : CF_INT;
+ RemoveCode (Mark2);
+
+ /* Get a pointer to the array into the primary. We have changed
+ * e_tptr above but we need the original type to load the
+ * address, so restore it temporarily.
+ */
+ SavedType = lval->e_tptr;
+ lval->e_tptr = tptr1;
+ exprhs (CF_NONE, k, lval);
+ lval->e_tptr = SavedType;
+
+ /* Add the variable */
+ if (rflags == E_MLOCAL) {
+ g_addlocal (flags, lval2.e_const);
+ } else {
+ flags |= GlobalModeFlags (lval2.e_flags);
+ g_addstatic (flags, lval2.e_name, lval2.e_const);
+ }
+ } else {
+ if (lflags == E_MCONST) {
+ /* Constant numeric address. Just add it */
+ g_inc (CF_INT | CF_UNSIGNED, lval->e_const);
+ } else if (lflags == E_MLOCAL) {
+ /* Base address is a local variable address */
+ if (IsArray (tptr1)) {
+ g_addaddr_local (CF_INT, lval->e_const);
+ } else {
+ g_addlocal (CF_PTR, lval->e_const);
+ }
+ } else {
+ /* Base address is a static variable address */
+ unsigned flags = CF_INT;
+ flags |= GlobalModeFlags (lval->e_flags);
+ if (IsArray (tptr1)) {
+ g_addaddr_static (flags, lval->e_name, lval->e_const);
+ } else {
+ g_addstatic (flags, lval->e_name, lval->e_const);
+ }
+ }
+ }
+ }
+ }
+ lval->e_flags = E_MEXPR;
+end_array:
+ ConsumeRBrack ();
+ return !IsArray (lval->e_tptr);
+
+}
+
+
+
+static int structref (int k, struct expent* lval)
+/* Process struct field after . or ->. */
+{
+ ident Ident;
+ SymEntry* Field;
+ int flags;
+
+ /* Skip the token and check for an identifier */
+ gettok ();
+ if (curtok != IDENT) {
+ Error (ERR_IDENT_EXPECTED);
+ lval->e_tptr = type_int;
+ return 0;
+ }
+
+ /* Get the symbol table entry and check for a struct field */
+ strcpy (Ident, CurTok.Ident);
+ gettok ();
+ Field = FindStructField (lval->e_tptr, Ident);
+ if (Field == 0) {
+ Error (ERR_STRUCT_FIELD_MISMATCH, Ident);
+ lval->e_tptr = type_int;
+ return 0;
+ }
+
+ /* If we have constant input data, the result is also constant */
+ flags = lval->e_flags & ~E_MCTYPE;
+ if (flags == E_MCONST ||
+ (k == 0 && (flags == E_MLOCAL ||
+ (flags & E_MGLOBAL) != 0 ||
+ lval->e_flags == E_MEOFFS))) {
+ lval->e_const += Field->V.Offs;
+ } else {
+ if ((flags & E_MEXPR) == 0 || k != 0) {
+ exprhs (CF_NONE, k, lval);
+ }
+ lval->e_const = Field->V.Offs;
+ lval->e_flags = E_MEOFFS;
+ }
+ lval->e_tptr = Field->Type;
+ return !IsArray (Field->Type);
+}
+
+
+
+static int hie11 (struct expent *lval)
+/* Handle compound types (structs and arrays) */
+{
+ int k;
+ type* tptr;
+
+
+ k = primary (lval);
+ if (curtok < LBRACK || curtok > PREF) {
+ /* Not for us */
+ return k;
+ }
+
+ while (1) {
+
+ if (curtok == LBRACK) {
+
+ /* Array reference */
+ k = arrayref (k, lval);
+
+ } else if (curtok == LPAREN) {
+
+ /* Function call. Skip the opening parenthesis */
+ gettok ();
+ tptr = lval->e_tptr;
+ if (IsFunc (tptr) || IsFuncPtr (tptr)) {
+ if (IsFuncPtr (tptr)) {
+ /* Pointer to function. Handle transparently */
+ exprhs (CF_NONE, k, lval); /* Function pointer to A/X */
+ ++lval->e_tptr; /* Skip T_PTR */
+ lval->e_flags |= E_MEXPR;
+ }
+ callfunction (lval);
+ lval->e_flags = E_MEXPR;
+ lval->e_tptr += DECODE_SIZE + 1; /* Set to result */
+ } else {
+ Error (ERR_ILLEGAL_FUNC_CALL);
+ }
+ k = 0;
+
+ } else if (curtok == DOT) {
+
+ if (!IsStruct (lval->e_tptr)) {
+ Error (ERR_STRUCT_EXPECTED);
+ }
+ k = structref (0, lval);
+
+ } else if (curtok == PREF) {
+
+ tptr = lval->e_tptr;
+ if (tptr[0] != T_PTR || (tptr[1] & T_STRUCT) == 0) {
+ Error (ERR_STRUCT_PTR_EXPECTED);
+ }
+ k = structref (k, lval);
+
+ } else {
+ return k;
+ }
+ }
+}
+
+
+
+static void store (struct expent* lval)
+/* Store primary reg into this reference */
+{
+ int f;
+ unsigned flags;
+
+ f = lval->e_flags;
+ flags = TypeOf (lval->e_tptr);
+ if (f & E_MGLOBAL) {
+ flags |= GlobalModeFlags (f);
+ if (lval->e_test) {
+ /* Just testing */
+ flags |= CF_TEST;
+ }
+
+ /* Generate code */
+ g_putstatic (flags, lval->e_name, lval->e_const);
+
+ } else if (f & E_MLOCAL) {
+ g_putlocal (flags, lval->e_const);
+ } else if (f == E_MEOFFS) {
+ g_putind (flags, lval->e_const);
+ } else if (f != E_MREG) {
+ if (f & E_MEXPR) {
+ g_putind (flags, 0);
+ } else {
+ /* Store into absolute address */
+ g_putstatic (flags | CF_ABSOLUTE, lval->e_const, 0);
+ }
+ }
+
+ /* Assume that each one of the stores will invalidate CC */
+ lval->e_test &= ~E_CC;
+}
+
+
+
+static void pre_incdec (struct expent* lval, void (*inc) (unsigned, unsigned long))
+/* Handle --i and ++i */
+{
+ int k;
+ unsigned flags;
+ unsigned long val;
+
+ gettok ();
+ if ((k = hie10 (lval)) == 0) {
+ Error (ERR_LVALUE_EXPECTED);
+ return;
+ }
+
+ /* Get the data type */
+ flags = TypeOf (lval->e_tptr) | CF_FORCECHAR | CF_CONST;
+
+ /* Get the increment value in bytes */
+ val = (lval->e_tptr [0] == T_PTR)? PSizeOf (lval->e_tptr) : 1;
+
+ /* We're currently only able to handle some adressing modes */
+ if ((lval->e_flags & E_MGLOBAL) == 0 && /* Global address? */
+ (lval->e_flags & E_MLOCAL) == 0 && /* Local address? */
+ (lval->e_flags & E_MCONST) == 0 && /* Constant address? */
+ (lval->e_flags & E_MEXPR) == 0) { /* Address in a/x? */
+
+ /* Use generic code. Push the address if needed */
+ PushAddr (lval);
+
+ /* Fetch the value */
+ exprhs (CF_NONE, k, lval);
+
+ /* Increment value in primary */
+ inc (flags, val);
+
+ /* Store the result back */
+ store (lval);
+
+ } else {
+
+ /* Special code for some addressing modes - use the special += ops */
+ if (lval->e_flags & E_MGLOBAL) {
+ flags |= GlobalModeFlags (lval->e_flags);
+ if (inc == g_inc) {
+ g_addeqstatic (flags, lval->e_name, lval->e_const, val);
+ } else {
+ g_subeqstatic (flags, lval->e_name, lval->e_const, val);
+ }
+ } else if (lval->e_flags & E_MLOCAL) {
+ /* ref to localvar */
+ if (inc == g_inc) {
+ g_addeqlocal (flags, lval->e_const, val);
+ } else {
+ g_subeqlocal (flags, lval->e_const, val);
+ }
+ } else if (lval->e_flags & E_MCONST) {
+ /* ref to absolute address */
+ flags |= CF_ABSOLUTE;
+ if (inc == g_inc) {
+ g_addeqstatic (flags, lval->e_const, 0, val);
+ } else {
+ g_subeqstatic (flags, lval->e_const, 0, val);
+ }
+ } else if (lval->e_flags & E_MEXPR) {
+ /* Address in a/x. */
+ if (inc == g_inc) {
+ g_addeqind (flags, lval->e_const, val);
+ } else {
+ g_subeqind (flags, lval->e_const, val);
+ }
+ } else {
+ Internal ("Invalid addressing mode");
+ }
+
+ }
+
+ /* Result is an expression */
+ lval->e_flags = E_MEXPR;
+}
+
+
+
+static void post_incdec (struct expent *lval, int k, void (*inc) (unsigned, unsigned long))
+/* Handle i-- and i++ */
+{
+ unsigned flags;
+
+ gettok ();
+ if (k == 0) {
+ Error (ERR_LVALUE_EXPECTED);
+ return;
+ }
+
+ /* Get the data type */
+ flags = TypeOf (lval->e_tptr);
+
+ /* Push the address if needed */
+ PushAddr (lval);
+
+ /* Fetch the value and save it (since it's the result of the expression) */
+ exprhs (CF_NONE, 1, lval);
+ g_save (flags | CF_FORCECHAR);
+
+ /* If we have a pointer expression, increment by the size of the type */
+ if (lval->e_tptr[0] == T_PTR) {
+ inc (flags | CF_CONST | CF_FORCECHAR, SizeOf (lval->e_tptr + 1));
+ } else {
+ inc (flags | CF_CONST | CF_FORCECHAR, 1);
+ }
+
+ /* Store the result back */
+ store (lval);
+
+ /* Restore the original value */
+ g_restore (flags | CF_FORCECHAR);
+ lval->e_flags = E_MEXPR;
+}
+
+
+
+static void unaryop (int tok, struct expent* lval)
+/* Handle unary -/+ and ~ */
+{
+ int k;
+ unsigned flags;
+
+ gettok ();
+ k = hie10 (lval);
+ if (k == 0 && lval->e_flags & E_MCONST) {
+ /* Value is constant */
+ switch (tok) {
+ case MINUS: lval->e_const = -lval->e_const; break;
+ case PLUS: break;
+ case COMP: lval->e_const = ~lval->e_const; break;
+ default: Internal ("Unexpected token: %d", tok);
+ }
+ } else {
+ /* Value is not constant */
+ exprhs (CF_NONE, k, lval);
+
+ /* Get the type of the expression */
+ flags = TypeOf (lval->e_tptr);
+
+ /* Handle the operation */
+ switch (tok) {
+ case MINUS: g_neg (flags); break;
+ case PLUS: break;
+ case COMP: g_com (flags); break;
+ default: Internal ("Unexpected token: %d", tok);
+ }
+ lval->e_flags = E_MEXPR;
+ }
+}
+
+
+
+static int typecast (struct expent* lval)
+/* Handle an explicit cast */
+{
+ int k;
+ type Type[MAXTYPELEN];
+ unsigned rflags;
+
+ /* Skip the left paren */
+ gettok ();
+
+ /* Read the type */
+ ParseType (Type);
+
+ /* Closing paren */
+ ConsumeRParen ();
+
+ /* Read the expression we have to cast */
+ k = hie10 (lval);
+
+ /* Get the type of the expression and honor constant values */
+ rflags = TypeOf (lval->e_tptr);
+ if (lval->e_flags & E_MCONST) {
+ rflags |= CF_CONST;
+ }
+
+ /* Do the actual cast. Special handling for void casts */
+ if (!IsVoid (Type)) {
+ /* Mark the lhs as const to avoid a manipulation of TOS */
+ g_typecast (TypeOf (Type) | CF_CONST, rflags);
+ }
+
+ /* Use the new type */
+ lval->e_tptr = TypeDup (Type);
+
+ /* Done */
+ return k;
+}
+
+
+
+static int hie10 (struct expent* lval)
+/* Handle ++, --, !, unary - etc. */
+{
+ int k;
+ type* t;
+
+ switch (curtok) {
+
+ case INC:
+ pre_incdec (lval, g_inc);
+ return 0;
+
+ case DEC:
+ pre_incdec (lval, g_dec);
+ return 0;
+
+ case PLUS:
+ case MINUS:
+ case COMP:
+ unaryop (curtok, lval);
+ return 0;
+
+ case BANG:
+ gettok ();
+ if (evalexpr (CF_NONE, hie10, lval) == 0) {
+ /* Constant expression */
+ lval->e_const = !lval->e_const;
+ } else {
+ g_bneg (TypeOf (lval->e_tptr));
+ lval->e_test |= E_CC; /* bneg will set cc */
+ lval->e_flags = E_MEXPR; /* say it's an expr */
+ }
+ return 0; /* expr not storable */
+
+ case STAR:
+ gettok ();
+ if (evalexpr (CF_NONE, hie10, lval) != 0) {
+ /* Expression is not const, indirect value loaded into primary */
+ lval->e_flags = E_MEXPR;
+ lval->e_const = 0; /* Offset is zero now */
+ }
+ t = lval->e_tptr;
+ if (IsPtr (t)) {
+ lval->e_tptr = Indirect (t);
+ } else {
+ Error (ERR_ILLEGAL_INDIRECT);
+ }
+ return 1;
+
+ case AMP:
+ gettok ();
+ k = hie10 (lval);
+ if (k == 0) {
+ /* Allow the & operator with an array */
+ if (!IsArray (lval->e_tptr)) {
+ Error (ERR_ILLEGAL_ADDRESS);
+ }
+ } else {
+ t = TypeAlloc (TypeLen (lval->e_tptr) + 2);
+ t [0] = T_PTR;
+ TypeCpy (t + 1, lval->e_tptr);
+ lval->e_tptr = t;
+ }
+ return 0;
+
+ case SIZEOF:
+ gettok ();
+ if (istypeexpr ()) {
+ type Type[MAXTYPELEN];
+ gettok ();
+ lval->e_const = SizeOf (ParseType (Type));
+ ConsumeRParen ();
+ } else {
+ /* Remember the output queue pointer */
+ CodeMark Mark = GetCodePos ();
+ hie10 (lval);
+ lval->e_const = SizeOf (lval->e_tptr);
+ /* Remove any generated code */
+ RemoveCode (Mark);
+ }
+ lval->e_flags = E_MCONST | E_TCONST;
+ lval->e_tptr = type_uint;
+ lval->e_test &= ~E_CC;
+ return 0;
+
+ default:
+ if (istypeexpr ()) {
+ /* A cast */
+ return typecast (lval);
+ }
+ }
+
+ k = hie11 (lval);
+ switch (curtok) {
+ case INC:
+ post_incdec (lval, k, g_inc);
+ return 0;
+
+ case DEC:
+ post_incdec (lval, k, g_dec);
+ return 0;
+
+ default:
+ return k;
+ }
+}
+
+
+
+static int hie_internal (GenDesc** ops, /* List of generators */
+ struct expent* lval, /* parent expr's lval */
+ int (*hienext) (struct expent*),
+ int* UsedGen) /* next higher level */
+/* Helper function */
+{
+ int k;
+ struct expent lval2;
+ CodeMark Mark1;
+ CodeMark Mark2;
+ GenDesc* Gen;
+ int tok; /* The operator token */
+ unsigned ltype, type;
+ int rconst; /* Operand is a constant */
+
+
+ k = hienext (lval);
+
+ *UsedGen = 0;
+ while ((Gen = FindGen (curtok, ops)) != 0) {
+
+ /* Tell the caller that we handled it's ops */
+ *UsedGen = 1;
+
+ /* All operators that call this function expect an int on the lhs */
+ if (!IsInt (lval->e_tptr)) {
+ Error (ERR_INT_EXPR_EXPECTED);
+ }
+
+ /* Remember the operator token, then skip it */
+ tok = curtok;
+ gettok ();
+
+ /* Get the lhs on stack */
+ Mark1 = GetCodePos ();
+ ltype = TypeOf (lval->e_tptr);
+ if (k == 0 && lval->e_flags == E_MCONST) {
+ /* Constant value */
+ Mark2 = GetCodePos ();
+ g_push (ltype | CF_CONST, lval->e_const);
+ } else {
+ /* Value not constant */
+ exprhs (CF_NONE, k, lval);
+ Mark2 = GetCodePos ();
+ g_push (ltype, 0);
+ }
+
+ /* Get the right hand side */
+ rconst = (evalexpr (CF_NONE, hienext, &lval2) == 0);
+
+ /* Check the type of the rhs */
+ if (!IsInt (lval2.e_tptr)) {
+ Error (ERR_INT_EXPR_EXPECTED);
+ }
+
+ /* Check for const operands */
+ if (k == 0 && lval->e_flags == E_MCONST && rconst) {
+
+ /* Both operands are constant, remove the generated code */
+ RemoveCode (Mark1);
+ pop (ltype);
+
+ /* Evaluate the result */
+ lval->e_const = kcalc (tok, lval->e_const, lval2.e_const);
+
+ /* Get the type of the result */
+ lval->e_tptr = promoteint (lval->e_tptr, lval2.e_tptr);
+
+ } else {
+
+ /* If the right hand side is constant, and the generator function
+ * expects the lhs in the primary, remove the push of the primary
+ * now.
+ */
+ unsigned rtype = TypeOf (lval2.e_tptr);
+ type = 0;
+ if (rconst) {
+ /* Second value is constant - check for div */
+ type |= CF_CONST;
+ rtype |= CF_CONST;
+ if (tok == DIV && lval2.e_const == 0) {
+ Error (ERR_DIV_BY_ZERO);
+ } else if (tok == MOD && lval2.e_const == 0) {
+ Error (ERR_MOD_BY_ZERO);
+ }
+ if ((Gen->Flags & GEN_NOPUSH) != 0) {
+ RemoveCode (Mark2);
+ pop (ltype);
+ ltype |= CF_REG; /* Value is in register */
+ }
+ }
+
+ /* Determine the type of the operation result. */
+ type |= g_typeadjust (ltype, rtype);
+ lval->e_tptr = promoteint (lval->e_tptr, lval2.e_tptr);
+
+ /* Generate code */
+ Gen->Func (type, lval2.e_const);
+ lval->e_flags = E_MEXPR;
+ }
+
+ /* We have a rvalue now */
+ k = 0;
+ }
+
+ return k;
+}
+
+
+
+static int hie_compare (GenDesc** ops, /* List of generators */
+ struct expent* lval, /* parent expr's lval */
+ int (*hienext) (struct expent*))
+/* Helper function for the compare operators */
+{
+ int k;
+ struct expent lval2;
+ CodeMark Mark1;
+ CodeMark Mark2;
+ GenDesc* Gen;
+ int tok; /* The operator token */
+ unsigned ltype;
+ int rconst; /* Operand is a constant */
+
+
+ k = hienext (lval);
+
+ while ((Gen = FindGen (curtok, ops)) != 0) {
+
+ /* Remember the operator token, then skip it */
+ tok = curtok;
+ gettok ();
+
+ /* Get the lhs on stack */
+ Mark1 = GetCodePos ();
+ ltype = TypeOf (lval->e_tptr);
+ if (k == 0 && lval->e_flags == E_MCONST) {
+ /* Constant value */
+ Mark2 = GetCodePos ();
+ g_push (ltype | CF_CONST, lval->e_const);
+ } else {
+ /* Value not constant */
+ exprhs (CF_NONE, k, lval);
+ Mark2 = GetCodePos ();
+ g_push (ltype, 0);
+ }
+
+ /* Get the right hand side */
+ rconst = (evalexpr (CF_NONE, hienext, &lval2) == 0);
+
+ /* Make sure, the types are compatible */
+ if (IsInt (lval->e_tptr)) {
+ if (!IsInt (lval2.e_tptr) && !(IsPtr(lval2.e_tptr) && IsNullPtr(lval))) {
+ Error (ERR_INCOMPATIBLE_TYPES);
+ }
+ } else if (IsPtr (lval->e_tptr)) {
+ if (IsPtr (lval2.e_tptr)) {
+ /* Both pointers are allowed in comparison if they point to
+ * the same type, or if one of them is a void pointer.
+ */
+ type* left = Indirect (lval->e_tptr);
+ type* right = Indirect (lval2.e_tptr);
+ if (!EqualTypes (left, right) && *left != T_VOID && *right != T_VOID) {
+ /* Incomatible pointers */
+ Error (ERR_INCOMPATIBLE_TYPES);
+ }
+ } else if (!IsNullPtr (&lval2)) {
+ Error (ERR_INCOMPATIBLE_TYPES);
+ }
+ }
+
+ /* Check for const operands */
+ if (k == 0 && lval->e_flags == E_MCONST && rconst) {
+
+ /* Both operands are constant, remove the generated code */
+ RemoveCode (Mark1);
+ pop (ltype);
+
+ /* Evaluate the result */
+ lval->e_const = kcalc (tok, lval->e_const, lval2.e_const);
+
+ } else {
+
+ /* If the right hand side is constant, and the generator function
+ * expects the lhs in the primary, remove the push of the primary
+ * now.
+ */
+ unsigned flags = 0;
+ if (rconst) {
+ flags |= CF_CONST;
+ if ((Gen->Flags & GEN_NOPUSH) != 0) {
+ RemoveCode (Mark2);
+ pop (ltype);
+ ltype |= CF_REG; /* Value is in register */
+ }
+ }
+
+ /* Determine the type of the operation result. If the left
+ * operand is of type char and the right is a constant, or
+ * if both operands are of type char, we will encode the
+ * operation as char operation. Otherwise the default
+ * promotions are used.
+ */
+ if (IsChar (lval->e_tptr) && (IsChar (lval2.e_tptr) || rconst)) {
+ flags |= CF_CHAR;
+ if (IsUnsigned (lval->e_tptr) || IsUnsigned (lval2.e_tptr)) {
+ flags |= CF_UNSIGNED;
+ }
+ if (rconst) {
+ flags |= CF_FORCECHAR;
+ }
+ } else {
+ unsigned rtype = TypeOf (lval2.e_tptr) | (flags & CF_CONST);
+ flags |= g_typeadjust (ltype, rtype);
+ }
+
+ /* Generate code */
+ Gen->Func (flags, lval2.e_const);
+ lval->e_flags = E_MEXPR;
+ }
+
+ /* Result type is always int */
+ lval->e_tptr = type_int;
+
+ /* We have a rvalue now, condition codes are set */
+ k = 0;
+ lval->e_test |= E_CC;
+ }
+
+ return k;
+}
+
+
+
+static int hie9 (struct expent *lval)
+/* Process * and / operators. */
+{
+ static GenDesc* hie9_ops [] = {
+ &GenMUL, &GenDIV, &GenMOD, 0
+ };
+ int UsedGen;
+
+ return hie_internal (hie9_ops, lval, hie10, &UsedGen);
+}
+
+
+
+static void parseadd (int k, struct expent* lval)
+/* Parse an expression with the binary plus operator. lval contains the
+ * unprocessed left hand side of the expression and will contain the
+ * result of the expression on return.
+ */
+{
+ struct expent lval2;
+ unsigned flags; /* Operation flags */
+ CodeMark Mark; /* Remember code position */
+ type* lhst; /* Type of left hand side */
+ type* rhst; /* Type of right hand side */
+
+
+ /* Skip the PLUS token */
+ gettok ();
+
+ /* Get the left hand side type, initialize operation flags */
+ lhst = lval->e_tptr;
+ flags = 0;
+
+ /* Check for constness on both sides */
+ if (k == 0 && lval->e_flags == E_MCONST) {
+
+ /* The left hand side is a constant. Good. Get rhs */
+ if (evalexpr (CF_NONE, hie9, &lval2) == 0) {
+
+ /* Right hand side is also constant. Get the rhs type */
+ rhst = lval2.e_tptr;
+
+ /* Both expressions are constants. Check for pointer arithmetic */
+ if (IsPtr (lhst) && IsInt (rhst)) {
+ /* Left is pointer, right is int, must scale rhs */
+ lval->e_const = lval->e_const + lval2.e_const * PSizeOf (lhst);
+ /* Result type is a pointer */
+ } else if (IsInt (lhst) && IsPtr (rhst)) {
+ /* Left is int, right is pointer, must scale lhs */
+ lval->e_const = lval->e_const * PSizeOf (rhst) + lval2.e_const;
+ /* Result type is a pointer */
+ lval->e_tptr = lval2.e_tptr;
+ } else if (IsInt (lhst) && IsInt (rhst)) {
+ /* Integer addition */
+ lval->e_const += lval2.e_const;
+ typeadjust (lval, &lval2, 1);
+ } else {
+ /* OOPS */
+ Error (ERR_OP_NOT_ALLOWED);
+ }
+
+ /* Result is constant, condition codes not set */
+ lval->e_test = E_MCONST;
+
+ } else {
+
+ /* lhs is constant, rhs is not. Get the rhs type. */
+ rhst = lval2.e_tptr;
+
+ /* Check for pointer arithmetic */
+ if (IsPtr (lhst) && IsInt (rhst)) {
+ /* Left is pointer, right is int, must scale rhs */
+ g_scale (CF_INT, PSizeOf (lhst));
+ /* Operate on pointers, result type is a pointer */
+ flags = CF_PTR;
+ } else if (IsInt (lhst) && IsPtr (rhst)) {
+ /* Left is int, right is pointer, must scale lhs */
+ lval->e_const *= PSizeOf (rhst);
+ /* Operate on pointers, result type is a pointer */
+ flags = CF_PTR;
+ lval->e_tptr = lval2.e_tptr;
+ } else if (IsInt (lhst) && IsInt (rhst)) {
+ /* Integer addition */
+ flags = typeadjust (lval, &lval2, 1);
+ } else {
+ /* OOPS */
+ Error (ERR_OP_NOT_ALLOWED);
+ }
+
+ /* Generate code for the add */
+ g_inc (flags | CF_CONST, lval->e_const);
+
+ /* Result is in primary register */
+ lval->e_flags = E_MEXPR;
+ lval->e_test &= ~E_CC;
+
+ }
+
+ } else {
+
+ /* Left hand side is not constant. Get the value onto the stack. */
+ exprhs (CF_NONE, k, lval); /* --> primary register */
+ Mark = GetCodePos ();
+ g_push (TypeOf (lval->e_tptr), 0); /* --> stack */
+
+ /* Evaluate the rhs */
+ if (evalexpr (CF_NONE, hie9, &lval2) == 0) {
+
+ /* Right hand side is a constant. Get the rhs type */
+ rhst = lval2.e_tptr;
+
+ /* Remove pushed value from stack */
+ RemoveCode (Mark);
+ pop (TypeOf (lval->e_tptr));
+
+ /* Check for pointer arithmetic */
+ if (IsPtr (lhst) && IsInt (rhst)) {
+ /* Left is pointer, right is int, must scale rhs */
+ lval2.e_const *= PSizeOf (lhst);
+ /* Operate on pointers, result type is a pointer */
+ flags = CF_PTR;
+ } else if (IsInt (lhst) && IsPtr (rhst)) {
+ /* Left is int, right is pointer, must scale lhs (ptr only) */
+ g_scale (CF_INT | CF_CONST, PSizeOf (rhst));
+ /* Operate on pointers, result type is a pointer */
+ flags = CF_PTR;
+ lval->e_tptr = lval2.e_tptr;
+ } else if (IsInt (lhst) && IsInt (rhst)) {
+ /* Integer addition */
+ flags = typeadjust (lval, &lval2, 1);
+ } else {
+ /* OOPS */
+ Error (ERR_OP_NOT_ALLOWED);
+ }
+
+ /* Generate code for the add */
+ g_inc (flags | CF_CONST, lval2.e_const);
+
+ /* Result is in primary register */
+ lval->e_flags = E_MEXPR;
+ lval->e_test &= ~E_CC;
+
+ } else {
+
+ /* lhs and rhs are not constant. Get the rhs type. */
+ rhst = lval2.e_tptr;
+
+ /* Check for pointer arithmetic */
+ if (IsPtr (lhst) && IsInt (rhst)) {
+ /* Left is pointer, right is int, must scale rhs */
+ g_scale (CF_INT, PSizeOf (lhst));
+ /* Operate on pointers, result type is a pointer */
+ flags = CF_PTR;
+ } else if (IsInt (lhst) && IsPtr (rhst)) {
+ /* Left is int, right is pointer, must scale lhs */
+ g_tosint (TypeOf (rhst)); /* Make sure, TOS is int */
+ g_swap (CF_INT); /* Swap TOS and primary */
+ g_scale (CF_INT, PSizeOf (rhst));
+ /* Operate on pointers, result type is a pointer */
+ flags = CF_PTR;
+ lval->e_tptr = lval2.e_tptr;
+ } else if (IsInt (lhst) && IsInt (rhst)) {
+ /* Integer addition */
+ flags = typeadjust (lval, &lval2, 0);
+ } else {
+ /* OOPS */
+ Error (ERR_OP_NOT_ALLOWED);
+ }
+
+ /* Generate code for the add */
+ g_add (flags, 0);
+
+ /* Result is in primary register */
+ lval->e_flags = E_MEXPR;
+ lval->e_test &= ~E_CC;
+
+ }
+
+ }
+}
+
+
+
+static void parsesub (int k, struct expent* lval)
+/* Parse an expression with the binary minus operator. lval contains the
+ * unprocessed left hand side of the expression and will contain the
+ * result of the expression on return.
+ */
+{
+ struct expent lval2;
+ unsigned flags; /* Operation flags */
+ type* lhst; /* Type of left hand side */
+ type* rhst; /* Type of right hand side */
+ CodeMark Mark1; /* Save position of output queue */
+ CodeMark Mark2; /* Another position in the queue */
+ int rscale; /* Scale factor for the result */
+
+
+ /* Skip the MINUS token */
+ gettok ();
+
+ /* Get the left hand side type, initialize operation flags */
+ lhst = lval->e_tptr;
+ flags = 0;
+ rscale = 1; /* Scale by 1, that is, don't scale */
+
+ /* Remember the output queue position, then bring the value onto the stack */
+ Mark1 = GetCodePos ();
+ exprhs (CF_NONE, k, lval); /* --> primary register */
+ Mark2 = GetCodePos ();
+ g_push (TypeOf (lhst), 0); /* --> stack */
+
+ /* Parse the right hand side */
+ if (evalexpr (CF_NONE, hie9, &lval2) == 0) {
+
+ /* The right hand side is constant. Get the rhs type. */
+ rhst = lval2.e_tptr;
+
+ /* Check left hand side */
+ if (k == 0 && lval->e_flags & E_MCONST) {
+
+ /* Both sides are constant, remove generated code */
+ RemoveCode (Mark1);
+ pop (TypeOf (lhst)); /* Clean up the stack */
+
+ /* Check for pointer arithmetic */
+ if (IsPtr (lhst) && IsInt (rhst)) {
+ /* Left is pointer, right is int, must scale rhs */
+ lval->e_const -= lval2.e_const * PSizeOf (lhst);
+ /* Operate on pointers, result type is a pointer */
+ } else if (IsPtr (lhst) && IsPtr (rhst)) {
+ /* Left is pointer, right is pointer, must scale result */
+ if (TypeCmp (Indirect (lhst), Indirect (rhst)) != 0) {
+ Error (ERR_INCOMPATIBLE_POINTERS);
+ } else {
+ lval->e_const = (lval->e_const - lval2.e_const) / PSizeOf (lhst);
+ }
+ /* Operate on pointers, result type is an integer */
+ lval->e_tptr = type_int;
+ } else if (IsInt (lhst) && IsInt (rhst)) {
+ /* Integer subtraction */
+ typeadjust (lval, &lval2, 1);
+ lval->e_const -= lval2.e_const;
+ } else {
+ /* OOPS */
+ Error (ERR_OP_NOT_ALLOWED);
+ }
+
+ /* Result is constant, condition codes not set */
+ lval->e_flags = E_MCONST;
+ lval->e_test &= ~E_CC;
+
+ } else {
+
+ /* Left hand side is not constant, right hand side is.
+ * Remove pushed value from stack.
+ */
+ RemoveCode (Mark2);
+ pop (TypeOf (lhst));
+
+ if (IsPtr (lhst) && IsInt (rhst)) {
+ /* Left is pointer, right is int, must scale rhs */
+ lval2.e_const *= PSizeOf (lhst);
+ /* Operate on pointers, result type is a pointer */
+ flags = CF_PTR;
+ } else if (IsPtr (lhst) && IsPtr (rhst)) {
+ /* Left is pointer, right is pointer, must scale result */
+ if (TypeCmp (Indirect (lhst), Indirect (rhst)) != 0) {
+ Error (ERR_INCOMPATIBLE_POINTERS);
+ } else {
+ rscale = PSizeOf (lhst);
+ }
+ /* Operate on pointers, result type is an integer */
+ flags = CF_PTR;
+ lval->e_tptr = type_int;
+ } else if (IsInt (lhst) && IsInt (rhst)) {
+ /* Integer subtraction */
+ flags = typeadjust (lval, &lval2, 1);
+ } else {
+ /* OOPS */
+ Error (ERR_OP_NOT_ALLOWED);
+ }
+
+ /* Do the subtraction */
+ g_dec (flags | CF_CONST, lval2.e_const);
+
+ /* If this was a pointer subtraction, we must scale the result */
+ if (rscale != 1) {
+ g_scale (flags, -rscale);
+ }
+
+ /* Result is in primary register */
+ lval->e_flags = E_MEXPR;
+ lval->e_test &= ~E_CC;
+
+ }
+
+ } else {
+
+ /* Right hand side is not constant. Get the rhs type. */
+ rhst = lval2.e_tptr;
+
+ /* Check for pointer arithmetic */
+ if (IsPtr (lhst) && IsInt (rhst)) {
+ /* Left is pointer, right is int, must scale rhs */
+ g_scale (CF_INT, PSizeOf (lhst));
+ /* Operate on pointers, result type is a pointer */
+ flags = CF_PTR;
+ } else if (IsPtr (lhst) && IsPtr (rhst)) {
+ /* Left is pointer, right is pointer, must scale result */
+ if (TypeCmp (Indirect (lhst), Indirect (rhst)) != 0) {
+ Error (ERR_INCOMPATIBLE_POINTERS);
+ } else {
+ rscale = PSizeOf (lhst);
+ }
+ /* Operate on pointers, result type is an integer */
+ flags = CF_PTR;
+ lval->e_tptr = type_int;
+ } else if (IsInt (lhst) && IsInt (rhst)) {
+ /* Integer subtraction. If the left hand side descriptor says that
+ * the lhs is const, we have to remove this mark, since this is no
+ * longer true, lhs is on stack instead.
+ */
+ if (lval->e_flags == E_MCONST) {
+ lval->e_flags = E_MEXPR;
+ }
+ /* Adjust operand types */
+ flags = typeadjust (lval, &lval2, 0);
+ } else {
+ /* OOPS */
+ Error (ERR_OP_NOT_ALLOWED);
+ }
+
+ /* Generate code for the sub (the & is a hack here) */
+ g_sub (flags & ~CF_CONST, 0);
+
+ /* If this was a pointer subtraction, we must scale the result */
+ if (rscale != 1) {
+ g_scale (flags, -rscale);
+ }
+
+ /* Result is in primary register */
+ lval->e_flags = E_MEXPR;
+ lval->e_test &= ~E_CC;
+ }
+}
+
+
+
+static int hie8 (struct expent* lval)
+/* Process + and - binary operators. */
+{
+ int k = hie9 (lval);
+ while (curtok == PLUS || curtok == MINUS) {
+
+ if (curtok == PLUS) {
+ parseadd (k, lval);
+ } else {
+ parsesub (k, lval);
+ }
+ k = 0;
+ }
+ return k;
+}
+
+
+
+
+static int hie7 (struct expent *lval)
+/* Parse << and >>. */
+{
+ static GenDesc* hie7_ops [] = {
+ &GenASL, &GenASR, 0
+ };
+ int UsedGen;
+
+ return hie_internal (hie7_ops, lval, hie8, &UsedGen);
+}
+
+
+
+static int hie6 (struct expent *lval)
+/* process greater-than type comparators */
+{
+ static GenDesc* hie6_ops [] = {
+ &GenLT, &GenLE, &GenGE, &GenGT, 0
+ };
+ return hie_compare (hie6_ops, lval, hie7);
+}
+
+
+
+static int hie5 (struct expent *lval)
+{
+ static GenDesc* hie5_ops[] = {
+ &GenEQ, &GenNE, 0
+ };
+ return hie_compare (hie5_ops, lval, hie6);
+}
+
+
+
+static int hie4 (struct expent* lval)
+/* Handle & (bitwise and) */
+{
+ static GenDesc* hie4_ops [] = {
+ &GenAND, 0
+ };
+ int UsedGen;
+
+ return hie_internal (hie4_ops, lval, hie5, &UsedGen);
+}
+
+
+
+static int hie3 (struct expent *lval)
+/* Handle ^ (bitwise exclusive or) */
+{
+ static GenDesc* hie3_ops [] = {
+ &GenXOR, 0
+ };
+ int UsedGen;
+
+ return hie_internal (hie3_ops, lval, hie4, &UsedGen);
+}
+
+
+
+static int hie2 (struct expent *lval)
+/* Handle | (bitwise or) */
+{
+ static GenDesc* hie2_ops [] = {
+ &GenOR, 0
+ };
+ int UsedGen;
+
+ return hie_internal (hie2_ops, lval, hie3, &UsedGen);
+}
+
+
+
+static int hieAnd (struct expent* lval, unsigned TrueLab, int* BoolOp)
+/* Process "exp && exp" */
+{
+ int k;
+ int lab;
+ struct expent lval2;
+
+ k = hie2 (lval);
+ if (curtok == DAMP) {
+
+ /* Tell our caller that we're evaluating a boolean */
+ *BoolOp = 1;
+
+ /* Get a label that we will use for false expressions */
+ lab = GetLabel ();
+
+ /* If the expr hasn't set condition codes, set the force-test flag */
+ if ((lval->e_test & E_CC) == 0) {
+ lval->e_test |= E_FORCETEST;
+ }
+
+ /* Load the value */
+ exprhs (CF_FORCECHAR, k, lval);
+
+ /* Generate the jump */
+ g_falsejump (CF_NONE, lab);
+
+ /* Parse more boolean and's */
+ while (curtok == DAMP) {
+
+ /* Skip the && */
+ gettok ();
+
+ /* Get rhs */
+ k = hie2 (&lval2);
+ if ((lval2.e_test & E_CC) == 0) {
+ lval2.e_test |= E_FORCETEST;
+ }
+ exprhs (CF_FORCECHAR, k, &lval2);
+
+ /* Do short circuit evaluation */
+ if (curtok == DAMP) {
+ g_falsejump (CF_NONE, lab);
+ } else {
+ /* Last expression - will evaluate to true */
+ g_truejump (CF_NONE, TrueLab);
+ }
+ }
+
+ /* Define the false jump label here */
+ g_defloclabel (lab);
+
+ /* Define the label */
+ lval->e_flags = E_MEXPR;
+ lval->e_test |= E_CC; /* Condition codes are set */
+ k = 0;
+ }
+ return k;
+}
+
+
+
+static int hieOr (struct expent *lval)
+/* Process "exp || exp". */
+{
+ int k;
+ struct expent lval2;
+ int BoolOp = 0; /* Did we have a boolean op? */
+ int AndOp; /* Did we have a && operation? */
+ unsigned TrueLab; /* Jump to this label if true */
+ unsigned DoneLab;
+
+ /* Get a label */
+ TrueLab = GetLabel ();
+
+ /* Call the next level parser */
+ k = hieAnd (lval, TrueLab, &BoolOp);
+
+ /* Any boolean or's? */
+ if (curtok == DBAR) {
+
+ /* If the expr hasn't set condition codes, set the force-test flag */
+ if ((lval->e_test & E_CC) == 0) {
+ lval->e_test |= E_FORCETEST;
+ }
+
+ /* Get first expr */
+ exprhs (CF_FORCECHAR, k, lval);
+
+ /* For each expression jump to TrueLab if true. Beware: If we
+ * had && operators, the jump is already in place!
+ */
+ if (!BoolOp) {
+ g_truejump (CF_NONE, TrueLab);
+ }
+
+ /* Remember that we had a boolean op */
+ BoolOp = 1;
+
+ /* while there's more expr */
+ while (curtok == DBAR) {
+
+ /* skip the || */
+ gettok ();
+
+ /* Get a subexpr */
+ AndOp = 0;
+ k = hieAnd (&lval2, TrueLab, &AndOp);
+ if ((lval2.e_test & E_CC) == 0) {
+ lval2.e_test |= E_FORCETEST;
+ }
+ exprhs (CF_FORCECHAR, k, &lval2);
+
+ /* If there is more to come, add shortcut boolean eval.
+ * Beware: If we had && operators, the jump is already
+ * in place!
+ */
+#if 0
+/* Seems this sometimes generates wrong code */
+ if (curtok == DBAR && !AndOp) {
+ g_truejump (CF_NONE, TrueLab);
+ }
+#else
+ g_truejump (CF_NONE, TrueLab);
+#endif
+ }
+ lval->e_flags = E_MEXPR;
+ lval->e_test |= E_CC; /* Condition codes are set */
+ k = 0;
+ }
+
+ /* If we really had boolean ops, generate the end sequence */
+ if (BoolOp) {
+ DoneLab = GetLabel ();
+ g_getimmed (CF_INT | CF_CONST, 0, 0); /* Load FALSE */
+ g_falsejump (CF_NONE, DoneLab);
+ g_defloclabel (TrueLab);
+ g_getimmed (CF_INT | CF_CONST, 1, 0); /* Load TRUE */
+ g_defloclabel (DoneLab);
+ }
+ return k;
+}
+
+
+
+static int hieQuest (struct expent *lval)
+/* Parse "lvalue ? exp : exp" */
+{
+ int k;
+ int labf;
+ int labt;
+ struct expent lval2; /* Expression 2 */
+ struct expent lval3; /* Expression 3 */
+ type* type2; /* Type of expression 2 */
+ type* type3; /* Type of expression 3 */
+ type* rtype; /* Type of result */
+ CodeMark Mark1; /* Save position in output code */
+ CodeMark Mark2; /* Save position in output code */
+
+
+
+ k = hieOr (lval);
+ if (curtok == QUEST) {
+ gettok ();
+ if ((lval->e_test & E_CC) == 0) {
+ /* Condition codes not set, force a test */
+ lval->e_test |= E_FORCETEST;
+ }
+ exprhs (CF_NONE, k, lval);
+ labf = GetLabel ();
+ g_falsejump (CF_NONE, labf);
+
+ /* Parse second and third expression */
+ expression1 (&lval2);
+ labt = GetLabel ();
+ ConsumeColon ();
+ g_jump (labt);
+ g_defloclabel (labf);
+ expression1 (&lval3);
+
+ /* Check if any conversions are needed, if so, do them.
+ * Conversion rules for ?: expression are:
+ * - if both expressions are int expressions, default promotion
+ * rules for ints apply.
+ * - if both expressions are pointers of the same type, the
+ * result of the expression is of this type.
+ * - if one of the expressions is a pointer and the other is
+ * a zero constant, the resulting type is that of the pointer
+ * type.
+ * - all other cases are flagged by an error.
+ */
+ type2 = lval2.e_tptr;
+ type3 = lval3.e_tptr;
+ if (IsInt (type2) && IsInt (type3)) {
+
+ /* Get common type */
+ rtype = promoteint (type2, type3);
+
+ /* Convert the third expression to this type if needed */
+ g_typecast (TypeOf (rtype), TypeOf (type3));
+
+ /* Setup a new label so that the expr3 code will jump around
+ * the type cast code for expr2.
+ */
+ labf = GetLabel (); /* Get new label */
+ Mark1 = GetCodePos (); /* Remember current position */
+ g_jump (labf); /* Jump around code */
+
+ /* The jump for expr2 goes here */
+ g_defloclabel (labt);
+
+ /* Create the typecast code for expr2 */
+ Mark2 = GetCodePos (); /* Remember position */
+ g_typecast (TypeOf (rtype), TypeOf (type2));
+
+ /* If the typecast did not produce code, remove the jump,
+ * otherwise output the label.
+ */
+ if (GetCodePos() == Mark2) {
+ RemoveCode (Mark1); /* Remove code */
+ } else {
+ /* We have typecast code, output label */
+ g_defloclabel (labf);
+ labt = 0; /* Mark other label as invalid */
+ }
+
+ } else if (IsPtr (type2) && IsPtr (type3)) {
+ /* Must point to same type */
+ if (TypeCmp (Indirect (type2), Indirect (type3)) != 0) {
+ Error (ERR_INCOMPATIBLE_TYPES);
+ }
+ /* Result has the common type */
+ rtype = lval2.e_tptr;
+ } else if (IsPtr (type2) && IsNullPtr (&lval3)) {
+ /* Result type is pointer, no cast needed */
+ rtype = lval2.e_tptr;
+ } else if (IsNullPtr (&lval2) && IsPtr (type3)) {
+ /* Result type is pointer, no cast needed */
+ rtype = lval3.e_tptr;
+ } else {
+ Error (ERR_INCOMPATIBLE_TYPES);
+ rtype = lval2.e_tptr; /* Doesn't matter here */
+ }
+
+ /* If we don't have the label defined until now, do it */
+ if (labt) {
+ g_defloclabel (labt);
+ }
+
+ /* Setup the target expression */
+ lval->e_flags = E_MEXPR;
+ lval->e_tptr = rtype;
+ k = 0;
+ }
+ return k;
+}
+
+
+
+static void opeq (GenDesc* Gen, struct expent *lval, int k)
+/* Process "op=" operators. */
+{
+ struct expent lval2;
+ unsigned flags;
+ CodeMark Mark;
+ int MustScale;
+
+ gettok ();
+ if (k == 0) {
+ Error (ERR_LVALUE_EXPECTED);
+ return;
+ }
+
+ /* Determine the type of the lhs */
+ flags = TypeOf (lval->e_tptr);
+ MustScale = (Gen->Func == g_add || Gen->Func == g_sub) &&
+ lval->e_tptr [0] == T_PTR;
+
+ /* Get the lhs address on stack (if needed) */
+ PushAddr (lval);
+
+ /* Fetch the lhs into the primary register if needed */
+ exprhs (CF_NONE, k, lval);
+
+ /* Bring the lhs on stack */
+ Mark = GetCodePos ();
+ g_push (flags, 0);
+
+ /* Evaluate the rhs */
+ if (evalexpr (CF_NONE, hie1, &lval2) == 0) {
+ /* The resulting value is a constant. If the generator has the NOPUSH
+ * flag set, don't push the lhs.
+ */
+ if (Gen->Flags & GEN_NOPUSH) {
+ RemoveCode (Mark);
+ pop (flags);
+ }
+ if (MustScale) {
+ /* lhs is a pointer, scale rhs */
+ lval2.e_const *= SizeOf (lval->e_tptr+1);
+ }
+
+ /* If the lhs is character sized, the operation may be later done
+ * with characters.
+ */
+ if (SizeOf (lval->e_tptr) == 1) {
+ flags |= CF_FORCECHAR;
+ }
+
+ /* Special handling for add and sub - some sort of a hack, but short code */
+ if (Gen->Func == g_add) {
+ g_inc (flags | CF_CONST, lval2.e_const);
+ } else if (Gen->Func == g_sub) {
+ g_dec (flags | CF_CONST, lval2.e_const);
+ } else {
+ Gen->Func (flags | CF_CONST, lval2.e_const);
+ }
+ } else {
+ /* rhs is not constant and already in the primary register */
+ if (MustScale) {
+ /* lhs is a pointer, scale rhs */
+ g_scale (TypeOf (lval2.e_tptr), SizeOf (lval->e_tptr+1));
+ }
+
+ /* If the lhs is character sized, the operation may be later done
+ * with characters.
+ */
+ if (SizeOf (lval->e_tptr) == 1) {
+ flags |= CF_FORCECHAR;
+ }
+
+ /* Adjust the types of the operands if needed */
+ Gen->Func (g_typeadjust (flags, TypeOf (lval2.e_tptr)), 0);
+ }
+ store (lval);
+ lval->e_flags = E_MEXPR;
+}
+
+
+
+static void addsubeq (GenDesc* Gen, struct expent *lval, int k)
+/* Process the += and -= operators */
+{
+ struct expent lval2;
+ unsigned flags;
+ int MustScale;
+
+
+ if (k == 0) {
+ Error (ERR_LVALUE_EXPECTED);
+ return;
+ }
+
+
+ /* We're currently only able to handle some adressing modes */
+ if ((lval->e_flags & E_MGLOBAL) == 0 && /* Global address? */
+ (lval->e_flags & E_MLOCAL) == 0 && /* Local address? */
+ (lval->e_flags & E_MCONST) == 0) { /* Constant address? */
+ /* Use generic routine */
+ opeq (Gen, lval, k);
+ return;
+ }
+
+ /* Skip the operator */
+ gettok ();
+
+ /* Check if we have a pointer expression and must scale rhs */
+ MustScale = (lval->e_tptr [0] == T_PTR);
+
+ /* Determine the code generator flags */
+ flags = TypeOf (lval->e_tptr) | CF_FORCECHAR;
+
+ /* Evaluate the rhs */
+ if (evalexpr (CF_NONE, hie1, &lval2) == 0) {
+ /* The resulting value is a constant. */
+ if (MustScale) {
+ /* lhs is a pointer, scale rhs */
+ lval2.e_const *= SizeOf (lval->e_tptr+1);
+ }
+ flags |= CF_CONST;
+ } else {
+ /* rhs is not constant and already in the primary register */
+ if (MustScale) {
+ /* lhs is a pointer, scale rhs */
+ g_scale (TypeOf (lval2.e_tptr), SizeOf (lval->e_tptr+1));
+ }
+ }
+
+ /* If the lhs is character sized, the operation may be later done
+ * with characters.
+ */
+ if (SizeOf (lval->e_tptr) == 1) {
+ flags |= CF_FORCECHAR;
+ }
+
+ /* Output apropriate code */
+ if (lval->e_flags & E_MGLOBAL) {
+ /* Static variable */
+ flags |= GlobalModeFlags (lval->e_flags);
+ if (Gen->Tok == PASGN) {
+ g_addeqstatic (flags, lval->e_name, lval->e_const, lval2.e_const);
+ } else {
+ g_subeqstatic (flags, lval->e_name, lval->e_const, lval2.e_const);
+ }
+ } else if (lval->e_flags & E_MLOCAL) {
+ /* ref to localvar */
+ if (Gen->Tok == PASGN) {
+ g_addeqlocal (flags, lval->e_const, lval2.e_const);
+ } else {
+ g_subeqlocal (flags, lval->e_const, lval2.e_const);
+ }
+ } else if (lval->e_flags & E_MCONST) {
+ /* ref to absolute address */
+ flags |= CF_ABSOLUTE;
+ if (Gen->Tok == PASGN) {
+ g_addeqstatic (flags, lval->e_const, 0, lval2.e_const);
+ } else {
+ g_subeqstatic (flags, lval->e_const, 0, lval2.e_const);
+ }
+ } else if (lval->e_flags & E_MEXPR) {
+ /* Address in a/x. */
+ if (Gen->Tok == PASGN) {
+ g_addeqind (flags, lval->e_const, lval2.e_const);
+ } else {
+ g_subeqind (flags, lval->e_const, lval2.e_const);
+ }
+ } else {
+ Internal ("Invalid addressing mode");
+ }
+
+ /* Expression is in the primary now */
+ lval->e_flags = E_MEXPR;
+}
+
+
+
+static void Assignment (struct expent* lval)
+/* Parse an assignment */
+{
+ int k;
+ struct expent lval2;
+ unsigned flags;
+ type* ltype = lval->e_tptr;
+
+ /* cc65 does not have full support for handling structs by value. Since
+ * assigning structs is one of the more useful operations from this
+ * familiy, allow it here.
+ */
+ if (IsStruct (ltype)) {
+
+ /* Bring the address of the lhs into the primary and push it */
+ exprhs (0, 0, lval);
+ g_push (CF_PTR | CF_UNSIGNED, 0);
+
+ /* Get the expression on the right of the '=' into the primary */
+ k = hie1 (&lval2);
+ if (k) {
+ /* Get the address */
+ exprhs (0, 0, &lval2);
+ } else {
+ /* We need an lvalue */
+ Error (ERR_LVALUE_EXPECTED);
+ }
+
+ /* Push the address (or whatever is in ax in case of errors) */
+ g_push (CF_PTR | CF_UNSIGNED, 0);
+
+ /* Check for equality of the structs */
+ if (!EqualTypes (ltype, lval2.e_tptr)) {
+ Error (ERR_INCOMPATIBLE_TYPES);
+ }
+
+ /* Load the size of the struct into the primary */
+ g_getimmed (CF_INT | CF_UNSIGNED | CF_CONST, SizeOf (ltype), 0);
+
+ /* Call the memcpy function */
+ g_call (CF_FIXARGC, "memcpy", 4);
+
+ } else {
+
+ /* Get the address on stack if needed */
+ PushAddr (lval);
+
+ /* No struct, setup flags for the load */
+ flags = SizeOf (ltype) == 1? CF_FORCECHAR : CF_NONE;
+
+ /* Get the expression on the right of the '=' into the primary */
+ if (evalexpr (flags, hie1, &lval2) == 0) {
+ /* Constant expression. Adjust the types */
+ assignadjust (ltype, &lval2);
+ /* Put the value into the primary register */
+ lconst (flags, &lval2);
+ } else {
+ /* Expression is not constant and already in the primary */
+ assignadjust (ltype, &lval2);
+ }
+
+ /* Generate a store instruction */
+ store (lval);
+
+ }
+
+ /* Value is still in primary */
+ lval->e_flags = E_MEXPR;
+}
+
+
+
+int hie1 (struct expent* lval)
+/* Parse first level of expression hierarchy. */
+{
+ int k;
+
+ k = hieQuest (lval);
+ switch (curtok) {
+
+ case RPAREN:
+ case SEMI:
+ return k;
+
+ case ASGN:
+ gettok ();
+ if (k == 0) {
+ Error (ERR_LVALUE_EXPECTED);
+ } else {
+ Assignment (lval);
+ }
+ break;
+
+ case PASGN:
+ addsubeq (&GenPASGN, lval, k);
+ break;
+
+ case SASGN:
+ addsubeq (&GenSASGN, lval, k);
+ break;
+
+ case MASGN:
+ opeq (&GenMASGN, lval, k);
+ break;
+
+ case DASGN:
+ opeq (&GenDASGN, lval, k);
+ break;
+
+ case MOASGN:
+ opeq (&GenMOASGN, lval, k);
+ break;
+
+ case SLASGN:
+ opeq (&GenSLASGN, lval, k);
+ break;
+
+ case SRASGN:
+ opeq (&GenSRASGN, lval, k);
+ break;
+
+ case AASGN:
+ opeq (&GenAASGN, lval, k);
+ break;
+
+ case XOASGN:
+ opeq (&GenXOASGN, lval, k);
+ break;
+
+ case OASGN:
+ opeq (&GenOASGN, lval, k);
+ break;
+
+ default:
+ return k;
+ }
+ return 0;
+}
+
+
+
+int hie0 (struct expent *lval)
+/* Parse comma operator. */
+{
+ int k;
+
+ k = hie1 (lval);
+ while (curtok == COMMA) {
+ gettok ();
+ k = hie1 (lval);
+ }
+ return k;
+}
+
+
+
+int evalexpr (unsigned flags, int (*f) (struct expent*), struct expent* lval)
+/* Will evaluate an expression via the given function. If the result is a
+ * constant, 0 is returned and the value is put in the lval struct. If the
+ * result is not constant, exprhs is called to bring the value into the
+ * primary register and 1 is returned.
+ */
+{
+ int k;
+
+ /* Evaluate */
+ k = f (lval);
+ if (k == 0 && lval->e_flags == E_MCONST) {
+ /* Constant expression */
+ return 0;
+ } else {
+ /* Not constant, load into the primary */
+ exprhs (flags, k, lval);
+ return 1;
+ }
+}
+
+
+
+int expr (int (*func) (), struct expent *lval)
+/* Expression parser; func is either hie0 or hie1. */
+{
+ int k;
+ int savsp;
+
+ savsp = oursp;
+
+ k = (*func) (lval);
+
+ /* Do some checks if code generation is still constistent */
+ if (savsp != oursp) {
+ if (Debug) {
+ fprintf (stderr, "oursp != savesp (%d != %d)\n", oursp, savsp);
+ } else {
+ Internal ("oursp != savsp (%d != %d)", oursp, savsp);
+ }
+ }
+ return k;
+}
+
+
+
+void expression1 (struct expent* lval)
+/* Evaluate an expression on level 1 (no comma operator) and put it into
+ * the primary register
+ */
+{
+ memset (lval, 0, sizeof (*lval));
+ exprhs (CF_NONE, expr (hie1, lval), lval);
+}
+
+
+
+void expression (struct expent* lval)
+/* Evaluate an expression and put it into the primary register */
+{
+ memset (lval, 0, sizeof (*lval));
+ exprhs (CF_NONE, expr (hie0, lval), lval);
+}
+
+
+
+void constexpr (struct expent* lval)
+/* Get a constant value */
+{
+ memset (lval, 0, sizeof (*lval));
+ if (expr (hie1, lval) != 0 || (lval->e_flags & E_MCONST) == 0) {
+ Error (ERR_CONST_EXPR_EXPECTED);
+ /* To avoid any compiler errors, make the expression a valid const */
+ lval->e_flags = E_MCONST;
+ lval->e_tptr = type_int;
+ lval->e_const = 0;
+ }
+}
+
+
+
+void intexpr (struct expent* lval)
+/* Get an integer expression */
+{
+ expression (lval);
+ if (!IsInt (lval->e_tptr)) {
+ Error (ERR_INT_EXPR_EXPECTED);
+ /* To avoid any compiler errors, make the expression a valid int */
+ lval->e_flags = E_MCONST;
+ lval->e_tptr = type_int;
+ lval->e_const = 0;
+ }
+}
+
+
+
+void boolexpr (struct expent* lval)
+/* Get a boolean expression */
+{
+ /* Read an expression */
+ expression (lval);
+
+ /* If it's an integer, it's ok. If it's not an integer, but a pointer,
+ * the pointer used in a boolean context is also ok (Ootherwise check if it's a pointer
+ * expression.
+ */
+ if (!IsInt (lval->e_tptr) && !IsPtr (lval->e_tptr)) {
+ Error (ERR_INT_EXPR_EXPECTED);
+ /* To avoid any compiler errors, make the expression a valid int */
+ lval->e_flags = E_MCONST;
+ lval->e_tptr = type_int;
+ lval->e_const = 0;
+ }
+}
+
+
+
+void test (unsigned label, int cond)
+/* Generate code to perform test and jump if false. */
+{
+ int k;
+ struct expent lval;
+
+ /* Eat the parenthesis */
+ ConsumeLParen ();
+
+ /* Prepare the expression, setup labels */
+ memset (&lval, 0, sizeof (lval));
+ lval.e_test = E_TEST;
+
+ /* Generate code to eval the expr */
+ k = expr (hie0, &lval);
+ if (k == 0 && lval.e_flags == E_MCONST) {
+ /* Constant rvalue */
+ if (cond == 0 && lval.e_const == 0) {
+ g_jump (label);
+ Warning (WARN_UNREACHABLE_CODE);
+ } else if (cond && lval.e_const) {
+ g_jump (label);
+ }
+ ConsumeRParen ();
+ return;
+ }
+
+ /* If the expr hasn't set condition codes, set the force-test flag */
+ if ((lval.e_test & E_CC) == 0) {
+ lval.e_test |= E_FORCETEST;
+ }
+
+ /* Load the value into the primary register */
+ exprhs (CF_FORCECHAR, k, &lval);
+
+ /* Check for the closing brace */
+ ConsumeRParen ();
+
+ /* Generate the jump */
+ if (cond) {
+ g_truejump (CF_NONE, label);
+ } else {
+ /* Special case (putting this here is a small hack - but hey, the
+ * compiler itself is one big hack...): If a semicolon follows, we
+ * don't have a statement and may omit the jump.
+ */
+ if (curtok != SEMI) {
+ g_falsejump (CF_NONE, label);
+ }
+ }
+}
+
+
+
+
--- /dev/null
+/*
+ * expr.h
+ *
+ * Ullrich von Bassewitz, 21.06.1998
+ */
+
+
+
+#ifndef EXPR_H
+#define EXPR_H
+
+
+
+#include "datatype.h"
+
+
+
+/*****************************************************************************/
+/* data */
+/*****************************************************************************/
+
+
+
+/* Defines for the flags field of the expression descriptor */
+#define E_MREG 0x0110 /* Special: Expression is primary register */
+#define E_MGLOBAL 0x0080 /* Reference to static variable */
+#define E_MLOCAL 0x0040 /* Reference to local variable (stack offset) */
+#define E_MCONST 0x0020 /* Constant value */
+#define E_MEXPR 0x0010 /* Result is in primary register */
+#define E_MEOFFS 0x0011 /* Offset is in primary register, base on stack */
+
+#define E_MCTYPE 0x0007 /* Type of a constant */
+#define E_TCONST 0x0000 /* Constant */
+#define E_TGLAB 0x0001 /* Global label */
+#define E_TLIT 0x0002 /* Literal of some kind */
+#define E_TLOFFS 0x0003 /* Constant stack offset */
+#define E_TLLAB 0x0004 /* Local label */
+#define E_TREGISTER 0x0005 /* Register variable */
+
+/* Defines for the test field of the expression descriptor */
+#define E_CC 0x0001 /* expr has set cond codes apropos result value */
+#define E_FORCETEST 0x0002 /* if expr has NOT set CC, force a test */
+#define E_LOGL 0x0004 /* expr has left a logical value (1 or 0) in AX */
+#define E_XINV 0x0008 /* flip this bit to invert sense of test */
+#define E_TEST 0x0010 /* We're evaluating a test */
+
+/* Describe the result of an expression */
+struct expent {
+ struct SymEntry* Sym; /* Symbol table entry if known */
+ type* e_tptr; /* Type array of expression */
+ long e_const; /* Value if expression constant */
+ unsigned e_flags;
+ unsigned e_test; /* */
+ unsigned long e_name; /* Name or label number */
+};
+
+
+
+/*****************************************************************************/
+/* code */
+/*****************************************************************************/
+
+
+
+void doasm (void);
+/* This function parses ASM statements. The syntax of the ASM directive
+ * looks like the one defined for C++ (C has no ASM directive), that is,
+ * a string literal in parenthesis.
+ */
+
+unsigned assignadjust (type* lhst, struct expent* rhs);
+/* Adjust the type of the right hand expression so that it can be assigned to
+ * the type on the left hand side. This function is used for assignment and
+ * for converting parameters in a function call. It returns the code generator
+ * flags for the operation.
+ */
+
+void exprhs (unsigned flags, int k, struct expent *lval);
+/* Put the result of an expression into the primary register */
+
+void expression1 (struct expent* lval);
+/* Evaluate an expression on level 1 (no comma operator) and put it into
+ * the primary register
+ */
+
+void expression (struct expent* lval);
+/* Evaluate an expression and put it into the primary register */
+
+int evalexpr (unsigned flags, int (*f) (struct expent*), struct expent* lval);
+/* Will evaluate an expression via the given function. If the result is a
+ * constant, 0 is returned and the value is put in the lval struct. If the
+ * result is not constant, exprhs is called to bring the value into the
+ * primary register and 1 is returned.
+ */
+
+void constexpr (struct expent* lval);
+/* Get a constant value */
+
+void intexpr (struct expent* lval);
+/* Get an integer expression */
+
+void boolexpr (struct expent* lval);
+/* Get a boolean expression */
+
+void test (unsigned label, int cond);
+/* Generate code to perform test and jump if false. */
+
+int hie1 (struct expent* lval);
+/* Parse first level of expression hierarchy. */
+
+int hie0 (struct expent* lval);
+/* Parse comma operator (highest level of expression hierarchy) */
+
+void DefineData (struct expent* lval);
+/* Output a data definition for the given expression */
+
+
+
+/* End of expr.h */
+
+#endif
+
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* funcdesc.c */
+/* */
+/* Function descriptor structure for the cc65 C compiler */
+/* */
+/* */
+/* */
+/* (C) 2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include "mem.h"
+#include "funcdesc.h"
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+FuncDesc* NewFuncDesc (void)
+/* Create a new symbol table with the given name */
+{
+ /* Create a new function descriptor */
+ FuncDesc* F = xmalloc (sizeof (FuncDesc));
+
+ /* Nullify the fields */
+ F->Flags = 0;
+ F->SymTab = 0;
+ F->StructTab = 0;
+ F->EnumTab = 0;
+ F->ParamCount = 0;
+ F->ParamSize = 0;
+
+ /* Return the new struct */
+ return F;
+}
+
+
+
+void FreeFuncDesc (FuncDesc* F)
+/* Free a function descriptor */
+{
+ /* Free the structure */
+ xfree (F);
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* funcdesc.h */
+/* */
+/* Function descriptor structure for the cc65 C compiler */
+/* */
+/* */
+/* */
+/* (C) 2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef FUNCDESC_H
+#define FUNCDESC_H
+
+
+
+/*****************************************************************************/
+/* struct FuncDesc */
+/*****************************************************************************/
+
+
+
+/* Masks for the Flags field in FuncDesc */
+#define FD_IMPLICIT 0x0001U /* Implicitly declared function */
+#define FD_EMPTY 0x0002U /* Function with empty param list */
+#define FD_VOID_PARAM 0x0004U /* Function with a void param list */
+#define FD_ELLIPSIS 0x0008U /* Function with variable param list */
+#define FD_FASTCALL 0x0010U /* __fastcall__ function */
+
+/* Function descriptor */
+typedef struct FuncDesc FuncDesc;
+struct FuncDesc {
+ unsigned Flags; /* Bitmapped flags FD_... */
+ struct SymTable* SymTab; /* Symbol table */
+ struct SymTable* StructTab; /* Struct table */
+ struct SymTable* EnumTab; /* Enum table */
+ unsigned ParamCount; /* Number of parameters */
+ unsigned ParamSize; /* Size of the parameters */
+};
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+FuncDesc* NewFuncDesc (void);
+/* Create a new symbol table with the given name */
+
+void FreeFuncDesc (FuncDesc* E);
+/* Free a function descriptor */
+
+
+
+/* End of funcdesc.h */
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* function.c */
+/* */
+/* Parse function entry/body/exit */
+/* */
+/* */
+/* */
+/* (C) 2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include "asmcode.h"
+#include "asmlabel.h"
+#include "codegen.h"
+#include "error.h"
+#include "funcdesc.h"
+#include "litpool.h"
+#include "locals.h"
+#include "mem.h"
+#include "scanner.h"
+#include "stmt.h"
+#include "symtab.h"
+#include "function.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Structure that holds all data needed for function activation */
+struct Function {
+ struct SymEntry* FuncEntry; /* Symbol table entry */
+ type* ReturnType; /* Function return type */
+ struct FuncDesc* Desc; /* Function descriptor */
+ CodeMark EntryCode; /* Backpatch addr for entry code */
+ unsigned LocalMax; /* Total space for locals */
+ unsigned LocalSize; /* Current space for locals */
+ unsigned RetLab; /* Return code label */
+};
+
+/* Pointer to current function */
+Function* CurrentFunc = 0;
+
+
+
+/*****************************************************************************/
+/* code */
+/*****************************************************************************/
+
+
+
+static Function* NewFunction (struct SymEntry* Sym)
+/* Create a new function activation structure and return it */
+{
+ /* Allocate a new structure */
+ Function* F = xmalloc (sizeof (Function));
+
+ /* Initialize the fields */
+ F->FuncEntry = Sym;
+ F->ReturnType = Sym->Type + 1 + DECODE_SIZE;
+ F->Desc = DecodePtr (Sym->Type + 1);
+ F->EntryCode = GetCodePos ();
+ F->LocalMax = 0;
+ F->LocalSize = 0;
+ F->RetLab = GetLabel ();
+
+ /* Return the new structure */
+ return F;
+}
+
+
+
+static void FreeFunction (Function* F)
+/* Free a function activation structure */
+{
+ xfree (F);
+}
+
+
+
+const char* GetFuncName (const Function* F)
+/* Return the name of the current function */
+{
+ return F->FuncEntry->Name;
+}
+
+
+
+unsigned GetParamSize (const Function* F)
+/* Return the parameter size for the current function */
+{
+ return F->Desc->ParamSize;
+}
+
+
+
+type* GetReturnType (Function* F)
+/* Get the return type for the function */
+{
+ return F->ReturnType;
+}
+
+
+
+int HasVoidReturn (const Function* F)
+/* Return true if the function does not have a return value */
+{
+ return IsVoid (F->ReturnType);
+}
+
+
+
+unsigned GetRetLab (const Function* F)
+/* Return the return jump label */
+{
+ return F->RetLab;
+}
+
+
+
+unsigned AllocLocalSpace (Function* F, unsigned Size)
+/* Allocate space for the function locals, return stack offset */
+{
+ /* Remember the current offset */
+ unsigned Offs = F->LocalSize;
+
+ /* Add the size */
+ F->LocalSize += Size;
+ if (F->LocalSize > F->LocalMax) {
+ F->LocalMax = F->LocalSize;
+ }
+
+ /* Return the offset */
+ return Offs;
+}
+
+
+
+void FreeLocalSpace (Function* F, unsigned Size)
+/* Free space allocated for function locals */
+{
+ F->LocalSize -= Size;
+}
+
+
+
+void NewFunc (SymEntry* Func)
+/* Parse argument declarations and function body. */
+{
+ int isbrk;
+
+ /* Get the function descriptor from the function entry */
+ FuncDesc* D = DecodePtr (Func->Type+1);
+
+ /* Allocate the function activation record for the function */
+ CurrentFunc = NewFunction (Func);
+
+ /* Reenter the lexical level */
+ ReenterFunctionLevel (D);
+
+ /* Function body now defined */
+ Func->Flags |= SC_DEF;
+
+ /* C functions cannot currently have __fastcall__ calling conventions */
+ if (IsFastCallFunc (Func->Type)) {
+ Error (ERR_FASTCALL);
+ }
+
+ /* Need a starting curly brace */
+ if (curtok != LCURLY) {
+ Error (ERR_LCURLY_EXPECTED);
+ }
+
+ /* Setup register variables */
+ InitRegVars ();
+
+ /* Switch to the code segment and generate function entry code */
+ g_usecode ();
+ g_enter (TypeOf (Func->Type), Func->Name, GetParamSize (CurrentFunc));
+
+ /* Parse the function body */
+ oursp = 0;
+ isbrk = compound ();
+
+ /* If the function did not end with an return statement, create exit code */
+ if (!isbrk) {
+#if 0
+ /* If the function has a return type, flag an error */
+ if (!voidfunc) {
+ Error (ERR_MUST_RETURN_VALUE);
+ }
+#endif
+ RestoreRegVars (0);
+ g_leave (CF_NONE, 0);
+ }
+
+ /* Dump literal data created by the function */
+ DumpLiteralPool ();
+
+ /* Cleanup register variables */
+ DoneRegVars ();
+
+ /* Leave the lexical level */
+ LeaveFunctionLevel ();
+
+ /* Reset the current function pointer */
+ FreeFunction (CurrentFunc);
+ CurrentFunc = 0;
+}
+
+
+
--- /dev/null
+/*
+ * function.h
+ *
+ * Ullrich von Bassewitz, 07.06.1998
+ */
+
+
+
+#ifndef FUNCTION_H
+#define FUNCTION_H
+
+
+
+/*****************************************************************************/
+/* data */
+/*****************************************************************************/
+
+
+
+/* Structure that holds all data needed for function activation */
+typedef struct Function Function;
+
+/* Function activation data for current function (or NULL) */
+extern Function* CurrentFunc;
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+const char* GetFuncName (const Function* F);
+/* Return the name of the current function */
+
+unsigned GetParamSize (const Function* F);
+/* Return the parameter size for the current function */
+
+type* GetReturnType (Function* F);
+/* Get the return type for the function */
+
+int HasVoidReturn (const Function* F);
+/* Return true if the function does not have a return value */
+
+unsigned GetRetLab (const Function* F);
+/* Return the return jump label */
+
+unsigned AllocLocalSpace (Function* F, unsigned Size);
+/* Allocate space for the function locals, return stack offset */
+
+void FreeLocalSpace (Function* F, unsigned Size);
+/* Free space allocated for function locals */
+
+void NewFunc (struct SymEntry* Func);
+/* Parse argument declarations and function body. */
+
+
+
+/* End of function.h */
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* global.c */
+/* */
+/* Global variables for the cc65 C compiler */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include "global.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+unsigned char Target = TGT_NONE; /* Target system */
+unsigned char ANSI = 0; /* Strict ANSI flag */
+unsigned char WriteableStrings = 0; /* Literal strings are r/w */
+unsigned char NoWarn = 0; /* Suppress warnings */
+unsigned char Optimize = 0; /* Optimize flag */
+unsigned char FavourSize = 1; /* Favour size over speed */
+unsigned char InlineStdFuncs = 0; /* Inline some known functions */
+unsigned char EnableRegVars = 0; /* Enable register variables */
+unsigned char AllowRegVarAddr = 0; /* Allow taking addresses of register vars */
+unsigned char RegVarsToCallStack= 0; /* Save reg variables on call stack */
+unsigned char LocalsAreStatic = 0; /* Make local variables static */
+unsigned char SignedChars = 0; /* Make characters signed by default */
+unsigned char Verbose = 0; /* Verbose flag */
+unsigned char IncSource = 0; /* Include source as comments */
+unsigned char DebugInfo = 0; /* Add debug info to the obj */
+unsigned char Debug = 0; /* Debug mode */
+
+
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* global.h */
+/* */
+/* Global variables for the cc65 C compiler */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef GLOBAL_H
+#define GLOBAL_H
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Supported systems */
+#define TGT_NONE 0
+#define TGT_ATARI 1
+#define TGT_C64 2
+#define TGT_C128 3
+#define TGT_ACE 4
+#define TGT_PLUS4 5
+#define TGT_CBM610 6
+#define TGT_PET 7
+#define TGT_NES 8
+#define TGT_APPLE2 9
+#define TGT_GEOS 10
+#define TGT_COUNT 11
+
+
+
+extern unsigned char Target; /* Target system */
+extern unsigned char ANSI; /* Strict ANSI flag */
+extern unsigned char WriteableStrings; /* Literal strings are r/w */
+extern unsigned char NoWarn; /* Suppress warnings */
+extern unsigned char Optimize; /* Optimize flag */
+extern unsigned char FavourSize; /* Favour size over speed */
+extern unsigned char InlineStdFuncs; /* Inline some known functions */
+extern unsigned char EnableRegVars; /* Enable register variables */
+extern unsigned char AllowRegVarAddr; /* Allow taking addresses of register vars */
+extern unsigned char RegVarsToCallStack; /* Save reg variables on call stack */
+extern unsigned char LocalsAreStatic; /* Make local variables static */
+extern unsigned char SignedChars; /* Make characters signed by default */
+extern unsigned char Verbose; /* Verbose flag */
+extern unsigned char IncSource; /* Include source as comments */
+extern unsigned char DebugInfo; /* Add debug info to the obj */
+extern unsigned char Debug; /* Debug mode */
+
+
+
+/* End of global.h */
+
+#endif
+
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* goto.c */
+/* */
+/* Goto and label handling for the cc65 C compiler */
+/* */
+/* */
+/* */
+/* (C) 2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include "codegen.h"
+#include "error.h"
+#include "scanner.h"
+#include "symtab.h"
+#include "goto.h"
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void DoGoto (void)
+/* Process a goto statement. */
+{
+ /* Eat the "goto" */
+ gettok ();
+
+ /* Label name must follow */
+ if (curtok != IDENT) {
+
+ Error (ERR_IDENT_EXPECTED);
+
+ } else {
+
+ /* Add a new label symbol if we don't have one until now */
+ SymEntry* Entry = AddLabelSym (CurTok.Ident, SC_REF);
+
+ /* Jump to the label */
+ g_jump (Entry->V.Label);
+ }
+
+ /* Eat the label name */
+ gettok ();
+}
+
+
+
+void DoLabel (void)
+/* Define a label. */
+{
+ /* Add a label symbol */
+ SymEntry* Entry = AddLabelSym (CurTok.Ident, SC_DEF);
+
+ /* Emit the jump label */
+ g_defloclabel (Entry->V.Label);
+
+ /* Eat the ident and colon */
+ gettok ();
+ gettok ();
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* goto.h */
+/* */
+/* Goto and label handling for the cc65 C compiler */
+/* */
+/* */
+/* */
+/* (C) 2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef GOTO_H
+#define GOTO_H
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void DoGoto (void);
+/* Process a goto statement. */
+
+void DoLabel (void);
+/* Define a goto label. */
+
+
+
+/* End of goto.h */
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* hashstr.c */
+/* */
+/* Hash function for strings */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include "hashstr.h"
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+unsigned HashStr (const char* S)
+/* Return a hash value for the given string */
+{
+ unsigned L, H;
+
+ /* Do the hash */
+ H = L = 0;
+ while (*S) {
+ H = ((H << 3) ^ ((unsigned char) *S++)) + L++;
+ }
+ return H;
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* hashstr.h */
+/* */
+/* Hash function for strings */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef HASHSTR_H
+#define HASHSTR_H
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+unsigned HashStr (const char* S);
+/* Return a hash value for the given string */
+
+
+
+/* End of hashstr.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* ident.c */
+/* */
+/* Identifier handling for the cc65 compiler */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <ctype.h>
+
+#include "ident.h"
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+int IsIdent (char c)
+/* Return true if the given char may start an identifier */
+{
+ return (isalpha (c) || c == '_');
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* ident.h */
+/* */
+/* Identifier handling for the cc65 compiler */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef IDENT_H
+#define IDENT_H
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Maximum length of an identifier and the corresponding char array */
+#define MAX_IDENTLEN 64
+#define IDENTSIZE (MAX_IDENTLEN+1)
+
+/* Variable that holds an identifer */
+typedef char ident [IDENTSIZE];
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+int IsIdent (char c);
+/* Return true if the given char may start an identifier */
+
+
+
+/* End of ident.h */
+#endif
+
+
+
--- /dev/null
+/*
+ * include.c - Include file handling for cc65
+ *
+ * Ullrich von Bassewitz, 18.08.1998
+ */
+
+
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "mem.h"
+#include "include.h"
+
+
+
+/*****************************************************************************/
+/* data */
+/*****************************************************************************/
+
+
+
+static char* SysIncludePath = 0;
+static char* UserIncludePath = 0;
+
+
+
+/*****************************************************************************/
+/* code */
+/*****************************************************************************/
+
+
+
+static char* Add (char* Orig, char* New)
+/* Create a new path from Orig and New, delete Orig, return the result */
+{
+ unsigned Len, NewLen;
+ char* NewPath;
+
+ /* Check for a trailing path separator and remove it */
+ NewLen = strlen (New);
+ if (NewLen > 0 && (New [NewLen-1] == '\\' || New [NewLen-1] == '/')) {
+ New [--NewLen] = '\0';
+ }
+
+ /* Calculate the length of the combined paths */
+ if (Orig) {
+ Len = strlen (Orig) + NewLen;
+ } else {
+ Len = NewLen;
+ }
+
+ /* Allocate memory for the new string */
+ NewPath = xmalloc (Len + 2);
+
+ /* Copy the strings */
+ if (Orig) {
+ strcpy (NewPath, Orig);
+ } else {
+ NewPath [0] = '\0';
+ }
+ strcat (NewPath, New);
+ strcat (NewPath, ";");
+
+ /* Delete the original path */
+ xfree (Orig);
+
+ /* Return the new path */
+ return NewPath;
+}
+
+
+
+static char* Find (char* Path, char* File)
+/* Search for a file in a list of directories. If found, return the complete
+ * name including the path in a malloced data area, if not found, return 0.
+ */
+{
+ char* P;
+ unsigned Count;
+ int Max;
+ char PathName [FILENAME_MAX];
+
+ /* Initialize variables */
+ Max = sizeof (PathName) - strlen (File) - 2;
+ if (Max < 0) {
+ return 0;
+ }
+ P = Path;
+
+ /* Handle a NULL pointer as replacement for an empty string */
+ if (P == 0) {
+ P = "";
+ }
+
+ /* Start the search */
+ while (*P) {
+ /* Copy the next path element into the buffer */
+ Count = 0;
+ while (*P != '\0' && *P != ';' && Count < Max) {
+ PathName [Count++] = *P++;
+ }
+
+ /* Add a path separator and the filename */
+ if (Count) {
+ PathName [Count++] = '/';
+ }
+ strcpy (PathName + Count, File);
+
+ /* Check if this file exists */
+ if (access (PathName, R_OK) == 0) {
+ /* The file exists */
+ return xstrdup (PathName);
+ }
+
+ /* Skip a list separator if we have one */
+ if (*P == ';') {
+ ++P;
+ }
+ }
+
+ /* Not found */
+ return 0;
+}
+
+
+
+void AddIncludePath (char* NewPath, unsigned Where)
+/* Add a new include path to the existing one */
+{
+ /* Allow a NULL path */
+ if (NewPath) {
+ if (Where & INC_SYS) {
+ SysIncludePath = Add (SysIncludePath, NewPath);
+ }
+ if (Where & INC_USER) {
+ UserIncludePath = Add (UserIncludePath, NewPath);
+ }
+ }
+}
+
+
+
+char* FindInclude (char* Name, unsigned Where)
+/* Find an include file. Return a pointer to a malloced area that contains
+ * the complete path, if found, return 0 otherwise.
+ */
+{
+ if (Where & INC_SYS) {
+ /* Search in the system include directories */
+ return Find (SysIncludePath, Name);
+ }
+ if (Where & INC_USER) {
+ /* Search in the user include directories */
+ return Find (UserIncludePath, Name);
+ }
+ return 0;
+}
+
+
+
--- /dev/null
+/*
+ * include.h - Include file handling for cc65
+ *
+ * Ullrich von Bassewitz, 18.08.1998
+ */
+
+
+
+#ifndef INCLUDE_H
+#define INCLUDE_H
+
+
+
+/*****************************************************************************/
+/* data */
+/*****************************************************************************/
+
+
+
+#define INC_SYS 0x0001 /* Add to system include path */
+#define INC_USER 0x0002 /* Add to user include path */
+
+
+
+/*****************************************************************************/
+/* code */
+/*****************************************************************************/
+
+
+
+void AddIncludePath (char* NewPath, unsigned Where);
+/* Add a new include path to the existing one */
+
+char* FindInclude (char* Name, unsigned Where);
+/* Find an include file. Return a pointer to a malloced area that contains
+ * the complete path, if found, return 0 otherwise.
+ */
+
+
+
+/* End of include.h */
+#endif
+
+
+
--- /dev/null
+
+/* C I/O functions */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+
+#include "asmcode.h"
+#include "global.h"
+#include "error.h"
+#include "mem.h"
+#include "codegen.h"
+#include "optimize.h"
+#include "io.h"
+
+
+
+/*****************************************************************************/
+/* data */
+/*****************************************************************************/
+
+
+
+/* Input line stuff */
+char linebuf [LINESIZE];
+char* line = linebuf;
+char* lptr = 0;
+
+/* Input file table and number of open input files */
+struct filent filetab[MAXFILES];
+int ifile = 0;
+
+/* Current input file stream data */
+FILE* inp = 0;
+char* fin = 0;
+unsigned ln = 0;
+
+
+
+/*****************************************************************************/
+/* code */
+/*****************************************************************************/
+
+
+
+int nch (void)
+/* Get the next char in input stream (the one behind the current one) */
+{
+ if (*lptr == '\0') {
+ return 0;
+ } else {
+ return lptr[1] & 0xFF;
+ }
+}
+
+
+
+int cgch (void)
+/* Get the current character in the input stream and advance line
+ * pointer (unless already at end of line).
+ */
+{
+ if (*lptr == '\0') {
+ return (0);
+ } else {
+ return (*lptr++ & 0xFF);
+ }
+}
+
+
+
+int gch (void)
+/* Get the current character in the input stream and advance line
+ * pointer (no end of line check is performed).
+ */
+{
+ return (*lptr++ & 0xFF);
+}
+
+
+
+void kill (void)
+/* Reset input line pointer, clear input line */
+{
+ lptr = line;
+ *lptr = '\0';
+}
+
+
+
+static void CloseInclude (void)
+/* Close an include file and switch to the higher level file. Set inp to NULL
+ * if this was the main file.
+ */
+{
+ struct filent* pftab;
+
+ /* Close the file */
+ fclose(inp);
+
+ /* Leave the include file */
+ if (ifile > 0) {
+ xfree (fin);
+ inp = (pftab = &filetab[--ifile])->f_iocb;
+ ln = pftab->f_ln;
+ fin = pftab->f_name;
+ } else {
+ inp = 0;
+ }
+}
+
+
+
+int readline (void)
+/* Get a line from the current input. Returns -1 on end of file. */
+{
+ unsigned Len;
+ unsigned Part;
+ unsigned Start;
+ int Done;
+
+ /* Setup the line */
+ kill ();
+
+ /* If there is no file open, bail out */
+ if (inp == 0) {
+ return 0;
+ }
+
+ /* Read lines until we get one with real contents */
+ Len = 0;
+ Done = 0;
+ while (!Done && Len < LINESIZE) {
+
+ while (fgets (line + Len, LINESIZE - Len, inp) == 0) {
+
+ /* eof */
+ kill ();
+
+ /* Leave the current file */
+ CloseInclude ();
+
+ /* If this was the last file, bail out */
+ if (inp == 0) {
+ return 0;
+ }
+ }
+
+ /* We got a new line */
+ ++ln;
+
+ /* Remove the trailing newline if we have one */
+ Part = strlen (line + Len);
+ Start = Len;
+ Len += Part;
+ while (Len > 0 && line [Len-1] == '\n') {
+ --Len;
+ }
+ line [Len] = '\0';
+
+ /* Output the source line in the generated assembler file
+ * if requested.
+ */
+ if (IncSource && line[Start] != '\0') {
+ AddCodeLine ("; %s", line+Start);
+ }
+
+ /* Check if we have a line continuation character at the end. If not,
+ * we're done.
+ */
+ if (Len > 0 && line[Len-1] == '\\') {
+ line[Len-1] = '\n'; /* Replace by newline */
+ } else {
+ Done = 1;
+ }
+ }
+
+ /* Got a line */
+ return 1;
+}
+
+
+
--- /dev/null
+/*
+ * io.h
+ *
+ * Ullrich von Bassewitz, 19.06.1998
+ */
+
+
+
+#ifndef IO_H
+#define IO_H
+
+
+
+#include <stdio.h>
+
+
+
+/*****************************************************************************/
+/* data */
+/*****************************************************************************/
+
+
+
+/* Maximum length of an input line and the corresponding char array */
+#define LINEMAX 4095
+#define LINESIZE LINEMAX+1
+
+/* Maximum number of nested input files */
+#define MAXFILES 16
+
+/* Input line stuff */
+extern char linebuf [LINESIZE];
+extern char* line;
+extern char* lptr;
+
+/* File table entry */
+struct filent {
+ FILE* f_iocb;
+ char* f_name;
+ int f_ln;
+};
+
+/* Input file table and number of open input files */
+extern struct filent filetab[MAXFILES];
+extern int ifile;
+
+/* Current input file stream data */
+extern FILE* inp; /* Input file stream */
+extern char* fin; /* Input file name */
+extern unsigned ln; /* Line number */
+
+
+
+/*****************************************************************************/
+/* code */
+/*****************************************************************************/
+
+
+
+void kill (void);
+/* Reset input line pointer, clear input line */
+
+int nch (void);
+/* Get the next char in input stream (the one behind the current one) */
+
+int cgch (void);
+/* Get the current character in the input stream and advance line
+ * pointer (unless already at end of line).
+ */
+
+int gch (void);
+/* Get the current character in the input stream and advance line
+ * pointer (no end of line check is performed).
+ */
+
+int readline (void);
+/* Get a line from the current input. Returns -1 on end of file. */
+
+
+
+/* End of io.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* litpool.c */
+/* */
+/* Literal string handling for the cc65 C compiler */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+
+#include "asmlabel.h"
+#include "check.h"
+#include "ctrans.h"
+#include "codegen.h"
+#include "error.h"
+#include "global.h"
+#include "litpool.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+#define LITPOOL_SIZE 4096 /* Max strings per function */
+static unsigned char LiteralPool[LITPOOL_SIZE]; /* The literal pool */
+static unsigned LiteralOffs = 0; /* Current pool offset */
+static unsigned LiteralSpace = 0; /* Space used (stats only) */
+
+unsigned LiteralLabel = 1; /* Pool asm label */
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void TranslateLiteralPool (unsigned Offs)
+/* Translate the literals starting from the given offset into the target
+ * charset.
+ */
+{
+ while (Offs < LiteralOffs) {
+ LiteralPool[Offs] = ctrans (LiteralPool[Offs]);
+ ++Offs;
+ }
+}
+
+
+
+void DumpLiteralPool (void)
+/* Dump the literal pool */
+{
+ /* if nothing there, exit... */
+ if (LiteralOffs == 0) {
+ return;
+ }
+
+ /* Switch to the data segment */
+ if (WriteableStrings) {
+ g_usedata ();
+ } else {
+ g_userodata ();
+ }
+
+ /* Define the label */
+ g_defloclabel (LiteralLabel);
+
+ /* Translate the buffer contents into the target charset */
+ TranslateLiteralPool (0);
+
+ /* Output the buffer data */
+ g_defbytes (LiteralPool, LiteralOffs);
+
+ /* Switch back to the code segment */
+ g_usecode ();
+
+ /* Reset the buffer */
+ LiteralSpace += LiteralOffs; /* Count literal bytes emitted */
+ LiteralLabel = GetLabel (); /* Get a new pool label */
+ LiteralOffs = 0;
+}
+
+
+
+unsigned GetLiteralOffs (void)
+/* Return the current offset into the literal pool */
+{
+ return LiteralOffs;
+}
+
+
+
+void ResetLiteralOffs (unsigned Offs)
+/* Reset the offset into the literal pool to some earlier value, effectively
+ * removing values from the pool.
+ */
+{
+ CHECK (Offs <= LiteralOffs);
+ LiteralOffs = Offs;
+}
+
+
+
+void AddLiteralChar (char C)
+/* Add one character to the literal pool */
+{
+ if (LiteralOffs >= LITPOOL_SIZE) {
+ Fatal (FAT_OUT_OF_STRSPACE);
+ }
+ LiteralPool[LiteralOffs++] = C;
+}
+
+
+
+unsigned AddLiteral (const char* S)
+/* Add a literal string to the literal pool. Return the starting offset into
+ * the pool
+ */
+{
+ /* Remember the starting offset */
+ unsigned Start = LiteralOffs;
+
+ /* Copy the string doing a range check */
+ do {
+ AddLiteralChar (*S);
+ } while (*S++);
+
+ /* Return the starting offset */
+ return Start;
+}
+
+
+
+const char* GetLiteral (unsigned Offs)
+/* Get a pointer to the literal with the given offset in the pool */
+{
+ CHECK (Offs < LiteralOffs);
+ return &LiteralPool[Offs];
+}
+
+
+
+void PrintLiteralStats (FILE* F)
+/* Print statistics about the literal space used */
+{
+ fprintf (F, "Literal space used: %d bytes\n", LiteralSpace);
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* litpool.h */
+/* */
+/* Literal string handling for the cc65 C compiler */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef LITPOOL_H
+#define LITPOOL_H
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+extern unsigned LiteralLabel; /* Pool asm label */
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void TranslateLiteralPool (unsigned Offs);
+/* Translate the literals starting from the given offset into the target
+ * charset.
+ */
+
+void DumpLiteralPool (void);
+/* Dump the literal pool */
+
+unsigned GetLiteralOffs (void);
+/* Return the current offset into the literal pool */
+
+void ResetLiteralOffs (unsigned Offs);
+/* Reset the offset into the literal pool to some earlier value, effectively
+ * removing values from the pool.
+ */
+
+void AddLiteralChar (char C);
+/* Add one character to the literal pool */
+
+unsigned AddLiteral (const char* S);
+/* Add a literal string to the literal pool. Return the starting offset into
+ * the pool for this string.
+ */
+
+const char* GetLiteral (unsigned Offs);
+/* Get a pointer to the literal with the given offset in the pool */
+
+void PrintLiteralStats (FILE* F);
+/* Print statistics about the literal space used */
+
+
+
+/* End of litpool.h */
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* locals.c */
+/* */
+/* Local variable handling for the cc65 C compiler */
+/* */
+/* */
+/* */
+/* (C) 2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include "anonname.h"
+#include "asmlabel.h"
+#include "codegen.h"
+#include "declare.h"
+#include "expr.h"
+#include "function.h" /* ## */
+#include "global.h"
+#include "mem.h"
+#include "symtab.h"
+#include "locals.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Register variable management */
+unsigned MaxRegSpace = 6; /* Maximum space available */
+static int RegOffs = 0; /* Offset into register space */
+static const SymEntry** RegSyms = 0; /* The register variables */
+static unsigned RegSymCount = 0; /* Number of register variables */
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void InitRegVars (void)
+/* Initialize register variable control data */
+{
+ /* If the register space is zero, bail out */
+ if (MaxRegSpace == 0) {
+ return;
+ }
+
+ /* The maximum number of register variables is equal to the register
+ * variable space available. So allocate one pointer per byte. This
+ * will usually waste some space but we don't need to dynamically
+ * grow the array.
+ */
+ RegSyms = xmalloc (MaxRegSpace * sizeof (RegSyms[0]));
+ RegOffs = MaxRegSpace;
+}
+
+
+
+void DoneRegVars (void)
+/* Free the register variables */
+{
+ xfree (RegSyms);
+ RegSyms = 0;
+ RegOffs = MaxRegSpace;
+ RegSymCount = 0;
+}
+
+
+
+static int AllocRegVar (const SymEntry* Sym, const type* tarray)
+/* Allocate a register variable with the given amount of storage. If the
+ * allocation was successful, return the offset of the register variable in
+ * the register bank (zero page storage). If there is no register space left,
+ * return -1.
+ */
+{
+ /* Maybe register variables are disabled... */
+ if (EnableRegVars) {
+
+ /* Get the size of the variable */
+ unsigned Size = SizeOf (tarray);
+
+ /* Do we have space left? */
+ if (RegOffs >= Size) {
+
+ /* Space left. We allocate the variables from high to low addresses,
+ * so the adressing is compatible with the saved values on stack.
+ * This allows shorter code when saving/restoring the variables.
+ */
+ RegOffs -= Size;
+ RegSyms [RegSymCount++] = Sym;
+ return RegOffs;
+ }
+ }
+
+ /* No space left or no allocation */
+ return -1;
+}
+
+
+
+void DeclareLocals (void)
+/* Declare local variables and types. */
+{
+ int offs = oursp; /* Current stack offset for variable */
+ int AutoSpace = 0; /* Unallocated space on the stack */
+ int Size; /* Size of an auto variable */
+ int Reg; /* Register variable offset */
+ unsigned flags = 0; /* Code generator flags */
+ int SymbolSC; /* Storage class for symbol */
+ int ldata = 0; /* Local symbol data temp storage */
+
+ /* Loop until we don't find any more variables */
+ while (1) {
+
+ /* Check variable declarations. We need to distinguish between a
+ * default int type and the end of variable declarations. So we
+ * will do the following: If there is no explicit storage class
+ * specifier *and* no explicit type given, it is assume that we
+ * have reached the end of declarations.
+ */
+ DeclSpec Spec;
+ ParseDeclSpec (&Spec, SC_AUTO, T_INT);
+ if ((Spec.Flags & DS_DEF_STORAGE) != 0 && (Spec.Flags & DS_DEF_TYPE) != 0) {
+ break;
+ }
+
+ /* Accept type only declarations */
+ if (curtok == SEMI) {
+ /* Type declaration only ### Check struct/union here */
+ gettok ();
+ continue;
+ }
+
+ /* Parse a comma separated variable list */
+ while (1) {
+
+ Declaration Decl;
+
+ /* Remember the storage class for the new symbol */
+ SymbolSC = Spec.StorageClass;
+
+ /* Read the declaration */
+ ParseDecl (&Spec, &Decl, DM_NEED_IDENT);
+
+ /* If we don't have a name, this was flagged as an error earlier.
+ * To avoid problems later, use an anonymous name here.
+ */
+ if (Decl.Ident[0] == '\0') {
+ AnonName (Decl.Ident, "param");
+ }
+
+ if (!IsFunc (Decl.Type) && (SymbolSC & SC_TYPEDEF) != SC_TYPEDEF) {
+
+ /* Get the size of the variable */
+ Size = SizeOf (Decl.Type);
+
+#if 0
+ /* Check the storage class */
+ if ((SymbolSC & SC_REGISTER) && (Reg = AllocRegVar (psym, tarray)) >= 0) {
+
+ /* We will store the current value of the register onto the
+ * stack, thus making functions with register variables
+ * reentrant. If we have pending auto variables, emit them
+ * now.
+ */
+ g_usecode ();
+ g_space (AutoSpace);
+ oursp -= AutoSpace;
+ AutoSpace = 0;
+
+ /* Remember the register bank offset */
+ ldata = Reg;
+
+ /* Save the current register value onto the stack */
+ g_save_regvars (Reg, Size);
+
+ /* Allow variable initialization */
+ if (curtok == ASGN) {
+
+ struct expent lval;
+
+ /* Skip the '=' */
+ gettok ();
+
+ /* Get the expression into the primary */
+ expression1 (&lval);
+
+ /* Make type adjustments if needed */
+ assignadjust (tarray, &lval);
+
+ /* Setup the type flags for the assignment */
+ flags = TypeOf (tarray) | CF_REGVAR;
+ if (Size == 1) {
+ flags |= CF_FORCECHAR;
+ }
+
+ /* Store the value into the register */
+ g_putstatic (flags, Reg, 0);
+
+ /* Mark the variable as referenced */
+ SymbolSC |= SC_REF;
+
+ }
+
+ /* Account for the stack space needed and remember the
+ * stack offset of the save area.
+ */
+ offs -= Size;
+ psym->h_lattr = offs;
+
+ } else if (SymbolSC & (SC_AUTO | SC_REGISTER)) {
+#endif
+ if (SymbolSC & (SC_AUTO | SC_REGISTER)) {
+
+ /* Auto variable */
+ if (LocalsAreStatic == 0) {
+
+ /* Change SC in case it was register */
+ SymbolSC = (SymbolSC & ~SC_REGISTER) | SC_AUTO;
+ if (curtok == ASGN) {
+
+ struct expent lval;
+
+ /* Switch to the code segment, allocate space for
+ * uninitialized variables.
+ */
+ g_usecode ();
+ g_space (AutoSpace);
+ oursp -= AutoSpace;
+ AutoSpace = 0;
+
+ /* Skip the '=' */
+ gettok ();
+
+ /* Setup the type flags for the assignment */
+ flags = Size == 1? CF_FORCECHAR : CF_NONE;
+
+ /* Get the expression into the primary */
+ if (evalexpr (flags, hie1, &lval) == 0) {
+ /* Constant expression. Adjust the types */
+ assignadjust (Decl.Type, &lval);
+ flags |= CF_CONST;
+ } else {
+ /* Expression is not constant and in the primary */
+ assignadjust (Decl.Type, &lval);
+ }
+
+ /* Push the value */
+ g_push (flags | TypeOf (Decl.Type), lval.e_const);
+
+ /* Mark the variable as referenced */
+ SymbolSC |= SC_REF;
+
+ } else {
+ /* Non-initialized local variable. Just keep track of
+ * the space needed.
+ */
+ AutoSpace += Size;
+ }
+
+ /* Allocate space on the stack, assign the offset */
+ offs -= Size;
+ ldata = offs;
+
+ } else {
+
+ /* Static local variables. */
+ SymbolSC = (SymbolSC & ~(SC_REGISTER | SC_AUTO)) | SC_STATIC;
+
+ /* Put them into the BSS */
+ g_usebss ();
+
+ /* Define the variable label */
+ g_defloclabel (ldata = GetLabel ());
+
+ /* Reserve space for the data */
+ g_res (Size);
+
+ /* Allow assignments */
+ if (curtok == ASGN) {
+
+ struct expent lval;
+
+ /* Switch to the code segment. */
+ g_usecode ();
+
+ /* Skip the '=' */
+ gettok ();
+
+ /* Get the expression into the primary */
+ expression1 (&lval);
+
+ /* Make type adjustments if needed */
+ assignadjust (Decl.Type, &lval);
+
+ /* Setup the type flags for the assignment */
+ flags = TypeOf (Decl.Type);
+ if (Size == 1) {
+ flags |= CF_FORCECHAR;
+ }
+
+ /* Store the value into the variable */
+ g_putstatic (flags, ldata, 0);
+
+ /* Mark the variable as referenced */
+ SymbolSC |= SC_REF;
+ }
+ }
+
+ } else if ((SymbolSC & SC_STATIC) == SC_STATIC) {
+
+ /* Static data */
+ if (curtok == ASGN) {
+
+ /* Initialization ahead, switch to data segment */
+ g_usedata ();
+
+ /* Define the variable label */
+ g_defloclabel (ldata = GetLabel ());
+
+ /* Skip the '=' */
+ gettok ();
+
+ /* Allow initialization of static vars */
+ ParseInit (Decl.Type);
+
+ /* Mark the variable as referenced */
+ SymbolSC |= SC_REF;
+
+ } else {
+
+ /* Uninitialized data, use BSS segment */
+ g_usebss ();
+
+ /* Define the variable label */
+ g_defloclabel (ldata = GetLabel ());
+
+ /* Reserve space for the data */
+ g_res (Size);
+
+ }
+ }
+
+ }
+
+ /* If the symbol is not marked as external, it will be defined */
+ if ((SymbolSC & SC_EXTERN) == 0) {
+ SymbolSC |= SC_DEF;
+ }
+
+ /* Add the symbol to the symbol table */
+ AddLocalSym (Decl.Ident, Decl.Type, SymbolSC, ldata);
+
+ if (curtok != COMMA) {
+ break;
+ }
+ gettok ();
+ }
+ if (curtok == SEMI) {
+ gettok ();
+ }
+ }
+
+ /* In case we switched away from code segment, switch back now */
+ g_usecode ();
+
+ /* Create space for locals */
+ g_space (AutoSpace);
+ oursp -= AutoSpace;
+}
+
+
+
+void RestoreRegVars (int HaveResult)
+/* Restore the register variables for the local function if there are any.
+ * The parameter tells us if there is a return value in ax, in that case,
+ * the accumulator must be saved across the restore.
+ */
+{
+ int I, J, Bytes, Offs;
+
+ /* If we don't have register variables in this function, bail out early */
+ if (RegSymCount == 0) {
+ return;
+ }
+
+ /* Save the accumulator if needed */
+ if (!HasVoidReturn (CurrentFunc) && HaveResult) {
+ g_save (CF_CHAR | CF_FORCECHAR);
+ }
+
+ /* Walk through all variables. If there are several variables in a row
+ * (that is, with increasing stack offset), restore them in one chunk.
+ */
+ I = 0;
+ while (I < RegSymCount) {
+
+ /* Check for more than one variable */
+ const SymEntry* Sym = RegSyms[I];
+ Offs = Sym->V.Offs;
+ Bytes = SizeOf (Sym->Type);
+ J = I+1;
+
+ while (J < RegSymCount) {
+
+ /* Get the next symbol */
+ const SymEntry* NextSym = RegSyms [J];
+
+ /* Get the size */
+ int Size = SizeOf (NextSym->Type);
+
+ /* Adjacent variable? */
+ if (NextSym->V.Offs + Size != Offs) {
+ /* No */
+ break;
+ }
+
+ /* Adjacent variable */
+ Bytes += Size;
+ Offs -= Size;
+ Sym = NextSym;
+ ++J;
+ }
+
+ /* Restore the memory range */
+ g_restore_regvars (Offs, Sym->V.Offs, Bytes);
+
+ /* Next round */
+ I = J;
+ }
+
+ /* Restore the accumulator if needed */
+ if (!HasVoidReturn (CurrentFunc) && HaveResult) {
+ g_restore (CF_CHAR | CF_FORCECHAR);
+ }
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* locals.h */
+/* */
+/* Local variable handling for the cc65 C compiler */
+/* */
+/* */
+/* */
+/* (C) 2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef LOCALS_H
+#define LOCALS_H
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void InitRegVars (void);
+/* Initialize register variable control data */
+
+void DoneRegVars (void);
+/* Free the register variables */
+
+void DeclareLocals (void);
+/* Declare local variables and types. */
+
+void RestoreRegVars (int HaveResult);
+/* Restore the register variables for the local function if there are any.
+ * The parameter tells us if there is a return value in ax, in that case,
+ * the accumulator must be saved across the restore.
+ */
+
+
+
+/* End of locals.h */
+#endif
+
+
+
--- /dev/null
+/*
+ * loop.c
+ *
+ * Ullrich von Bassewitz, 20.06.1998
+ */
+
+
+
+#include "error.h"
+#include "mem.h"
+#include "loop.h"
+
+
+
+/*****************************************************************************/
+/* data */
+/*****************************************************************************/
+
+
+
+/* The root */
+static struct loopdesc* loopstack = 0;
+
+
+
+/*****************************************************************************/
+/* code */
+/*****************************************************************************/
+
+
+
+struct loopdesc* addloop (unsigned sp, unsigned loop, unsigned label,
+ unsigned linc, unsigned lstat)
+/* Create and add a new loop descriptor */
+{
+ struct loopdesc* l;
+
+ /* Allocate a new struct */
+ l = xmalloc (sizeof (struct loopdesc));
+
+ /* Fill in the data */
+ l->sp = sp;
+ l->loop = loop;
+ l->label = label;
+ l->linc = linc;
+ l->lstat = lstat;
+
+ /* Insert it into the list */
+ l->next = loopstack;
+ loopstack = l;
+
+ /* Return a pointer to the struct */
+ return l;
+}
+
+
+
+struct loopdesc* currentloop (void)
+/* Return a pointer to the descriptor of the current loop */
+{
+ if (loopstack == 0) {
+ /* Stack is empty */
+ Error (ERR_NO_ACTIVE_LOOP);
+ }
+ return loopstack;
+}
+
+
+
+void delloop (void)
+/* Remove the current loop */
+{
+ struct loopdesc* l;
+
+ l = loopstack;
+ loopstack = loopstack->next;
+ xfree (l);
+}
+
+
+
--- /dev/null
+/*
+ * loop.h
+ *
+ * Ullrich von Bassewitz, 20.06.1998
+ */
+
+
+
+#ifndef LOOP_H
+#define LOOP_H
+
+
+
+/*****************************************************************************/
+/* data */
+/*****************************************************************************/
+
+
+
+struct loopdesc {
+ struct loopdesc* next;
+ unsigned sp;
+ unsigned loop;
+ unsigned label;
+ unsigned linc;
+ unsigned lstat;
+};
+
+
+
+/*****************************************************************************/
+/* code */
+/*****************************************************************************/
+
+
+
+struct loopdesc* addloop (unsigned sp, unsigned loop, unsigned label,
+ unsigned linc, unsigned lstat);
+/* Create and add a new loop descriptor */
+
+struct loopdesc* currentloop (void);
+/* Return a pointer to the descriptor of the current loop */
+
+void delloop (void);
+/* Remove the current loop */
+
+
+
+/* End of loop.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* macrotab.h */
+/* */
+/* Preprocessor macro table for the cc65 C compiler */
+/* */
+/* */
+/* */
+/* (C) 2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <string.h>
+
+#include "error.h"
+#include "hashstr.h"
+#include "mem.h"
+#include "macrotab.h"
+
+
+
+/*****************************************************************************/
+/* data */
+/*****************************************************************************/
+
+
+
+/* The macro hash table */
+#define MACRO_TAB_SIZE 211
+static Macro* MacroTab[MACRO_TAB_SIZE];
+
+/* A table that holds the count of macros that start with a specific character.
+ * It is used to determine quickly, if an identifier may be a macro or not
+ * without calculating the hash over the name.
+ */
+static unsigned short MacroFlagTab[256];
+
+
+
+/*****************************************************************************/
+/* code */
+/*****************************************************************************/
+
+
+
+Macro* NewMacro (const char* Name)
+/* Allocate a macro structure with the given name. The structure is not
+ * inserted into the macro table.
+ */
+{
+ /* Get the length of the macro name */
+ unsigned Len = strlen(Name);
+
+ /* Allocate the structure */
+ Macro* M = xmalloc (sizeof(Macro) + Len);
+
+ /* Initialize the data */
+ M->Next = 0;
+ M->ArgCount = -1; /* Flag: Not a function like macro */
+ M->MaxArgs = 0;
+ M->FormalArgs = 0;
+ M->ActualArgs = 0;
+ M->Replacement = 0;
+ memcpy (M->Name, Name, Len+1);
+
+ /* Return the new macro */
+ return M;
+}
+
+
+
+void FreeMacro (Macro* M)
+/* Delete a macro definition. The function will NOT remove the macro from the
+ * table, use UndefineMacro for that.
+ */
+{
+ int I;
+
+ for (I = 0; I < M->ArgCount; ++I) {
+ xfree (M->FormalArgs[I]);
+ }
+ xfree (M->FormalArgs);
+ xfree (M->ActualArgs);
+ xfree (M->Replacement);
+ xfree (M);
+}
+
+
+
+void AddNumericMacro (const char* Name, long Val)
+/* Add a macro for a numeric constant */
+{
+ char Buf[64];
+
+ /* Make a string from the number */
+ sprintf (Buf, "%ld", Val);
+
+ /* Handle as text macro */
+ AddTextMacro (Name, Buf);
+}
+
+
+
+void AddTextMacro (const char* Name, const char* Val)
+/* Add a macro for a textual constant */
+{
+ /* Create a new macro */
+ Macro* M = NewMacro (Name);
+
+ /* Set the value as replacement text */
+ M->Replacement = xstrdup (Val);
+
+ /* Insert the macro into the macro table */
+ InsertMacro (M);
+}
+
+
+
+void InsertMacro (Macro* M)
+/* Insert the given macro into the macro table. This call will also allocate
+ * the ActualArgs parameter array.
+ */
+{
+ unsigned Hash;
+
+ /* Allocate the ActualArgs parameter array */
+ if (M->ArgCount > 0) {
+ M->ActualArgs = xmalloc (M->ArgCount * sizeof(char*));
+ }
+
+ /* Get the hash value of the macro name */
+ Hash = HashStr (M->Name) % MACRO_TAB_SIZE;
+
+ /* Insert the macro */
+ M->Next = MacroTab[Hash];
+ MacroTab[Hash] = M;
+
+ /* Increment the number of macros starting with this char */
+ MacroFlagTab[(unsigned)(unsigned char)M->Name[0]]++;
+}
+
+
+
+int UndefineMacro (const char* Name)
+/* Search for the macro with the given name and remove it from the macro
+ * table if it exists. Return 1 if a macro was found and deleted, return
+ * 0 otherwise.
+ */
+{
+ /* Get the hash value of the macro name */
+ unsigned Hash = HashStr (Name) % MACRO_TAB_SIZE;
+
+ /* Search the hash chain */
+ Macro* L = 0;
+ Macro* M = MacroTab[Hash];
+ while (M) {
+ if (strcmp (M->Name, Name) == 0) {
+
+ /* Found it */
+ if (L == 0) {
+ /* First in chain */
+ MacroTab[Hash] = M->Next;
+ } else {
+ L->Next = M->Next;
+ }
+
+ /* Decrement the number of macros starting with this char */
+ MacroFlagTab[(unsigned)(unsigned char)M->Name[0]]--;
+
+ /* Delete the macro */
+ FreeMacro (M);
+
+ /* Done */
+ return 1;
+ }
+
+ /* Next macro */
+ L = M;
+ M = M->Next;
+ }
+
+ /* Not found */
+ return 0;
+}
+
+
+
+Macro* FindMacro (const char* Name)
+/* Find a macro with the given name. Return the macro definition or NULL */
+{
+ /* Get the hash value of the macro name */
+ unsigned Hash = HashStr (Name) % MACRO_TAB_SIZE;
+
+ /* Search the hash chain */
+ Macro* M = MacroTab[Hash];
+ while (M) {
+ if (strcmp (M->Name, Name) == 0) {
+ /* Found it */
+ return M;
+ }
+
+ /* Next macro */
+ M = M->Next;
+ }
+
+ /* Not found */
+ return 0;
+}
+
+
+
+int IsMacro (const char* Name)
+/* Return true if the given name is the name of a macro, return false otherwise */
+{
+ return FindMacro(Name) != 0;
+}
+
+
+
+int MaybeMacro (unsigned char C)
+/* Return true if the given character may be the start of the name of an
+ * existing macro, return false if not.
+ */
+{
+ return (MacroFlagTab[C] > 0);
+}
+
+
+
+const char* FindMacroArg (Macro* M, const char* Arg)
+/* Search for a formal macro argument. If found, return the actual
+ * (replacement) argument. If the argument was not found, return NULL.
+ */
+{
+ int I;
+ for (I = 0; I < M->ArgCount; ++I) {
+ if (strcmp (M->FormalArgs[I], Arg) == 0) {
+ /* Found */
+ return M->ActualArgs[I];
+ }
+ }
+ /* Not found */
+ return 0;
+}
+
+
+
+void AddMacroArg (Macro* M, const char* Arg)
+/* Add a formal macro argument. */
+{
+ /* Check if we have a duplicate macro argument, but add it anyway.
+ * Beware: Don't use FindMacroArg here, since the actual argument array
+ * may not be initialized.
+ */
+ int I;
+ for (I = 0; I < M->ArgCount; ++I) {
+ if (strcmp (M->FormalArgs[I], Arg) == 0) {
+ /* Found */
+ Error (ERR_DUPLICATE_MACRO_ARG, Arg);
+ break;
+ }
+ }
+
+ /* Check if we have enough room available, otherwise expand the array
+ * that holds the formal argument list.
+ */
+ if (M->ArgCount >= M->MaxArgs) {
+ /* We must expand the array */
+ char** OldArgs = M->FormalArgs;
+ M->MaxArgs += 10;
+ M->FormalArgs = xmalloc (M->MaxArgs * sizeof(char*));
+ memcpy (M->FormalArgs, OldArgs, M->ArgCount * sizeof (char*));
+ xfree (OldArgs);
+ }
+
+ /* Add the new argument */
+ M->FormalArgs[M->ArgCount++] = xstrdup (Arg);
+}
+
+
+
+void PrintMacroStats (FILE* F)
+/* Print macro statistics to the given text file. */
+{
+ unsigned I;
+ Macro* M;
+
+ fprintf (F, "\n\nMacro Hash Table Summary\n");
+ for (I = 0; I < MACRO_TAB_SIZE; ++I) {
+ fprintf (F, "%3u : ", I);
+ M = MacroTab [I];
+ if (M) {
+ while (M) {
+ fprintf (F, "%s ", M->Name);
+ M = M->Next;
+ }
+ fprintf (F, "\n");
+ } else {
+ fprintf (F, "empty\n");
+ }
+ }
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* macrotab.h */
+/* */
+/* Preprocessor macro table for the cc65 C compiler */
+/* */
+/* */
+/* */
+/* (C) 2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef MACROTAB_H
+#define MACROTAB_H
+
+
+
+/*****************************************************************************/
+/* data */
+/*****************************************************************************/
+
+
+
+typedef struct Macro_ Macro;
+struct Macro_ {
+ Macro* Next; /* Next macro with same hash value */
+ int ArgCount; /* Number of parameters, -1 = no parens */
+ unsigned MaxArgs; /* Size of formal argument list */
+ char** FormalArgs; /* Formal argument list */
+ char const** ActualArgs; /* Actual argument list */
+ char* Replacement; /* Replacement text */
+ char Name[1]; /* Name, dynamically allocated */
+};
+
+
+
+/*****************************************************************************/
+/* code */
+/*****************************************************************************/
+
+
+
+Macro* NewMacro (const char* Name);
+/* Allocate a macro structure with the given name. The structure is not
+ * inserted into the macro table.
+ */
+
+void FreeMacro (Macro* M);
+/* Delete a macro definition. The function will NOT remove the macro from the
+ * table, use UndefineMacro for that.
+ */
+
+void AddNumericMacro (const char* Name, long Val);
+/* Add a macro for a numeric constant */
+
+void AddTextMacro (const char* Name, const char* Val);
+/* Add a macro for a textual constant */
+
+void InsertMacro (Macro* M);
+/* Insert the given macro into the macro table. This call will also allocate
+ * the ActualArgs parameter array.
+ */
+
+int UndefineMacro (const char* Name);
+/* Search for the macro with the given name and remove it from the macro
+ * table if it exists. Return 1 if a macro was found and deleted, return
+ * 0 otherwise.
+ */
+
+Macro* FindMacro (const char* Name);
+/* Find a macro with the given name. Return the macro definition or NULL */
+
+int IsMacro (const char* Name);
+/* Return true if the given name is the name of a macro, return false otherwise */
+
+int MaybeMacro (unsigned char C);
+/* Return true if the given character may be the start of the name of an
+ * existing macro, return false if not.
+ */
+
+const char* FindMacroArg (Macro* M, const char* Arg);
+/* Search for a formal macro argument. If found, return the actual
+ * (replacement) argument. If the argument was not found, return NULL.
+ */
+
+void AddMacroArg (Macro* M, const char* Arg);
+/* Add a formal macro argument. */
+
+void PrintMacroStats (FILE* F);
+/* Print macro statistics to the given text file. */
+
+
+
+/* End of macrotab.h */
+#endif
+
+
+
+
--- /dev/null
+/* CC65 main program */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "../common/version.h"
+
+#include "asmcode.h"
+#include "asmlabel.h"
+#include "codegen.h"
+#include "datatype.h"
+#include "declare.h"
+#include "error.h"
+#include "expr.h"
+#include "function.h"
+#include "global.h"
+#include "include.h"
+#include "io.h"
+#include "litpool.h"
+#include "macrotab.h"
+#include "mem.h"
+#include "optimize.h"
+#include "pragma.h"
+#include "scanner.h"
+#include "stmt.h"
+#include "symtab.h"
+
+
+
+/*****************************************************************************/
+/* data */
+/*****************************************************************************/
+
+
+
+/* Names of the target systems sorted by target name */
+static const char* TargetNames [] = {
+ "none",
+ "atari",
+ "c64",
+ "c128",
+ "ace",
+ "plus4",
+ "cbm610",
+ "pet",
+ "nes",
+ "apple2",
+ "geos",
+};
+
+
+
+/*****************************************************************************/
+/* code */
+/*****************************************************************************/
+
+
+
+static void usage (int ExitCode)
+{
+ fputs ("Usage: cc65 [options] file\n"
+ "\t-d\t\tDebug mode\n"
+ "\t-g\t\tAdd debug info to object files\n"
+ "\t-h\t\tPrint this help\n"
+ "\t-j\t\tDefault characters are signed\n"
+ "\t-o name\t\tName the output file\n"
+ "\t-tx\t\tSet target system x\n"
+ "\t-v\t\tVerbose mode\n"
+ "\t-A\t\tStrict ANSI mode\n"
+ "\t-Cl\t\tMake local variables static\n"
+ "\t-Dsym[=defn]\tDefine a symbol\n"
+ "\t-I path\t\tSet include directory\n"
+ "\t-O\t\tOptimize code\n"
+ "\t-Oi\t\tOptimize code, inline more code\n"
+ "\t-Or\t\tEnable register variables\n"
+ "\t-Os\t\tInline some known functions\n"
+ "\t-T\t\tInclude source as comment\n"
+ "\t-V\t\tPrint version number\n"
+ "\t-W\t\tSuppress warnings\n",
+ stderr);
+ exit (ExitCode);
+}
+
+
+
+static char* GetArg (int* ArgNum, char* argv [], unsigned Len)
+/* Get an option argument */
+{
+ char* Arg = argv [*ArgNum];
+ if (Arg [Len] != '\0') {
+ /* Argument appended */
+ return Arg + Len;
+ } else {
+ /* Separate argument */
+ Arg = argv [*ArgNum + 1];
+ if (Arg == 0) {
+ /* End of arguments */
+ fprintf (stderr, "Option requires an argument: %s\n", argv [*ArgNum]);
+ exit (EXIT_FAILURE);
+ }
+ ++(*ArgNum);
+ return Arg;
+ }
+}
+
+
+
+/* Define a CBM system */
+static void cbmsys (const char* sys)
+{
+ AddNumericMacro ("__CBM__", 1);
+ AddNumericMacro (sys, 1);
+}
+
+
+
+static int MapSys (const char* Name)
+/* Map a target name to a system code. Return -1 in case of an error */
+{
+ unsigned I;
+
+ /* Check for a numeric target */
+ if (isdigit (*Name)) {
+ int Target = atoi (Name);
+ if (Target >= 0 && Target < TGT_COUNT) {
+ return Target;
+ }
+ }
+
+ /* Check for a target string */
+ for (I = 0; I < TGT_COUNT; ++I) {
+ if (strcmp (TargetNames [I], Name) == 0) {
+ return I;
+ }
+ }
+ /* Not found */
+ return -1;
+}
+
+
+
+/* Define a target system */
+static void SetSys (const char* Sys)
+{
+ switch (Target = MapSys (Sys)) {
+
+ case TGT_NONE:
+ break;
+
+ case TGT_ATARI:
+ AddNumericMacro ("__ATARI__", 1);
+ break;
+
+ case TGT_C64:
+ cbmsys ("__C64__");
+ break;
+
+ case TGT_C128:
+ cbmsys ("__C128__");
+ break;
+
+ case TGT_ACE:
+ cbmsys ("__ACE__");
+ break;
+
+ case TGT_PLUS4:
+ cbmsys ("__PLUS4__");
+ break;
+
+ case TGT_CBM610:
+ cbmsys ("__CBM610__");
+ break;
+
+ case TGT_PET:
+ cbmsys ("__PET__");
+ break;
+
+ case TGT_NES:
+ AddNumericMacro ("__NES__", 1);
+ break;
+
+ case TGT_APPLE2:
+ AddNumericMacro ("__APPLE2__", 1);
+ break;
+
+ case TGT_GEOS:
+ /* Do not handle as a CBM system */
+ AddNumericMacro ("__GEOS__", 1);
+ break;
+
+ default:
+ fputs ("Unknown system type\n", stderr);
+ usage (EXIT_FAILURE);
+ }
+}
+
+
+
+static void InvSym (const char* Def)
+/* Print an error about an invalid macro definition and die */
+{
+ fprintf (stderr, "Invalid macro definition: `%s'\n", Def);
+ exit (EXIT_FAILURE);
+}
+
+
+
+static void DefineSym (const char* Def)
+/* Define a symbol on the command line */
+{
+ const char* P = Def;
+
+ /* The symbol must start with a character or underline */
+ if (Def [0] != '_' && !isalpha (Def [0])) {
+ InvSym (Def);
+ }
+
+ /* Check the symbol name */
+ while (isalnum (*P) || *P == '_') {
+ ++P;
+ }
+
+ /* Do we have a value given? */
+ if (*P != '=') {
+ if (*P != '\0') {
+ InvSym (Def);
+ }
+ /* No value given. Define the macro with the value 1 */
+ AddNumericMacro (Def, 1);
+ } else {
+ /* We have a value, P points to the '=' character. Since the argument
+ * is const, create a copy and replace the '=' in the copy by a zero
+ * terminator.
+ */
+ char* Q;
+ unsigned Len = strlen (Def)+1;
+ char* S = xmalloc (Len);
+ memcpy (S, Def, Len);
+ Q = S + (P - Def);
+ *Q++ = '\0';
+
+ /* Define this as a macro */
+ AddTextMacro (S, Q);
+
+ /* Release the allocated memory */
+ xfree (S);
+ }
+}
+
+
+
+static void Parse (void)
+/* Process all input text.
+ * At this level, only static declarations, defines, includes, and function
+ * definitions are legal....
+ */
+{
+ int comma;
+ SymEntry* Entry;
+
+ kill ();
+ gettok (); /* "prime" the pump */
+ gettok ();
+ while (curtok != CEOF) {
+
+ DeclSpec Spec;
+ Declaration Decl;
+ int NeedStorage;
+
+ /* Check for an ASM statement (which is allowed also on global level) */
+ if (curtok == ASM) {
+ doasm ();
+ ConsumeSemi ();
+ continue;
+ }
+
+ /* Check for a #pragma */
+ if (curtok == PRAGMA) {
+ DoPragma ();
+ continue;
+ }
+
+ /* Read variable defs and functions */
+ ParseDeclSpec (&Spec, SC_EXTERN | SC_STATIC, T_INT);
+
+ /* Don't accept illegal storage classes */
+ if (Spec.StorageClass == SC_AUTO || Spec.StorageClass == SC_REGISTER) {
+ Error (ERR_ILLEGAL_STORAGE_CLASS);
+ Spec.StorageClass = SC_EXTERN | SC_STATIC;
+ }
+
+ /* Check if this is only a type declaration */
+ if (curtok == SEMI) {
+ gettok ();
+ continue;
+ }
+
+ /* Check if we must reserve storage for the variable. We do
+ * this if we don't had a storage class given ("int i") or
+ * if the storage class is explicitly specified as static.
+ * This means that "extern int i" will not get storage
+ * allocated.
+ */
+ NeedStorage = (Spec.StorageClass & SC_TYPEDEF) == 0 &&
+ ((Spec.Flags & DS_DEF_STORAGE) != 0 ||
+ (Spec.StorageClass & (SC_STATIC | SC_EXTERN)) == SC_STATIC);
+
+ /* Read declarations for this type */
+ Entry = 0;
+ comma = 0;
+ while (1) {
+
+ unsigned SymFlags;
+
+ /* Read the next declaration */
+ ParseDecl (&Spec, &Decl, DM_NEED_IDENT);
+ if (Decl.Ident[0] == '\0') {
+ gettok ();
+ break;
+ }
+
+ /* Get the symbol flags */
+ SymFlags = Spec.StorageClass;
+ if (IsFunc (Decl.Type)) {
+ SymFlags |= SC_FUNC;
+ } else {
+ if (NeedStorage) {
+ /* We will allocate storage, variable is defined */
+ SymFlags |= SC_STORAGE | SC_DEF;
+ }
+ }
+
+ /* Add an entry to the symbol table */
+ Entry = AddGlobalSym (Decl.Ident, Decl.Type, SymFlags);
+
+ /* Reserve storage for the variable if we need to */
+ if (SymFlags & SC_STORAGE) {
+
+ /* Get the size of the variable */
+ unsigned Size = SizeOf (Decl.Type);
+
+ /* Allow initialization */
+ if (curtok == ASGN) {
+
+ /* We cannot initialize types of unknown size, or
+ * void types in non ANSI mode.
+ */
+ if (Size == 0) {
+ if (!IsVoid (Decl.Type)) {
+ if (!IsArray (Decl.Type)) {
+ /* Size is unknown and not an array */
+ Error (ERR_UNKNOWN_SIZE);
+ }
+ } else if (ANSI) {
+ /* We cannot declare variables of type void */
+ Error (ERR_ILLEGAL_TYPE);
+ }
+ }
+
+ /* Switch to the data segment */
+ g_usedata ();
+
+ /* Define a label */
+ g_defgloblabel (Entry->Name);
+
+ /* Skip the '=' */
+ gettok ();
+
+ /* Parse the initialization */
+ ParseInit (Entry->Type);
+ } else {
+
+ if (IsVoid (Decl.Type)) {
+ /* We cannot declare variables of type void */
+ Error (ERR_ILLEGAL_TYPE);
+ } else if (Size == 0) {
+ /* Size is unknown */
+ Error (ERR_UNKNOWN_SIZE);
+ }
+
+ /* Switch to the BSS segment */
+ g_usebss ();
+
+ /* Define a label */
+ g_defgloblabel (Entry->Name);
+
+ /* Allocate space for uninitialized variable */
+ g_res (SizeOf (Entry->Type));
+ }
+
+ }
+
+ /* Check for end of declaration list */
+ if (curtok == COMMA) {
+ gettok ();
+ comma = 1;
+ } else {
+ break;
+ }
+ }
+
+ /* Function declaration? */
+ if (IsFunc (Decl.Type)) {
+
+ /* Function */
+ if (!comma) {
+
+ if (curtok == SEMI) {
+
+ /* Prototype only */
+ gettok ();
+
+ } else {
+ if (Entry) {
+ NewFunc (Entry);
+ }
+ }
+ }
+
+ } else {
+
+ /* Must be followed by a semicolon */
+ ConsumeSemi ();
+
+ }
+ }
+}
+
+
+
+static void Compile (void)
+/* Compiler begins execution here. inp is input fd, output is output fd. */
+{
+ char* Path;
+
+
+ /* Setup variables */
+ filetab[0].f_iocb = inp;
+ LiteralLabel = GetLabel ();
+
+ /* Add some standard paths to the include search path */
+ AddIncludePath ("", INC_USER); /* Current directory */
+ AddIncludePath ("include", INC_SYS);
+#ifdef CC65_INC
+ /* Allow modifications of the given string by dup'ing it */
+ AddIncludePath (xstrdup (CC65_INC), INC_SYS);
+#else
+ AddIncludePath ("/usr/lib/cc65/include", INC_SYS);
+#endif
+ Path = getenv ("CC65_INC");
+ if (Path) {
+ AddIncludePath (Path, INC_SYS | INC_USER);
+ }
+
+ /* Add macros that are always defined */
+ AddNumericMacro ("__CC65__", (VER_MAJOR * 0x100) + (VER_MINOR * 0x10) + VER_PATCH);
+
+ /* Strict ANSI macro */
+ if (ANSI) {
+ AddNumericMacro ("__STRICT_ANSI__", 1);
+ }
+
+ /* Optimization macros */
+ if (Optimize) {
+ AddNumericMacro ("__OPT__", 1);
+ if (FavourSize == 0) {
+ AddNumericMacro ("__OPT_i__", 1);
+ }
+ if (EnableRegVars) {
+ AddNumericMacro ("__OPT_r__", 1);
+ }
+ if (InlineStdFuncs) {
+ AddNumericMacro ("__OPT_s__", 1);
+ }
+ }
+
+ /* Create the base lexical level */
+ EnterGlobalLevel ();
+
+ /* Generate the code generator preamble */
+ g_preamble ();
+
+ /* Ok, start the ball rolling... */
+ Parse ();
+
+ /* Dump literal pool. */
+ DumpLiteralPool ();
+
+ /* Write imported/exported symbols */
+ EmitExternals ();
+
+ if (Debug) {
+ PrintLiteralStats (stdout);
+ PrintMacroStats (stdout);
+ }
+
+ /* Leave the main lexical level */
+ LeaveGlobalLevel ();
+
+ /* Print an error report */
+ ErrorReport ();
+}
+
+
+
+int main (int argc, char **argv)
+{
+ int i;
+ char *argp;
+ char out_name [256];
+ char* p;
+
+ /* Initialize the output file name */
+ out_name [0] = '\0';
+
+ fin = NULL;
+
+ /* Parse the command line */
+ for (i = 1; i < argc; i++) {
+ if (*(argp = argv[i]) == '-') {
+ switch (argp[1]) {
+
+ case 'd': /* debug mode */
+ Debug = 1;
+ break;
+
+ case 'h':
+ case '?':
+ usage (EXIT_SUCCESS);
+ break;
+
+ case 'g':
+ DebugInfo = 1;
+ break;
+
+ case 'j':
+ SignedChars = 1;
+ break;
+
+ case 'o':
+ strcpy (out_name, GetArg (&i, argv, 2));
+ break;
+
+ case 't':
+ SetSys (GetArg (&i, argv, 2));
+ break;
+
+ case 'v':
+ ++Verbose;
+ break;
+
+ case 'A':
+ ANSI = 1;
+ break;
+
+ case 'C':
+ p = argp + 2;
+ while (*p) {
+ switch (*p++) {
+ case 'l':
+ LocalsAreStatic = 1;
+ break;
+ }
+ }
+ break;
+
+ case 'D':
+ DefineSym (GetArg (&i, argv, 2));
+ break;
+
+ case 'I':
+ AddIncludePath (GetArg (&i, argv, 2), INC_SYS | INC_USER);
+ break;
+
+ case 'O':
+ Optimize = 1;
+ p = argp + 2;
+ while (*p) {
+ switch (*p++) {
+ case 'f':
+ sscanf (p, "%lx", (long*) &OptDisable);
+ break;
+ case 'i':
+ FavourSize = 0;
+ break;
+ case 'r':
+ EnableRegVars = 1;
+ break;
+ case 's':
+ InlineStdFuncs = 1;
+ break;
+ }
+ }
+ break;
+
+ case 'T':
+ IncSource = 1;
+ break;
+
+ case 'V':
+ fprintf (stderr, "cc65 V%u.%u.%u\n",
+ VER_MAJOR, VER_MINOR, VER_PATCH);
+ break;
+
+ case 'W':
+ NoWarn = 1;
+ break;
+
+ default:
+ fprintf (stderr, "Invalid option %s\n", argp);
+ usage (EXIT_FAILURE);
+ }
+ } else {
+ if (fin) {
+ fprintf (stderr, "additional file specs ignored\n");
+ } else {
+ fin = xstrdup (argp);
+ inp = fopen (fin, "r");
+ if (inp == 0) {
+ Fatal (FAT_CANNOT_OPEN_INPUT, strerror (errno));
+ }
+ }
+ }
+ }
+ if (!fin) {
+ fprintf (stderr, "%s: No input files\n", argv [0]);
+ exit (EXIT_FAILURE);
+ }
+
+ /* Create the output file name. We should really have
+ * some checks for string overflow, but I'll drop this because of the
+ * additional code size it would need (as in other places). Sigh.
+ */
+ if (out_name [0] == '\0') {
+ /* No output name given, create default */
+ strcpy (out_name, fin);
+ if ((p = strrchr (out_name, '.'))) {
+ *p = '\0';
+ }
+ strcat (out_name, ".s");
+ }
+
+ /* Go! */
+ Compile ();
+
+ /* Create the output file if we didn't had any errors */
+ if (ErrorCount == 0 || Debug) {
+
+ FILE* F;
+
+ /* Optimize the output if requested */
+ if (Optimize) {
+ OptDoOpt ();
+ }
+
+ /* Open the file */
+ F = fopen (out_name, "w");
+ if (F == 0) {
+ Fatal (FAT_CANNOT_OPEN_OUTPUT, strerror (errno));
+ }
+
+ /* Write the output to the file */
+ WriteOutput (F);
+
+ /* Close the file, check for errors */
+ if (fclose (F) != 0) {
+ remove (out_name);
+ Fatal (FAT_CANNOT_WRITE_OUTPUT);
+ }
+ }
+
+ /* Return an apropriate exit code */
+ return (ErrorCount > 0)? EXIT_FAILURE : EXIT_SUCCESS;
+}
+
+
--- /dev/null
+#
+# Makefile for CC65.COM.
+#
+
+.SUFFIXES: .o .obj .m65 .c
+
+.c.m65:
+ @echo $<
+ @cc65 -I../lib65/ -O -t4 $<
+
+.m65.obj:
+ ../ra65/ra65 -o $@ ../lib65/ace/global.m65 $<
+
+C_SRCS = code-gen.c error.c expr1.c expr2.c expr3.c function.c mem.c loop.c\
+ globlvar.c io.c scanner.c main.c optimize.c preproc.c\
+ stmt.c symtab.c util.c declare.c
+
+H_SRCS = cc65.h scanner.h error.h mem.h optimize.h code-gen.h function.h\
+ preproc.h util.h symtab.h io.h ctrans.h stmt.h declare.h loop.h\
+ expr.h
+
+M65_FILES = ccmisc.m65 extra.m65 rtextra.m65
+
+OBJS = code-gen.obj error.obj expr1.obj expr2.obj expr3.obj function.obj \
+ globlvar.obj io.obj scanner.obj main.obj\
+ optimize.obj preproc.obj stmt.obj symtab.obj declare.obj loop.obj\
+ ccmisc.obj extra.obj rtextra.obj ctrans.obj mem.obj util.obj
+
+cc65.com: $(OBJS)
+ @../ra65/link65 -t4 -m -o cc65.com ../lib65/ace/crt0.obj $(OBJS)\
+ ../lib65/ace.olb
+
+.PRECIOUS: $(C_SRCS:.c=.m65)
+
+
+$(OBJS) : $(H_SRCS)
+
+clean :
+ rm -f $(OBJS)
+ rm -f $(C_SRCS:.c=.m65)
--- /dev/null
+#
+# Makefile for cross-compiler version of CC65.
+#
+
+
+# Default for the compiler lib search path as compiler define
+CDEFS=-DCC65_INC=\"/usr/lib/cc65/include/\"
+CFLAGS = -O2 -g -Wall $(CDEFS)
+CC=gcc
+LDFLAGS=
+
+OBJS = anonname.o \
+ asmcode.o \
+ asmlabel.o \
+ asmline.o \
+ check.o \
+ codegen.o \
+ ctrans.o \
+ datatype.o \
+ declare.o \
+ error.o \
+ expr.o \
+ funcdesc.o \
+ function.o \
+ global.o \
+ goto.o \
+ hashstr.o \
+ ident.o \
+ include.o \
+ io.o \
+ litpool.o \
+ locals.o \
+ loop.o \
+ macrotab.o \
+ main.o \
+ mem.o \
+ optimize.o \
+ preproc.o \
+ pragma.o \
+ scanner.o \
+ stdfunc.o \
+ stmt.o \
+ symentry.o \
+ symtab.o \
+ util.o
+
+EXECS = cc65
+
+
+.PHONY: all
+ifeq (.depend,$(wildcard .depend))
+all : $(EXECS)
+include .depend
+else
+all: depend
+ @$(MAKE) -f make/gcc.mak all
+endif
+
+
+cc65: $(OBJS)
+ $(CC) $(LDFLAGS) -o cc65 $(CFLAGS) $(OBJS)
+
+clean:
+ rm -f *~ core *.map
+
+zap: clean
+ rm -f *.o $(EXECS) .depend
+
+# ------------------------------------------------------------------------------
+# Make the dependencies
+
+.PHONY: depend dep
+depend dep: $(OBJS:.o=.c)
+ @echo "Creating dependency information"
+ $(CC) -MM $^ > .depend
+
+
--- /dev/null
+#
+# CC65 Makefile for the Watcom compiler
+#
+
+# ------------------------------------------------------------------------------
+# Generic stuff
+
+.AUTODEPEND
+.SUFFIXES .ASM .C .CC .CPP
+.SWAP
+
+AR = WLIB
+LD = WLINK
+
+!if !$d(TARGET)
+!if $d(__OS2__)
+TARGET = OS2
+!else
+TARGET = NT
+!endif
+!endif
+
+# target specific macros.
+!if $(TARGET)==OS2
+
+# --------------------- OS2 ---------------------
+SYSTEM = os2v2
+CC = WCC386
+CCCFG = -bt=$(TARGET) -d1 -onatx -zp4 -5 -zq -w2
+
+!elif $(TARGET)==DOS32
+
+# -------------------- DOS4G --------------------
+SYSTEM = dos4g
+CC = WCC386
+CCCFG = -bt=$(TARGET) -d1 -onatx -zp4 -5 -zq -w2
+
+!elif $(TARGET)==DOS
+
+# --------------------- DOS ---------------------
+SYSTEM = dos
+CC = WCC
+CCCFG = -bt=$(TARGET) -d1 -onatx -zp2 -2 -ml -zq -w2
+
+!elif $(TARGET)==NT
+
+# --------------------- NT ----------------------
+SYSTEM = nt
+CC = WCC386
+CCCFG = -bt=$(TARGET) -d1 -onatx -zp4 -5 -zq -w2
+
+!else
+!error
+!endif
+
+# ------------------------------------------------------------------------------
+# Implicit rules
+
+.c.obj:
+ $(CC) $(CCCFG) $<
+
+
+# ------------------------------------------------------------------------------
+# All library OBJ files
+
+OBJS = anonname.obj \
+ asmcode.obj \
+ asmlabel.obj \
+ asmline.obj \
+ check.obj \
+ codegen.obj \
+ ctrans.obj \
+ datatype.obj \
+ declare.obj \
+ error.obj \
+ expr.obj \
+ funcdesc.obj \
+ function.obj \
+ global.obj \
+ goto.obj \
+ hashstr.obj \
+ ident.obj \
+ include.obj \
+ io.obj \
+ litpool.obj \
+ locals.obj \
+ loop.obj \
+ macrotab.obj \
+ main.obj \
+ mem.obj \
+ optimize.obj \
+ pragma.obj \
+ preproc.obj \
+ stmt.obj \
+ scanner.obj \
+ stdfunc.obj \
+ symentry.obj \
+ symtab.obj \
+ util.obj
+
+
+.PRECIOUS $(OBJS:.obj=.c)
+
+# ------------------------------------------------------------------------------
+# Main targets
+
+all: cc65
+
+cc65: cc65.exe
+
+
+# ------------------------------------------------------------------------------
+# Other targets
+
+
+cc65.exe: $(OBJS)
+ $(LD) system $(SYSTEM) @&&|
+DEBUG ALL
+OPTION QUIET
+NAME $<
+FILE anonname.obj
+FILE asmcode.obj
+FILE asmlabel.obj
+FILE asmline.obj
+FILE check.obj
+FILE codegen.obj
+FILE ctrans.obj
+FILE datatype.obj
+FILE declare.obj
+FILE error.obj
+FILE expr.obj
+FILE funcact.obj
+FILE funcdesc.obj
+FILE function.obj
+FILE global.obj
+FILE goto.obj
+FILE hashstr.obj
+FILE ident.obj
+FILE include.obj
+FILE io.obj
+FILE litpool.obj
+FILE locals.obj
+FILE loop.obj
+FILE macrotab.obj
+FILE main.obj
+FILE mem.obj
+FILE optimize.obj
+FILE pragma.obj
+FILE preproc.obj
+FILE stmt.obj
+FILE scanner.obj
+FILE stdfunc.obj
+FILE symentry.obj
+FILE symtab.obj
+FILE util.obj
+|
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* MEMCHECK.CC */
+/* */
+/* (C) 1995 Ullrich von Bassewitz */
+/* Zwehrenbuehlstrasse 33 */
+/* D-72070 Tuebingen */
+/* EMail: uz@ibb.schwaben.com */
+/* */
+/*****************************************************************************/
+
+
+
+// Poor man's memory checker. Overloads the global operators new and delete
+// and does some additional checks if the variable MemCheck is set to true:
+//
+// * Check if an allocated block is already allocated (heap corrupt)
+// * Check if a block that should be freed is allocated
+// * Check if there have been writes outside the blocks bounds (by
+// adding a signature to the end)
+// * Check if new does not provide a NULL pointer.
+
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#ifdef __WATCOMC__
+# include <malloc.h>
+#endif
+
+#include "check.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+typedef unsigned long u32;
+
+
+
+// Signature of a memory block
+static u32 MemSig = 0x12785634;
+
+// Switch memory checking on or off
+int MemCheck = 0;
+
+// Switch memory filling on or off
+int MemFill = 0;
+
+// Validation on each call?
+int MemValidate = 0;
+
+// Don't really free blocks
+int MemDontFree = 0;
+
+// Logfile for allocations/deallocations
+static const char* MemLogFile = 0;
+static FILE* LogFile = 0;
+
+// Statistics
+u32 MemNewCount = 0;
+u32 MemDelCount = 0;
+u32 MemDelNULLCount = 0;
+u32 MemNewCheckCount = 0;
+u32 MemDelCheckCount = 0;
+u32 MemLargestBlock = 0;
+u32 MemUsage = 0;
+u32 MemMaxUsage = 0;
+
+// This is the fill value for memory blocks if MemFill is true. On intel
+// architectures, this is the code for "INT 3", an instruction that is
+// often used by debuggers as a breakpoint.
+unsigned char FillVal = 0xCC;
+
+
+
+/*****************************************************************************/
+/* struct BlockInfo */
+/*****************************************************************************/
+
+
+
+typedef struct {
+ unsigned char* Ptr;
+ u32 Size;
+} BlockInfo;
+
+//
+const int FirstChunk = 2000;
+const int Delta = 1000;
+
+// Variables needed
+static int IsInitialized = 0;
+static int BlockCount = 0;
+static int BlockLimit = 0;
+static BlockInfo* Blocks = 0;
+
+
+
+/*****************************************************************************/
+/* class BlockInfoColl */
+/*****************************************************************************/
+
+
+
+static void MemSetCount (int NewCount)
+// Make shure, there is space for NewSize blocks in Blocks
+{
+ if (NewCount > BlockLimit) {
+ // OOPS, need realloc
+ if (BlockLimit == 0 && NewCount <= FirstChunk) {
+ BlockLimit = FirstChunk;
+ } else {
+ BlockLimit = ((NewCount / Delta) + 1) * Delta;
+ }
+ Blocks = (BlockInfo*) realloc (Blocks, BlockLimit * sizeof (BlockInfo));
+ }
+ BlockCount = NewCount;
+}
+
+
+
+static int MemSearch (const unsigned char* Ptr, int* Index)
+// Search for the block. Return 1 if the block is found (Index holds the
+// block index in this case). Return 0 if the block is not found and return
+// in Index the index where the block should be inserted.
+{
+ // do a binary search
+ int First = 0;
+ int Last = BlockCount - 1;
+ int Current;
+ int S = 0;
+
+ while (First <= Last) {
+
+ // Set current to mid of range
+ Current = (Last + First) / 2;
+
+ // Do a compare
+ if (Blocks [Current].Ptr < Ptr) {
+ First = Current + 1;
+ } else {
+ Last = Current - 1;
+ if (Blocks [Current].Ptr == Ptr) {
+ // Found.
+ S = 1; // function result
+ // Set condition to terminate loop
+ First = Current;
+ }
+ }
+
+ }
+
+ *Index = First;
+ return S;
+}
+
+
+
+static void MemDelBlock (int Index)
+// Delete the block with the given index
+{
+ BlockCount--;
+ memmove (Blocks+Index, Blocks+Index+1, (BlockCount-Index) * sizeof (BlockInfo));
+}
+
+
+
+static void MemInsBlock (int Index, unsigned char* Ptr, u32 Size)
+{
+ // Set the new size
+ MemSetCount (BlockCount + 1);
+
+ // We can insert the element. If the item is not inserted at the end
+ // of the collection, we must create a "hole"
+ if (Index != BlockCount - 1) {
+ memmove (Blocks + Index + 1,
+ Blocks + Index,
+ (BlockCount - 1 - Index) * sizeof (BlockInfo));
+ }
+
+ // store the new data
+ Blocks [Index].Ptr = Ptr;
+ Blocks [Index].Size = Size;
+}
+
+
+
+u32 MemBlocksInUse ()
+{
+ return (u32) BlockCount;
+}
+
+
+
+static void PrintContents (const void* B, unsigned Size, FILE* F)
+// Print the contents of the block
+{
+ unsigned I;
+ static const unsigned MaxPrint = 14;
+
+ const unsigned char* P = (const unsigned char*) B;
+ if (Size > MaxPrint) {
+ Size = MaxPrint;
+ }
+
+ // Two characters space
+ fprintf (F, " ");
+
+ // Print the first few bytes in hex
+ for (I = 0; I < Size; I++) {
+ fprintf (F, "%02X ", P [I]);
+ }
+ fprintf (F, "%*s ", (MaxPrint-Size)*3, "");
+
+ // Print the bytes again in ASCII
+ for (I = 0; I < Size; I++) {
+ unsigned char C = P [I];
+ if (C < ' ' || C > 0x7E) {
+ C = '.';
+ }
+ putc (C, F);
+ }
+}
+
+
+
+void MemLogBlocksInUse (const char* Name)
+{
+ BlockInfo* Block;
+ int I;
+
+ FILE* F = fopen (Name, "w+t");
+ if (F == 0) {
+ // This is a debug function, so ignore the error
+ return;
+ }
+
+ // Get the block count and log some statistics
+ fprintf (F, "Blocks currently in use: %8lu\n\n"
+ "Calls to operator new: %8lu\n"
+ "Calls to operator delete: %8lu\n"
+ "Checked calls to new: %8lu\n"
+ "Checked calls to delete: %8lu\n"
+ "Calls to delete with a NULL arg: %8lu\n\n"
+ "Largest block allocated: %8lu\n"
+ "Maximum memory usage: %8lu\n\n",
+ (unsigned long) BlockCount,
+ (unsigned long) MemNewCount,
+ (unsigned long) MemDelCount,
+ (unsigned long) MemNewCheckCount,
+ (unsigned long) MemDelCheckCount,
+ (unsigned long) MemDelNULLCount,
+ (unsigned long) MemLargestBlock,
+ (unsigned long) MemMaxUsage);
+
+ // Print a header
+ fprintf (F, "Num Address Size Contents\n");
+ fprintf (F, "----------------------------------------"
+ "---------------------------------------\n");
+
+ // Log the blocks
+ Block = Blocks;
+ for (I = 0; I < BlockCount; I++, Block++) {
+
+ // Print a line describing the block (convert pointers to hex values)
+ fprintf (F, "%-5u %08lX %5lu",
+ I, (unsigned long) Block->Ptr, (unsigned long) Block->Size);
+
+ // Print the first few bytes of the block
+ PrintContents (Block->Ptr, Block->Size, F);
+
+ // Check the block signature
+ if (memcmp (Block->Ptr + Block->Size, &MemSig, sizeof (MemSig)) != 0) {
+ // Signature overwritten
+ fprintf (F, " *** Signature overwritten ***\n");
+ } else {
+ fprintf (F, "\n");
+ }
+
+ }
+
+ // Close the file
+ fclose (F);
+}
+
+
+
+static long MemValidateBlocks ()
+// Validate all memory blocks. Return the index of a block where the
+// validation failed, otherwise return -1.
+{
+ // Validate the blocks
+ long I;
+ BlockInfo* Block = Blocks;
+ for (I = 0; I < BlockCount; I++, Block++) {
+
+ // Check the block signature
+ if (memcmp (Block->Ptr + Block->Size, &MemSig, sizeof (MemSig)) != 0) {
+ // Signature overwritten
+ return I;
+ }
+ }
+
+ // All is well...
+ return -1;
+}
+
+
+
+static void MemDone ()
+// Log the memory blocks if requested. Does *not* delete the block array
+// since the startup code may release memory after calling the exit functions
+// and in this case we will work with a freed block, if we free the block
+// array here
+{
+ // If the environment variable MEMLOGBLOCKS is set to something, use
+ // this "something" as a filename to log a list of still allocated blocks
+ const char* Name = getenv ("MEMLOGBLOCKS");
+ if (Name) {
+ MemLogBlocksInUse (Name);
+ }
+}
+
+
+
+static void MemInit ()
+// Initialize the memory checker.
+{
+ // Get the defaults for the memory checker
+ const char* Fill;
+ MemCheck = getenv ("MEMCHECK") != 0;
+ MemValidate = getenv ("MEMVALIDATE") != 0;
+ MemDontFree = getenv ("MEMDONTFREE") != 0;
+ MemLogFile = getenv ("MEMLOGFILE");
+ Fill = getenv ("MEMFILL");
+ if (Fill) {
+ MemFill = 1;
+ if (isdigit (*Fill)) {
+ FillVal = atoi (Fill);
+ }
+ }
+
+ // Open the logfile if set
+ if (MemLogFile) {
+ LogFile = fopen (MemLogFile, "w+t");
+ }
+
+ // Register the exit function
+ atexit (MemDone);
+
+ // Initialized now (maybe set already)
+ IsInitialized = 1;
+}
+
+
+
+/*****************************************************************************/
+/* Allocate/free blocks */
+/*****************************************************************************/
+
+
+
+static void* MemAlloc (size_t Size)
+{
+ unsigned char* Ptr;
+
+ // Last allocated block is remembered here
+ static void* LastBlock = 0;
+
+ // Initialize the memory checker on the first call
+ if (IsInitialized == 0) {
+ MemInit ();
+ }
+
+ // Count the calls to new
+ MemNewCount++;
+
+ // Update largest block info
+ if (Size > MemLargestBlock) {
+ MemLargestBlock = Size;
+ }
+ if (MemCheck) {
+
+ int Index;
+
+ // Count the checked calls
+ MemNewCheckCount++;
+
+ // If we need to validate all blocks, do that
+ if (MemValidate) {
+ long I = MemValidateBlocks ();
+ if (I != -1) {
+ // We have a problem. Be shure to switch of MemValidate before
+ // calling FAIL, otherwise we will get an endless loop...
+ MemValidate = 0;
+ FAIL ("MemCheck: Block signature overwritten!");
+ }
+ }
+
+ // Update memory usage
+ MemUsage += Size;
+ if (MemUsage > MemMaxUsage) {
+ MemMaxUsage = MemUsage;
+ }
+
+ // Get a memory block
+ Ptr = (unsigned char*) malloc (Size + sizeof (MemSig));
+
+ // Make a signature at the end of the block
+ memcpy (Ptr + Size, &MemSig, sizeof (MemSig));
+
+ // Search for the block
+ if (MemSearch (Ptr, &Index) != 0) {
+ // An item with this key exists. This means that the heap is
+ // corrupted
+ FAIL ("MemCheck: Duplicate block!");
+ } else {
+ // The returned pointer is not in the collection of already
+ // allocated blocks, but it may point inside of an already
+ // allocated block. Check this.
+ // Note: Index is the index of the item _before the given
+ // pointer, so simply check the range of the entry with index
+ // Index.
+ if (Index > 0) {
+ // There is a block that's memory address is less than the
+ // one returned by malloc
+ const BlockInfo* BB = Blocks + Index - 1;
+ if (Ptr < BB->Ptr + BB->Size) {
+ // Pointer points inside the block below - heap corrupted
+ FAIL ("MemCheck: Heap corrupt!");
+ }
+ }
+
+ // Heap ok, insert the new block
+ MemInsBlock (Index, Ptr, Size);
+ }
+
+ } else {
+
+ // No memory checking. Allocate a memory block, but beware: New is
+ // defined so that "new char [0]" points to a distinct object every
+ // time it is called, so one cannot return NULL for a size of 0!
+ Ptr = (unsigned char*) malloc (Size ? Size : 1);
+
+ }
+
+ // Remember the last block
+ LastBlock = Ptr;
+
+ // Check if we got memory, fail otherwise
+ if (Ptr == 0) {
+ FAIL ("MemCheck: Out of memory");
+ }
+
+ // Fill the memory block if requested
+ if (MemFill) {
+ memset (Ptr, FillVal, Size);
+ }
+
+ // Log the allocation if requested
+ if (LogFile) {
+ // Print a line describing the block (convert pointers to hex values)
+ fprintf (LogFile, "A %08lX %5lu",
+ (unsigned long) Ptr, (unsigned long) Size);
+
+ // Print the first few bytes of the block
+ PrintContents (Ptr, Size, LogFile);
+ fprintf (LogFile, "\n");
+ }
+
+ // Return a pointer to the memory block
+ return Ptr;
+}
+
+
+
+static void MemFree (void* P)
+{
+ // We cannot call delete if the memory system is not initialized
+ if (IsInitialized == 0) {
+ FAIL ("MemCheck: Trying to delete a block before the first call to new!");
+ }
+
+ // Count the calls to delete
+ MemDelCount++;
+
+ // Deleting NULL pointers is always ok, nothing has to be done
+ if (P == 0) {
+ MemDelNULLCount++;
+ return;
+ }
+
+ if (MemCheck) {
+
+ int Index;
+ unsigned char* Ptr;
+
+ // Count the calls
+ MemDelCheckCount++;
+
+ // If we need to validate all blocks, do that
+ if (MemValidate) {
+ long I = MemValidateBlocks ();
+ if (I != -1) {
+ // We have a problem. Be shure to switch of MemValidate before
+ // calling FAIL, otherwise we will get an endless loop...
+ MemValidate = 0;
+ FAIL ("MemCheck: Block signature overwritten!");
+ }
+ }
+
+ // Cast the pointer
+ Ptr = (unsigned char*) P;
+
+ // Search for the block
+ if (MemSearch (Ptr, &Index) != 0) {
+
+ // The block exists.
+ BlockInfo* BI = Blocks + Index;
+
+ // Log the deallocation if requested
+ if (LogFile) {
+ // Print a line describing the block (convert pointers to hex values)
+ fprintf (LogFile, "D %08lX %5lu",
+ (unsigned long) BI->Ptr, (unsigned long) BI->Size);
+
+ // Print the first few bytes of the block
+ PrintContents (BI->Ptr, BI->Size, LogFile);
+ fprintf (LogFile, "\n");
+ }
+
+ // Check the signature
+ if (memcmp (Ptr + BI->Size, &MemSig, sizeof (MemSig)) != 0) {
+ // Signature overwritten
+ FAIL ("MemCheck: Block signature overwritten");
+ }
+
+ // Fill the memory block if requested
+ if (MemFill) {
+ memset (Ptr, FillVal, BI->Size);
+ }
+
+ // Should the block really be freed?
+ if (MemDontFree == 0) {
+
+ // Update memory usage
+ MemUsage -= BI->Size;
+
+ // Delete the entry
+ MemDelBlock (Index);
+
+ // Delete the memory block
+ free (P);
+
+ }
+
+ } else {
+ // Trying to free a block that is not allocated
+ FAIL ("MemCheck: Trying to free a block that is not allocated");
+ }
+ } else {
+
+ // Free the block without checks
+ free (P);
+
+ }
+}
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void* xmalloc (size_t Size)
+{
+ return MemAlloc (Size);
+}
+
+
+
+void xfree (const void* P)
+{
+ MemFree ((void*)P);
+}
+
+
+
+char* xstrdup (const char* S)
+{
+ unsigned Len = strlen (S) + 1;
+ return memcpy (xmalloc (Len), S, Len);
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* mem.h */
+/* */
+/* Safe memory allocation for the cc65 C compiler */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef MEM_H
+#define MEM_H
+
+
+
+#include <stddef.h>
+
+
+
+/*****************************************************************************/
+/* data */
+/*****************************************************************************/
+
+
+
+extern size_t memmax;
+
+
+
+/*****************************************************************************/
+/* code */
+/*****************************************************************************/
+
+
+
+void* xmalloc (size_t size);
+/* Allocate memory, check for out of memory condition. Do some debugging */
+
+void xfree (const void* block);
+/* Free the block, do some debugging */
+
+char* xstrdup (const char* s);
+/* Duplicate a string on the heap. The function checks for out of memory */
+
+
+
+/* End of mem.h */
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* optimize.c */
+/* */
+/* An optimizer for the cc65 C compiler */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "asmlabel.h"
+#include "asmline.h"
+#include "check.h"
+#include "error.h"
+#include "global.h"
+#include "io.h"
+#include "mem.h"
+#include "optimize.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Bitset of flags that switch the different optimizer passes */
+unsigned long OptDisable = 0;
+
+
+
+/* Bitmapped flags for the Flags field in the Line struct */
+#define OF_CODE 0x0001 /* This line is in a code segment */
+
+/* Pointer to first code line */
+static Line* FirstCode;
+
+/* Label list */
+static Line** Labels = 0; /* Pointers to label lines */
+static unsigned LabelCount = 0; /* Count of local labels found */
+
+/* A collection of lines */
+typedef struct LineColl_ LineColl;
+struct LineColl_ {
+ unsigned Count; /* Count of lines in the collection */
+ unsigned Max; /* Maximum count of lines */
+ Line* Lines[1]; /* Lines, dynamically allocated */
+};
+
+
+
+/* Calculate the element count of a table */
+#define COUNT(T) (sizeof (T) / sizeof (T [0]))
+
+/* Macro to increment and decrement register contents if they're valid */
+#define INC(reg,val) if ((reg) >= 0) (reg) = ((reg) + val) & 0xFF
+#define DEC(reg,val) if ((reg) >= 0) (reg) = ((reg) - val) & 0xFF
+
+/* Defines for the conditions in a compare */
+#define CMP_EQ 0
+#define CMP_NE 1
+#define CMP_GT 2
+#define CMP_GE 3
+#define CMP_LT 4
+#define CMP_LE 5
+#define CMP_UGT 6
+#define CMP_UGE 7
+#define CMP_ULT 8
+#define CMP_ULE 9
+
+/* Defines for registers */
+#define REG_NONE 0x00
+#define REG_A 0x01
+#define REG_X 0x02
+#define REG_Y 0x04
+#define REG_AX (REG_A | REG_X)
+#define REG_ALL (REG_A | REG_X | REG_Y)
+
+/* Description of the commands */
+static const struct {
+ const char* Insn; /* Instruction */
+ unsigned char FullMatch; /* Match full instuction? */
+ unsigned char Use; /* Registers used */
+ unsigned char Load; /* Registers loaded */
+} CmdDesc [] = {
+ { "\tadc\t", 0, REG_A, REG_NONE },
+ { "\tand\t", 0, REG_A, REG_NONE },
+ { "\tasl\ta", 1, REG_A, REG_NONE },
+ { "\tasl\t", 0, REG_NONE, REG_NONE },
+ { "\tclc", 1, REG_NONE, REG_NONE },
+ { "\tcld", 1, REG_NONE, REG_NONE },
+ { "\tcli", 1, REG_NONE, REG_NONE },
+ { "\tcmp\t", 0, REG_A, REG_NONE },
+ { "\tcpx\t", 0, REG_X, REG_NONE },
+ { "\tcpy\t", 0, REG_Y, REG_NONE },
+ { "\tdec\t", 0, REG_NONE, REG_NONE },
+ { "\tdex", 1, REG_X, REG_NONE },
+ { "\tdey", 1, REG_Y, REG_NONE },
+ { "\teor\t", 0, REG_A, REG_NONE },
+ { "\tinc\t", 0, REG_NONE, REG_NONE },
+ { "\tinx", 1, REG_X, REG_NONE },
+ { "\tiny", 1, REG_Y, REG_NONE },
+ { "\tjsr\tbool", 0, REG_NONE, REG_AX },
+ { "\tjsr\tdecaxy", 1, REG_ALL, REG_AX },
+ { "\tjsr\tdecax", 0, REG_AX, REG_AX },
+ { "\tjsr\tldax0sp", 1, REG_Y, REG_AX },
+ { "\tjsr\tldaxysp", 1, REG_Y, REG_AX },
+ { "\tjsr\tpusha", 1, REG_A, REG_Y },
+ { "\tjsr\tpusha0", 1, REG_A, REG_X | REG_Y },
+ { "\tjsr\tpushax", 1, REG_AX, REG_Y },
+ { "\tjsr\tpushw0sp", 1, REG_NONE, REG_ALL },
+ { "\tjsr\tpushwysp", 1, REG_Y, REG_ALL },
+ { "\tjsr\ttosicmp", 1, REG_AX, REG_ALL },
+ { "\tlda\t", 0, REG_NONE, REG_A },
+ { "\tldax\t", 0, REG_NONE, REG_AX },
+ { "\tldx\t", 0, REG_NONE, REG_X },
+ { "\tldy\t", 0, REG_NONE, REG_Y },
+ { "\tlsr\ta", 1, REG_A, REG_NONE },
+ { "\tlsr\t", 0, REG_NONE, REG_NONE },
+ { "\tnop", 1, REG_NONE, REG_NONE },
+ { "\tora\t", 0, REG_A, REG_NONE },
+ { "\tpha", 1, REG_A, REG_NONE },
+ { "\tphp", 1, REG_NONE, REG_NONE },
+ { "\tpla", 1, REG_NONE, REG_A },
+ { "\tplp", 1, REG_NONE, REG_NONE },
+ { "\trol\ta", 1, REG_A, REG_A },
+ { "\trol\t", 0, REG_NONE, REG_NONE },
+ { "\tror\ta", 1, REG_A, REG_A },
+ { "\tror\t", 0, REG_NONE, REG_NONE },
+ { "\tsbc\t", 0, REG_A, REG_NONE },
+ { "\tsec", 1, REG_NONE, REG_NONE },
+ { "\tsed", 1, REG_NONE, REG_NONE },
+ { "\tsei", 1, REG_NONE, REG_NONE },
+ { "\tsta\t", 0, REG_A, REG_NONE },
+ { "\tstx\t", 0, REG_X, REG_NONE },
+ { "\tsty\t", 0, REG_Y, REG_NONE },
+ { "\ttax", 1, REG_A, REG_X },
+ { "\ttay", 1, REG_A, REG_Y },
+ { "\ttsx", 1, REG_NONE, REG_X },
+ { "\ttxa", 1, REG_X, REG_A },
+ { "\ttya", 1, REG_Y, REG_A },
+};
+
+
+
+/* Table with the compare suffixes */
+static const char CmpSuffixTab [][4] = {
+ "eq", "ne", "gt", "ge", "lt", "le", "ugt", "uge", "ult", "ule"
+};
+
+/* Table used to invert a condition, indexed by condition */
+static const unsigned char CmpInvertTab [] = {
+ CMP_NE, CMP_EQ,
+ CMP_LE, CMP_LT, CMP_GE, CMP_GT,
+ CMP_ULE, CMP_ULT, CMP_UGE, CMP_UGT
+};
+
+/* Table to show which compares are signed (use the N flag) */
+static const char CmpSignedTab [] = {
+ 0, 0, 1, 1, 1, 1, 0, 0, 0, 0
+};
+
+
+
+/* Lists of branches */
+static const char* ShortBranches [] = {
+ "\tbeq\t",
+ "\tbne\t",
+ "\tbpl\t",
+ "\tbmi\t",
+ "\tbcc\t",
+ "\tbcs\t",
+ "\tbvc\t",
+ "\tbvs\t",
+ 0
+};
+static const char* LongBranches [] = {
+ "\tjeq\t",
+ "\tjne\t",
+ "\tjpl\t",
+ "\tjmi\t",
+ "\tjcc\t",
+ "\tjcs\t",
+ "\tjvc\t",
+ "\tjvs\t",
+ 0
+};
+
+
+
+/*****************************************************************************/
+/* Forwards */
+/*****************************************************************************/
+
+
+
+static unsigned EstimateSize (Line* L);
+/* Estimate the size of an instruction */
+
+static int IsLocalLabel (const Line* L);
+/* Return true if the line is a local label line */
+
+static unsigned GetLabelNum (const char* L);
+/* Return the label number of a label line */
+
+static unsigned RVUInt1 (Line* L, LineColl* LC, unsigned Used, unsigned Unused);
+/* Subfunction for RegValUsed. Will be called recursively in case of branches. */
+
+
+
+/*****************************************************************************/
+/* List stuff */
+/*****************************************************************************/
+
+
+
+static Line* NewLineAfter (Line* LineBefore, const char* Format, ...)
+/* Create a new line, insert it after L and return it. The new line is marked
+ * as code line.
+ */
+{
+ Line* L;
+
+ /* Format the new line and add it */
+ va_list ap;
+ va_start (ap, Format);
+ L = NewCodeLineAfter (LineBefore, Format, ap);
+ va_end (ap);
+
+ /* Make the line a code line */
+ L->Flags = OF_CODE;
+
+ /* Estimate the code size */
+ L->Size = EstimateSize (L);
+
+ /* Return the new line */
+ return L;
+}
+
+
+
+static Line* NewLabelAfter (Line* L, unsigned Label)
+/* Add a new line with a definition of a local label after the line L */
+{
+ char Buf [32];
+
+ /* Create the label */
+ sprintf (Buf, "L%04X:", Label);
+
+ /* Create a new line */
+ L = NewLineAfter (L, Buf);
+
+ /* Insert this label into the label list */
+ Labels [Label] = L;
+
+ /* Return the new line */
+ return L;
+}
+
+
+
+static void FreeLine (Line* L)
+/* Remove a line from the list and free it */
+{
+ /* If this is a label line, remove it from the label list */
+ if (IsLocalLabel (L)) {
+ Labels [GetLabelNum (L->Line)] = 0;
+ }
+
+ /* Unlink the line */
+ FreeCodeLine (L);
+}
+
+
+
+static Line* ReplaceLine (Line* L, const char* Format, ...)
+/* Replace one line by another */
+{
+ unsigned Len;
+ char S [256];
+
+ /* Format the new line */
+ va_list ap;
+ va_start (ap, Format);
+ vsprintf (S, Format, ap);
+ va_end (ap);
+
+ /* Get the length of the new line */
+ Len = strlen (S);
+
+ /* We can copy the line if the old line has space enough */
+ if (Len <= L->Len) {
+
+ /* Just copy the new line, but don't update the length */
+ memcpy (L->Line, S, Len);
+ L->Line [Len] = '\0';
+
+ } else {
+
+ /* We must allocate new space */
+ Line* NewLine = xmalloc (sizeof (Line) + Len);
+
+ /* Set the values in the new struct */
+ NewLine->Flags = L->Flags;
+ NewLine->Index = L->Index;
+ NewLine->Size = L->Size; /* Hmm ... */
+ NewLine->Len = Len;
+ memcpy (NewLine->Line, S, Len + 1);
+
+ /* Replace the old struct in the list */
+ NewLine->Next = L->Next;
+ if (NewLine->Next) {
+ NewLine->Next->Prev = NewLine;
+ } else {
+ /* Last line */
+ LastLine = NewLine;
+ }
+ NewLine->Prev = L->Prev;
+ if (NewLine->Prev) {
+ NewLine->Prev->Next = NewLine;
+ } else {
+ /* First line */
+ FirstLine = NewLine;
+ }
+
+ /* Free the old struct */
+ xfree (L);
+ L = NewLine;
+ }
+
+ /* Estimate the new size */
+ if (L->Flags & OF_CODE) {
+ L->Size = EstimateSize (L);
+ }
+
+ /* Return the line */
+ return L;
+}
+
+
+
+static Line* PrevCodeLine (Line* L)
+/* Return the previous line containing code */
+{
+ L = L->Prev;
+ while (L) {
+ if (L->Flags & OF_CODE && L->Line [0] != '+') {
+ break;
+ }
+ L = L->Prev;
+ }
+ return L;
+}
+
+
+
+static Line* NextCodeSegLine (Line* L)
+/* Return the next line in the code segment */
+{
+ L = L->Next;
+ while (L) {
+ if (L->Flags & OF_CODE) {
+ break;
+ }
+ L = L->Next;
+ }
+ return L;
+}
+
+
+
+static Line* NextCodeLine (Line* L)
+/* Return the next line containing code */
+{
+ L = L->Next;
+ while (L) {
+ if ((L->Flags & OF_CODE) != 0 && L->Line [0] != '+') {
+ break;
+ }
+ L = L->Next;
+ }
+ return L;
+}
+
+
+
+static Line* NextInstruction (Line* L)
+/* Return the next line containing code, ignoring labels. */
+{
+ do {
+ L = NextCodeLine (L);
+ } while (L && (L->Line[0] == '+' || IsLocalLabel(L)));
+ return L;
+}
+
+
+
+static void FreeLines (Line* Start, Line* End)
+/* Delete all lines from Start to End, both inclusive */
+{
+ Line* L;
+ do {
+ L = Start;
+ Start = NextCodeSegLine (Start);
+ FreeLine (L);
+ } while (L != End);
+}
+
+
+
+/*****************************************************************************/
+/* Line Collections */
+/*****************************************************************************/
+
+
+
+static LineColl* NewLineColl (unsigned Size)
+/* Create a new line collection and return it */
+{
+ /* Allocate memory */
+ LineColl* LC = xmalloc (sizeof (LineColl) + sizeof (Line) * (Size-1));
+
+ /* Initialize members */
+ LC->Count = 0;
+ LC->Max = Size;
+
+ /* Return the new collection */
+ return LC;
+}
+
+
+
+static void FreeLineColl (LineColl* LC)
+/* Delete a line collection */
+{
+ xfree (LC);
+}
+
+
+
+static int LCAddLine (LineColl* LC, Line* L)
+/* Add a line. Return 0 if no space available, return 1 otherwise */
+{
+ /* Check if there is enough space available */
+ if (LC->Count >= LC->Max) {
+ /* No room available */
+ return 0;
+ }
+
+ /* Add the line */
+ LC->Lines [LC->Count++] = L;
+
+ /* Done */
+ return 1;
+}
+
+
+
+static int LCHasLine (LineColl* LC, Line* L)
+/* Check if the given line is in the collection */
+{
+ unsigned I;
+ for (I = 0; I < LC->Count; ++I) {
+ if (LC->Lines[I] == L) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+
+/*****************************************************************************/
+/* Test a line for several things */
+/*****************************************************************************/
+
+
+
+static int IsLocalLabel (const Line* L)
+/* Return true if the line is a local label line */
+{
+ return (L->Line [0] == 'L' && isxdigit (L->Line [1]));
+}
+
+
+
+static int IsLabel (const Line* L)
+/* Return true if the line is a label line */
+{
+ return (L->Line [0] == 'L' && isxdigit (L->Line [1])) ||
+ (L->Line [0] == '_');;
+}
+
+
+
+static int IsHintLine (const Line* L)
+/* Return true if the line contains an optimizer hint */
+{
+ return L->Line [0] == '+';
+}
+
+
+
+static int IsSegHint (const Line* L)
+/* Return true if the given line contains a segment hint */
+{
+ return (L->Line [0] == '+' && strncmp (L->Line + 1, "seg:", 4) == 0);
+}
+
+
+
+static int IsHint (const Line* L, const char* Hint)
+/* Check if the line contains a given hint */
+{
+ return (L->Line [0] == '+' && strcmp (L->Line + 1, Hint) == 0);
+}
+
+
+
+static int IsCondJump (Line* L)
+/* Return true if the line contains a conditional jump */
+{
+ return (L->Line [0] == '\t' &&
+ (strncmp (L->Line + 1, "beq\t", 4) == 0 ||
+ strncmp (L->Line + 1, "bne\t", 4) == 0 ||
+ strncmp (L->Line + 1, "jeq\t", 4) == 0 ||
+ strncmp (L->Line + 1, "jne\t", 4) == 0));
+}
+
+
+
+static int IsXIndAddrMode (Line* L)
+/* Return true if the given line does use the X register */
+{
+ unsigned Len = strlen (L->Line);
+ return (strcmp (L->Line + Len - 3, ",x)") == 0 ||
+ strcmp (L->Line + Len - 2, ",x") == 0);
+}
+
+
+
+static int NoXIndAddrMode (Line* L)
+/* Return true if the given line does use the X register */
+{
+ return !IsXIndAddrMode (L);
+}
+
+
+
+static int IsYIndAddrMode (Line* L)
+/* Return true if the given line does use the Y register */
+{
+ unsigned Len = strlen (L->Line);
+ return (strcmp (L->Line + Len - 2, ",y") == 0);
+}
+
+
+
+static Line* FindHint (Line* L, const char* Hint)
+/* Search for a line with the given hint */
+{
+ while (L) {
+ if (IsHint (L, Hint)) {
+ break;
+ }
+ L = L->Next;
+ }
+ return L;
+}
+
+
+
+static unsigned GetHexNum (const char* S)
+/* Get a hex number from a string */
+{
+ unsigned I = 0;
+ unsigned Val = 0;
+ while (isxdigit (S [I])) {
+ int C = (unsigned char) (S [I++]);
+ if (C >= 'A') {
+ C -= 'A' - 10;
+ } else {
+ C -= '0';
+ }
+ Val = (Val << 4) + C;
+ }
+ return Val;
+}
+
+
+
+static unsigned GetLabelNum (const char* L)
+/* Return the label number of a label line */
+{
+ CHECK (*L == 'L');
+ return GetHexNum (L+1);
+}
+
+
+
+static Line* GetTargetLine (const char* L)
+/* Get the line with the target label of a jump. L must be a pointer to the
+ * string containing the label number.
+ */
+{
+ Line* Target;
+
+ /* Get the label number of the target */
+ unsigned Label = GetLabelNum (L);
+ CHECK (Label < LabelCount);
+
+ /* Get the line with this label */
+ Target = Labels [Label];
+ CHECK (Target != 0 && (Target->Flags & OF_CODE) != 0);
+
+ /* And return it */
+ return Target;
+}
+
+
+
+static unsigned GetJumpDistance (Line* L, Line* Target)
+/* Get the distance between both lines */
+{
+ unsigned Distance = 0;
+
+ if (L != Target) {
+ if (Target->Index > L->Index) {
+ /* This is a forward jump. */
+ do {
+ L = NextCodeLine (L);
+ Distance += L->Size;
+ } while (L != Target);
+ } else {
+ /* This is a backward jump */
+ do {
+ L = PrevCodeLine (L);
+ Distance += L->Size;
+ } while (L != Target);
+ }
+ }
+
+ /* Return the calculated distance */
+ return Distance;
+}
+
+
+
+static int LineMatch (const Line* L, const char* Start)
+/* Check if the start of the line matches Start */
+{
+ return strncmp (L->Line, Start, strlen (Start)) == 0;
+}
+
+
+
+static int LineFullMatch (const Line* L, const char* Start)
+/* Check if the matches Start */
+{
+ return strcmp (L->Line, Start) == 0;
+}
+
+
+
+static int LineMatchX (const Line* L, const char** Start)
+/* Check the start of the line against a list of patterns. Return the
+ * number of the pattern that matched, or -1 in case of no match.
+ */
+{
+ unsigned I = 0;
+ while (*Start) {
+ if (LineMatch (L, *Start)) {
+ /* Found */
+ return I;
+ }
+ ++Start;
+ ++I;
+ }
+ /* Not found */
+ return -1;
+}
+
+
+
+static int LineFullMatchX (const Line* L, const char** Start)
+/* Check the the line against a list of patterns. Return the
+ * number of the pattern that matched, or -1 in case of no match.
+ */
+{
+ unsigned I = 0;
+ while (*Start) {
+ if (LineFullMatch (L, *Start)) {
+ /* Found */
+ return I;
+ }
+ ++Start;
+ ++I;
+ }
+ /* Not found */
+ return -1;
+}
+
+
+
+static int IsLoadAX (Line* L1, Line* L2)
+/* Check if the both lines load a static variable into ax. That is, both lines
+ * look like
+ * lda x+0
+ * ldx x+0+1
+ */
+{
+ return LineMatch (L1, "\tlda\t") &&
+ LineMatch (L2, "\tldx\t") &&
+ strncmp (L1->Line+5, L2->Line+5, strlen (L1->Line+5)) == 0 &&
+ strcmp (L2->Line+strlen(L1->Line), "+1") == 0;
+}
+
+
+
+/*****************************************************************************/
+/* Initial optimizer setup */
+/*****************************************************************************/
+
+
+
+static void FindCodeStart (void)
+/* Find and remember the first line of actual code */
+{
+ Line* L = FindHint (FirstLine, "end_of_preamble");
+ FirstCode = L? L->Next : 0;
+}
+
+
+
+static unsigned EstimateDataSize (Line* L, unsigned Chunk)
+/* Estimate the size of a .byte, .word or .dword command */
+{
+ unsigned Size = Chunk;
+ char* S = L->Line;
+ while ((S = strchr (S, ',')) != 0) {
+ Size += Chunk;
+ ++S;
+ }
+ return Size;
+}
+
+
+
+static unsigned EstimateSize (Line* L)
+/* Estimate the size of an instruction */
+{
+ static const char* Transfers [] = {
+ "\ttax",
+ "\ttay",
+ "\ttsx",
+ "\ttxa",
+ "\ttya",
+ 0
+ };
+ char OpStart;
+
+ if (L->Line [0] != '\t') {
+ return 0;
+ }
+ if (LineMatch (L, "\tldax\t")) {
+ /* Immidiate load of both, A and X */
+ return 4;
+ }
+ if (LineMatch (L, "\tld")) {
+ OpStart = L->Line [5];
+ return (OpStart == '#' || OpStart == '(')? 2 : 3;
+ }
+ if (LineMatch (L, "\tst")) {
+ OpStart = L->Line [5];
+ return (OpStart == '(')? 2 : 3;
+ }
+ if (LineMatch (L, "\t.byte\t")) {
+ return EstimateDataSize (L, 1);
+ }
+ if (LineMatch (L, "\t.word\t")) {
+ return EstimateDataSize (L, 2);
+ }
+ if (LineMatch (L, "\t.dword\t")) {
+ return EstimateDataSize (L, 4);
+ }
+ if (LineMatchX (L, ShortBranches) >= 0) {
+ return 2;
+ }
+ if (LineMatchX (L, LongBranches) >= 0) {
+ return 5;
+ }
+ if (LineMatchX (L, Transfers) >= 0) {
+ return 1;
+ }
+ return 3;
+}
+
+
+
+static void MarkCodeLines (void)
+/* Mark all lines that are inside a code segment */
+{
+ int InCode = 1;
+ Line* L = FirstCode;
+ while (L) {
+ if (IsSegHint (L)) {
+ InCode = IsHint (L, "seg:code");
+ } else if (InCode && L->Line[0] != '\0') {
+ L->Flags |= OF_CODE;
+ L->Size = EstimateSize (L);
+ }
+ L = L->Next;
+ }
+}
+
+
+
+static void CreateLabelList (void)
+/* Create a list with pointers to local labels */
+{
+ unsigned I;
+ Line* L;
+
+
+ /* Get the next label number. This is also the current label count.
+ * Make some room for more labels when optimizing code.
+ */
+ LabelCount = GetLabel () + 100;
+
+ /* Allocate memory for the array and clear it */
+ Labels = xmalloc (LabelCount * sizeof (Line*));
+ for (I = 0; I < LabelCount; ++I) {
+ Labels [I] = 0;
+ }
+
+ /* Walk through the code and insert all label lines */
+ L = FirstLine;
+ while (L) {
+ if (IsLocalLabel (L)) {
+ unsigned LabelNum = GetLabelNum (L->Line);
+ CHECK (LabelNum < LabelCount);
+ Labels [LabelNum] = L;
+ }
+ L = L->Next;
+ }
+}
+
+
+
+static unsigned AllocLabel (void)
+/* Get a new label. The current code does not realloc the label list, so there
+ * must be room enough in the current list.
+ */
+{
+ unsigned I;
+
+ /* Search for a free slot, start at 1, since 0 is "no label" */
+ for (I = 1; I < LabelCount; ++I) {
+ if (Labels[I] == 0) {
+ /* Found a free slot */
+ return I;
+ }
+ }
+
+ /* No label space available */
+ Internal ("Out of label space in the optimizer");
+
+ /* Not reached */
+ return 0;
+}
+
+
+
+/*****************************************************************************/
+/* Helper functions */
+/*****************************************************************************/
+
+
+
+static int GetNextCodeLines (Line* L, Line** Lines, unsigned Count)
+/* Get a number of code lines ignoring hints and other stuff. The function
+ * returns 1 if we got the lines and 0 if we are at the end of the code
+ * segment or if we hit a label.
+ */
+{
+ while (Count--) {
+
+ /* Get the next valid line */
+ do {
+ L = NextCodeLine (L);
+ } while (L && IsHintLine (L));
+
+ /* Did we get one? */
+ if (L == 0 || IsLabel (L)) {
+ /* Error */
+ return 0;
+ }
+
+ /* Remember the line */
+ *Lines++ = L;
+ }
+
+ /* Success */
+ return 1;
+}
+
+
+
+static int FindCond (const char* Suffix)
+/* Map a condition suffix to a code. Return the code or -1 on failure */
+{
+ int I;
+
+ /* Linear search */
+ for (I = 0; I < sizeof (CmpSuffixTab) / sizeof (CmpSuffixTab [0]); ++I) {
+ if (strncmp (Suffix, CmpSuffixTab [I], strlen (CmpSuffixTab[I])) == 0) {
+ /* Found */
+ return I;
+ }
+ }
+
+ /* Not found */
+ return -1;
+}
+
+
+
+static int CheckAndGetIntCmp (const Line* JSR, const Line* JMP)
+/* Helper function to check for a compare subroutine call followed by a
+ * conditional branch. Will return the condition found, or -1 if no
+ * or invalid condition.
+ */
+{
+ char Cond[5];
+ const char* Tail;
+ int C;
+
+ /* Extract the condition from the function name. */
+ if ((Cond [0] = JSR->Line [8]) == 'u') {
+ Cond [1] = JSR->Line [9];
+ Cond [2] = JSR->Line [10];
+ Cond [3] = '\0';
+ Tail = JSR->Line + 11;
+ } else {
+ Cond [1] = JSR->Line [9];
+ Cond [2] = '\0';
+ Tail = JSR->Line + 10;
+ }
+
+ /* Check if this is indeed an integer function */
+ if (strcmp (Tail, "ax") != 0) {
+ /* No! */
+ return -1;
+ }
+
+ /* Get the condition code */
+ C = FindCond (Cond);
+ if (C < 0) {
+ /* OOPS! */
+ return -1;
+ }
+
+ /* Invert the code if we jump on condition not met. */
+ if (JMP->Line [2] == 'e' && JMP->Line [3] == 'q') {
+ /* Jumps if condition false, invert condition */
+ C = CmpInvertTab [C];
+ }
+
+ /* Return the condition code */
+ return C;
+}
+
+
+
+static int TosCmpFunc (Line* L)
+/* Check if this is a call to one of the TOS compare functions (tosgtax).
+ * Return the condition code or -1 if not found.
+ */
+{
+ if (LineMatch (L, "\tjsr\ttos") &&
+ strcmp (L->Line+strlen(L->Line)-2, "ax") == 0) {
+
+ /* Ok, found. Get the condition. */
+ return FindCond (L->Line+8);
+
+ } else {
+
+ /* Not found */
+ return -1;
+ }
+}
+
+
+
+static int IsUnsignedCmp (int Code)
+/* Check if this is an unsigned compare */
+{
+ CHECK (Code >= 0);
+ return CmpSignedTab [Code] == 0;
+}
+
+
+
+static void InvertZJump (Line* L)
+/* Invert a jeq/jne jump */
+{
+ if (L->Line [2] == 'n' && L->Line [3] == 'e') {
+ /* This was a bne/jne */
+ L->Line [2] = 'e';
+ L->Line [3] = 'q';
+ } else {
+ /* This was (hopefully) a beq/jeq */
+ L->Line [2] = 'n';
+ L->Line [3] = 'e';
+ }
+}
+
+
+
+static int FindCmd (Line* L)
+{
+ int I;
+
+ /* Search for the known patterns */
+ for (I = 0; I < COUNT(CmdDesc); ++I) {
+ if (CmdDesc[I].FullMatch) {
+ if (LineFullMatch (L, CmdDesc[I].Insn)) {
+ /* found */
+ return I;
+ }
+ } else {
+ if (LineMatch (L, CmdDesc[I].Insn)) {
+ /* found */
+ return I;
+ }
+ }
+ }
+ /* Not found */
+ return -1;
+}
+
+
+
+static unsigned RVUInt2 (Line* L,
+ LineColl* LC, /* To remember visited lines */
+ unsigned Used, /* Definitely used registers */
+ unsigned Unused) /* Definitely unused registers */
+/* Subfunction for RegValUsed. Will be called recursively in case of branches. */
+{
+ int I;
+
+ /* Check the following instructions. We classifiy them into primary
+ * loads (register value not used), neutral (check next instruction),
+ * and unknown (assume register was used).
+ */
+ while (1) {
+
+ unsigned R;
+
+ /* Get the next line and follow jumps */
+ do {
+
+ /* Handle jumps to local labels (continue there) */
+ if (LineMatch (L, "\tjmp\tL")) {
+ /* Get the target of the jump */
+ L = GetTargetLine (L->Line+5);
+ }
+
+ /* Get the next instruction line */
+ L = NextInstruction (L);
+
+ /* Bail out if we're done */
+ if (L == 0 || IsLabel (L)) {
+ /* Something is wrong */
+ return REG_ALL;
+ }
+
+ /* Check if we had this line already. If so, bail out, if not,
+ * add it to the list of known lines.
+ */
+ if (LCHasLine (LC, L) || !LCAddLine (LC, L)) {
+ goto ExitPoint;
+ }
+
+ } while (LineMatch (L, "\tjmp\tL"));
+
+ /* Special handling for branches */
+ if (LineMatchX (L, ShortBranches) >= 0 ||
+ LineMatchX (L, LongBranches) >= 0) {
+ const char* Target = L->Line+5;
+ if (Target[0] == 'L') {
+ /* Jump to local label. Check the register usage starting at
+ * the branch target and at the code following the branch.
+ * All registers that are unused in both execution flows are
+ * returned as unused.
+ */
+ unsigned U1, U2;
+ U2 = RVUInt1 (GetTargetLine (Target), LC, Used, Unused);
+ U1 = RVUInt1 (L, LC, Used, Unused);
+ return U1 | U2; /* Used in any of the branches */
+ }
+ }
+
+ /* Search for the instruction in this line */
+ I = FindCmd (L);
+
+ /* If we don't find it, assume all other registers are */
+ if (I < 0) {
+ break;
+ }
+
+ /* Evaluate the use flags, check for addressing modes */
+ R = CmdDesc[I].Use;
+ if (IsXIndAddrMode (L)) {
+ R |= REG_X;
+ } else if (IsYIndAddrMode (L)) {
+ R |= REG_Y;
+ }
+ if (R) {
+ /* Remove registers that were already new loaded */
+ R &= ~Unused;
+
+ /* Remember the remaining registers */
+ Used |= R;
+ }
+
+ /* Evaluate the load flags */
+ R = CmdDesc[I].Load;
+ if (R) {
+ /* Remove registers that were already used */
+ R &= ~Used;
+
+ /* Remember the remaining registers */
+ Unused |= R;
+ }
+
+ /* If we know about all registers, bail out */
+ if ((Used | Unused) == REG_ALL) {
+ break;
+ }
+ }
+
+ExitPoint:
+ /* Return to the caller the complement of all unused registers */
+ return ~Unused & REG_ALL;
+}
+
+
+
+static unsigned RVUInt1 (Line* L,
+ LineColl* LC, /* To remember visited lines */
+ unsigned Used, /* Definitely used registers */
+ unsigned Unused) /* Definitely unused registers */
+/* Subfunction for RegValUsed. Will be called recursively in case of branches. */
+{
+ /* Remember the current count of the line collection */
+ unsigned Count = LC->Count;
+
+ /* Call the worker routine */
+ unsigned R = RVUInt2 (L, LC, Used, Unused);
+
+ /* Restore the old count */
+ LC->Count = Count;
+
+ /* Return the result */
+ return R;
+}
+
+
+
+static unsigned RegValUsed (Line* Start)
+/* Check the next instructions after the one in L for register usage. If
+ * a register is used as an index, or in a store or other instruction, it
+ * is assumed to be used. If a register is loaded with a value, before it
+ * was used by one of the actions described above, it is assumed unused.
+ * If the end of the lookahead is reached, all registers that are uncertain
+ * are marked as used.
+ * The result of the search is returned.
+ */
+{
+ unsigned R;
+
+ /* Create a new line collection and enter the start line */
+ LineColl* LC = NewLineColl (256);
+ LCAddLine (LC, Start);
+
+ /* Call the recursive subfunction */
+ R = RVUInt1 (Start, LC, REG_NONE, REG_NONE);
+
+ /* Delete the line collection */
+ FreeLineColl (LC);
+
+ /* Return the registers used */
+ return R;
+}
+
+
+
+static int RegAUsed (Line* Start)
+/* Check if the value in A is used. */
+{
+ return (RegValUsed (Start) & REG_A) != 0;
+}
+
+
+
+static int RegXUsed (Line* Start)
+/* Check if the value in X is used. */
+{
+ return (RegValUsed (Start) & REG_X) != 0;
+}
+
+
+
+static int RegYUsed (Line* Start)
+/* Check if the value in Y is used. */
+{
+ return (RegValUsed (Start) & REG_Y) != 0;
+}
+
+
+
+/*****************************************************************************/
+/* Real optimizer routines */
+/*****************************************************************************/
+
+
+
+static void OptCompares1 (void)
+/* Try to optimize the integer compare subroutines. */
+{
+ Line* L2[10]; /* Line lookahead */
+ int Cond; /* Condition to evaluate */
+ unsigned Label; /* Local label number */
+ unsigned Offs; /* Stack offset */
+ Line* DelStart; /* First line to delete */
+
+ Line* L = FirstCode;
+ while (L) {
+
+ /* Search for compares of local byte sized variables. This looks
+ * like:
+ *
+ * ldy #$xx
+ * ldx #$00
+ * lda (sp),y
+ * jsr pushax
+ * ldy #$yy
+ * ldx #$00
+ * lda (sp),y
+ * jsr tosugtax
+ *
+ * Replace it by a direct compare:
+ *
+ * ldy #$xx
+ * lda (sp),y
+ * ldy #$yy
+ * cmp (sp),y
+ * jsr boolugt
+ */
+ if (LineMatch (L, "\tldy\t#$") &&
+ GetNextCodeLines (L, L2, 7) &&
+ LineFullMatch (L2[0], "\tldx\t#$00") &&
+ LineFullMatch (L2[1], "\tlda\t(sp),y") &&
+ LineFullMatch (L2[2], "\tjsr\tpushax") &&
+ LineMatch (L2[3], "\tldy\t#$") &&
+ LineFullMatch (L2[4], "\tldx\t#$00") &&
+ LineFullMatch (L2[5], "\tlda\t(sp),y") &&
+ (Cond = TosCmpFunc (L2[6])) >= 0) {
+
+ /* Get the stack offset and correct it, since we will remove
+ * the pushax.
+ */
+ Offs = GetHexNum (L2[3]->Line+7) - 2;
+
+ /* Replace it */
+ L = NewLineAfter (L, "\tlda\t(sp),y");
+ L = NewLineAfter (L, "\tldy\t#$%02X", Offs);
+ L = NewLineAfter (L, "\tcmp\t(sp),y");
+ L = NewLineAfter (L, "\tjsr\tbool%s", CmpSuffixTab[Cond]);
+
+ /* Remove the old cruft */
+ FreeLines (L2[0], L2[6]);
+ }
+
+ /* Compares of byte sized global variables */
+ else if (LineFullMatch (L, "\tldx\t#$00") &&
+ GetNextCodeLines (L, L2, 5) &&
+ LineMatch (L2[0], "\tlda\t") &&
+ LineFullMatch (L2[1], "\tjsr\tpushax") &&
+ LineFullMatch (L2[2], "\tldx\t#$00") &&
+ LineMatch (L2[3], "\tlda\t") &&
+ (Cond = TosCmpFunc (L2[4])) >= 0) {
+
+ /* Replace it */
+ if (IsXIndAddrMode (L2[0])) {
+ /* The load is X indirect, so we may not remove the load
+ * of the X register.
+ */
+ L = L2[0];
+ DelStart = L2[1];
+ } else {
+ L = ReplaceLine (L, L2[0]->Line);
+ DelStart = L2[0];
+ }
+ L = NewLineAfter (L, "\tcmp\t%s", L2[3]->Line+5);
+ L = NewLineAfter (L, "\tjsr\tbool%s", CmpSuffixTab[Cond]);
+
+ /* Remove the old cruft */
+ FreeLines (DelStart, L2[4]);
+
+ }
+
+ /* Byte sized local to global */
+ else if (LineMatch (L, "\tldy\t#$") &&
+ GetNextCodeLines (L, L2, 6) &&
+ LineFullMatch (L2[0], "\tldx\t#$00") &&
+ LineFullMatch (L2[1], "\tlda\t(sp),y") &&
+ LineFullMatch (L2[2], "\tjsr\tpushax") &&
+ LineFullMatch (L2[3], "\tldx\t#$00") &&
+ LineMatch (L2[4], "\tlda\t") &&
+ (Cond = TosCmpFunc (L2[5])) >= 0) {
+
+ /* Replace it */
+ L = NewLineAfter (L, L2[1]->Line);
+ L = NewLineAfter (L, "\tcmp\t%s", L2[4]->Line+5);
+ L = NewLineAfter (L, "\tjsr\tbool%s", CmpSuffixTab[Cond]);
+
+ /* Remove the old cruft */
+ FreeLines (L2[0], L2[5]);
+
+ }
+
+ /* Byte sized global to local */
+ else if (LineFullMatch (L, "\tldx\t#$00") &&
+ GetNextCodeLines (L, L2, 6) &&
+ LineMatch (L2[0], "\tlda\t") &&
+ LineFullMatch (L2[1], "\tjsr\tpushax") &&
+ LineMatch (L2[2], "\tldy\t#$") &&
+ LineFullMatch (L2[3], "\tldx\t#$00") &&
+ LineFullMatch (L2[4], "\tlda\t(sp),y") &&
+ (Cond = TosCmpFunc (L2[5])) >= 0) {
+
+ /* Get the stack offset and correct it, since we will remove
+ * the pushax.
+ */
+ Offs = GetHexNum (L2[2]->Line+7) - 2;
+
+ /* Replace it */
+ if (IsXIndAddrMode (L2[0])) {
+ /* The load is X indirect, so we may not remove the load
+ * of the X register.
+ */
+ L = L2[0];
+ DelStart = L2[1];
+ } else {
+ L = ReplaceLine (L, L2[0]->Line);
+ DelStart = L2[0];
+ }
+ L = NewLineAfter (L, "\tldy\t#$%02X", Offs);
+ L = NewLineAfter (L, "\tcmp\t(sp),y");
+ L = NewLineAfter (L, "\tjsr\tbool%s", CmpSuffixTab[Cond]);
+
+ /* Remove the old cruft */
+ FreeLines (DelStart, L2[5]);
+
+ }
+
+ /* Search for unsigned compares against global variables. This looks
+ * like:
+ *
+ * jsr pushax
+ * lda _b+0
+ * ldx _b+0+1
+ * jsr tosugtax
+ *
+ * Replace that by a direct compare:
+ *
+ * cpx _b+0+1
+ * bne L
+ * cmp _b+0
+ * L:
+ * jsr boolugt
+ */
+ else if (LineFullMatch (L, "\tjsr\tpushax") &&
+ GetNextCodeLines (L, L2, 3) &&
+ IsLoadAX (L2[0], L2[1]) &&
+ (Cond = TosCmpFunc (L2[2])) >= 0 &&
+ IsUnsignedCmp (Cond)) {
+
+ /* Get a free label number */
+ Label = AllocLabel ();
+
+ /* Replace the code */
+ L = ReplaceLine (L, "\tcpx\t%s", L2[1]->Line+5);
+ L = NewLineAfter (L, "\tbne\tL%04X", Label);
+ L = NewLineAfter (L, "\tcmp\t%s", L2[0]->Line+5);
+ L = NewLabelAfter(L, Label);
+ L = NewLineAfter (L, "\tjsr\tbool%s", CmpSuffixTab[Cond]);
+
+ /* Remove the old code */
+ FreeLines (L2[0], L2[2]);
+
+ }
+
+ L = NextCodeLine (L);
+ }
+}
+
+
+
+static void OptDeadJumps (void)
+/* Remove jumps to the following instruction */
+{
+ static const char* Jumps [] = {
+ "\tbeq\tL",
+ "\tbne\tL",
+ "\tjeq\tL",
+ "\tjne\tL",
+ "\tjmp\tL",
+ 0
+ };
+
+ Line* L = FirstCode;
+ while (L) {
+
+ /* Get a pointer to the next instruction line */
+ Line* NextLine = NextInstruction (L);
+
+ /* Is this line a jump? */
+ int I = LineMatchX (L, Jumps);
+ if (I >= 0) {
+ /* Yes. Get the target label, skip labels */
+ Line* Target = NextInstruction (GetTargetLine (L->Line+5));
+
+ /* If the target label is the next line, remove the jump */
+ if (Target == NextLine) {
+ FreeLine (L);
+ }
+ }
+
+ /* Go to the next line */
+ L = NextLine;
+ }
+}
+
+
+
+static void OptLoads (void)
+/* Remove unnecessary loads of values */
+{
+ Line* L2 [10];
+
+ Line* L = FirstCode;
+ while (L) {
+
+ /* Check for
+ *
+ * ldy #$..
+ * lda (sp),y
+ * tax
+ * dey
+ * lda (sp),y
+ * jsr pushax
+ *
+ * and replace it by
+ *
+ * ldy #$..
+ * jsr pushwysp
+ *
+ * or even
+ *
+ * jsr pushw0sp
+ *
+ * This change will cost 3 cycles (one additional jump inside the
+ * subroutine), but it saves a lot of code (6 bytes per occurrence),
+ * so we will accept the overhead. It may even be possible to rewrite
+ * the library routine to get rid of the additional overhead.
+ */
+ if (LineMatch (L, "\tldy\t#$") &&
+ GetNextCodeLines (L, L2, 5) &&
+ LineFullMatch (L2 [0], "\tlda\t(sp),y") &&
+ LineFullMatch (L2 [1], "\ttax") &&
+ LineFullMatch (L2 [2], "\tdey") &&
+ LineFullMatch (L2 [3], "\tlda\t(sp),y") &&
+ LineFullMatch (L2 [4], "\tjsr\tpushax")) {
+
+ /* Found - replace it */
+ if (LineFullMatch (L, "\tldy\t#$01")) {
+ /* Word at offset zero */
+ FreeLine (L);
+ L = ReplaceLine (L2 [4], "\tjsr\tpushw0sp");
+ } else {
+ ReplaceLine (L2 [4], "\tjsr\tpushwysp");
+ }
+
+ /* Delete the remaining lines */
+ FreeLines (L2 [0], L2 [3]);
+ }
+
+ /* Check for
+ *
+ * ldy #$xx
+ * lda (sp),y
+ * tax
+ * dey
+ * lda (sp),y
+ * ldy #$yy
+ * jsr ldauidx
+ *
+ * and replace it by
+ *
+ * ldy #$xx
+ * ldx #$yy
+ * jsr ldauiysp
+ *
+ * or even
+ *
+ * jsr ldaui0sp
+ *
+ * This change will cost 2 cycles, but it saves a lot of code (6 bytes
+ * per occurrence), so we will accept the overhead. It may even be
+ * possible to rewrite the library routine to get rid of the additional
+ * overhead.
+ */
+ if (LineMatch (L, "\tldy\t#$") &&
+ GetNextCodeLines (L, L2, 6) &&
+ LineFullMatch (L2 [0], "\tlda\t(sp),y") &&
+ LineFullMatch (L2 [1], "\ttax") &&
+ LineFullMatch (L2 [2], "\tdey") &&
+ LineFullMatch (L2 [3], "\tlda\t(sp),y") &&
+ LineMatch (L2 [4], "\tldy\t#$") &&
+ LineFullMatch (L2 [5], "\tjsr\tldauidx")) {
+
+ /* Found - replace it */
+ L2 [4]->Line [3] = 'x'; /* Change to ldx */
+ if (LineFullMatch (L, "\tldy\t#$01")) {
+ /* Word at offset zero */
+ FreeLine (L);
+ L = ReplaceLine (L2 [5], "\tjsr\tldaui0sp");
+ } else {
+ ReplaceLine (L2 [5], "\tjsr\tldauiysp");
+ }
+
+ /* Delete the remaining lines */
+ FreeLines (L2 [0], L2 [3]);
+ }
+
+ /* Search for:
+ *
+ * lda (sp),y
+ * jsr pusha
+ *
+ * And replace by
+ *
+ * jsr pushaysp
+ */
+ if (LineFullMatch (L, "\tlda\t(sp),y") &&
+ GetNextCodeLines (L, L2, 1) &&
+ LineFullMatch (L2 [0], "\tjsr\tpusha")) {
+
+ /* Found, replace it */
+ L = ReplaceLine (L, "\tjsr\tpushaysp");
+ FreeLine (L2 [0]);
+ }
+
+ /* All other patterns start with this one: */
+ if (!LineFullMatch (L, "\tldx\t#$00")) {
+ /* Next line */
+ goto NextLine;
+ }
+
+ /* Search for:
+ *
+ * ldx #$00
+ * jsr pushax
+ *
+ * and replace it by:
+ *
+ * jsr pusha0
+ *
+ */
+ if (GetNextCodeLines (L, L2, 1) &&
+ LineFullMatch (L2 [0], "\tjsr\tpushax")) {
+
+ /* Replace the subroutine call */
+ L = ReplaceLine (L, "\tjsr\tpusha0");
+
+ /* Remove the unnecessary line */
+ FreeLine (L2[0]);
+ }
+
+ /* Search for:
+ *
+ * ldx #$00
+ * lda ...
+ * jsr pushax
+ *
+ * and replace it by:
+ *
+ * lda ...
+ * jsr pusha0
+ *
+ */
+ else if (GetNextCodeLines (L, L2, 2) &&
+ LineMatch (L2 [0], "\tlda\t") &&
+ LineFullMatch (L2 [1], "\tjsr\tpushax")) {
+
+ /* Be sure, X is not used in the load */
+ if (NoXIndAddrMode (L2 [0])) {
+
+ /* Replace the subroutine call */
+ L2 [1] = ReplaceLine (L2 [1], "\tjsr\tpusha0");
+
+ /* Remove the unnecessary load */
+ FreeLine (L);
+
+ /* L must be valid */
+ L = L2 [0];
+ }
+
+ }
+
+ /* Search for:
+ *
+ * ldx #$00
+ * lda ...
+ * cmp #$..
+ *
+ * and replace it by:
+ *
+ * lda ...
+ * cmp #$..
+ */
+ else if (GetNextCodeLines (L, L2, 2) &&
+ LineMatch (L2 [0], "\tlda\t") &&
+ LineMatch (L2 [1], "\tcmp\t#$")) {
+
+ /* Be sure, X is not used in the load */
+ if (NoXIndAddrMode (L2 [0])) {
+
+ /* Remove the unnecessary load */
+ FreeLine (L);
+
+ /* L must be valid */
+ L = L2 [0];
+ }
+ }
+
+ /* Search for:
+ *
+ * ldx #$00
+ * lda ...
+ * jsr bnega
+ *
+ * and replace it by:
+ *
+ * lda ...
+ * jsr bnega
+ */
+ else if (GetNextCodeLines (L, L2, 2) &&
+ LineMatch (L2 [0], "\tlda\t") &&
+ LineFullMatch (L2 [1], "\tjsr\tbnega")) {
+
+ /* Be sure, X is not used in the load */
+ if (NoXIndAddrMode (L2 [0])) {
+
+ /* Remove the unnecessary load */
+ FreeLine (L);
+
+ /* L must be valid */
+ L = L2 [0];
+ }
+ }
+
+NextLine:
+ /* Go to the next line */
+ L = NextCodeLine (L);
+ }
+}
+
+
+
+static void OptRegLoads (void)
+/* Remove unnecessary loads of registers */
+{
+ unsigned Deletions;
+ Line* L;
+ Line* Lx;
+
+ /* Repeat this until there is nothing more to delete */
+ do {
+ Deletions = 0;
+ L = FirstCode;
+ while (L) {
+
+ int Delete = 0;
+
+ /* Search for a load of X and check if the value is used later */
+ if (LineMatch (L, "\tldx\t") &&
+ !RegXUsed (L) &&
+ !IsCondJump (NextInstruction (L))) {
+
+ /* Remember to delete this line */
+ Delete = 1;
+ }
+
+ /* Search for a load of A and check if the value is used later */
+ else if (LineMatch (L, "\tlda\t") &&
+ !RegAUsed (L) &&
+ !IsCondJump (NextInstruction (L))) {
+
+ /* Remember to delete this line */
+ Delete = 1;
+ }
+
+ /* Search for a load of Y and check if the value is used later */
+ else if (LineMatch (L, "\tldy\t") &&
+ !RegYUsed (L) &&
+ !IsCondJump (NextInstruction (L))) {
+
+ /* Remember to delete this line */
+ Delete = 1;
+ }
+
+ /* Go to the next line, delete the current if requested */
+ Lx = L;
+ L = NextCodeLine (L);
+ if (Delete) {
+ FreeLine (Lx);
+ ++Deletions;
+ }
+ }
+ } while (Deletions > 0);
+}
+
+
+
+static int OptPtrOps1 (Line** Start)
+/* Optimize several pointer and array constructs - subfunction 1 */
+{
+ Line* L2[15];
+ Line** L3;
+ unsigned NeedLoad;
+ unsigned LinesToRemove;
+ unsigned Inc;
+ unsigned Done;
+ unsigned Offs;
+
+ /* Use a local variable for the working line */
+ Line* L = *Start;
+
+ /* Search for (23B/XXT)
+ *
+ * lda _b+0
+ * ldx _b+0+1
+ * sta regsave
+ * stx regsave+1
+ * jsr incax1
+ * sta _b+0
+ * stx _b+0+1
+ * lda regsave
+ * ldx regsave+1
+ *
+ * and replace it by something like (24B/26T)
+ *
+ * lda _b+0
+ * sta regsave
+ * clc
+ * adc #$01
+ * sta _b+0
+ * lda _b+0+1
+ * sta regsave+1
+ * adc #$00
+ * sta _b+0+1
+ * tax
+ * lda regsave
+ */
+ if (!LineMatch (L, "\tlda\t") ||
+ !GetNextCodeLines (L, L2, 4) ||
+ !IsLoadAX (L, L2 [0]) ||
+ !LineFullMatch (L2[1], "\tsta\tregsave") ||
+ !LineFullMatch (L2[2], "\tstx\tregsave+1")) {
+
+ /* Not found */
+ return 0;
+ }
+
+ /* */
+ if (LineMatch (L2[3], "\tjsr\tincax")) {
+ /* Get next code lines */
+ if (GetNextCodeLines (L2[3], &L2[4], 4) == 0) {
+ /* Cannot get lines */
+ return 0;
+ }
+ Inc = GetHexNum (L2[3]->Line+10);
+ L3 = &L2[4];
+ LinesToRemove = 8;
+ } else {
+ /* Get next code lines */
+ if (GetNextCodeLines (L2[3], &L2[4], 7) == 0) {
+ /* Cannot get lines */
+ return 0;
+ }
+ if (LineFullMatch (L2[3], "\tclc") &&
+ LineMatch (L2[4], "\tadc\t#$") &&
+ LineFullMatch (L2[5], "\tbcc\t*+3") &&
+ LineFullMatch (L2[6], "\tinx")) {
+ /* Inlined increment */
+ Inc = GetHexNum (L2[4]->Line+7);
+ L3 = &L2[7];
+ LinesToRemove = 11;
+ } else {
+ /* Not found */
+ return 0;
+ }
+ }
+
+ /* Check for the remainder */
+ if (!LineMatch (L3[0], "\tsta\t") ||
+ strcmp (L3[0]->Line+5, L->Line+5) != 0 ||
+ !LineMatch (L3[1], "\tstx\t") ||
+ strcmp (L3[1]->Line+5, L2[0]->Line+5) != 0 ||
+ !LineFullMatch (L3[2], "\tlda\tregsave") ||
+ !LineFullMatch (L3[3], "\tldx\tregsave+1")) {
+
+ /* Not found */
+ return 0;
+ }
+
+ /* Check if AX is actually used following the code above. If not,
+ * we don't need to load A/X from regsave. Since X will never by
+ * used without A, check just for A.
+ */
+ NeedLoad = 1;
+ if (!RegAUsed (L3[3])) {
+ /* We don't need to load regsave */
+ NeedLoad = 0;
+ }
+
+ /* Special code for register variables */
+ Done = 0;
+ if (LineMatch (L, "\tlda\tregbank+") &&
+ GetNextCodeLines (L3[3], &L3[4], 1) &&
+ Inc == 1) {
+
+ /* Remember the offset into the register bank */
+ char Reg[20];
+ strcpy (Reg, L->Line+5);
+
+ /* Check for several special sequences */
+ if (LineFullMatch (L3[4], "\tjsr\tldaui")) {
+ /* Load char indirect */
+ L = ReplaceLine (L, "\tldx\t#$00");
+ L = NewLineAfter (L, "\tlda\t(%s,x)", Reg);
+ L = NewLineAfter (L, "\tinc\t%s", Reg);
+ L = NewLineAfter (L, "\tbne\t*+4");
+ L = NewLineAfter (L, "\tinc\t%s+1", Reg);
+ Done = 1;
+ ++LinesToRemove;
+ } else if (LineFullMatch (L3[4], "\tsta\tptr1") &&
+ GetNextCodeLines (L3[4], &L3[5], 3) &&
+ LineFullMatch (L3[5], "\tstx\tptr1+1") &&
+ LineFullMatch (L3[6], "\tldx\t#$00") &&
+ LineFullMatch (L3[7], "\tlda\t(ptr1,x)")) {
+
+ /* Load char indirect, inlined */
+ L = ReplaceLine (L, "\tldx\t#$00");
+ L = NewLineAfter (L, "\tlda\t(%s,x)", Reg);
+ L = NewLineAfter (L, "\tinc\t%s", Reg);
+ L = NewLineAfter (L, "\tbne\t*+4");
+ L = NewLineAfter (L, "\tinc\t%s+1", Reg);
+ Done = 1;
+ LinesToRemove += 4;
+
+ } else if (LineFullMatch (L3[4], "\tjsr\tpushax")) {
+ if (GetNextCodeLines (L3[4], &L3[5], 2) &&
+ LineMatch (L3[5], "\tlda\t") &&
+ LineFullMatch (L3[6], "\tjsr\tstaspp")) {
+
+ /* Store to pointer */
+ L = ReplaceLine (L, L3[5]->Line);
+ L = NewLineAfter (L, "\tldy\t#$00");
+ L = NewLineAfter (L, "\tsta\t(%s),y", Reg);
+ L = NewLineAfter (L, "\tinc\t%s", Reg);
+ L = NewLineAfter (L, "\tbne\t*+4");
+ L = NewLineAfter (L, "\tinc\t%s+1", Reg);
+
+ Done = 1;
+ LinesToRemove += 3;
+
+ } else if (GetNextCodeLines (L3[4], &L3[5], 3) &&
+ LineMatch (L3[5], "\tldy\t#$") &&
+ LineFullMatch (L3[6], "\tlda\t(sp),y") &&
+ LineFullMatch (L3[7], "\tjsr\tstaspp")) {
+
+ /* Beware: We have to correct the stack offset, since we will
+ * remove the pushax instruction!
+ */
+ Offs = GetHexNum (L3[5]->Line+7) - 2;
+
+ /* Store to pointer */
+ L = ReplaceLine (L, "\tldy\t#$%02X", Offs);
+ L = NewLineAfter (L, "\tldx\t#$00");
+ L = NewLineAfter (L, "\tlda\t(sp),y");
+ L = NewLineAfter (L, "\tsta\t(%s,x)", Reg);
+ L = NewLineAfter (L, "\tinc\t%s", Reg);
+ L = NewLineAfter (L, "\tbne\t*+4");
+ L = NewLineAfter (L, "\tinc\t%s+1", Reg);
+
+ Done = 1;
+ LinesToRemove += 4;
+ }
+ }
+ }
+
+ if (Done == 0) {
+
+ /* No register variable - insert the first part of the code */
+ if (NeedLoad) {
+ L = NewLineAfter (L, "\tsta\tptr1");
+ }
+ L = NewLineAfter (L, "\tclc");
+ L = NewLineAfter (L, "\tadc\t#$%02X", Inc);
+ L = NewLineAfter (L, "\tsta\t%s", L3[0]->Line+5);
+ L = NewLineAfter (L, "\tlda\t%s", L3[1]->Line+5);
+ if (NeedLoad) {
+ L = NewLineAfter (L, "\tsta\tptr1+1");
+ }
+ L = NewLineAfter (L, "\tadc\t#$00");
+ L = NewLineAfter (L, "\tsta\t%s", L3[1]->Line+5);
+
+ /* Check if we must really load the old value into a/x or if the
+ * code may be replaced by something else.
+ */
+ if (GetNextCodeLines (L3[3], &L3[4], 1)) {
+ if (LineFullMatch (L3[4], "\tjsr\tldaui")) {
+ /* Load char indirect */
+ L = NewLineAfter (L, "\tldx\t#$00");
+ L = NewLineAfter (L, "\tlda\t(ptr1,x)");
+ NeedLoad = 0;
+ ++LinesToRemove;
+ } else if (LineFullMatch (L3[4], "\tsta\tptr1") &&
+ GetNextCodeLines (L3[4], &L3[5], 3) &&
+ LineFullMatch (L3[5], "\tstx\tptr1+1") &&
+ LineFullMatch (L3[6], "\tldx\t#$00") &&
+ LineFullMatch (L3[7], "\tlda\t(ptr1,x)")) {
+
+ /* Load char indirect, inlined */
+ L = NewLineAfter (L, "\tldx\t#$00");
+ L = NewLineAfter (L, "\tlda\t(ptr1,x)");
+ NeedLoad = 0;
+ LinesToRemove += 4;
+
+ } else if (LineFullMatch (L3[4], "\tjsr\tldaxi")) {
+ /* Load word indirect */
+ L = NewLineAfter (L, "\tldy\t#$01");
+ L = NewLineAfter (L, "\tlda\t(ptr1),y");
+ L = NewLineAfter (L, "\ttax");
+ L = NewLineAfter (L, "\tdey");
+ L = NewLineAfter (L, "\tlda\t(ptr1),y");
+ NeedLoad = 0;
+ ++LinesToRemove;
+
+ } else if (LineFullMatch (L3[4], "\tjsr\tpushax")) {
+ if (GetNextCodeLines (L3[4], &L3[5], 2) &&
+ LineMatch (L3[5], "\tlda\t") &&
+ LineFullMatch (L3[6], "\tjsr\tstaspp")) {
+
+ /* Store to pointer */
+ L = NewLineAfter (L, L3[5]->Line);
+ L = NewLineAfter (L, "\tldy\t#$00");
+ L = NewLineAfter (L, "\tsta\t(ptr1),y");
+
+ NeedLoad = 0;
+ LinesToRemove += 3;
+ } else if (GetNextCodeLines (L3[4], &L3[5], 3) &&
+ LineMatch (L3[5], "\tldy\t#$") &&
+ LineFullMatch (L3[6], "\tlda\t(sp),y") &&
+ LineFullMatch (L3[7], "\tjsr\tstaspp")) {
+
+ /* Beware: We have to correct the stack offset, since we will
+ * remove the pushax instruction!
+ */
+ sprintf (L3[5]->Line+7, "%02X", GetHexNum (L3[5]->Line+7)-2);
+
+ /* Store to pointer */
+ L = NewLineAfter (L, L3[5]->Line);
+ L = NewLineAfter (L, L3[6]->Line);
+ L = NewLineAfter (L, "\tldy\t#$00");
+ L = NewLineAfter (L, "\tsta\t(ptr1),y");
+
+ NeedLoad = 0;
+ LinesToRemove += 4;
+ }
+
+ }
+ }
+
+ /* If we need to load a/x, add the code */
+ if (NeedLoad) {
+ L = NewLineAfter (L, "\ttax");
+ L = NewLineAfter (L, "\tlda\tptr1");
+ }
+ }
+
+ /* Remove the code that is no longer needed */
+ FreeLines (L2[0], L2[LinesToRemove-1]);
+
+ /* Return the new line and success */
+ *Start = NextCodeLine (L);
+ return 1;
+}
+
+
+
+static int OptPtrOps2 (Line** Start)
+/* Optimize several pointer and array constructs - subfunction 2 */
+{
+ Line* L2[25];
+ Line** L3;
+ unsigned NeedLoad;
+ unsigned LinesToRemove;
+ unsigned Inc;
+ unsigned Offs;
+
+
+ /* Use a local variable for the working line */
+ Line* L = *Start;
+
+ /* Same as subfunction 1 but for local variables. */
+ if (LineMatch (L, "\tldy\t#$") == 0) {
+ return 0;
+ }
+
+ /* Get the stack offset. The offset points to the high byte, correct that. */
+ Offs = GetHexNum (L->Line+7) - 1;
+
+ /* Check for the actual sequences */
+ if (GetNextCodeLines (L, L2, 7) &&
+ LineFullMatch (L2[0], "\tjsr\tldaxysp") &&
+ LineFullMatch (L2[1], "\tsta\tregsave") &&
+ LineFullMatch (L2[2], "\tstx\tregsave+1") &&
+ LineMatch (L2[3], "\tjsr\tincax")) {
+
+ /* Non inlined version */
+ Inc = GetHexNum (L2[3]->Line+10);
+
+ /* Check for stack offset zero */
+ if (LineFullMatch (L2[4], "\tjsr\tstax0sp") &&
+ LineFullMatch (L2[5], "\tlda\tregsave") &&
+ LineFullMatch (L2[6], "\tldx\tregsave+1")) {
+
+ LinesToRemove = 7;
+
+ } else if (GetNextCodeLines (L2[6], &L2[7], 1) &&
+ LineMatch (L2[4], "\tldy\t#$") &&
+ GetHexNum (L2[4]->Line+7) == Offs &&
+ LineFullMatch (L2[5], "\tjsr\tstaxysp") &&
+ LineFullMatch (L2[6], "\tlda\tregsave") &&
+ LineFullMatch (L2[7], "\tldx\tregsave+1")) {
+
+ LinesToRemove = 8;
+
+ } else {
+ /* Not found */
+ return 0;
+ }
+
+ } else if (GetNextCodeLines (L, L2, 13) &&
+ LineFullMatch (L2[0], "\tlda\t(sp),y") &&
+ LineFullMatch (L2[1], "\ttax") &&
+ LineFullMatch (L2[2], "\tdey") &&
+ LineFullMatch (L2[3], "\tlda\t(sp),y") &&
+ LineFullMatch (L2[4], "\tsta\tregsave") &&
+ LineFullMatch (L2[5], "\tstx\tregsave+1") &&
+ LineFullMatch (L2[6], "\tclc") &&
+ LineMatch (L2[7], "\tadc\t#$") &&
+ LineFullMatch (L2[8], "\tbcc\t*+3") &&
+ LineFullMatch (L2[9], "\tinx")) {
+
+ /* Inlined version */
+ Inc = GetHexNum (L2[7]->Line+7);
+
+ /* Check for stack offset zero */
+ if (LineFullMatch (L2[10], "\tjsr\tstax0sp") &&
+ LineFullMatch (L2[11], "\tlda\tregsave") &&
+ LineFullMatch (L2[12], "\tldx\tregsave+1")) {
+
+ LinesToRemove = 13;
+
+ } else if (GetNextCodeLines (L2[12], &L2[13], 1) &&
+ LineMatch (L2[10], "\tldy\t#$") &&
+ GetHexNum (L2[10]->Line+7) == Offs &&
+ LineFullMatch (L2[11], "\tjsr\tstaxysp") &&
+ LineFullMatch (L2[12], "\tlda\tregsave") &&
+ LineFullMatch (L2[13], "\tldx\tregsave+1")) {
+
+ LinesToRemove = 14;
+
+ } else {
+ /* Not found */
+ return 0;
+ }
+ } else {
+ /* Not found */
+ return 0;
+ }
+
+ /* Get a pointer to the last line of the preceding sequence */
+ L3 = &L2[LinesToRemove-1];
+
+ /* Check if AX is actually used following the code above. If not,
+ * we don't need to load A/X from regsave. Since X will never by
+ * used without A, check just for A.
+ */
+ NeedLoad = 1;
+ if (!RegAUsed (L3[0])) {
+ /* We don't need to load regsave */
+ NeedLoad = 0;
+ }
+
+ /* Replace the ldy instruction, offset must point to the low byte */
+ sprintf (L->Line+7, "%02X", Offs);
+
+ /* Insert the first part of the code */
+ L = NewLineAfter (L, "\tlda\t(sp),y");
+ if (NeedLoad) {
+ L = NewLineAfter (L, "\tsta\tptr1");
+ }
+ L = NewLineAfter (L, "\tclc");
+ L = NewLineAfter (L, "\tadc\t#$%02X", Inc);
+ L = NewLineAfter (L, "\tsta\t(sp),y");
+ L = NewLineAfter (L, "\tiny");
+ L = NewLineAfter (L, "\tlda\t(sp),y");
+ if (NeedLoad) {
+ L = NewLineAfter (L, "\tsta\tptr1+1");
+ }
+ L = NewLineAfter (L, "\tadc\t#$00");
+ L = NewLineAfter (L, "\tsta\t(sp),y");
+
+ /* Check if we must really load the old value into a/x or if the
+ * code may be replaced by something else.
+ */
+ if (GetNextCodeLines (L3[0], &L3[1], 1)) {
+ if (LineFullMatch (L3[1], "\tjsr\tldaui")) {
+ /* Load char indirect */
+ L = NewLineAfter (L, "\tldx\t#$00");
+ L = NewLineAfter (L, "\tlda\t(ptr1,x)");
+ NeedLoad = 0;
+ ++LinesToRemove;
+ } else if (LineFullMatch (L3[1], "\tsta\tptr1") &&
+ GetNextCodeLines (L3[1], &L3[2], 3) &&
+ LineFullMatch (L3[2], "\tstx\tptr1+1") &&
+ LineFullMatch (L3[3], "\tldx\t#$00") &&
+ LineFullMatch (L3[4], "\tlda\t(ptr1,x)")) {
+
+ /* Load char indirect, inlined */
+ L = NewLineAfter (L, "\tldx\t#$00");
+ L = NewLineAfter (L, "\tlda\t(ptr1,x)");
+ NeedLoad = 0;
+ LinesToRemove += 4;
+
+ } else if (LineFullMatch (L3[1], "\tjsr\tldaxi")) {
+ /* Load word indirect */
+ L = NewLineAfter (L, "\tldy\t#$01");
+ L = NewLineAfter (L, "\tlda\t(ptr1),y");
+ L = NewLineAfter (L, "\ttax");
+ L = NewLineAfter (L, "\tdey");
+ L = NewLineAfter (L, "\tlda\t(ptr1),y");
+ NeedLoad = 0;
+ ++LinesToRemove;
+
+ } else if (LineFullMatch (L3[1], "\tjsr\tpushax")) {
+ if (GetNextCodeLines (L3[1], &L3[2], 2) &&
+ LineMatch (L3[2], "\tlda\t") &&
+ LineFullMatch (L3[3], "\tjsr\tstaspp")) {
+
+ /* Store to pointer */
+ L = NewLineAfter (L, L3[2]->Line);
+ L = NewLineAfter (L, "\tldy\t#$00");
+ L = NewLineAfter (L, "\tsta\t(ptr1),y");
+
+ NeedLoad = 0;
+ LinesToRemove += 3;
+ } else if (GetNextCodeLines (L3[1], &L3[2], 3) &&
+ LineMatch (L3[2], "\tldy\t#$") &&
+ LineFullMatch (L3[3], "\tlda\t(sp),y") &&
+ LineFullMatch (L3[4], "\tjsr\tstaspp")) {
+
+ /* Beware: We have to correct the stack offset, since we will
+ * remove the pushax instruction!
+ */
+ sprintf (L3[2]->Line+7, "%02X", GetHexNum (L3[2]->Line+7)-2);
+
+ /* Store to pointer */
+ L = NewLineAfter (L, L3[2]->Line);
+ L = NewLineAfter (L, L3[3]->Line);
+ L = NewLineAfter (L, "\tldy\t#$00");
+ L = NewLineAfter (L, "\tsta\t(ptr1),y");
+
+ NeedLoad = 0;
+ LinesToRemove += 4;
+ }
+ }
+
+ }
+
+ /* If we need to load a/x, add the code */
+ if (NeedLoad) {
+ L = NewLineAfter (L, "\ttax");
+ L = NewLineAfter (L, "\tlda\tptr1");
+ }
+
+ /* Remove the code that is no longer needed */
+ FreeLines (L2[0], L2[LinesToRemove-1]);
+
+ /* Return the new line and success */
+ *Start = NextCodeLine (L);
+ return 1;
+}
+
+
+
+static void OptPtrOps (void)
+/* Optimize several pointer and array constructs */
+{
+ Line* L2 [10];
+
+ Line* L = FirstCode;
+ while (L) {
+
+ if (OptPtrOps1 (&L)) {
+ continue;
+ } else if (OptPtrOps2 (&L)) {
+ continue;
+ }
+
+ /* Search for the following sequence:
+ *
+ * lda regsave
+ * ldx regsave+1
+ * jsr pushax
+ * lda #$..
+ * jsr staspp
+ *
+ * and replace it by:
+ *
+ * lda #$..
+ * ldy #$00
+ * sta (regsave),y
+ *
+ */
+ else if (LineFullMatch (L, "\tlda\tregsave") && /* Match on start */
+ GetNextCodeLines (L, L2, 4) && /* Fetch next lines */
+ LineFullMatch (L2 [0], "\tldx\tregsave+1") && /* Match line 2 ... */
+ LineFullMatch (L2 [1], "\tjsr\tpushax") &&
+ LineMatch (L2 [2], "\tlda\t#$") &&
+ LineFullMatch (L2 [3], "\tjsr\tstaspp")) {
+
+ /* Found the sequence, replace it */
+ L = ReplaceLine (L, L2 [2]->Line); /* lda #$.. */
+ L2 [0] = ReplaceLine (L2 [0], "\tldy\t#$00");
+ L2 [1] = ReplaceLine (L2 [1], "\tsta\t(regsave),y");
+
+ /* Free the remaining lines */
+ FreeLines (L2 [2], L2 [3]);
+ }
+
+ /* Search for the following sequence:
+ *
+ * lda regsave
+ * ldx regsave+1
+ * jsr ldaui
+ *
+ * and replace it by:
+ *
+ * ldx #$00
+ * lda (regsave,x)
+ *
+ */
+ else if (LineFullMatch (L, "\tlda\tregsave") && /* Match on start */
+ GetNextCodeLines (L, L2, 2) && /* Fetch next lines */
+ LineFullMatch (L2 [0], "\tldx\tregsave+1") && /* Match line 2 ... */
+ LineFullMatch (L2 [1], "\tjsr\tldaui")) {
+
+ /* Found the sequence, replace it */
+ L = ReplaceLine (L, "\tldx\t#$00");
+ L2 [0] = ReplaceLine (L2 [0], "\tlda\t(regsave,x)");
+
+ /* Free the remaining lines */
+ FreeLine (L2 [1]);
+ }
+
+ /*
+ * Search for the following sequence:
+ *
+ * lda regsave
+ * ldx regsave+1
+ * jsr pushax
+ * ldx #$high
+ * lda #$low
+ * jsr staxspp
+ *
+ * and replace it by:
+ *
+ * ldy #$01
+ * lda #$high
+ * sta (regsave),y
+ * tax
+ * dey
+ * lda #$low
+ * sta (regsave),y
+ *
+ */
+ else if (LineFullMatch (L, "\tlda\tregsave") &&
+ GetNextCodeLines (L, L2, 5) &&
+ LineFullMatch (L2 [0], "\tldx\tregsave+1") &&
+ LineFullMatch (L2 [1], "\tjsr\tpushax") &&
+ LineMatch (L2 [2], "\tldx\t#$") &&
+ LineMatch (L2 [3], "\tlda\t#$") &&
+ LineFullMatch (L2 [4], "\tjsr\tstaxspp")) {
+
+ /* Found the sequence, replace it */
+ L = ReplaceLine (L, "\tldy\t#$01");
+ L2 [0] = ReplaceLine (L2 [0], L2 [2]->Line);
+ L2 [0]->Line [3] = 'a';
+ L2 [1] = ReplaceLine (L2 [1], "\tsta\t(regsave),y");
+ L2 [4] = ReplaceLine (L2 [4], L2 [3]->Line);
+ L2 [2] = ReplaceLine (L2 [2], "\ttax");
+ L2 [3] = ReplaceLine (L2 [3], "\tdey");
+ L = NewLineAfter (L2 [4], "\tsta\t(regsave),y");
+ }
+
+ /*
+ * Search for the following sequence:
+ *
+ * lda regsave
+ * ldx regsave+1
+ * sta ptr1
+ * stx ptr1+1
+ * ldx #$00
+ * lda (ptr1,x)
+ *
+ * and replace it by:
+ *
+ * ldx #$00
+ * lda (regsave,x)
+ *
+ */
+ else if (LineFullMatch (L, "\tlda\tregsave") &&
+ GetNextCodeLines (L, L2, 5) &&
+ LineFullMatch (L2 [0], "\tldx\tregsave+1") &&
+ LineFullMatch (L2 [1], "\tsta\tptr1") &&
+ LineFullMatch (L2 [2], "\tstx\tptr1+1") &&
+ LineFullMatch (L2 [3], "\tldx\t#$00") &&
+ LineFullMatch (L2 [4], "\tlda\t(ptr1,x)")) {
+
+ /* Found the sequence, replace it */
+ L = ReplaceLine (L, "\tldx\t#$00");
+ L2 [0] = ReplaceLine (L2 [0], "\tlda\t(regsave,x)");
+
+ /* Remove the remaining lines */
+ FreeLines (L2 [1], L2 [4]);
+ }
+
+ /* Search for the following sequence:
+ *
+ * jsr pushax
+ * lda ...
+ * jsr staspp
+ *
+ * and replace it by:
+ *
+ * sta ptr1
+ * stx ptr1+1
+ * lda ...
+ * ldy #$00
+ * sta (ptr1),y
+ *
+ */
+ else if (LineFullMatch (L, "\tjsr\tpushax") &&
+ GetNextCodeLines (L, L2, 2) &&
+ LineMatch (L2 [0], "\tlda\t") &&
+ LineFullMatch (L2 [1], "\tjsr\tstaspp")) {
+
+ /* Found the sequence, replace it */
+ L = ReplaceLine (L, "\tsta\tptr1");
+ L2 [1] = ReplaceLine (L2 [1], L2 [0]->Line); /* lda ... */
+ L2 [0] = ReplaceLine (L2 [0], "\tstx\tptr1+1");
+ L2 [2] = NewLineAfter (L2 [1], "\tldy\t#$00");
+ L = NewLineAfter (L2 [2], "\tsta\t(ptr1),y");
+ }
+
+ /* Search for the following sequence:
+ *
+ * jsr pushax
+ * lda ...
+ * ldy #$nn
+ * jsr staspidx
+ *
+ * and replace it by:
+ *
+ * sta ptr1
+ * stx ptr1+1
+ * lda ...
+ * ldy #$nn
+ * sta (ptr1),y
+ *
+ */
+ else if (LineFullMatch (L, "\tjsr\tpushax") &&
+ GetNextCodeLines (L, L2, 3) &&
+ LineMatch (L2 [0], "\tlda\t") &&
+ LineMatch (L2 [1], "\tldy\t#$") &&
+ LineFullMatch (L2 [2], "\tjsr\tstaspidx")) {
+
+ /* Found the sequence, replace it */
+ L = ReplaceLine (L, "\tsta\tptr1");
+ L = NewLineAfter (L, "\tstx\tptr1+1");
+ L2 [2] = ReplaceLine (L2 [2], "\tsta\t(ptr1),y");
+ }
+
+ /* Search for the following sequence:
+ *
+ * jsr pushax
+ * ldy #$..
+ * lda (sp),y
+ * jsr staspp
+ *
+ * and replace it by:
+ *
+ * sta ptr1
+ * stx ptr1+1
+ * ldy #$..
+ * lda (sp),y
+ * ldy #$00
+ * sta (ptr1),y
+ *
+ * Beware: Since we remove a call to a function that changes the stack
+ * pointer, we have to adjust the stack address for the lda.
+ *
+ */
+ else if (LineFullMatch (L, "\tjsr\tpushax") &&
+ GetNextCodeLines (L, L2, 3) &&
+ LineMatch (L2 [0], "\tldy\t#$") &&
+ LineFullMatch (L2 [1], "\tlda\t(sp),y") &&
+ LineFullMatch (L2 [2], "\tjsr\tstaspp")) {
+
+ /* Found the sequence, replace it. First create a new load
+ * instruction for the changed stack offset.
+ */
+ char Buf [30];
+ sprintf (Buf, "\tldy\t#$%02X", GetHexNum (L2 [0]->Line+7) - 2);
+ L = ReplaceLine (L, "\tsta\tptr1");
+ L2 [1] = ReplaceLine (L2 [1], Buf); /* ldy ... */
+ L2 [0] = ReplaceLine (L2 [0], "\tstx\tptr1+1");
+ L2 [2] = ReplaceLine (L2 [2], "\tlda\t(sp),y");
+ L2 [3] = NewLineAfter (L2 [2], "\tldy\t#$00");
+ L = NewLineAfter (L2 [3], "\tsta\t(ptr1),y");
+ }
+
+ /* Search for the following sequence:
+ *
+ * jsr pushax
+ * ldy #$nn
+ * lda (sp),y
+ * ldy #$mm
+ * jsr staspidx
+ *
+ * and replace it by:
+ *
+ * sta ptr1
+ * stx ptr1+1
+ * ldy #$nn
+ * lda (sp),y
+ * ldy #$mm
+ * sta (ptr1),y
+ *
+ * Beware: Since we remove a call to a function that changes the stack
+ * pointer, we have to adjust the stack address for the lda.
+ *
+ */
+ else if (LineFullMatch (L, "\tjsr\tpushax") &&
+ GetNextCodeLines (L, L2, 4) &&
+ LineMatch (L2 [0], "\tldy\t#$") &&
+ LineFullMatch (L2 [1], "\tlda\t(sp),y") &&
+ LineMatch (L2 [2], "\tldy\t#$") &&
+ LineFullMatch (L2 [3], "\tjsr\tstaspidx")) {
+
+ /* Found the sequence, replace it. First create a new load
+ * instruction for the changed stack offset.
+ */
+ char Buf [30];
+ sprintf (Buf, "\tldy\t#$%02X", GetHexNum (L2 [0]->Line+7) - 2);
+ L = ReplaceLine (L, "\tsta\tptr1");
+ L = NewLineAfter (L, "\tstx\tptr1+1");
+ L2 [0] = ReplaceLine (L2 [0], Buf); /* ldy ... */
+ L2 [3] = ReplaceLine (L2 [3], "\tsta\t(ptr1),y");
+ }
+
+ /* Search for the following sequence:
+ *
+ * ldax _label+0
+ * ldy #$..
+ * clc
+ * adc (sp),y
+ * bcc *+3
+ * inx
+ * sta ptr1
+ * stx ptr1+1
+ * ldx #$00
+ * lda (ptr1,x)
+ *
+ * and replace it by:
+ *
+ * ldy #$..
+ * lda (sp),y
+ * tay
+ * ldx #$00
+ * lda _label+0,y
+ *
+ * The load of X may be omitted if X is not used below.
+ */
+ else if (LineMatch (L, "\tldax\t_") &&
+ GetNextCodeLines (L, L2, 9) &&
+ LineMatch (L2 [0], "\tldy\t#$") &&
+ LineFullMatch (L2 [1], "\tclc") &&
+ LineFullMatch (L2 [2], "\tadc\t(sp),y") &&
+ LineFullMatch (L2 [3], "\tbcc\t*+3") &&
+ LineFullMatch (L2 [4], "\tinx") &&
+ LineFullMatch (L2 [5], "\tsta\tptr1") &&
+ LineFullMatch (L2 [6], "\tstx\tptr1+1") &&
+ LineFullMatch (L2 [7], "\tldx\t#$00") &&
+ LineFullMatch (L2 [8], "\tlda\t(ptr1,x)")) {
+
+ /* Found the sequence, replace it */
+ char Label [256];
+ strcpy (Label, L->Line + 6); /* Remember the label */
+ L = ReplaceLine (L, L2 [0]->Line); /* ldy .. */
+ L = NewLineAfter (L, "\tlda\t(sp),y");
+ L = NewLineAfter (L, "\ttay");
+ if (RegXUsed (L2[8])) {
+ L = NewLineAfter (L, "\tldx\t#$00");
+ }
+ L = NewLineAfter (L, "\tlda\t%s,y", Label);
+
+ /* Remove the remaining stuff. There may be hints between the
+ * instructions, remove them too
+ */
+ FreeLines (L2[0], L2 [8]);
+
+ }
+
+ /* Check for
+ *
+ * ldy #$xx
+ * lda (sp),y
+ * tax
+ * dey
+ * lda (sp),y
+ * ldy #$yy
+ * jsr ldauidx
+ *
+ * and replace it by
+ *
+ * ldy #$xx
+ * ldx #$yy
+ * jsr ldauiysp
+ *
+ * or even
+ *
+ * jsr ldaui0sp
+ *
+ * This change will cost 2 cycles, but it saves a lot of code (6 bytes
+ * per occurrence), so we will accept the overhead. It may even be
+ * possible to rewrite the library routine to get rid of the additional
+ * overhead.
+ */
+ else if (LineMatch (L, "\tldy\t#$") &&
+ GetNextCodeLines (L, L2, 6) &&
+ LineFullMatch (L2 [0], "\tlda\t(sp),y") &&
+ LineFullMatch (L2 [1], "\ttax") &&
+ LineFullMatch (L2 [2], "\tdey") &&
+ LineFullMatch (L2 [3], "\tlda\t(sp),y") &&
+ LineMatch (L2 [4], "\tldy\t#$") &&
+ LineFullMatch (L2 [5], "\tjsr\tldauidx")) {
+
+ /* Found - replace it */
+ L2 [4]->Line [3] = 'x'; /* Change to ldx */
+ if (LineFullMatch (L, "\tldy\t#$01")) {
+ /* Word at offset zero */
+ FreeLine (L);
+ L = ReplaceLine (L2 [5], "\tjsr\tldaui0sp");
+ } else {
+ ReplaceLine (L2 [5], "\tjsr\tldauiysp");
+ }
+
+ /* Delete the remaining lines */
+ FreeLines (L2 [0], L2 [3]);
+ }
+
+ /* Check for
+ *
+ * ldy #$xx
+ * lda (sp),y
+ * tax
+ * dey
+ * lda (sp),y
+ * sta ptr1
+ * stx ptr1+1
+ * ldx #$00
+ * lda (ptr1,x)
+ *
+ * and replace it by
+ *
+ * ldy #$xx
+ * jsr ldau0ysp
+ *
+ * or even
+ *
+ * jsr ldau00sp
+ *
+ * This change will has an overhead of 10 cycles, but it saves 11(!)
+ * bytes per invocation. Maybe we should apply only if FavourSize is
+ * true?
+ */
+ else if (LineMatch (L, "\tldy\t#$") &&
+ GetNextCodeLines (L, L2, 8) &&
+ LineFullMatch (L2 [0], "\tlda\t(sp),y") &&
+ LineFullMatch (L2 [1], "\ttax") &&
+ LineFullMatch (L2 [2], "\tdey") &&
+ LineFullMatch (L2 [3], "\tlda\t(sp),y") &&
+ LineFullMatch (L2 [4], "\tsta\tptr1") &&
+ LineFullMatch (L2 [5], "\tstx\tptr1+1") &&
+ LineFullMatch (L2 [6], "\tldx\t#$00") &&
+ LineFullMatch (L2 [7], "\tlda\t(ptr1,x)")) {
+
+ /* Found - replace it */
+ if (LineFullMatch (L, "\tldy\t#$01")) {
+ /* Word at offset zero */
+ FreeLine (L);
+ L = ReplaceLine (L2 [0], "\tjsr\tldau00sp");
+ } else {
+ ReplaceLine (L2 [0], "\tjsr\tldau0ysp");
+ }
+
+ /* Delete the remaining lines */
+ FreeLines (L2 [1], L2 [7]);
+ }
+
+ /* Next Line */
+ L = NextCodeLine (L);
+ }
+}
+
+
+
+static void OptRegVars (void)
+/* Optimize register variable uses */
+{
+ Line* L2 [10];
+
+ Line* L = FirstCode;
+ while (L) {
+
+ /* Search for the following sequence:
+ *
+ * lda regbank+n
+ * ldx regbank+n+1
+ * jsr ldaui
+ *
+ * and replace it by:
+ *
+ * ldx #$00
+ * lda (regbank+n,x)
+ *
+ */
+ if (LineMatch (L, "\tlda\tregbank+") && /* Match on start */
+ GetNextCodeLines (L, L2, 2) && /* Fetch next lines */
+ LineMatch (L2 [0], "\tldx\tregbank+") && /* Match line 2 ... */
+ LineFullMatch (L2 [1], "\tjsr\tldaui") &&
+ L->Line [13] == L2 [0]->Line [13] && /* Offset equal */
+ strcmp (L2 [0]->Line + 14, "+1") == 0) {
+
+ char Buf [100];
+ sprintf (Buf, "\tlda\t(%s,x)", L->Line + 5);
+
+ /* Found the sequence, replace it */
+ L = ReplaceLine (L, "\tldx\t#$00");
+ L2 [0] = ReplaceLine (L2 [0], Buf);
+
+ /* Free the remaining lines */
+ FreeLine (L2 [1]);
+ }
+
+ /* Search for the following sequence:
+ *
+ * lda regbank+n
+ * ldx regbank+n+1
+ * sta ptr1
+ * stx ptr1+1
+ * ldx #$00
+ * lda (ptr1,x)
+ *
+ * and replace it by:
+ *
+ * ldx #$00
+ * lda (regbank+n,x)
+ *
+ */
+ else if (LineMatch (L, "\tlda\tregbank+") && /* Match on start */
+ GetNextCodeLines (L, L2, 5) && /* Fetch next lines */
+ LineMatch (L2 [0], "\tldx\tregbank+") && /* Match line 2 ... */
+ L->Line [13] == L2 [0]->Line [13] && /* Offset equal */
+ strcmp (L2 [0]->Line + 14, "+1") == 0 &&
+ LineFullMatch (L2 [1], "\tsta\tptr1") &&
+ LineFullMatch (L2 [2], "\tstx\tptr1+1") &&
+ LineFullMatch (L2 [3], "\tldx\t#$00") &&
+ LineFullMatch (L2 [4], "\tlda\t(ptr1,x)")) {
+
+ char Buf [100];
+ sprintf (Buf, "\tlda\t(%s,x)", L->Line + 5);
+
+ /* Found the sequence, replace it */
+ L = ReplaceLine (L, "\tldx\t#$00");
+ L2 [0] = ReplaceLine (L2 [0], Buf);
+
+ /* Free the remaining lines */
+ FreeLines (L2 [1], L2 [4]);
+ }
+
+ /* Search for the following sequence:
+ *
+ * lda regbank+n
+ * ldx regbank+n+1
+ * ldy #$..
+ * jsr ldauidx
+ *
+ * and replace it by:
+ *
+ * ldy #$..
+ * ldx #$00
+ * lda (regbank+n),y
+ *
+ */
+ else if (LineMatch (L, "\tlda\tregbank+") && /* Match on start */
+ GetNextCodeLines (L, L2, 3) && /* Fetch next lines */
+ LineMatch (L2 [0], "\tldx\tregbank+") && /* Match line 2 ... */
+ L->Line [13] == L2 [0]->Line [13] && /* Offset equal */
+ strcmp (L2 [0]->Line + 14, "+1") == 0 &&
+ LineMatch (L2 [1], "\tldy\t#$") &&
+ LineFullMatch (L2 [2], "\tjsr\tldauidx")) {
+
+ char Buf [100];
+ sprintf (Buf, "\tlda\t(%s),y", L->Line + 5);
+
+ /* Found the sequence, replace it */
+ L = ReplaceLine (L, L2 [1]->Line);
+ L2 [0] = ReplaceLine (L2 [0], "\tldx\t#$00");
+ L2 [1] = ReplaceLine (L2 [1], Buf);
+
+ /* Free the remaining lines */
+ FreeLine (L2 [2]);
+ }
+
+ /* Search for the following sequence:
+ *
+ * lda regbank+n
+ * ldx regbank+n+1
+ * sta ptr1
+ * stx ptr1+1
+ * lda ...
+ * ldy #$mm
+ * sta (ptr1),y
+ *
+ * and replace it by:
+ *
+ * lda ...
+ * ldy #$mm
+ * sta (regbank+n),y
+ *
+ * The source form is not generated by the parser but by the optimizer.
+ */
+ else if (LineMatch (L, "\tlda\tregbank+") && /* Match on start */
+ GetNextCodeLines (L, L2, 6) && /* Fetch next lines */
+ LineMatch (L2 [0], "\tldx\tregbank+") && /* Match line 2 ... */
+ L->Line [13] == L2 [0]->Line [13] && /* Offset equal */
+ strcmp (L2 [0]->Line + 14, "+1") == 0 &&
+ LineFullMatch (L2 [1], "\tsta\tptr1") &&
+ LineFullMatch (L2 [2], "\tstx\tptr1+1") &&
+ LineMatch (L2 [3], "\tlda\t") &&
+ LineMatch (L2 [4], "\tldy\t#$") &&
+ LineMatch (L2 [5], "\tsta\t(ptr1),y")) {
+
+ char Buf [100];
+ sprintf (Buf, "\tsta\t(%s),y", L->Line + 5);
+
+ /* Found the sequence, replace it */
+ L2 [5] = ReplaceLine (L2 [5], Buf);
+
+ /* Free the remaining lines */
+ FreeLines (L, L2 [2]);
+
+ /* Make the line pointer valid again */
+ L = L2 [5];
+ }
+
+ /* Search for the following sequence:
+ *
+ * lda regbank+n
+ * ldx regbank+n+1
+ * sta ptr1
+ * stx ptr1+1
+ * ldy #$mm
+ * lda (sp),y
+ * ldy #$ll
+ * sta (ptr1),y
+ *
+ * and replace it by:
+ *
+ * ldy #$mm
+ * lda (sp),y
+ * ldy #$ll
+ * sta (regbank+n),y
+ *
+ * The source form is not generated by the parser but by the optimizer.
+ */
+ else if (LineMatch (L, "\tlda\tregbank+") && /* Match on start */
+ GetNextCodeLines (L, L2, 7) && /* Fetch next lines */
+ LineMatch (L2 [0], "\tldx\tregbank+") && /* Match line 2 ... */
+ L->Line [13] == L2 [0]->Line [13] && /* Offset equal */
+ strcmp (L2 [0]->Line + 14, "+1") == 0 &&
+ LineFullMatch (L2 [1], "\tsta\tptr1") &&
+ LineFullMatch (L2 [2], "\tstx\tptr1+1") &&
+ LineMatch (L2 [3], "\tldy\t#$") &&
+ LineFullMatch (L2 [4], "\tlda\t(sp),y") &&
+ LineMatch (L2 [5], "\tldy\t#$") &&
+ LineMatch (L2 [6], "\tsta\t(ptr1),y")) {
+
+ char Buf [100];
+ sprintf (Buf, "\tsta\t(%s),y", L->Line + 5);
+
+ /* Found the sequence, replace it */
+ L2 [6] = ReplaceLine (L2 [6], Buf);
+
+ /* Free the remaining lines */
+ FreeLines (L, L2 [2]);
+
+ /* Make the line pointer valid again */
+ L = L2 [6];
+ }
+
+ /* Next Line */
+ L = NextCodeLine (L);
+ }
+}
+
+
+
+static void OptDoubleJumps (void)
+/* Remove/rearrange jumps that jump to other jumps */
+{
+ static const char* Jumps [] = {
+ "\tjeq\tL",
+ "\tjne\tL",
+ "\tbeq\tL",
+ "\tbne\tL",
+ "\tjmp\tL",
+ 0
+ };
+
+ unsigned D;
+
+ Line* L = FirstCode;
+ while (L) {
+
+ int I;
+
+ /* Is this a jump? */
+ while ((I = LineMatchX (L, Jumps)) >= 0) {
+
+ /* Yes. Get the target label */
+ Line* Target = GetTargetLine (L->Line + 5);
+
+ /* Target points to the label itself. Skip lines until we reach
+ * one that is not a label.
+ */
+ Target = NextInstruction (Target);
+
+ /* Be sure, this line is not the same as the one the jump is
+ * in (this happens if there is an empty loop).
+ */
+ if (Target == L) {
+ break;
+ }
+ D = 0;
+ if (LineMatch (Target, "\tjmp\t")) {
+
+ /* The target is itself a jump. If this is a short branch, get
+ * the final target and check if it is in reach. Bail out if
+ * not.
+ */
+ if (L->Line[1] == 'b') {
+ Line* FinalTarget = GetTargetLine (Target->Line+5);
+ FinalTarget = NextInstruction (FinalTarget);
+ if ((D = GetJumpDistance (L, FinalTarget)) >= 123) {
+ break;
+ }
+ }
+
+ /* Make sure the jump does indeed point to another label.
+ * It may happen that this is not the case for some endless
+ * loop (while(1) and similar).
+ */
+ if (strcmp (L->Line+5, Target->Line+5) == 0) {
+ /* Same label, bail out */
+ break;
+ }
+
+ /* Use the label in the original jump instead */
+ L = ReplaceLine (L, "%.5s%s", L->Line, Target->Line+5);
+
+ } else if (I < 2 && LineMatch (Target, Jumps [I])) {
+
+ /* Conditional jump. Use final label */
+ strcpy (L->Line+5, Target->Line+5);
+
+ } else {
+ break;
+ }
+ }
+
+ /* Next line */
+ L = NextCodeLine (L);
+ }
+}
+
+
+
+static void OptJumpRTS (void)
+/* Replace jumps to an RTS by an RTS */
+{
+ Line* L = FirstCode;
+ while (L) {
+ /* Is this a jump to a numbered label? */
+ if (LineMatch (L, "\tjmp\t") && L->Line [5] == 'L' && isdigit (L->Line [6])) {
+
+ /* Yes. Get the target label */
+ Line* Target = GetTargetLine (L->Line+5);
+
+ /* Target points to the label itself. Get the next line */
+ Target = NextCodeLine (Target);
+ if (LineFullMatch (Target, "\trts")) {
+ /* Replace the jump by an RTS */
+ L = ReplaceLine (L, "\trts");
+ }
+ }
+ L = NextCodeLine (L);
+ }
+}
+
+
+
+static void OptBoolTransforms (void)
+/* Try to remove the boolean transformation subroutines where they aren't
+ * necessary.
+ */
+{
+ Line* L2 [2];
+ unsigned Label;
+ const char* BranchTarget;
+
+ Line* L = FirstCode;
+ while (L) {
+
+ /* Search for a boolean transformer followed by a conditional jump. */
+ if (LineMatch (L, "\tjsr\tbool") &&
+ GetNextCodeLines (L, L2, 1) &&
+ IsCondJump (L2 [0])) {
+
+ /* Make the boolean transformer unnecessary by changing the
+ * the conditional jump to evaluate the condition flags that
+ * are set after the compare directly. Note: jeq jumps if
+ * the condition is not met, jne jumps if the condition is met.
+ */
+
+ /* Get the condition code */
+ int Cond = FindCond (L->Line + 9);
+ if (Cond < 0) {
+ /* OOPS! */
+ goto NextLine;
+ }
+
+ /* Invert the code if we jump on condition not met. */
+ if (L2[0]->Line [2] == 'e' && L2[0]->Line [3] == 'q') {
+ /* Jumps if condition false, invert condition */
+ Cond = CmpInvertTab [Cond];
+ }
+
+ /* For easier reading, get a pointer to the jump target */
+ BranchTarget = L2[0]->Line+5;
+
+ /* Check if we can replace the jump (sometimes we would need two
+ * conditional jumps, we will not handle that for now since it
+ * has some complications - both jumps may be far jumps for
+ * example making the jumps more costly than the bool transformer
+ * subroutine). If we cannot replace the jump, bail out.
+ */
+ switch (Cond) {
+
+ case CMP_EQ:
+ L = ReplaceLine (L, "\tjeq\t%s", BranchTarget);
+ break;
+
+ case CMP_NE:
+ L = ReplaceLine (L, "\tjne\t%s", BranchTarget);
+ break;
+
+ case CMP_GT:
+ Label = AllocLabel ();
+ L = ReplaceLine (L, "\tbeq\tL%04X", Label);
+ L = NewLineAfter (L, "\tjpl\t%s", BranchTarget);
+ L = NewLabelAfter(L, Label);
+ break;
+
+ case CMP_GE:
+ L = ReplaceLine (L, "\tjpl\t%s", BranchTarget);
+ break;
+
+ case CMP_LT:
+ L = ReplaceLine (L, "\tjmi\t%s", BranchTarget);
+ break;
+
+ case CMP_LE:
+ L = ReplaceLine (L, "\tjeq\t%s", BranchTarget);
+ L = NewLineAfter (L, "\tjmi\t%s", BranchTarget);
+ break;
+
+ case CMP_UGT:
+ Label = AllocLabel ();
+ L = ReplaceLine (L, "\tbeq\tL%04X", Label);
+ L = NewLineAfter (L, "\tjcs\t%s", BranchTarget);
+ L = NewLabelAfter(L, Label);
+ break;
+
+ case CMP_UGE:
+ L = ReplaceLine (L, "\tjcs\t%s", BranchTarget);
+ break;
+
+ case CMP_ULT:
+ L = ReplaceLine (L, "\tjcc\t%s", BranchTarget);
+ break;
+
+ case CMP_ULE:
+ L = ReplaceLine (L, "\tjeq\t%s", BranchTarget);
+ L = NewLineAfter (L, "\tjcc\t%s", BranchTarget);
+ break;
+
+ default:
+ Internal ("Unknown jump condition: %u", Cond);
+
+ }
+
+ /* Remove the old stuff */
+ FreeLine (L2[0]);
+
+ }
+
+NextLine:
+ L = NextCodeLine (L);
+ }
+}
+
+
+
+static void OptCompares2 (void)
+/* Try to optimize the integer compare subroutines. */
+{
+ Line* L2[10];
+ unsigned Label;
+ const char* BranchTarget;
+ int C;
+
+ Line* L = FirstCode;
+ while (L) {
+
+ /* Search for
+ *
+ * lda x
+ * ldx x+1
+ * cpx #$00
+ * bne *+4
+ * cmp #$00
+ * jne/jeq ...
+ *
+ * and replace it by
+ *
+ * lda x
+ * ora x+1
+ * jne/jeq ...
+ */
+ if (LineMatch (L, "\tlda\t") &&
+ GetNextCodeLines (L, L2, 5) &&
+ IsLoadAX (L, L2[0]) &&
+ LineFullMatch (L2[1], "\tcpx\t#$00") &&
+ LineFullMatch (L2[2], "\tbne\t*+4") &&
+ LineFullMatch (L2[3], "\tcmp\t#$00") &&
+ IsCondJump (L2[4])) {
+
+ /* Replace the load of X by an ora */
+ L2[0]->Line[1] = 'o';
+ L2[0]->Line[2] = 'r';
+ L2[0]->Line[3] = 'a';
+
+ /* Remove unneeded stuff */
+ FreeLines (L2[1], L2[3]);
+
+ }
+
+ /* Same for local variables: Replace
+ *
+ * ldy #$xx
+ * lda (sp),y
+ * tax
+ * dey
+ * lda (sp),y
+ * cpx #$00
+ * bne *+4 cmp #$00
+ * cmp #$00
+ * jne/jeq ...
+ *
+ * by
+ *
+ * ldy #$xx
+ * lda (sp),y
+ * dey
+ * ora (sp),y
+ * jne/jeq ...
+ */
+ else if (LineMatch (L, "\tldy\t#$") &&
+ GetNextCodeLines (L, L2, 8) &&
+ LineFullMatch (L2[0], "\tlda\t(sp),y") &&
+ LineFullMatch (L2[1], "\ttax") &&
+ LineFullMatch (L2[2], "\tdey") &&
+ LineFullMatch (L2[3], "\tlda\t(sp),y") &&
+ LineFullMatch (L2[4], "\tcpx\t#$00") &&
+ LineFullMatch (L2[5], "\tbne\t*+4") &&
+ LineFullMatch (L2[6], "\tcmp\t#$00") &&
+ IsCondJump (L2[7])) {
+
+ /* Replace the second load by an ora */
+ L2[3]->Line[1] = 'o';
+ L2[3]->Line[2] = 'r';
+ L2[3]->Line[3] = 'a';
+
+ /* Remove unneeded stuff */
+ FreeLine (L2[1]);
+ FreeLines (L2[4], L2[6]);
+
+ }
+
+ /* Search for the call to a compare subroutine followed by a
+ * conditional jump.
+ */
+ else if (LineMatch (L, "\tjsr\ttos") &&
+ (L2[0] = NextCodeLine (L)) != 0 &&
+ IsCondJump (L2[0])) {
+
+ /* Extract the condition from the function name and branch */
+ C = CheckAndGetIntCmp (L, L2[0]);
+ if (C < 0) {
+ /* Something is wrong */
+ goto NextLine;
+ }
+
+ /* Replace the subroutine call by a cheaper one */
+ L = ReplaceLine (L, "\tjsr\ttosicmp");
+
+ /* For easier reading, get a pointer to the jump target */
+ BranchTarget = L2[0]->Line+5;
+
+ /* Check if we can replace the jump (sometimes we would need two
+ * conditional jumps, we will not handle that for now since it
+ * has some complications - both jumps may be far jumps for
+ * example making the jumps more costly than the bool transformer
+ * subroutine). If we cannot replace the jump, bail out.
+ */
+ switch (C) {
+
+ case CMP_EQ:
+ L = NewLineAfter (L, "\tjeq\t%s", BranchTarget);
+ break;
+
+ case CMP_NE:
+ L = NewLineAfter (L, "\tjne\t%s", BranchTarget);
+ break;
+
+ case CMP_GT:
+ Label = AllocLabel ();
+ L = NewLineAfter (L, "\tbeq\tL%04X", Label);
+ L = NewLineAfter (L, "\tjpl\t%s", BranchTarget);
+ L = NewLabelAfter(L, Label);
+ break;
+
+ case CMP_GE:
+ L = NewLineAfter (L, "\tjpl\t%s", BranchTarget);
+ break;
+
+ case CMP_LT:
+ L = NewLineAfter (L, "\tjmi\t%s", BranchTarget);
+ break;
+
+ case CMP_LE:
+ L = NewLineAfter (L, "\tjeq\t%s", BranchTarget);
+ L = NewLineAfter (L, "\tjmi\t%s", BranchTarget);
+ break;
+
+ case CMP_UGT:
+ Label = AllocLabel ();
+ L = NewLineAfter (L, "\tbeq\tL%04X", Label);
+ L = NewLineAfter (L, "\tjcs\t%s", BranchTarget);
+ L = NewLabelAfter(L, Label);
+ break;
+
+ case CMP_UGE:
+ L = NewLineAfter (L, "\tjcs\t%s", BranchTarget);
+ break;
+
+ case CMP_ULT:
+ L = NewLineAfter (L, "\tjcc\t%s", BranchTarget);
+ break;
+
+ case CMP_ULE:
+ L = NewLineAfter (L, "\tjeq\t%s", BranchTarget);
+ L = NewLineAfter (L, "\tjcc\t%s", BranchTarget);
+ break;
+
+ default:
+ Internal ("Unknown jump condition: %u", C);
+
+ }
+
+ /* Remove the old stuff */
+ FreeLine (L2[0]);
+ }
+
+NextLine:
+ L = NextCodeLine (L);
+ }
+}
+
+
+
+static void OptTests (void)
+/* Remove unnecessary tests */
+{
+ Line* L2 [2];
+
+ const char* BitOps [] = {
+ "\tand\t",
+ "\tora\t",
+ "\teor\t",
+ 0
+ };
+
+ /* Search for lda/tay/jne or lda/tay/jeq, remove the tay.
+ * Search for
+ * lda ...
+ * cmp #$00
+ * jne/jeq
+ * Remove the cmp.
+ */
+ Line* L = FirstCode;
+ while (L) {
+
+ /* Search for lda/tay/jne or lda/tay/jeq, remove the tay.
+ * Search for
+ * lda/and/ora/eor
+ * cmp #$00
+ * jne/jeq ...
+ * Remove the cmp.
+ */
+ if ((LineMatch (L, "\tlda\t") ||
+ LineMatch (L, "\tand\t") ||
+ LineMatch (L, "\tora\t") ||
+ LineMatch (L, "\teor\t")) &&
+ GetNextCodeLines (L, L2, 2) &&
+ (LineFullMatch (L2 [0], "\ttay") ||
+ LineFullMatch (L2 [0], "\tcmp\t#$00")) &&
+ IsCondJump (L2 [1])) {
+
+ /* We can remove the tay */
+ FreeLine (L2 [0]);
+
+ }
+
+ /* Search for
+ *
+ * and ...
+ * tax
+ * jeq/jne
+ *
+ * and remove the tax.
+ */
+ else if (LineMatchX (L, BitOps) >= 0 &&
+ GetNextCodeLines (L, L2, 2) &&
+ LineFullMatch (L2[0], "\ttax") &&
+ IsCondJump (L2[1])) {
+
+ /* Remove the tax including a hint line of there is one */
+ if (LineFullMatch (L2[0]->Prev, "+forcetest")) {
+ FreeLine (L2[0]->Prev);
+ }
+ FreeLine (L2[0]);
+
+ /* If the line before L loads X, this is useless and may be removed */
+ L2[0] = PrevCodeLine (L);
+ if (LineFullMatch (L2[0], "\tldx\t#$00")) {
+ FreeLine (L2[0]);
+ }
+
+ }
+
+ /* Search for the sequence
+ *
+ * stx xx
+ * stx tmp1
+ * ora tmp1
+ *
+ * and replace it by
+ *
+ * stx xx
+ * ora xx
+ */
+ else if (LineMatch (L, "\tstx\t") &&
+ GetNextCodeLines (L, L2, 2) &&
+ LineFullMatch (L2[0], "\tstx\ttmp1") &&
+ LineFullMatch (L2[1], "\tora\ttmp1")) {
+
+ /* Found, replace it */
+ L = NewLineAfter (L, "\tora\t%s", L->Line+5);
+
+ /* Remove remaining stuff */
+ FreeLines (L2[0], L2[1]);
+
+ }
+
+
+ /* Next line */
+ L = NextCodeLine (L);
+ }
+}
+
+
+
+static void OptNeg (void)
+/* Optimize the "bnegax/jeq" and "bnegax/jne" sequences */
+{
+ Line* L2 [10];
+
+ Line* L = FirstCode;
+ while (L) {
+
+ /* Search for the sequence:
+ *
+ * lda ...
+ * jsr bnega
+ * jeq/jne ...
+ *
+ * and replace it by:
+ *
+ * lda ...
+ * jne/jeq ...
+ */
+ if (LineMatch (L, "\tlda\t") && /* Match on start */
+ GetNextCodeLines (L, L2, 2) && /* Fetch next lines */
+ LineFullMatch (L2 [0], "\tjsr\tbnega") &&
+ IsCondJump (L2 [1])) {
+
+ /* Found the sequence, replace it */
+ FreeLine (L2 [0]);
+ InvertZJump (L2 [1]);
+
+ }
+
+ /* Search for the sequence:
+ *
+ * ldy #$xx
+ * lda (sp),y
+ * tax
+ * dey
+ * lda (sp),y
+ * jsr bnegax
+ * jne/jeq ...
+ *
+ * and replace it by
+ *
+ * ldy #$xx
+ * lda (sp),y
+ * dey
+ * ora (sp),y
+ * jeq/jne ...
+ */
+ else if (LineMatch (L, "\tldy\t#$") &&
+ GetNextCodeLines (L, L2, 6) &&
+ LineFullMatch (L2[0], "\tlda\t(sp),y") &&
+ LineFullMatch (L2[1], "\ttax") &&
+ LineFullMatch (L2[2], "\tdey") &&
+ LineFullMatch (L2[3], "\tlda\t(sp),y") &&
+ LineFullMatch (L2[4], "\tjsr\tbnegax") &&
+ IsCondJump (L2[5])) {
+
+ L2[1] = ReplaceLine (L2[1], "\tdey");
+ L2[2] = ReplaceLine (L2[2], "\tora\t(sp),y");
+ FreeLines (L2[3], L2[4]);
+ InvertZJump (L2[5]);
+
+ }
+
+ /* Search for the sequence:
+ *
+ * lda xx
+ * ldx xx+1
+ * jsr bnegax
+ * jne/jeq ...
+ *
+ * and replace it by
+ *
+ * lda xx
+ * ora xx+1
+ * jeq/jne ...
+ */
+ else if (LineMatch (L, "\tlda\t") &&
+ GetNextCodeLines (L, L2, 3) &&
+ IsLoadAX (L, L2[0]) &&
+ LineFullMatch (L2[1], "\tjsr\tbnegax") &&
+ IsCondJump (L2[2])) {
+
+ /* Replace the load of X by ora */
+ L2[0]->Line[1] = 'o';
+ L2[0]->Line[2] = 'r';
+ L2[0]->Line[3] = 'a';
+ FreeLine (L2[1]);
+ InvertZJump (L2[2]);
+
+ }
+
+ /* Search for the sequence:
+ *
+ * jsr _xxx
+ * jsr bnega(x)
+ * jeq/jne ...
+ *
+ * and replace it by:
+ *
+ * jsr _xxx
+ * <boolean test>
+ * jne/jeq ...
+ */
+ else if (LineMatch (L, "\tjsr\t_") && /* Match on start */
+ GetNextCodeLines (L, L2, 2) &&
+ LineMatch (L2 [0], "\tjsr\tbnega") &&
+ IsCondJump (L2 [1])) {
+
+ if (LineFullMatch (L2 [0], "\tjsr\tbnega")) {
+ /* Byte sized */
+ L2 [0] = ReplaceLine (L2 [0], "\ttax"); /* Test a */
+ } else {
+ /* Word sized */
+ L2 [0] = ReplaceLine (L2 [0], "\tstx\ttmp1");
+ NewLineAfter (L2 [0], "\tora\ttmp1");
+ }
+
+ /* Invert the jump */
+ InvertZJump (L2 [1]);
+
+ }
+
+ /* Next line */
+ L = NextCodeLine (L);
+ }
+}
+
+
+
+static void OptTriples (void)
+/* Replace code triples */
+{
+ static const char* Pat1 [] = {
+ "\tjsr\tldaxysp",
+ "\tjsr\tldax0sp",
+ "\tjsr\tldaysp",
+ "\tjsr\tleaysp",
+ "\tjsr\tldaxi",
+ 0
+ };
+ static const char* Pat2 [] = {
+ "\tjsr\tpushax",
+ "\tjsr\tpushax",
+ "\tjsr\tpushax",
+ "\tjsr\tpushax",
+ "\tjsr\tpushax",
+ 0
+ };
+ static const char* Replace [] = {
+ "\tjsr\tpushwysp",
+ "\tjsr\tpushw0sp",
+ "\tjsr\tpushbysp",
+ "\tjsr\tpleaysp",
+ "\tjsr\tpushw",
+ };
+
+ Line* L = FirstCode;
+ while (L) {
+ int I = LineFullMatchX (L, Pat1);
+ if (I >= 0) {
+ /* We found the first match, get the next line */
+ Line* L2 = NextCodeLine (L);
+ if (L2 && LineFullMatch (L2, Pat2 [I])) {
+ /* Found. Replace by the short call */
+ FreeLine (L2);
+ L = ReplaceLine (L, Replace [I]);
+ }
+ }
+ /* Next line */
+ L = NextCodeLine (L);
+ }
+}
+
+
+
+static Line* OptOneBlock (Line* L)
+/* Optimize the register contents inside one basic block */
+{
+ static const char* Compares [] = {
+ "\tjsr\ttoseq00", "\tjsr\ttoseqa0", "\tjsr\ttoseqax",
+ "\tjsr\ttoseqeax", "\tjsr\ttosne00", "\tjsr\ttosnea0",
+ "\tjsr\ttosneax", "\tjsr\ttosneeax", "\tjsr\ttoslt00",
+ "\tjsr\ttoslta0", "\tjsr\ttosltax", "\tjsr\ttosult00",
+ "\tjsr\ttosulta0", "\tjsr\ttosultax", "\tjsr\ttoslteax",
+ "\tjsr\ttosulteax", "\tjsr\ttosle00", "\tjsr\ttoslea0",
+ "\tjsr\ttosleax", "\tjsr\ttosule00", "\tjsr\ttosulea0",
+ "\tjsr\ttosuleax", "\tjsr\ttosleeax", "\tjsr\ttosuleeax",
+ "\tjsr\ttosgt00", "\tjsr\ttosgta0", "\tjsr\ttosgtax",
+ "\tjsr\ttosugt00", "\tjsr\ttosugta0", "\tjsr\ttosugtax",
+ "\tjsr\ttosgteax", "\tjsr\ttosugteax", "\tjsr\ttosge00",
+ "\tjsr\ttosgea0", "\tjsr\ttosgeax", "\tjsr\ttosuge00",
+ "\tjsr\ttosugea0", "\tjsr\ttosugeax", "\tjsr\ttosgeeax",
+ "\tjsr\ttosugeeax",
+ 0
+ };
+
+ static const char* MakeBool [] = {
+ "\tjsr\tbooleq", "\tjsr\tboolne", "\tjsr\tboollt",
+ "\tjsr\tboolle", "\tjsr\tboolgt", "\tjsr\tboolge",
+ "\tjsr\tboolult", "\tjsr\tboolule", "\tjsr\tboolugt",
+ "\tjsr\tbooluge",
+ 0
+ };
+
+ int A = -1; /* Contents of A register */
+ int X = -1; /* Contents of X register */
+ int Y = -1; /* Contents of Y register */
+ Line* L2;
+ unsigned NewVal;
+ int Delete;
+
+ while (L && !IsLabel (L)) {
+
+ /* Handle all instructions. All instructions not tested here have
+ * no effects on the register contents.
+ */
+ Delete = 0;
+ if (L->Line [0] == '+') {
+ /* This is a hint */
+ if (LineMatch (L, "+a:")) {
+ /* Information about a */
+ switch (L->Line [3]) {
+ case '!': A = -1; break;
+ case '=': A = GetHexNum (L->Line + 4); break;
+ }
+ } else if (LineMatch (L, "+x:")) {
+ /* The code generator tells something about the x register */
+ switch (L->Line [3]) {
+ case '!': X = -1; break;
+ case '=': X = GetHexNum (L->Line + 4); break;
+ }
+ } else if (LineMatch (L, "+y:")) {
+ /* Information about the y register */
+ switch (L->Line [3]) {
+ case '!': Y = -1; break;
+ case '=': Y = GetHexNum (L->Line + 4); break;
+ }
+ }
+ } else if (LineMatch (L, "\tadc\t")) {
+ A = -1;
+ } else if (LineMatch (L, "\tand\t")) {
+ A = -1;
+ } else if (LineFullMatch (L, "\tasl\ta")) {
+ if (A != -1) {
+ A = (A << 1) & 0xFF;
+ }
+ } else if (LineFullMatch (L, "\tdex")) {
+ DEC (X, 1);
+ } else if (LineFullMatch (L, "\tdey")) {
+ DEC (Y, 1);
+ } else if (LineMatch (L, "\teor")) {
+ A = -1;
+ } else if (LineFullMatch (L, "\tinx")) {
+ INC (X, 1);
+ } else if (LineFullMatch (L, "\tiny")) {
+ INC (Y, 1);
+ } else if (LineFullMatch (L, "\tjsr\taddeq0sp")) {
+ /* We know about this function */
+ A = X = -1;
+ Y = 1;
+ } else if (LineFullMatch (L, "\tjsr\taddeqysp")) {
+ /* We know about this function */
+ A = X = -1;
+ INC (Y, 1);
+ } else if (LineFullMatch (L, "\tjsr\tbnega")) {
+ /* We know about this function */
+ A = -1;
+ X = 0;
+ } else if (LineFullMatch (L, "\tjsr\tbnegax")) {
+ /* We know about this function */
+ A = -1;
+ X = 0;
+ } else if (LineFullMatch (L, "\tjsr\tbnegeax")) {
+ /* We know about this function */
+ A = -1;
+ X = 0;
+ } else if (LineFullMatch (L, "\tjsr\tincax1")) {
+ /* We know about this function */
+ A = X = -1;
+ } else if (LineFullMatch (L, "\tjsr\tincax2")) {
+ /* We know about this function */
+ A = X = -1;
+ } else if (LineFullMatch (L, "\tjsr\tladdeq")) {
+ /* We know about this function */
+ A = X = -1;
+ Y = 3;
+ } else if (LineFullMatch (L, "\tjsr\tladdeqb")) {
+ /* We know about this function */
+ A = X = -1;
+ Y = 3;
+ } else if (LineFullMatch (L, "\tjsr\tldau00sp")) {
+ /* We know about this function */
+ A = -1;
+ X = 0;
+ Y = 0;
+ } else if (LineFullMatch (L, "\tjsr\tldau0ysp")) {
+ /* We know about this function */
+ A = -1;
+ X = 0;
+ DEC (Y, 1);
+ } else if (LineFullMatch (L, "\tjsr\tldaui")) {
+ /* We know about this function */
+ A = -1;
+ X = 0;
+ Y = 0;
+ } else if (LineFullMatch (L, "\tjsr\tldaui0sp")) {
+ A = -1;
+ Y = X;
+ X = 0;
+ } else if (LineFullMatch (L, "\tjsr\tldauidx")) {
+ /* We know about this function */
+ A = -1;
+ X = 0;
+ } else if (LineFullMatch (L, "\tjsr\tldauiysp")) {
+ /* We know about this function */
+ A = -1;
+ Y = X;
+ X = 0;
+ } else if (LineFullMatch (L, "\tjsr\tldax0sp")) {
+ /* We know about this function */
+ A = X = -1;
+ Y = 0;
+ } else if (LineFullMatch (L, "\tjsr\tldaxi")) {
+ /* We know about this function */
+ A = X = -1;
+ Y = 0;
+ } else if (LineFullMatch (L, "\tjsr\tldaxidx")) {
+ /* We know about this function */
+ A = X = -1;
+ DEC (Y, 1);
+ } else if (LineFullMatch (L, "\tjsr\tldaxysp")) {
+ /* We know about this function */
+ A = X = -1;
+ DEC (Y, 1);
+ } else if (LineFullMatch (L, "\tjsr\tldeaxi")) {
+ /* We know about this function */
+ A = X = -1;
+ Y = 0;
+ } else if (LineFullMatch (L, "\tjsr\tldeaxidx")) {
+ /* We know about this function */
+ A = X = -1;
+ DEC (Y, 3);
+ } else if (LineFullMatch (L, "\tjsr\tlsubeq")) {
+ /* We know about this function */
+ A = X = -1;
+ Y = 3;
+ } else if (LineFullMatch (L, "\tjsr\tlsubeqb")) {
+ /* We know about this function */
+ A = X = -1;
+ Y = 3;
+ } else if (LineFullMatch (L, "\tjsr\tpush0")) {
+ /* We know about this function */
+ A = 0;
+ X = 0;
+ Y = 1;
+ } else if (LineFullMatch (L, "\tjsr\tpush1")) {
+ /* We know about this function */
+ A = 1;
+ X = 0;
+ Y = 1;
+ } else if (LineFullMatch (L, "\tjsr\tpush2")) {
+ /* We know about this function */
+ A = 2;
+ X = 0;
+ Y = 1;
+ } else if (LineFullMatch (L, "\tjsr\tpush3")) {
+ /* We know about this function */
+ A = 3;
+ X = 0;
+ Y = 1;
+ } else if (LineFullMatch (L, "\tjsr\tpush4")) {
+ /* We know about this function */
+ A = 4;
+ X = 0;
+ Y = 1;
+ } else if (LineFullMatch (L, "\tjsr\tpush5")) {
+ /* We know about this function */
+ A = 5;
+ X = 0;
+ Y = 1;
+ } else if (LineFullMatch (L, "\tjsr\tpush6")) {
+ /* We know about this function */
+ A = 6;
+ X = 0;
+ Y = 1;
+ } else if (LineFullMatch (L, "\tjsr\tpush7")) {
+ /* We know about this function */
+ A = 7;
+ X = 0;
+ Y = 1;
+ } else if (LineFullMatch (L, "\tjsr\tpusha")) {
+ /* We know about this function */
+ Y = 0;
+ } else if (LineFullMatch (L, "\tjsr\tpusha0")) {
+ /* We know about this function */
+ X = 0;
+ Y = 1;
+ } else if (LineFullMatch (L, "\tjsr\tpusha0")) {
+ /* We know about this function
+ * If X is already zero, we may call pushax instead and save two
+ * cycles.
+ */
+ if (X == 0) {
+ L = ReplaceLine (L, "\tjsr\tpushax");
+ }
+ X = 0;
+ Y = 1;
+ } else if (LineFullMatch (L, "\tjsr\tpushax")) {
+ /* We know about this function */
+ Y = 1;
+ } else if (LineFullMatch (L, "\tjsr\tpushc0")) {
+ /* We know about this function */
+ A = 0;
+ Y = 0;
+ } else if (LineFullMatch (L, "\tjsr\tpushc1")) {
+ /* We know about this function */
+ A = 1;
+ Y = 0;
+ } else if (LineFullMatch (L, "\tjsr\tpushc2")) {
+ /* We know about this function */
+ A = 2;
+ Y = 0;
+ } else if (LineFullMatch (L, "\tjsr\tpushw")) {
+ /* We know about this function (calls pushax) */
+ A = X = -1;
+ Y = 1;
+ } else if (LineFullMatch (L, "\tjsr\tpushw0sp")) {
+ /* We know about this function(calls pushax) */
+ A = X = -1;
+ Y = 1;
+ } else if (LineFullMatch (L, "\tjsr\tpushwidx")) {
+ /* We know about this function (calls pushax) */
+ A = X = -1;
+ Y = 1;
+ } else if (LineFullMatch (L, "\tjsr\tpushwysp")) {
+ /* We know about this function (calls pushax) */
+ A = X = -1;
+ Y = 1;
+ } else if (LineFullMatch (L, "\tjsr\tstaspp")) {
+ /* We know about this function */
+ Y = -1;
+ } else if (LineFullMatch (L, "\tjsr\tstaxspp")) {
+ /* We know about this function */
+ Y = -1;
+ } else if (LineFullMatch (L, "\tjsr\tstax0sp")) {
+ /* We know about this function */
+ Y = 1;
+ } else if (LineFullMatch (L, "\tjsr\tstaxysp")) {
+ /* We know about this function */
+ INC (Y, 1);
+ } else if (LineFullMatch (L, "\tjsr\tsubeq0sp")) {
+ /* We know about this function */
+ A = X = -1;
+ Y = 1;
+ } else if (LineFullMatch (L, "\tjsr\tsubeqysp")) {
+ /* We know about this function */
+ A = X = -1;
+ INC (Y, 1);
+ } else if (LineFullMatch (L, "\tjsr\ttosicmp")) {
+ /* We know about this function */
+ A = X = -1;
+ Y = 0;
+ } else if (LineFullMatchX (L, Compares) >= 0) {
+ A = Y = -1;
+ X = 0;
+ } else if (LineFullMatchX (L, MakeBool) >= 0) {
+ A = -1;
+ X = 0;
+ } else if (LineMatch (L, "\tjsr\t")) {
+ /* Subroutine call, forget all register information */
+ A = X = Y = -1;
+ } else if (LineMatch (L, "\tlda\t")) {
+ if (!RegAUsed (L) && !IsCondJump (NextInstruction (L))) {
+ /* The value loaded is not used later, remove it */
+ Delete = 1;
+ } else if (LineMatch (L, "\tlda\t(")) {
+ if (IsXIndAddrMode (L)) {
+ /* lda (zp,x) - if Y and X are both zero, replace by
+ * load indirect y and save one cycle in some cases.
+ */
+ if (X == 0 && Y == 0) {
+ char Buf [256];
+ const char* S = L->Line + 6;
+ char* T = Buf + 6;
+ strcpy (Buf, "\tlda\t(");
+ while (*S != ',') {
+ *T++ = *S++;
+ }
+ *T++ = ')';
+ *T++ = ',';
+ *T++ = 'y';
+ *T = '\0';
+ L = ReplaceLine (L, Buf);
+ }
+ }
+ /* In any case invalidate A */
+ A = -1;
+ } else if (LineMatch (L, "\tlda\t#$")) {
+ /* Immidiate load into A */
+ NewVal = GetHexNum (L->Line + 7);
+ if (NewVal == A) {
+ /* Load has no effect */
+ Delete = 1;
+ } else if (NewVal == X) {
+ /* Requested value is already in X */
+ L = ReplaceLine (L, "\ttxa");
+ } else if (NewVal == Y) {
+ /* Requested value is already in Y */
+ L = ReplaceLine (L, "\ttya");
+ }
+ /* Anyway, the new value is now in A */
+ A = NewVal;
+ } else {
+ /* Memory load into A */
+ A = -1;
+ }
+ } else if (LineMatch (L, "\tldax\t")) {
+ /* Memory load into A and X */
+ A = X = -1;
+ } else if (LineMatch (L, "\tldx\t")) {
+ if (!RegXUsed (L) && !IsCondJump (NextInstruction (L))) {
+ /* The value loaded is not used later, remove it */
+ Delete = 1;
+ } else if (LineMatch (L, "\tldx\t#$")) {
+ /* Immidiate load into X */
+ NewVal = GetHexNum (L->Line + 7);
+ if (NewVal == X) {
+ /* Load has no effect */
+ Delete = 1;
+ } else if (NewVal == A) {
+ /* Requested value is already in A */
+ L = ReplaceLine (L, "\ttax");
+ } else if (X != -1 && NewVal == ((X + 1) & 0xFF)) {
+ /* Requested value is one more than current contents */
+ L = ReplaceLine (L, "\tinx");
+ } else if (X != -1 && NewVal == ((X - 1) & 0xFF)) {
+ /* Requested value is one less than current contents */
+ L = ReplaceLine (L, "\tdex");
+ }
+ /* Anyway, the new value is now in X */
+ X = NewVal;
+ } else {
+ /* Memory load into X */
+ X = -1;
+ }
+ } else if (LineMatch (L, "\tldy\t")) {
+ if (!RegYUsed (L) && !IsCondJump (NextInstruction (L))) {
+ /* The value loaded is not used later, remove it */
+ Delete = 1;
+ } else if (LineMatch (L, "\tldy\t#$")) {
+ /* Immidiate load into Y */
+ NewVal = GetHexNum (L->Line + 7);
+ if (NewVal == Y) {
+ /* Load has no effect */
+ Delete = 1;
+ } else if (NewVal == A) {
+ /* Requested value is already in A */
+ L = ReplaceLine (L, "\ttay");
+ } else if (Y != -1 && NewVal == ((Y + 1) & 0xFF)) {
+ /* Requested value is one more than current contents */
+ L = ReplaceLine (L, "\tiny");
+ } else if (Y != -1 && NewVal == ((Y - 1) & 0xFF)) {
+ /* Requested value is one less than current contents */
+ L = ReplaceLine (L, "\tdey");
+ }
+ /* Anyway, the new value is now in Y */
+ Y = NewVal;
+ } else {
+ /* Memory load into Y */
+ Y = -1;
+ }
+ } else if (LineFullMatch (L, "\tlsr\ta")) {
+ if (A != -1) {
+ A >>= 1;
+ }
+ } else if (LineMatch (L, "\tora\t#$")) {
+ if (A != -1) {
+ A |= GetHexNum (L->Line + 7);
+ }
+ } else if (LineMatch (L, "\tora\t")) {
+ A = -1;
+ } else if (LineFullMatch (L, "\tpla")) {
+ A = -1;
+ } else if (LineFullMatch (L, "\trol\ta")) {
+ A = -1;
+ } else if (LineFullMatch (L, "\tror\ta")) {
+ A = -1;
+ } else if (LineFullMatch (L, "\trts")) {
+ A = X = Y = -1;
+ } else if (LineFullMatch (L, "\trti")) {
+ A = X = Y = -1;
+ } else if (LineMatch (L, "\tsbc\t")) {
+ A = -1;
+ } else if (LineFullMatch (L, "\ttax")) {
+ if (A != -1 && X == A) {
+ /* Load has no effect */
+ Delete = 1;
+ } else {
+ X = A;
+ }
+ } else if (LineFullMatch (L, "\ttay")) {
+ if (A != -1 && Y == A) {
+ /* Load has no effect */
+ Delete = 1;
+ } else {
+ Y = A;
+ }
+ } else if (LineFullMatch (L, "\ttsx")) {
+ X = -1;
+ } else if (LineFullMatch (L, "\ttxa")) {
+ if (X != -1 && A == X) {
+ /* Load has no effect */
+ Delete = 1;
+ } else {
+ A = X;
+ }
+ } else if (LineFullMatch (L, "\ttya")) {
+ if (Y != -1 && A == Y) {
+ /* Load has no effect */
+ Delete = 1;
+ } else {
+ A = Y;
+ }
+ }
+
+ /* Set to next line, handle deletions */
+ L2 = NextCodeSegLine (L);
+ if (Delete) {
+ FreeLine (L);
+ }
+ L = L2;
+
+ }
+ if (L) {
+ /* Skip the label */
+ L = NextCodeSegLine (L);
+ }
+ return L;
+}
+
+
+
+static void OptBlocks (void)
+/* Optimize the register contents inside basic blocks */
+{
+ Line* L = FirstCode;
+ while (L) {
+ L = OptOneBlock (L);
+ }
+}
+
+
+
+static void OptJumps (void)
+/* Optimize jumps */
+{
+ static const char* Jumps [] = {
+ "\tjeq\tL",
+ "\tjne\tL",
+ "\tjmi\tL",
+ "\tjpl\tL",
+ "\tjcs\tL",
+ "\tjcc\tL",
+ 0
+ };
+
+ Line* L = FirstCode;
+ while (L) {
+ int I = LineMatchX (L, Jumps);
+ if (I >= 0) {
+ Line* Target = GetTargetLine (L->Line+5);
+ if (Target->Index > L->Index) {
+ /* This is a forward jump. Backward jumps are handled
+ * automagically by the assembler.
+ */
+ unsigned Distance = GetJumpDistance (L, Target);
+ if (Distance < 123) { /* Safety */
+ L->Line [1] = 'b'; /* Make a short branch */
+ L->Size = 2; /* Set new size */
+ }
+ }
+ }
+ L = NextCodeLine (L);
+ }
+}
+
+
+
+static void OptRTS (void)
+/* Change sequences of jsr XXX/rts to jmp XXX */
+{
+ Line* L = FirstCode;
+ while (L) {
+ if (LineMatch (L, "\tjsr\t")) {
+ /* This is a jsr, get the next instruction */
+ Line* L2 = NextCodeLine (L);
+ if (L2 && LineFullMatch (L2, "\trts")) {
+ /* We found a sequence */
+ FreeLine (L2);
+ L->Line [2] = 'm';
+ L->Line [3] = 'p';
+ }
+ }
+ /* Try the next line */
+ L = NextCodeLine (L);
+ }
+}
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+static void OptOnePass (unsigned long Flag, void (*F) (void))
+/* Call one optimizer pass if enabled */
+{
+ if ((OptDisable & Flag) == 0) {
+ F ();
+ } else if (Verbose || Debug) {
+ printf ("Optimizer pass %04lX skipped\n", Flag);
+ }
+}
+
+
+
+void OptDoOpt (void)
+/* Run the optimizer over the collected stuff */
+{
+ /* Find and remember the first line of code */
+ FindCodeStart ();
+
+ /* Mark all lines inside the code segment */
+ MarkCodeLines ();
+
+ /* Create a list of all local labels for fast access */
+ CreateLabelList ();
+
+ /* Ok, now start the real optimizations */
+
+ /* Optimize compares - first step */
+ OptOnePass (0x0001, OptCompares1);
+
+ /* Remove dead jumps */
+ OptOnePass (0x0002, OptDeadJumps);
+
+ /* Remove unnecessary loads */
+ OptOnePass (0x0004, OptLoads);
+
+ /* Remove unnecessary register loads */
+ OptOnePass (0x0008, OptRegLoads);
+
+ /* Optimize stores through pointers */
+ OptOnePass (0x0010, OptPtrOps);
+
+ /* Optimize use of register variables */
+ OptOnePass (0x0020, OptRegVars);
+
+ /* Remove jump cascades - must be used before OptNeg */
+ OptOnePass (0x0040, OptDoubleJumps);
+
+ /* Remove unnecessary boolean negates */
+ OptOnePass (0x0080, OptNeg);
+
+ /* Replace jumps to an RTS by an RTS */
+ OptOnePass (0x0100, OptJumpRTS);
+
+ /* Optimize boolean transforms */
+ OptOnePass (0x0200, OptBoolTransforms);
+
+ /* Optimize compares */
+ OptOnePass (0x0400, OptCompares2);
+
+ /* Remove unnecessary tests */
+ OptOnePass (0x0800, OptTests);
+
+ /* Optimize several triples */
+ OptOnePass (0x1000, OptTriples);
+
+ /* Optimize basic blocks */
+ OptOnePass (0x2000, OptBlocks);
+
+ /* Remove unnecessary register loads (another pass) */
+ OptOnePass (0x0008, OptRegLoads);
+
+ /* Optimize jumps */
+ OptOnePass (0x4000, OptJumps);
+
+ /* Optimize jsr/rts sequences */
+ OptOnePass (0x8000, OptRTS);
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* optimize.h */
+/* */
+/* An optimizer for the cc65 C compiler */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef OPTIMIZE_H
+#define OPTIMIZE_H
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Bitset of flags that switch the different optimizer passes */
+extern unsigned long OptDisable;
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void OptDoOpt (void);
+/* Run the optimizer over the collected stuff */
+
+
+
+/* End of optimize.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* pragma.c */
+/* */
+/* Pragma handling for the cc65 C compiler */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <stdlib.h>
+#include <ctype.h>
+
+#include "global.h"
+#include "error.h"
+#include "io.h"
+#include "litpool.h"
+#include "symtab.h"
+#include "preproc.h"
+#include "scanner.h"
+#include "codegen.h"
+#include "expr.h"
+#include "pragma.h"
+
+
+
+/*****************************************************************************/
+/* data */
+/*****************************************************************************/
+
+
+
+/* Tokens for the #pragmas */
+enum {
+ PR_BSSSEG,
+ PR_CODESEG,
+ PR_DATASEG,
+ PR_REGVARADDR,
+ PR_RODATASEG,
+ PR_SIGNEDCHARS,
+ PR_STATICLOCALS,
+ PR_ZPSYM,
+ PR_ILLEGAL
+};
+
+
+
+/*****************************************************************************/
+/* code */
+/*****************************************************************************/
+
+
+
+static void StringPragma (void (*Func) (const char*))
+/* Handle a pragma that expects a string parameter */
+{
+ if (curtok != SCONST) {
+ Error (ERR_STRLIT_EXPECTED);
+ } else {
+ /* Get the string */
+ const char* Name = GetLiteral (curval);
+
+ /* Call the given function with the string argument */
+ Func (Name);
+
+ /* Reset the string pointer, removing the string from the pool */
+ ResetLiteralOffs (curval);
+ }
+
+ /* Skip the string (or error) token */
+ gettok ();
+}
+
+
+
+static void FlagPragma (unsigned char* Flag)
+/* Handle a pragma that expects a boolean paramater */
+{
+ /* Read a constant expression */
+ struct expent val;
+ constexpr (&val);
+
+ /* Store the value into the flag parameter */
+ *Flag = val.e_const;
+}
+
+
+
+void DoPragma (void)
+/* Handle pragmas */
+{
+ static const struct tok_elt Pragmas [] = {
+ { "bssseg", PR_BSSSEG },
+ { "codeseg", PR_CODESEG },
+ { "dataseg", PR_DATASEG },
+ { "regvaraddr", PR_REGVARADDR },
+ { "rodataseg", PR_RODATASEG },
+ { "signedchars", PR_SIGNEDCHARS },
+ { "staticlocals", PR_STATICLOCALS },
+ { "zpsym", PR_ZPSYM },
+ { 0, PR_ILLEGAL },
+ };
+
+ int Pragma;
+
+ /* Skip the token itself */
+ gettok ();
+
+ /* Identifier must follow */
+ if (curtok != IDENT) {
+ Error (ERR_IDENT_EXPECTED);
+ return;
+ }
+
+ /* Do we know this pragma? */
+ Pragma = searchtok (CurTok.Ident, Pragmas);
+ if (Pragma == PR_ILLEGAL) {
+ /* According to the ANSI standard, we're not allowed to generate errors
+ * for unknown pragmas, however, we're allowed to warn - and we will
+ * do so. Otherwise one typo may give you hours of bug hunting...
+ */
+ Warning (WARN_UNKNOWN_PRAGMA);
+ return;
+ }
+
+ /* Skip the identifier and check for an open paren */
+ gettok ();
+ ConsumeLParen ();
+
+ /* Switch for the different pragmas */
+ switch (Pragma) {
+
+ case PR_BSSSEG:
+ StringPragma (g_bssname);
+ break;
+
+ case PR_CODESEG:
+ StringPragma (g_codename);
+ break;
+
+ case PR_DATASEG:
+ StringPragma (g_dataname);
+ break;
+
+ case PR_REGVARADDR:
+ FlagPragma (&AllowRegVarAddr);
+ break;
+
+ case PR_RODATASEG:
+ StringPragma (g_rodataname);
+ break;
+
+ case PR_SIGNEDCHARS:
+ FlagPragma (&SignedChars);
+ break;
+
+ case PR_STATICLOCALS:
+ FlagPragma (&LocalsAreStatic);
+ break;
+
+ case PR_ZPSYM:
+ StringPragma (MakeZPSym);
+ break;
+
+ default:
+ Internal ("Invalid pragma");
+ }
+
+ /* Closing paren needed */
+ ConsumeRParen ();
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* pragma.h */
+/* */
+/* Pragma handling for the cc65 C compiler */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef PRAGMA_H
+#define PRAGMA_H
+
+
+
+/*****************************************************************************/
+/* code */
+/*****************************************************************************/
+
+
+
+void DoPragma (void);
+/* Handle pragmas */
+
+
+
+/* End of pragma.h */
+#endif
+
+
+
+
+
--- /dev/null
+
+/* C pre-processor functions */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "codegen.h"
+#include "error.h"
+#include "expr.h"
+#include "global.h"
+#include "ident.h"
+#include "include.h"
+#include "io.h"
+#include "macrotab.h"
+#include "mem.h"
+#include "scanner.h"
+#include "util.h"
+#include "preproc.h"
+
+
+
+/*****************************************************************************/
+/* Forwards */
+/*****************************************************************************/
+
+
+
+static int Pass1 (char* from, char* to);
+
+
+
+/*****************************************************************************/
+/* data */
+/*****************************************************************************/
+
+
+
+/* Set when the pp calls expr() recursively */
+unsigned char Preprocessing = 0;
+
+/* Management data for #if */
+#define N_IFDEF 16
+static int i_ifdef = -1;
+static char s_ifdef[N_IFDEF];
+
+/* Buffer for macro expansion */
+static char mlinebuf [LINESIZE];
+static char* mline = mlinebuf;
+static char* mptr;
+
+/* Flag: Expand macros in this line */
+static int ExpandMacros = 1;
+
+
+
+/*****************************************************************************/
+/* code */
+/*****************************************************************************/
+
+
+
+static int keepch (char c)
+/* Put character c into translation buffer. */
+{
+ return (*mptr++ = c);
+}
+
+
+
+static void keepstr (const char* S)
+/* Put string str into translation buffer. */
+{
+ while (*S) {
+ keepch (*S++);
+ }
+}
+
+
+
+static void comment (void)
+/* Remove comment from line. */
+{
+ unsigned StartingLine = ln;
+
+ gch ();
+ gch ();
+ while (*lptr != '*' || nch () != '/') {
+ if (*lptr == '\0') {
+ if (readline () == 0) {
+ PPError (ERR_EOF_IN_COMMENT, StartingLine);
+ return;
+ }
+ } else {
+ if (*lptr == '/' && nch() == '*') {
+ PPWarning (WARN_NESTED_COMMENT);
+ }
+ ++lptr;
+ }
+ }
+ gch ();
+ gch ();
+}
+
+
+
+static void skipblank (void)
+/* Skip blanks and tabs in the input stream. */
+{
+ while (IsBlank (*lptr)) {
+ ++lptr;
+ }
+}
+
+
+
+static char* CopyQuotedString (int Quote, char* Target)
+/* Copy a single or double quoted string from lptr to Target. Return the
+ * new target pointer. Target will not be terminated after the copy.
+ */
+{
+ /* Copy the starting quote */
+ *Target++ = gch();
+
+ /* Copy the characters inside the string */
+ while (*lptr != '\0' && *lptr != Quote) {
+ /* Keep an escaped char */
+ if (*lptr == '\\') {
+ *Target++ = gch();
+ }
+ /* Copy the character */
+ *Target++ = cgch();
+ }
+
+ /* If we had a terminating quote, copy it */
+ if (*lptr) {
+ *Target++ = gch();
+ }
+
+ /* Return the new target pointer */
+ return Target;
+}
+
+
+
+/*****************************************************************************/
+/* Macro stuff */
+/*****************************************************************************/
+
+
+
+static int macname (char *sname)
+/* Get macro symbol name. If error, print message and kill line. */
+{
+ if (issym (sname) == 0) {
+ PPError (ERR_IDENT_EXPECTED);
+ kill ();
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+
+
+static void ExpandMacroArgs (Macro* M)
+/* Preprocessor pass 2. Perform macro substitution. */
+{
+ int C;
+ ident Ident;
+ const char* Replacement;
+ char* SavePtr;
+
+ /* Save the current line pointer and setup the new ones */
+ SavePtr = lptr;
+ lptr = M->Replacement;
+
+ /* Copy the macro replacement checking for parameters to replace */
+ while ((C = *lptr) != '\0') {
+ /* If the next token is an identifier, check for a macro arg */
+ if (IsIdent (C)) {
+ symname (Ident);
+ Replacement = FindMacroArg (M, Ident);
+ if (Replacement) {
+ /* Macro arg, keep the replacement */
+ keepstr (Replacement);
+ } else {
+ /* No macro argument, keep the original identifier */
+ keepstr (Ident);
+ }
+ } else if (C == '#' && IsIdent (nch ())) {
+ ++lptr;
+ symname (Ident);
+ Replacement = FindMacroArg (M, Ident);
+ if (Replacement) {
+ keepch ('\"');
+ keepstr (Replacement);
+ keepch ('\"');
+ } else {
+ keepch ('#');
+ keepstr (Ident);
+ }
+ } else if (IsQuoteChar(C)) {
+ mptr = CopyQuotedString (C, mptr);
+ } else {
+ *mptr++ = *lptr++;
+ }
+ }
+
+ /* Reset the line pointer */
+ lptr = SavePtr;
+}
+
+
+
+static int MacroCall (Macro* M)
+/* Process a function like macro */
+{
+ unsigned ArgCount; /* Macro argument count */
+ unsigned ParCount; /* Number of open parenthesis */
+ char Buf[LINESIZE]; /* Argument buffer */
+ char C;
+ const char* ArgStart;
+ char* B;
+
+ /* Expect an argument list */
+ skipblank ();
+ if (*lptr != '(') {
+ PPError (ERR_ILLEGAL_MACRO_CALL);
+ return 0;
+ }
+
+ /* Eat the left paren */
+ ++lptr;
+
+ /* Read the actual macro arguments and store pointers to these arguments
+ * into the array of actual arguments in the macro definition.
+ */
+ ArgCount = 0;
+ ParCount = 0;
+ ArgStart = Buf;
+ B = Buf;
+ while (1) {
+ C = *lptr;
+ if (C == '(') {
+ *B++ = gch ();
+ ++ParCount;
+ } else if (IsQuoteChar(C)) {
+ B = CopyQuotedString (C, B);
+ } else if (C == ',' || C == ')') {
+ if (ParCount == 0) {
+ /* End of actual argument */
+ gch ();
+ *B++ = '\0';
+ while (IsBlank(*ArgStart)) {
+ ++ArgStart;
+ }
+ if (ArgCount < M->ArgCount) {
+ M->ActualArgs[ArgCount++] = ArgStart;
+ } else if (C != ')' || *ArgStart != '\0' || M->ArgCount > 0) {
+ /* Be sure not to count the single empty argument for a
+ * macro that does not have arguments.
+ */
+ ++ArgCount;
+ }
+
+ /* Start the next one */
+ ArgStart = B;
+ if (C == ')') {
+ break;
+ }
+ } else {
+ *B++ = gch ();
+ if (C == ')') {
+ --ParCount;
+ }
+ }
+ } else if (IsBlank (C)) {
+ /* Squeeze runs of blanks */
+ *B++ = ' ';
+ skipblank ();
+ } else if (C == '\0') {
+ /* End of line inside macro argument list - read next line */
+ if (readline () == 0) {
+ return 0;
+ }
+ } else {
+ /* Just copy the character */
+ *B++ = *lptr++;
+ }
+ }
+
+ /* Compare formal argument count with actual */
+ if (M->ArgCount != ArgCount) {
+ PPError (ERR_MACRO_ARGCOUNT);
+ /* Be sure to make enough empty arguments available */
+ while (ArgCount < M->ArgCount) {
+ M->ActualArgs [ArgCount++] = "";
+ }
+ }
+
+ /* Preprocess the line, replacing macro parameters */
+ ExpandMacroArgs (M);
+
+ /* Done */
+ return 1;
+}
+
+
+
+static void ExpandMacro (Macro* M)
+/* Expand a macro */
+{
+ /* Check if this is a function like macro */
+ if (M->ArgCount >= 0) {
+ /* Function like macro */
+ if (MacroCall (M) == 0) {
+ kill ();
+ }
+ } else {
+ /* Just copy the replacement text */
+ keepstr (M->Replacement);
+ }
+}
+
+
+
+static void addmac (void)
+/* Add a macro to the macro table. */
+{
+ char* saveptr;
+ ident Ident;
+ char Buf[LINESIZE];
+ Macro* M;
+
+ /* Read the macro name */
+ skipblank ();
+ if (!macname (Ident)) {
+ return;
+ }
+
+ /* Create a new macro definition */
+ M = NewMacro (Ident);
+
+ /* Check if this is a function like macro */
+ if (*lptr == '(') {
+
+ /* Skip the left paren */
+ gch ();
+
+ /* Set the marker that this is a function like macro */
+ M->ArgCount = 0;
+
+ /* Read the formal parameter list */
+ while (1) {
+ skipblank ();
+ if (*lptr == ')')
+ break;
+ if (macname (Ident) == 0) {
+ return;
+ }
+ AddMacroArg (M, Ident);
+ skipblank ();
+ if (*lptr != ',')
+ break;
+ gch ();
+ }
+ if (*lptr != ')') {
+ PPError (ERR_RPAREN_EXPECTED);
+ kill ();
+ return;
+ }
+ gch ();
+ }
+
+ /* Insert the macro into the macro table and allocate the ActualArgs array */
+ InsertMacro (M);
+
+ /* Remove whitespace and comments from the line, store the preprocessed
+ * line into Buf.
+ */
+ skipblank ();
+ saveptr = mptr;
+ Pass1 (lptr, Buf);
+ mptr = saveptr;
+
+ /* Create a copy of the replacement */
+ M->Replacement = xstrdup (Buf);
+}
+
+
+
+/*****************************************************************************/
+
+/*****************************************************************************/
+
+
+
+static int Pass1 (char* from, char* to)
+/* Preprocessor pass 1. Remove whitespace and comments. */
+{
+ int c;
+ int done;
+ ident Ident;
+ int HaveParen;
+
+ lptr = from;
+ mptr = to;
+ done = 1;
+ while ((c = *lptr) != 0) {
+ if (IsBlank (c)) {
+ keepch (' ');
+ skipblank ();
+ } else if (IsIdent (c)) {
+ symname (Ident);
+ if (Preprocessing && strcmp(Ident, "defined") == 0) {
+ /* Handle the "defined" operator */
+ skipblank();
+ HaveParen = 0;
+ if (*lptr == '(') {
+ HaveParen = 1;
+ ++lptr;
+ skipblank();
+ }
+ if (!IsIdent(c)) {
+ PPError (ERR_IDENT_EXPECTED);
+ *mptr++ = '0';
+ } else {
+ symname (Ident);
+ *mptr++ = IsMacro(Ident)? '1' : '0';
+ if (HaveParen) {
+ skipblank();
+ if (*lptr != ')') {
+ PPError (ERR_RPAREN_EXPECTED);
+ } else {
+ ++lptr;
+ }
+ }
+ }
+ } else {
+ if (MaybeMacro(c)) {
+ done = 0;
+ }
+ keepstr (Ident);
+ }
+ } else if (IsQuoteChar(c)) {
+ mptr = CopyQuotedString (c, mptr);
+ } else if (c == '/' && nch () == '*') {
+ keepch (' ');
+ comment ();
+ } else if (ANSI == 0 && c == '/' && nch () == '/') {
+ keepch (' ');
+ /* Beware: Because line continuation chars are handled when reading
+ * lines, we may only skip til the end of the source line, which
+ * may not be the same as the end of the input line. The end of the
+ * source line is denoted by a lf (\n) character.
+ */
+ do {
+ ++lptr;
+ } while (*lptr != '\n' && *lptr != '\0');
+ if (*lptr == '\n') {
+ ++lptr;
+ }
+ } else {
+ *mptr++ = *lptr++;
+ }
+ }
+ keepch ('\0');
+ return done;
+}
+
+
+
+static int Pass2 (char *from, char *to)
+/* Preprocessor pass 2. Perform macro substitution. */
+{
+ int C;
+ int no_chg;
+ ident Ident;
+ Macro* M;
+
+ lptr = from;
+ mptr = to;
+ no_chg = 1;
+ while ((C = *lptr) != '\0') {
+ /* If we have an identifier, check if it's a macro */
+ if (IsIdent (C)) {
+ symname (Ident);
+ M = FindMacro (Ident);
+ if (M) {
+ ExpandMacro (M);
+ no_chg = 0;
+ } else {
+ keepstr (Ident);
+ }
+ } else if (IsQuoteChar(C)) {
+ mptr = CopyQuotedString (C, mptr);
+ } else {
+ *mptr++ = *lptr++;
+ }
+ }
+ return no_chg;
+}
+
+
+
+static void xlateline (void)
+/* Translate one line. */
+{
+ int cnt;
+ int Done;
+ char *p;
+
+ Done = Pass1 (line, mline);
+ if (ExpandMacros == 0) {
+ Done = 1;
+ ExpandMacros = 1; /* Reset to default */
+ }
+ cnt = 5;
+ do {
+ p = line;
+ line = mline;
+ mline = p;
+ if (Done)
+ break;
+ Done = Pass2 (line, mline);
+ keepch ('\0');
+ } while (--cnt);
+ lptr = line;
+}
+
+
+
+static void doundef (void)
+/* Process #undef directive */
+{
+ ident Ident;
+
+ skipblank ();
+ if (macname (Ident)) {
+ UndefineMacro (Ident);
+ }
+}
+
+
+
+static int setmflag (int skip, int flag, int cond)
+/* setmflag( skip, flag, cond ) */
+{
+ if (skip) {
+ s_ifdef[++i_ifdef] = 3;
+ return (1);
+ } else {
+ s_ifdef[++i_ifdef] = 6;
+ return (flag ^ cond);
+ }
+}
+
+
+
+static int doiff (int skip)
+/* Process #if directive */
+{
+ struct expent lval;
+ char* S;
+
+ /* We're about to abuse the compiler expression parser to evaluate the
+ * #if expression. Save the current tokens to come back here later.
+ */
+ Token sv1 = CurTok;
+ Token sv2 = NextTok;
+
+ /* Remove the #if from the line and add two semicolons as sentinels */
+ skipblank ();
+ S = line;
+ while ((*S++ = *lptr++) != '\0') ;
+ strcat (line, ";;");
+ lptr = line;
+
+ /* Switch into special preprocessing mode */
+ Preprocessing = 1;
+
+ /* Expand macros in this line */
+ xlateline ();
+
+ /* Prime the token pump (remove old tokens from the stream) */
+ gettok ();
+ gettok ();
+
+ /* Call the expression parser */
+ constexpr (&lval);
+
+ /* End preprocessing mode */
+ Preprocessing = 0;
+
+ /* Reset the old tokens */
+ CurTok = sv1;
+ NextTok = sv2;
+
+ /* Set the #if condition according to the expression result */
+ return (setmflag (skip, 1, lval.e_const != 0));
+}
+
+
+
+static int doifdef (int skip, int flag)
+/* Process #ifdef if flag == 1, or #ifndef if flag == 0. */
+{
+ ident Ident;
+
+ skipblank ();
+ if (macname (Ident) == 0) {
+ return 0;
+ } else {
+ return setmflag (skip, flag, IsMacro(Ident));
+ }
+}
+
+
+
+static void doinclude (void)
+/* Open an include file. */
+{
+ char name [80];
+ unsigned count;
+ char term;
+ char c;
+ char *p;
+
+ if (ifile >= MAXFILES) {
+ PPError (ERR_INCLUDE_NESTING);
+ goto done;
+ }
+ mptr = mline;
+ skipblank ();
+ if (!strchr ("\"<", (term = cgch ()))) {
+ PPError (ERR_INCLUDE_LTERM_EXPECTED);
+ goto done;
+ }
+ if (term == '<') {
+ term = '>'; /* get right terminator */
+ }
+
+ /* Get the name of the include file */
+ count = 0;
+ while ((c = *lptr) && (c != term) && count < sizeof (name)-1) {
+ name [count++] = c;
+ ++lptr;
+ }
+ if (c != term) {
+ PPError (ERR_INCLUDE_RTERM_EXPECTED);
+ goto done;
+ }
+ name [count] = '\0';
+
+ /* Now search for the name */
+ p = FindInclude (name, (term == '\"')? INC_USER : INC_SYS);
+ if (p == 0) {
+ PPError (ERR_INCLUDE_NOT_FOUND, name);
+ goto done;
+ }
+
+ /* Save the existing file info */
+ filetab[ifile].f_ln = ln;
+ filetab[ifile].f_name = fin;
+ filetab[ifile].f_iocb = inp;
+ ++ifile;
+
+ /* Assign the name and output it */
+ fin = p;
+ if (Verbose) {
+ printf ("including '%s'\n", fin);
+ }
+
+ /* Try to open the include file */
+ if ((inp = fopen (fin, "r")) == 0) {
+ /* oops! restore old file */
+ PPError (ERR_INCLUDE_OPEN_FAILURE, fin);
+ xfree (fin);
+ --ifile;
+ inp = filetab[ifile].f_iocb;
+ fin = filetab[ifile].f_name;
+ } else {
+ ln = 0;
+ }
+
+done:
+ /* clear rest of line so next read will come from new file (if open) */
+ kill ();
+}
+
+
+
+static void doerror (void)
+/* Print an error */
+{
+ skipblank ();
+ if (*lptr == '\0') {
+ PPError (ERR_INVALID_USER_ERROR);
+ } else {
+ PPError (ERR_USER_ERROR, lptr);
+ }
+
+ /* clear rest of line */
+ kill ();
+}
+
+
+
+/* C preprocessor. */
+
+/* stuff used to bum the keyword dispatching stuff */
+enum {
+ D_DEFINE,
+ D_ELSE,
+ D_ENDIF,
+ D_ERROR,
+ D_IF,
+ D_IFDEF,
+ D_IFNDEF,
+ D_INCLUDE,
+ D_LINE,
+ D_PRAGMA,
+ D_UNDEF,
+ D_ILLEGAL,
+};
+
+static const struct tok_elt pre_toks[] = {
+ { "define", D_DEFINE },
+ { "else", D_ELSE },
+ { "endif", D_ENDIF },
+ { "error", D_ERROR },
+ { "if", D_IF },
+ { "ifdef", D_IFDEF },
+ { "ifndef", D_IFNDEF },
+ { "include", D_INCLUDE },
+ { "line", D_LINE },
+ { "pragma", D_PRAGMA },
+ { "undef", D_UNDEF },
+ { 0, D_ILLEGAL }
+};
+
+
+
+int searchtok (const char *sym, const struct tok_elt *toks)
+/* Search a token in a table */
+{
+ while (toks->toknam && strcmp (toks->toknam, sym))
+ ++toks;
+ return (toks->toknbr);
+}
+
+
+
+void preprocess (void)
+/* Preprocess a line */
+{
+ int c;
+ int Skip;
+ ident sname;
+
+ /* Process compiler directives, skip empty lines */
+ lptr = line;
+
+ /* Skip white space at the beginning of the line */
+ skipblank ();
+
+ /* Check for stuff to skip */
+ Skip = 0;
+ while ((c = *lptr) == '\0' || c == '#' || Skip) {
+
+ /* Check for preprocessor lines lines */
+ if (c == '#') {
+ ++lptr;
+ skipblank ();
+ if (*lptr == '\0') {
+ /* ignore the empty preprocessor directive */
+ continue;
+ }
+ if (!issym (sname)) {
+ PPError (ERR_CPP_DIRECTIVE_EXPECTED);
+ kill ();
+ } else {
+ switch (searchtok (sname, pre_toks)) {
+
+ case D_DEFINE:
+ if (!Skip) {
+ addmac ();
+ }
+ break;
+
+ case D_ELSE:
+ if (s_ifdef[i_ifdef] & 2) {
+ if (s_ifdef[i_ifdef] & 4) {
+ Skip = !Skip;
+ }
+ s_ifdef[i_ifdef] ^= 2;
+ } else {
+ PPError (ERR_UNEXPECTED_CPP_ELSE);
+ }
+ break;
+
+ case D_ENDIF:
+ if (i_ifdef >= 0) {
+ Skip = s_ifdef[i_ifdef--] & 1;
+ } else {
+ PPError (ERR_UNEXPECTED_CPP_ENDIF);
+ }
+ break;
+
+ case D_ERROR:
+ if (!Skip) {
+ doerror ();
+ }
+ break;
+
+ case D_IF:
+ Skip = doiff (Skip);
+ break;
+
+ case D_IFDEF:
+ Skip = doifdef (Skip, 1);
+ break;
+
+ case D_IFNDEF:
+ Skip = doifdef (Skip, 0);
+ break;
+
+ case D_INCLUDE:
+ if (!Skip) {
+ doinclude ();
+ }
+ break;
+
+ case D_LINE:
+ /* Not allowed in strict ANSI mode */
+ if (ANSI) {
+ PPError (ERR_CPP_DIRECTIVE_EXPECTED);
+ kill ();
+ }
+ break;
+
+ case D_PRAGMA:
+ if (!Skip) {
+ /* Don't expand macros in this line */
+ ExpandMacros = 0;
+ /* #pragma is handled on the scanner level */
+ goto Done;
+ }
+ break;
+
+ case D_UNDEF:
+ if (!Skip) {
+ doundef ();
+ }
+ break;
+
+ default:
+ PPError (ERR_CPP_DIRECTIVE_EXPECTED);
+ kill ();
+ }
+ }
+
+ }
+ if (readline () == 0) {
+ if (i_ifdef >= 0) {
+ PPError (ERR_CPP_ENDIF_EXPECTED);
+ }
+ return;
+ }
+ skipblank ();
+ }
+
+Done:
+ xlateline ();
+ if (Verbose > 1) {
+ printf ("line: %s\n", line);
+ }
+}
+
--- /dev/null
+/*
+ * preproc.h
+ *
+ * Ullrich von Bassewitz, 07.06.1998
+ */
+
+
+
+#ifndef PREPROC_H
+#define PREPROC_H
+
+
+
+/*****************************************************************************/
+/* data */
+/*****************************************************************************/
+
+
+
+/* Token table entry */
+struct tok_elt {
+ char *toknam;
+ int toknbr;
+};
+
+/* Set when the pp calls expr() recursively */
+extern unsigned char Preprocessing;
+
+
+
+/*****************************************************************************/
+/* code */
+/*****************************************************************************/
+
+
+
+int searchtok (const char *sym, const struct tok_elt* toks);
+/* Search a token in a table */
+
+void preprocess (void);
+/* Preprocess a line */
+
+
+
+/* End of preproc.h */
+#endif
+
+
+
+
+
--- /dev/null
+/*
+ * scanner.c
+ *
+ * Ullrich von Bassewitz, 07.06.1998
+ */
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "ctrans.h"
+#include "datatype.h"
+#include "error.h"
+#include "function.h"
+#include "global.h"
+#include "ident.h"
+#include "io.h"
+#include "litpool.h"
+#include "preproc.h"
+#include "symtab.h"
+#include "util.h"
+#include "scanner.h"
+
+
+
+/*****************************************************************************/
+/* data */
+/*****************************************************************************/
+
+
+
+Token CurTok; /* The current token */
+Token NextTok; /* The next token */
+
+
+
+/* Token types */
+#define TT_C 0 /* ANSI C token */
+#define TT_EXT 1 /* cc65 extension */
+
+/* Token table */
+static struct Keyword {
+ char* Key; /* Keyword name */
+ unsigned char Tok; /* The token */
+ unsigned char Type; /* Token type */
+} Keywords [] = {
+ { "__AX__", AX, TT_C },
+ { "__EAX__", EAX, TT_C },
+ { "__asm__", ASM, TT_C },
+ { "__fastcall__", FASTCALL, TT_C },
+ { "asm", ASM, TT_EXT },
+ { "auto", AUTO, TT_C },
+ { "break", BREAK, TT_C },
+ { "case", CASE, TT_C },
+ { "char", CHAR, TT_C },
+ { "const", CONST, TT_C },
+ { "continue", CONTINUE, TT_C },
+ { "default", DEFAULT, TT_C },
+ { "do", DO, TT_C },
+ { "double", DOUBLE, TT_C },
+ { "else", ELSE, TT_C },
+ { "enum", ENUM, TT_C },
+ { "extern", EXTERN, TT_C },
+ { "fastcall", FASTCALL, TT_EXT },
+ { "float", FLOAT, TT_C },
+ { "for", FOR, TT_C },
+ { "goto", GOTO, TT_C },
+ { "if", IF, TT_C },
+ { "int", INT, TT_C },
+ { "long", LONG, TT_C },
+ { "register", REGISTER, TT_C },
+ { "return", RETURN, TT_C },
+ { "short", SHORT, TT_C },
+ { "signed", SIGNED, TT_C },
+ { "sizeof", SIZEOF, TT_C },
+ { "static", STATIC, TT_C },
+ { "struct", STRUCT, TT_C },
+ { "switch", SWITCH, TT_C },
+ { "typedef", TYPEDEF, TT_C },
+ { "union", UNION, TT_C },
+ { "unsigned", UNSIGNED, TT_C },
+ { "void", VOID, TT_C },
+ { "volatile", VOLATILE, TT_C },
+ { "while", WHILE, TT_C },
+};
+#define KEY_COUNT (sizeof (Keywords) / sizeof (Keywords [0]))
+
+
+
+/* Stuff for determining the type of an integer constant */
+#define IT_INT 0x01
+#define IT_UINT 0x02
+#define IT_LONG 0x04
+#define IT_ULONG 0x08
+
+
+
+/*****************************************************************************/
+/* code */
+/*****************************************************************************/
+
+
+
+static int CmpKey (const void* Key, const void* Elem)
+/* Compare function for bsearch */
+{
+ return strcmp ((const char*) Key, ((const struct Keyword*) Elem)->Key);
+}
+
+
+
+static int FindKey (char* Key)
+/* Find a keyword and return the token. Return IDENT if the token is not a
+ * keyword.
+ */
+{
+ struct Keyword* K;
+ K = bsearch (Key, Keywords, KEY_COUNT, sizeof (Keywords [0]), CmpKey);
+ if (K && (K->Type != TT_EXT || ANSI == 0)) {
+ return K->Tok;
+ } else {
+ return IDENT;
+ }
+}
+
+
+
+static int skipwhite (void)
+/* Skip white space in the input stream, reading and preprocessing new lines
+ * if necessary. Return 0 if end of file is reached, return 1 otherwise.
+ */
+{
+ while (1) {
+ while (*lptr == 0) {
+ if (readline () == 0) {
+ return 0;
+ }
+ preprocess ();
+ }
+ if (*lptr == ' ' || *lptr == '\r') {
+ ++lptr;
+ } else {
+ return 1;
+ }
+ }
+}
+
+
+
+void symname (char *s)
+/* Get symbol from input stream */
+{
+ unsigned k = 0;
+ do {
+ if (k != MAX_IDENTLEN) {
+ ++k;
+ *s++ = *lptr;
+ }
+ ++lptr;
+ } while (IsIdent (*lptr) || isdigit (*lptr));
+ *s = '\0';
+}
+
+
+
+int issym (char *s)
+/* Get symbol from input stream or return 0 if not a symbol. */
+{
+ if (IsIdent (*lptr)) {
+ symname (s);
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+
+
+static void unknown (unsigned char c)
+/* Error message for unknown character */
+{
+ Error (ERR_INVALID_CHAR, c);
+ gch (); /* Skip */
+}
+
+
+
+static unsigned hexval (int c)
+/* Convert a hex digit into a value */
+{
+ if (!isxdigit (c)) {
+ Error (ERR_ILLEGAL_HEX_DIGIT);
+ }
+ if (isdigit (c)) {
+ return c - '0';
+ } else {
+ return toupper (c) - 'A' + 10;
+ }
+}
+
+
+
+static void SetTok (int tok)
+/* set nxttok and bump line ptr */
+{
+ nxttok = tok;
+ ++lptr;
+}
+
+
+
+static int SignExtendChar (int C)
+/* Do correct sign extension of a character */
+{
+ if (SignedChars && (C & 0x80) != 0) {
+ return C | ~0xFF;
+ } else {
+ return C & 0xFF;
+ }
+}
+
+
+
+static int parsechar (int c)
+/* Parse a character. Converts \n into EOL, etc. */
+{
+ int i;
+ int val;
+
+ /* Check for escape chars */
+ if (c == '\\') {
+ switch (c = gch ()) {
+ case 'b':
+ c = '\b';
+ break;
+ case 'f':
+ c = '\f';
+ break;
+ case 'r':
+ c = '\r';
+ break;
+ case 'n':
+ c = '\n';
+ break;
+ case 't':
+ c = '\t';
+ break;
+ case '\"':
+ c = '\"';
+ break;
+ case '\'':
+ c = '\'';
+ break;
+ case '\\':
+ c = '\\';
+ break;
+ case 'x':
+ case 'X':
+ /* Hex character constant */
+ val = hexval (gch ()) << 4;
+ c = val | hexval (gch ()); /* Do not translate */
+ break;
+ case '0':
+ case '1':
+ /* Octal constant */
+ i = 0;
+ val = c - '0';
+ while ((c = *lptr) >= '0' && c <= '7' && i++ < 4) {
+ val = (val << 3) | (c - '0');
+ gch ();
+ }
+ c = val; /* Do not translate */
+ break;
+ default:
+ Error (ERR_ILLEGAL_CHARCONST);
+ }
+ }
+
+ /* Do correct sign extension */
+ return SignExtendChar (c);
+}
+
+
+
+static void CharConst (void)
+/* Parse a character constant. */
+{
+ int c;
+
+ /* Skip the quote */
+ ++lptr;
+
+ /* Get character */
+ c = parsechar (cgch ());
+
+ /* Check for closing quote */
+ if (cgch () != '\'') {
+ Error (ERR_QUOTE_EXPECTED);
+ }
+
+ /* Setup values and attributes */
+ nxttok = CCONST;
+ nxtval = SignExtendChar (ctrans (c)); /* Translate into target charset */
+ nxttype = type_int; /* Character constants have type int */
+}
+
+
+
+static void StringConst (void)
+/* Parse a quoted string */
+{
+ nxtval = GetLiteralOffs ();
+ nxttok = SCONST;
+
+ /* Be sure to concatenate strings */
+ while (*lptr == '\"') {
+
+ /* Skip the quote char */
+ ++lptr;
+
+ while (*lptr != '\"') {
+ if (*lptr == 0) {
+ Error (ERR_UNEXPECTED_NEWLINE);
+ break;
+ }
+ AddLiteralChar (parsechar (gch()));
+ }
+
+ /* Skip closing quote char if there was one */
+ cgch ();
+
+ /* Skip white space, read new input */
+ skipwhite ();
+
+ }
+
+ /* Terminate the string */
+ AddLiteralChar ('\0');
+}
+
+
+
+void gettok (void)
+/* Get next token from input stream */
+{
+ char c;
+ ident token;
+
+ /* Current token is the lookahead token */
+ CurTok = NextTok;
+
+ /* Remember the starting position of the next token */
+ NextTok.Pos = ln;
+
+ /* Skip spaces and read the next line if needed */
+ if (skipwhite () == 0) {
+ /* End of file reached */
+ nxttok = CEOF;
+ return;
+ }
+
+ /* Determine the next token from the lookahead */
+ c = *lptr;
+ if (isdigit (c)) {
+
+ /* A number */
+ int HaveSuffix; /* True if we have a type suffix */
+ unsigned types; /* Possible types */
+ unsigned base;
+ unsigned long k; /* Value */
+
+ k = 0;
+ base = 10;
+ types = IT_INT | IT_LONG | IT_ULONG;
+
+ if (c == '0') {
+ /* Octal or hex constants may also be of type unsigned int */
+ types = IT_INT | IT_UINT | IT_LONG | IT_ULONG;
+ /* gobble 0 and examin next char */
+ if (toupper (*++lptr) == 'X') {
+ base = 16;
+ nxttype = type_uint;
+ ++lptr; /* gobble "x" */
+ } else {
+ base = 8;
+ }
+ }
+ while (1) {
+ c = *lptr;
+ if (isdigit (c)) {
+ k = k * base + (c - '0');
+ } else if (base == 16 && isxdigit (c)) {
+ k = (k << 4) + hexval (c);
+ } else {
+ break; /* not digit */
+ }
+ ++lptr; /* gobble char */
+ }
+
+ /* Check for a suffix */
+ HaveSuffix = 1;
+ c = toupper (*lptr);
+ if (c == 'U') {
+ /* Unsigned type */
+ ++lptr;
+ if (toupper (*lptr) != 'L') {
+ types = IT_UINT | IT_ULONG;
+ } else {
+ ++lptr;
+ types = IT_ULONG;
+ }
+ } else if (c == 'L') {
+ /* Long type */
+ ++lptr;
+ if (toupper (*lptr) != 'U') {
+ types = IT_LONG | IT_ULONG;
+ } else {
+ ++lptr;
+ types = IT_ULONG;
+ }
+ } else {
+ HaveSuffix = 0;
+ }
+
+ /* Check the range to determine the type */
+ if (k > 0x7FFF) {
+ /* Out of range for int */
+ types &= ~IT_INT;
+ /* If the value is in the range 0x8000..0xFFFF, unsigned int is not
+ * allowed, and we don't have a type specifying suffix, emit a
+ * warning.
+ */
+ if (k <= 0xFFFF && (types & IT_UINT) == 0 && !HaveSuffix) {
+ Warning (WARN_CONSTANT_IS_LONG);
+ }
+ }
+ if (k > 0xFFFF) {
+ /* Out of range for unsigned int */
+ types &= ~IT_UINT;
+ }
+ if (k > 0x7FFFFFFF) {
+ /* Out of range for long int */
+ types &= ~IT_LONG;
+ }
+
+ /* Now set the type string to the smallest type in types */
+ if (types & IT_INT) {
+ nxttype = type_int;
+ } else if (types & IT_UINT) {
+ nxttype = type_uint;
+ } else if (types & IT_LONG) {
+ nxttype = type_long;
+ } else {
+ nxttype = type_ulong;
+ }
+
+ /* Set the value and the token */
+ nxtval = k;
+ nxttok = ICONST;
+ return;
+ }
+
+ if (issym (token)) {
+
+ /* Check for a keyword */
+ if ((nxttok = FindKey (token)) != IDENT) {
+ /* Reserved word found */
+ return;
+ }
+ /* No reserved word, check for special symbols */
+ if (token [0] == '_') {
+ /* Special symbols */
+ if (strcmp (token, "__FILE__") == 0) {
+ nxtval = AddLiteral (fin);
+ nxttok = SCONST;
+ return;
+ } else if (strcmp (token, "__LINE__") == 0) {
+ nxttok = ICONST;
+ nxtval = ln;
+ nxttype = type_int;
+ return;
+ } else if (strcmp (token, "__fixargs__") == 0) {
+ nxttok = ICONST;
+ nxtval = GetParamSize (CurrentFunc);
+ nxttype = type_uint;
+ return;
+ } else if (strcmp (token, "__func__") == 0) {
+ /* __func__ is only defined in functions */
+ if (CurrentFunc) {
+ nxtval = AddLiteral (GetFuncName (CurrentFunc));
+ nxttok = SCONST;
+ return;
+ }
+ }
+ }
+
+ /* No reserved word but identifier */
+ strcpy (NextTok.Ident, token);
+ NextTok.Tok = IDENT;
+ return;
+ }
+
+ /* Monstrous switch statement ahead... */
+ switch (c) {
+
+ case '!':
+ if (*++lptr == '=') {
+ SetTok (NE);
+ } else {
+ nxttok = BANG;
+ }
+ break;
+
+ case '\"':
+ StringConst ();
+ break;
+
+ case '%':
+ if (*++lptr == '=') {
+ SetTok (MOASGN);
+ } else {
+ nxttok = MOD;
+ }
+ break;
+
+ case '&':
+ switch (*++lptr) {
+ case '&':
+ SetTok (DAMP);
+ break;
+ case '=':
+ SetTok (AASGN);
+ break;
+ default:
+ nxttok = AMP;
+ }
+ break;
+
+ case '\'':
+ CharConst ();
+ break;
+
+ case '(':
+ SetTok (LPAREN);
+ break;
+
+ case ')':
+ SetTok (RPAREN);
+ break;
+
+ case '*':
+ if (*++lptr == '=') {
+ SetTok (MASGN);
+ } else {
+ nxttok = STAR;
+ }
+ break;
+
+ case '+':
+ switch (*++lptr) {
+ case '+':
+ SetTok (INC);
+ break;
+ case '=':
+ SetTok (PASGN);
+ break;
+ default:
+ nxttok = PLUS;
+ }
+ break;
+
+ case ',':
+ SetTok (COMMA);
+ break;
+
+ case '-':
+ switch (*++lptr) {
+ case '-':
+ SetTok (DEC);
+ break;
+ case '=':
+ SetTok (SASGN);
+ break;
+ case '>':
+ SetTok (PREF);
+ break;
+ default:
+ nxttok = MINUS;
+ }
+ break;
+
+ case '.':
+ if (*++lptr == '.') {
+ if (*++lptr == '.') {
+ SetTok (ELLIPSIS);
+ } else {
+ unknown (*lptr);
+ }
+ } else {
+ nxttok = DOT;
+ }
+ break;
+
+ case '/':
+ if (*++lptr == '=') {
+ SetTok (DASGN);
+ } else {
+ nxttok = DIV;
+ }
+ break;
+
+ case ':':
+ SetTok (COLON);
+ break;
+
+ case ';':
+ SetTok (SEMI);
+ break;
+
+ case '<':
+ switch (*++lptr) {
+ case '=':
+ SetTok (LE);
+ break;
+ case '<':
+ if (*++lptr == '=') {
+ SetTok (SLASGN);
+ } else {
+ nxttok = ASL;
+ }
+ break;
+ default:
+ nxttok = LT;
+ }
+ break;
+
+ case '=':
+ if (*++lptr == '=') {
+ SetTok (EQ);
+ } else {
+ nxttok = ASGN;
+ }
+ break;
+
+ case '>':
+ switch (*++lptr) {
+ case '=':
+ SetTok (GE);
+ break;
+ case '>':
+ if (*++lptr == '=') {
+ SetTok (SRASGN);
+ } else {
+ nxttok = ASR;
+ }
+ break;
+ default:
+ nxttok = GT;
+ }
+ break;
+
+ case '?':
+ SetTok (QUEST);
+ break;
+
+ case '[':
+ SetTok (LBRACK);
+ break;
+
+ case ']':
+ SetTok (RBRACK);
+ break;
+
+ case '^':
+ if (*++lptr == '=') {
+ SetTok (XOASGN);
+ } else {
+ nxttok = XOR;
+ }
+ break;
+
+ case '{':
+ SetTok (LCURLY);
+ break;
+
+ case '|':
+ switch (*++lptr) {
+ case '|':
+ SetTok (DBAR);
+ break;
+ case '=':
+ SetTok (OASGN);
+ break;
+ default:
+ nxttok = BAR;
+ }
+ break;
+
+ case '}':
+ SetTok (RCURLY);
+ break;
+
+ case '~':
+ SetTok (COMP);
+ break;
+
+ case '#':
+ while (*++lptr == ' ') ; /* Skip it and following whitespace */
+ if (!issym (token) || strcmp (token, "pragma") != 0) {
+ /* OOPS - should not happen */
+ Error (ERR_CPP_DIRECTIVE_EXPECTED);
+ }
+ nxttok = PRAGMA;
+ break;
+
+ default:
+ unknown (c);
+
+ }
+
+}
+
+
+
+void Consume (unsigned Token, unsigned char ErrNum)
+/* Eat token if it is the next in the input stream, otherwise print an error
+ * message.
+ */
+{
+ if (curtok == Token) {
+ gettok ();
+ } else {
+ Error (ErrNum);
+ }
+}
+
+
+
+void ConsumeColon (void)
+/* Check for a colon and skip it. */
+{
+ Consume (COLON, ERR_COLON_EXPECTED);
+}
+
+
+
+void ConsumeSemi (void)
+/* Check for a semicolon and skip it. */
+{
+ /* Try do be smart about typos... */
+ if (curtok == SEMI) {
+ gettok ();
+ } else {
+ Error (ERR_SEMICOLON_EXPECTED);
+ if (curtok == COLON || curtok == COMMA) {
+ gettok ();
+ }
+ }
+}
+
+
+
+void ConsumeLParen (void)
+/* Check for a left parenthesis and skip it */
+{
+ Consume (LPAREN, ERR_LPAREN_EXPECTED);
+}
+
+
+
+void ConsumeRParen (void)
+/* Check for a right parenthesis and skip it */
+{
+ Consume (RPAREN, ERR_RPAREN_EXPECTED);
+}
+
+
+
+void ConsumeLBrack (void)
+/* Check for a left bracket and skip it */
+{
+ Consume (LBRACK, ERR_LBRACK_EXPECTED);
+}
+
+
+
+void ConsumeRBrack (void)
+/* Check for a right bracket and skip it */
+{
+ Consume (RBRACK, ERR_RBRACK_EXPECTED);
+}
+
+
+
+void ConsumeLCurly (void)
+/* Check for a left curly brace and skip it */
+{
+ Consume (LCURLY, ERR_LCURLY_EXPECTED);
+}
+
+
+
+void ConsumeRCurly (void)
+/* Check for a right curly brace and skip it */
+{
+ Consume (RCURLY, ERR_RCURLY_EXPECTED);
+}
+
+
+
--- /dev/null
+/*
+ * scanner.h
+ *
+ * Ullrich von Bassewitz, 07.06.1998
+ */
+
+
+
+#ifndef SCANNER_H
+#define SCANNER_H
+
+
+
+#include "datatype.h"
+#include "ident.h"
+
+
+
+/*****************************************************************************/
+/* token definitions */
+/*****************************************************************************/
+
+
+
+#define CEOF 0
+
+#define AUTO 10
+#define EXTERN 11
+#define REGISTER 12
+#define STATIC 13
+#define TYPEDEF 14
+#define ENUM 15
+#define CONST 16
+#define VOLATILE 17
+
+#define FIRSTTYPE 19
+#define CHAR 19
+#define INT 20
+#define DOUBLE 21
+#define FLOAT 22
+#define LONG 23
+#define UNSIGNED 24
+#define SIGNED 25
+#define SHORT 26
+#define STRUCT 27
+#define UNION 28
+#define VOID 29
+#define LASTTYPE 29
+
+#define DO 30
+#define FOR 31
+#define GOTO 32
+#define IF 33
+#define RETURN 34
+#define SWITCH 35
+#define WHILE 36
+
+#define ASM 40
+#define CASE 41
+#define DEFAULT 42
+#define BREAK 43
+#define CONTINUE 44
+#define ELSE 45
+#define ELLIPSIS 46
+#define SIZEOF 47
+
+#define IDENT 50
+#define SEMI 51
+
+/* primary operators */
+#define LBRACK 52
+#define LPAREN 53
+#define DOT 54
+#define PREF 55
+
+#define LCURLY 56
+#define RBRACK 57
+#define COMP 58
+#define INC 59
+#define PASGN 60
+#define PLUS 61
+#define COMMA 62
+#define DEC 63
+#define SASGN 64
+#define RCURLY 65
+#define MINUS 66
+#define MASGN 67
+#define STAR 68
+#define DASGN 69
+#define DIV 70
+#define DAMP 71
+#define AASGN 72
+#define AMP 73
+#define NE 74
+#define BANG 75
+#define DBAR 76
+#define OASGN 77
+#define BAR 78
+#define EQ 79
+#define ASGN 80
+#define SLASGN 81
+#define ASL 82
+
+/* inequalities */
+#define LE 83
+#define LT 84
+#define GE 85
+#define GT 86
+
+#define SRASGN 87
+#define ASR 88
+#define XOASGN 89
+#define XOR 90
+#define MOASGN 91
+#define MOD 92
+#define QUEST 93
+#define COLON 94
+#define RPAREN 95
+#define SCONST 96
+#define ICONST 97
+#define CCONST 98
+#define FCONST 99
+
+#define FASTCALL 100
+#define AX 101
+#define EAX 102
+
+#define PRAGMA 110
+
+
+
+/*****************************************************************************/
+/* data */
+/*****************************************************************************/
+
+
+
+/* Token stuff */
+typedef struct Token_ Token;
+struct Token_ {
+ unsigned Tok; /* The token itself */
+ long IVal; /* The integer attribute */
+ ident Ident; /* Identifier if IDENT */
+ unsigned Pos; /* Source line where the token comes from */
+ type* IType; /* Type if integer constant */
+};
+
+extern Token CurTok; /* The current token */
+extern Token NextTok; /* The next token */
+
+/* Defines to make the old code work */
+#define curtok CurTok.Tok
+#define curval CurTok.IVal
+#define curpos CurTok.Pos
+#define curtype CurTok.IType
+
+#define nxttok NextTok.Tok
+#define nxtval NextTok.IVal
+#define nxtpos NextTok.Pos
+#define nxttype NextTok.IType
+
+
+
+/*****************************************************************************/
+/* code */
+/*****************************************************************************/
+
+
+
+void symname (char* s);
+/* Get symbol from input stream */
+
+int issym (char* s);
+/* Get symbol from input stream or return 0 if not a symbol. */
+
+void gettok (void);
+/* Get next token from input stream */
+
+void Consume (unsigned Token, unsigned char ErrNum);
+/* Eat token if it is the next in the input stream, otherwise print an error
+ * message.
+ */
+
+void ConsumeColon (void);
+/* Check for a colon and skip it. */
+
+void ConsumeSemi (void);
+/* Check for a semicolon and skip it. */
+
+void ConsumeLParen (void);
+/* Check for a left parenthesis and skip it */
+
+void ConsumeRParen (void);
+/* Check for a right parenthesis and skip it */
+
+void ConsumeLBrack (void);
+/* Check for a left bracket and skip it */
+
+void ConsumeRBrack (void);
+/* Check for a right bracket and skip it */
+
+void ConsumeLCurly (void);
+/* Check for a left curly brace and skip it */
+
+void ConsumeRCurly (void);
+/* Check for a right curly brace and skip it */
+
+
+
+/* End of scanner.h */
+#endif
+
+
+
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* stdfunc.c */
+/* */
+/* Handle inlining of known functions for the cc65 compiler */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "check.h"
+#include "codegen.h"
+#include "error.h"
+#include "global.h"
+#include "scanner.h"
+#include "stdfunc.h"
+
+
+
+/*****************************************************************************/
+/* Function forwards */
+/*****************************************************************************/
+
+
+
+static void StdFunc_strlen (struct expent*);
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Table with all known functions and their handlers. Must be sorted
+ * alphabetically!
+ */
+static struct FuncDesc {
+ const char* Name;
+ void (*Handler) (struct expent*);
+} StdFuncs [] = {
+ { "strlen", StdFunc_strlen },
+
+};
+#define FUNC_COUNT (sizeof (StdFuncs) / sizeof (StdFuncs [0]))
+
+
+/*****************************************************************************/
+/* Helper functions */
+/*****************************************************************************/
+
+
+
+static int CmpFunc (const void* Key, const void* Elem)
+/* Compare function for bsearch */
+{
+ return strcmp ((const char*) Key, ((const struct FuncDesc*) Elem)->Name);
+}
+
+
+
+static struct FuncDesc* FindFunc (const char* Name)
+/* Find a function with the given name. Return a pointer to the descriptor if
+ * found, return NULL otherwise.
+ */
+{
+ return bsearch (Name, StdFuncs, FUNC_COUNT, sizeof (StdFuncs [0]), CmpFunc);
+}
+
+
+
+/*****************************************************************************/
+/* Handle known functions */
+/*****************************************************************************/
+
+
+
+static void StdFunc_strlen (struct expent* lval)
+/* Handle the strlen function */
+{
+ struct expent pval;
+
+ /* Fetch the parameter */
+ int k = hie1 (&pval);
+
+ /* Check if the parameter is a const address */
+ unsigned flags = 0;
+ unsigned pflags = pval.e_flags & ~E_MCTYPE;
+ if (pflags == E_MCONST) {
+ /* Constant numeric address */
+ flags |= CF_CONST | CF_ABSOLUTE;
+ } else if (k == 0 && ((pflags & E_MGLOBAL) != 0 || pval.e_flags == E_MEOFFS)) {
+ /* Global array with or without offset */
+ flags |= CF_CONST;
+ if (pval.e_flags & E_TGLAB) {
+ /* External linkage */
+ flags |= CF_EXTERNAL;
+ } else {
+ flags |= CF_STATIC;
+ }
+ } else {
+ /* Not const, load parameter into primary */
+ exprhs (CF_NONE, k, &pval);
+ }
+
+ /* Convert the parameter type to the type needed, check for mismatches */
+ assignadjust (SignedChars? type_pschar : type_puchar, &pval);
+
+ /* Generate the strlen code */
+ g_strlen (flags, pval.e_name, pval.e_const);
+
+ /* We expect the closing brace */
+ ConsumeRParen ();
+}
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+int IsStdFunc (const char* Name)
+/* Determine if the given function is a known standard function that may be
+ * called in a special way.
+ */
+{
+ /* Look into the table for known names */
+ return FindFunc (Name) != 0;
+}
+
+
+
+void HandleStdFunc (struct expent* lval)
+/* Generate code for a known standard function. */
+{
+ /* Get a pointer to the table entry */
+ struct FuncDesc* F = FindFunc ((const char*) lval->e_name);
+ CHECK (F != 0);
+
+ /* Call the handler function */
+ F->Handler (lval);
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* stdfunc.h */
+/* */
+/* Handle inlining of known functions for the cc65 compiler */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef STDFUNC_H
+#define STDFUNC_H
+
+
+
+#include "symtab.h"
+#include "expr.h"
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+int IsStdFunc (const char* Name);
+/* Determine if the given function is a known standard function that may be
+ * called in a special way.
+ */
+
+void HandleStdFunc (struct expent* lval);
+/* Generate code for a known standard function. */
+
+
+
+/* End of stdfunc.h */
+
+#endif
+
+
+
--- /dev/null
+/*
+ * stmt.c
+ *
+ * Ullrich von Bassewitz, 06.08.1998
+ *
+ * Original by John R. Dunning - see copyleft.jrd
+ */
+
+
+
+#include <stdio.h>
+#include <string.h>
+
+#include "asmcode.h"
+#include "asmlabel.h"
+#include "codegen.h"
+#include "datatype.h"
+#include "error.h"
+#include "expr.h"
+#include "function.h"
+#include "global.h"
+#include "goto.h"
+#include "litpool.h"
+#include "locals.h"
+#include "loop.h"
+#include "mem.h"
+#include "pragma.h"
+#include "scanner.h"
+#include "symtab.h"
+#include "stmt.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Maximum count of cases */
+#define CASE_MAX 257
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+static int statement (void);
+/* Forward decl */
+
+
+
+static int doif (void)
+/* Handle 'if' statement here */
+{
+ int flab1;
+ int flab2;
+ int gotbreak;
+
+ /* Skip the if */
+ gettok ();
+
+ /* Generate a jump label and parse the condition */
+ flab1 = GetLabel ();
+ test (flab1, 0);
+
+ /* Parse the if body */
+ gotbreak = statement ();
+
+ /* Else clause present? */
+ if (curtok != ELSE) {
+
+ g_defloclabel (flab1);
+ /* Since there's no else clause, we're not sure, if the a break
+ * statement is really executed.
+ */
+ return 0;
+
+ } else {
+
+ /* Skip the else */
+ gettok ();
+
+ /* If we had some sort of break statement at the end of the if clause,
+ * there's no need to generate an additional jump around the else
+ * clause, since the jump is never reached.
+ */
+ if (!gotbreak) {
+ flab2 = GetLabel ();
+ g_jump (flab2);
+ } else {
+ /* Mark the label as unused */
+ flab2 = 0;
+ }
+ g_defloclabel (flab1);
+ gotbreak &= statement ();
+
+ /* Generate the label for the else clause */
+ if (flab2) {
+ g_defloclabel (flab2);
+ }
+
+ /* Done */
+ return gotbreak;
+ }
+}
+
+
+
+static void dowhile (char wtype)
+/* Handle 'while' statement here */
+{
+ int loop;
+ int lab;
+
+ gettok ();
+ loop = GetLabel ();
+ lab = GetLabel ();
+ addloop (oursp, loop, lab, 0, 0);
+ g_defloclabel (loop);
+ if (wtype == 'w') {
+
+ /* While loop */
+ test (lab, 0);
+
+ /* If the statement following the while loop is empty, that is, we have
+ * something like "while (1) ;", the test function ommitted the jump as
+ * an optimization. Since we know, the condition codes are set, we can
+ * do another small optimization here, and use a conditional jump
+ * instead an absolute one.
+ */
+ if (curtok == SEMI) {
+ /* Shortcut */
+ gettok ();
+ /* Use a conditional jump */
+ g_truejump (CF_NONE, loop);
+ } else {
+ /* There is code inside the while loop */
+ statement ();
+ g_jump (loop);
+ g_defloclabel (lab);
+ }
+
+ } else {
+
+ /* Do loop */
+ statement ();
+ Consume (WHILE, ERR_WHILE_EXPECTED);
+ test (loop, 1);
+ ConsumeSemi ();
+ g_defloclabel (lab);
+
+ }
+ delloop ();
+}
+
+
+
+static void doreturn (void)
+/* Handle 'return' statement here */
+{
+ struct expent lval;
+ unsigned etype = 0; /* Type of return expression */
+ int HaveVal = 0; /* Do we have a return value in ax? */
+
+
+ gettok ();
+ if (curtok != SEMI) {
+ if (HasVoidReturn (CurrentFunc)) {
+ Error (ERR_CANNOT_RETURN_VALUE);
+ }
+ if (evalexpr (CF_NONE, hie0, &lval) == 0) {
+ /* Constant value */
+ etype = CF_CONST;
+ } else {
+ /* Value in the primary register */
+ HaveVal = 1;
+ }
+
+ /* Convert the return value to the type of the function result */
+ if (!HasVoidReturn (CurrentFunc)) {
+ etype |= assignadjust (GetReturnType (CurrentFunc), &lval) & ~CF_CONST;
+ }
+ } else if (!HasVoidReturn (CurrentFunc)) {
+ Error (ERR_MUST_RETURN_VALUE);
+ }
+ RestoreRegVars (HaveVal);
+ g_leave (etype, lval.e_const);
+}
+
+
+
+static void dobreak (void)
+/* Handle 'break' statement here */
+{
+ struct loopdesc* l;
+
+ gettok ();
+ if ((l = currentloop ()) == 0) {
+ /* Error: No current loop */
+ return;
+ }
+ g_space (oursp - l->sp);
+ g_jump (l->label);
+}
+
+
+
+static void docontinue (void)
+/* Handle 'continue' statement here */
+{
+ struct loopdesc* l;
+
+ gettok ();
+ if ((l = currentloop ()) == 0) {
+ /* Error: Not in loop */
+ return;
+ }
+ do {
+ if (l->loop) {
+ break;
+ }
+ l = l->next;
+ } while (l);
+ if (l == 0) {
+ Error (ERR_UNEXPECTED_CONTINUE);
+ return;
+ }
+ g_space (oursp - l->sp);
+ if (l->linc) {
+ g_jump (l->linc);
+ } else {
+ g_jump (l->loop);
+ }
+}
+
+
+
+static void cascadeswitch (struct expent* eval)
+/* Handle a switch statement for chars with a cmp cascade for the selector */
+{
+ unsigned exitlab; /* Exit label */
+ unsigned nextlab; /* Next case label */
+ unsigned codelab; /* Label that starts the actual selector code */
+ int havebreak; /* Remember if we exited with break */
+ int lcount; /* Label count */
+ unsigned flags; /* Code generator flags */
+ struct expent lval; /* Case label expression */
+ long val; /* Case label value */
+
+
+ /* Create a loop so we may break out, init labels */
+ exitlab = GetLabel ();
+ addloop (oursp, 0, exitlab, 0, 0);
+
+ /* Setup some variables needed in the loop below */
+ flags = TypeOf (eval->e_tptr) | CF_CONST | CF_FORCECHAR;
+ codelab = nextlab = 0;
+ havebreak = 1;
+
+ /* Parse the labels */
+ lcount = 0;
+ while (curtok != RCURLY) {
+
+ if (curtok == CASE || curtok == DEFAULT) {
+
+ /* If the code for the previous selector did not end with a
+ * break statement, we must jump over the next selector test.
+ */
+ if (!havebreak) {
+ /* Define a label for the code */
+ if (codelab == 0) {
+ codelab = GetLabel ();
+ }
+ g_jump (codelab);
+ }
+
+ /* If we have a cascade label, emit it */
+ if (nextlab) {
+ g_defloclabel (nextlab);
+ nextlab = 0;
+ }
+
+ while (curtok == CASE || curtok == DEFAULT) {
+
+ /* Parse the selector */
+ if (curtok == CASE) {
+
+ /* Count labels */
+ ++lcount;
+
+ /* Skip the "case" token */
+ gettok ();
+
+ /* Read the selector expression */
+ constexpr (&lval);
+ if (!IsInt (lval.e_tptr)) {
+ Error (ERR_ILLEGAL_TYPE);
+ }
+
+ /* Check the range of the expression */
+ val = lval.e_const;
+ switch (*eval->e_tptr) {
+
+ case T_CHAR:
+ /* Signed char */
+ if (val < -128 || val > 127) {
+ Error (ERR_RANGE);
+ }
+ break;
+
+ case T_UCHAR:
+ if (val < 0 || val > 255) {
+ Error (ERR_RANGE);
+ }
+ break;
+
+ case T_INT:
+ if (val < -32768 || val > 32767) {
+ Error (ERR_RANGE);
+ }
+ break;
+
+ case T_UINT:
+ if (val < 0 || val > 65535) {
+ Error (ERR_RANGE);
+ }
+ break;
+
+ default:
+ Internal ("Invalid type: %02X", *eval->e_tptr & 0xFF);
+ }
+
+ /* Skip the colon */
+ ConsumeColon ();
+
+ /* Emit a compare */
+ g_cmp (flags, val);
+
+ /* If another case follows, we will jump to the code if
+ * the condition is true.
+ */
+ if (curtok == CASE) {
+ /* Create a code label if needed */
+ if (codelab == 0) {
+ codelab = GetLabel ();
+ }
+ g_falsejump (CF_NONE, codelab);
+ } else if (curtok != DEFAULT) {
+ /* No case follows, jump to next selector */
+ if (nextlab == 0) {
+ nextlab = GetLabel ();
+ }
+ g_truejump (CF_NONE, nextlab);
+ }
+
+ } else {
+
+ /* Default case */
+ gettok ();
+
+ /* Skip the colon */
+ ConsumeColon ();
+
+ /* Handle the pathologic case: DEFAULT followed by CASE */
+ if (curtok == CASE) {
+ if (codelab == 0) {
+ codelab = GetLabel ();
+ }
+ g_jump (codelab);
+ }
+ }
+
+ }
+
+ }
+
+ /* Emit a code label if we have one */
+ if (codelab) {
+ g_defloclabel (codelab);
+ codelab = 0;
+ }
+
+ /* Parse statements */
+ if (curtok != RCURLY) {
+ havebreak = statement ();
+ }
+ }
+
+ /* Check if we have any labels */
+ if (lcount == 0) {
+ Warning (WARN_NO_CASE_LABELS);
+ }
+
+ /* Eat the closing curly brace */
+ gettok ();
+
+ /* Define the exit label and, if there's a next label left, create this
+ * one, too.
+ */
+ if (nextlab) {
+ g_defloclabel (nextlab);
+ }
+ g_defloclabel (exitlab);
+
+ /* End the loop */
+ delloop ();
+}
+
+
+
+static void tableswitch (struct expent* eval)
+/* Handle a switch statement via table based selector */
+{
+ /* Entry for one case in a switch statement */
+ struct swent {
+ long sw_const; /* selector value */
+ unsigned sw_lab; /* label for this selector */
+ };
+
+ int dlabel; /* for default */
+ int lab; /* exit label */
+ int label; /* label for case */
+ int lcase; /* label for compares */
+ int lcount; /* Label count */
+ int havebreak; /* Last statement has a break */
+ unsigned flags; /* Code generator flags */
+ struct expent lval; /* Case label expression */
+ struct swent *p;
+ struct swent *swtab;
+
+ /* Allocate memory for the switch table */
+ swtab = xmalloc (CASE_MAX * sizeof (struct swent));
+
+ /* Create a look so we may break out, init labels */
+ havebreak = 0; /* Keep gcc silent */
+ dlabel = 0; /* init */
+ lab = GetLabel (); /* get exit */
+ p = swtab;
+ addloop (oursp, 0, lab, 0, 0);
+
+ /* Jump behind the code for the CASE labels */
+ g_jump (lcase = GetLabel ());
+ lcount = 0;
+ while (curtok != RCURLY) {
+ if (curtok == CASE || curtok == DEFAULT) {
+ if (lcount >= CASE_MAX) {
+ Fatal (FAT_TOO_MANY_CASE_LABELS);
+ }
+ label = GetLabel ();
+ do {
+ if (curtok == CASE) {
+ gettok ();
+ constexpr (&lval);
+ if (!IsInt (lval.e_tptr)) {
+ Error (ERR_ILLEGAL_TYPE);
+ }
+ p->sw_const = lval.e_const;
+ p->sw_lab = label;
+ ++p;
+ ++lcount;
+ } else {
+ gettok ();
+ dlabel = label;
+ }
+ ConsumeColon ();
+ } while (curtok == CASE || curtok == DEFAULT);
+ g_defloclabel (label);
+ havebreak = 0;
+ }
+ if (curtok != RCURLY) {
+ havebreak = statement ();
+ }
+ }
+
+ /* Check if we have any labels */
+ if (lcount == 0) {
+ Warning (WARN_NO_CASE_LABELS);
+ }
+
+ /* Eat the closing curly brace */
+ gettok ();
+
+ /* If the last statement doesn't have a break or return, add one */
+ if (!havebreak) {
+ g_jump (lab);
+ }
+
+ /* Actual selector code goes here */
+ g_defloclabel (lcase);
+
+ /* Create the call to the switch subroutine */
+ flags = TypeOf (eval->e_tptr);
+ g_switch (flags);
+
+ /* First entry is negative of label count */
+ g_defdata (CF_INT, -((int)lcount)-1, 0);
+
+ /* Create the case selector table */
+ AddCodeHint ("casetable");
+ p = swtab;
+ while (lcount) {
+ g_case (flags, p->sw_lab, p->sw_const); /* Create one label */
+ --lcount;
+ ++p;
+ }
+
+ if (dlabel) {
+ g_jump (dlabel);
+ }
+ g_defloclabel (lab);
+ delloop ();
+
+ /* Free the allocated space for the labels */
+ xfree (swtab);
+}
+
+
+
+static void doswitch (void)
+/* Handle 'switch' statement here */
+{
+ struct expent eval; /* Switch statement expression */
+
+ /* Eat the "switch" */
+ gettok ();
+
+ /* Read the switch expression */
+ ConsumeLParen ();
+ intexpr (&eval);
+ ConsumeRParen ();
+
+ /* result of expr is in P */
+ ConsumeLCurly ();
+
+ /* Now decide which sort of switch we will create: */
+ if (IsChar (eval.e_tptr) || (FavourSize == 0 && IsInt (eval.e_tptr))) {
+ cascadeswitch (&eval);
+ } else {
+ tableswitch (&eval);
+ }
+}
+
+
+
+static void dofor (void)
+/* Handle 'for' statement here */
+{
+ int loop;
+ int lab;
+ int linc;
+ int lstat;
+ struct expent lval1;
+ struct expent lval2;
+ struct expent lval3;
+
+ gettok ();
+ loop = GetLabel ();
+ lab = GetLabel ();
+ linc = GetLabel ();
+ lstat = GetLabel ();
+ addloop (oursp, loop, lab, linc, lstat);
+ ConsumeLParen ();
+ if (curtok != SEMI) { /* exp1 */
+ expression (&lval1);
+ }
+ ConsumeSemi ();
+ g_defloclabel (loop);
+ if (curtok != SEMI) { /* exp2 */
+ boolexpr (&lval2);
+ g_truejump (CF_NONE, lstat);
+ g_jump (lab);
+ } else {
+ g_jump (lstat);
+ }
+ ConsumeSemi ();
+ g_defloclabel (linc);
+ if (curtok != RPAREN) { /* exp3 */
+ expression (&lval3);
+ }
+ ConsumeRParen ();
+ g_jump (loop);
+ g_defloclabel (lstat);
+ statement ();
+ g_jump (linc);
+ g_defloclabel (lab);
+ delloop ();
+}
+
+
+
+static int statement (void)
+/* Statement parser. Called whenever syntax requires a statement.
+ * This routine performs that statement and returns 1 if it is a branch,
+ * 0 otherwise
+ */
+{
+ struct expent lval;
+
+ /* */
+ if (curtok == IDENT && nxttok == COLON) {
+
+ /* Special handling for a label */
+ DoLabel ();
+
+ } else {
+
+ switch (curtok) {
+
+ case LCURLY:
+ return compound ();
+
+ case IF:
+ return doif ();
+
+ case WHILE:
+ dowhile ('w');
+ break;
+
+ case DO:
+ dowhile ('d');
+ break;
+
+ case SWITCH:
+ doswitch ();
+ break;
+
+ case RETURN:
+ doreturn ();
+ ConsumeSemi ();
+ return 1;
+
+ case BREAK:
+ dobreak ();
+ ConsumeSemi ();
+ return 1;
+
+ case CONTINUE:
+ docontinue ();
+ ConsumeSemi ();
+ return 1;
+
+ case FOR:
+ dofor ();
+ break;
+
+ case GOTO:
+ DoGoto ();
+ ConsumeSemi ();
+ return 1;
+
+ case SEMI:
+ /* ignore it. */
+ gettok ();
+ break;
+
+ case PRAGMA:
+ DoPragma ();
+ break;
+
+ default:
+ AddCodeHint ("stmt:start");
+ expression (&lval);
+ AddCodeHint ("stmt:end");
+ ConsumeSemi ();
+ }
+ }
+ return 0;
+}
+
+
+
+int compound (void)
+/* Compound statement. Allow any number of statements, inside braces. */
+{
+ static unsigned CurrentLevel = 0;
+
+ int isbrk;
+ int oldsp;
+
+ /* eat LCURLY */
+ gettok ();
+
+ /* Remember the stack at block entry */
+ oldsp = oursp;
+
+ /* If we're not on function level, enter a new lexical level */
+ if (CurrentLevel++ > 0) {
+ /* A nested block */
+ EnterBlockLevel ();
+ }
+
+ /* Parse local variable declarations if any */
+ DeclareLocals ();
+
+ /* Now process statements in the function body */
+ isbrk = 0;
+ while (curtok != RCURLY) {
+ if (curtok == CEOF)
+ break;
+ else {
+ isbrk = statement ();
+ }
+ }
+
+ /* Emit references to imports/exports for this block */
+ EmitExternals ();
+
+ /* If this is not the top level compound statement, clean up the stack.
+ * For a top level statement this will be done by the function exit code.
+ */
+ if (--CurrentLevel != 0) {
+ /* Some sort of nested block */
+ LeaveBlockLevel ();
+ if (isbrk) {
+ oursp = oldsp;
+ } else {
+ g_space (oursp - oldsp);
+ oursp = oldsp;
+ }
+ }
+
+ /* Eat closing brace */
+ ConsumeRCurly ();
+
+ return isbrk;
+}
+
+
+
--- /dev/null
+/*
+ * stmt.h
+ *
+ * Ullrich von Bassewitz, 19.06.1998
+ */
+
+
+
+#ifndef STMT_H
+#define STMT_H
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+int compound ();
+/* Compound statement. Allow any number of statements, inside braces. */
+
+
+
+/* End of stmt.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* symentry.c */
+/* */
+/* Symbol table entries for the cc65 C compiler */
+/* */
+/* */
+/* */
+/* (C) 2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include "mem.h"
+#include "symentry.h"
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+SymEntry* NewSymEntry (const char* Name, unsigned Flags)
+/* Create a new symbol table with the given name */
+{
+ /* Get the length of the name */
+ unsigned Len = strlen (Name);
+
+ /* Allocate memory for the symbol entry */
+ SymEntry* E = xmalloc (sizeof (SymEntry) + Len);
+
+ /* Initialize the entry */
+ E->NextHash = 0;
+ E->PrevSym = 0;
+ E->NextSym = 0;
+ E->Link = 0;
+ E->Owner = 0;
+ E->Flags = Flags;
+ E->Type = 0;
+ memcpy (E->Name, Name, Len+1);
+
+ /* Return the new entry */
+ return E;
+}
+
+
+
+void FreeSymEntry (SymEntry* E)
+/* Free a symbol entry */
+{
+ TypeFree (E->Type);
+ xfree (E);
+}
+
+
+
+void DumpSymEntry (FILE* F, const SymEntry* E)
+/* Dump the given symbol table entry to the file in readable form */
+{
+ static const struct {
+ const char* Name;
+ unsigned Val;
+ } Flags [] = {
+ /* Beware: Order is important! */
+ { "SC_TYPEDEF", SC_TYPEDEF },
+ { "SC_SFLD", SC_SFLD },
+ { "SC_STRUCT", SC_STRUCT },
+ { "SC_AUTO", SC_AUTO },
+ { "SC_REGISTER", SC_REGISTER },
+ { "SC_STATIC", SC_STATIC },
+ { "SC_EXTERN", SC_EXTERN },
+ { "SC_ENUM", SC_ENUM },
+ { "SC_LABEL", SC_LABEL },
+ { "SC_PARAM", SC_PARAM },
+ { "SC_FUNC", SC_FUNC },
+ { "SC_STORAGE", SC_STORAGE },
+ { "SC_DEF", SC_DEF },
+ { "SC_REF", SC_REF },
+ { "SC_ZEROPAGE", SC_ZEROPAGE },
+ };
+
+ unsigned I;
+ unsigned SymFlags;
+
+ /* Print the name */
+ fprintf (F, "%s:\n", E->Name);
+
+ /* Print the flags */
+ SymFlags = E->Flags;
+ fprintf (F, " Flags: ");
+ for (I = 0; I < sizeof (Flags) / sizeof (Flags[0]) && SymFlags != 0; ++I) {
+ if ((SymFlags & Flags[I].Val) == Flags[I].Val) {
+ SymFlags &= ~Flags[I].Val;
+ fprintf (F, "%s ", Flags[I].Name);
+ }
+ }
+ if (SymFlags != 0) {
+ fprintf (F, "%04X", SymFlags);
+ }
+ fprintf (F, "\n");
+
+ /* Print the type */
+ fprintf (F, " Type: ");
+ if (E->Type) {
+ PrintType (F, E->Type);
+ } else {
+ fprintf (F, "(none)\n");
+ }
+}
+
+
+
+int IsTypeDef (const SymEntry* E)
+/* Return true if the given entry is a typedef entry */
+{
+ return ((E->Flags & SC_TYPEDEF) == SC_TYPEDEF);
+}
+
+
+
+void ChangeSymType (SymEntry* Entry, type* Type)
+/* Change the type of the given symbol */
+{
+ TypeFree (Entry->Type);
+ Entry->Type = TypeDup (Type);
+}
+
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* symentry.h */
+/* */
+/* Symbol table entries for the cc65 C compiler */
+/* */
+/* */
+/* */
+/* (C) 2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef SYMENTRY_H
+#define SYMENTRY_H
+
+
+
+#include <stdio.h>
+
+#include "datatype.h"
+
+
+
+/*****************************************************************************/
+/* struct SymEntry */
+/*****************************************************************************/
+
+
+
+/* Storage classes and flags */
+#define SC_AUTO 0x0001U
+#define SC_REGISTER 0x0002U /* Register variable, is in static storage */
+#define SC_STATIC 0x0004U
+#define SC_EXTERN 0x0008U
+
+#define SC_ENUM 0x0010U /* An enum (numeric constant) */
+#define SC_LABEL 0x0020U /* A goto label */
+#define SC_PARAM 0x0040U /* This is a function parameter */
+#define SC_FUNC 0x0080U /* Function entry */
+
+#define SC_STORAGE 0x0100U /* Symbol with associated storage */
+#define SC_DEFAULT 0x0200U /* Flag: default storage class was used */
+
+#define SC_DEF 0x0400U /* Symbol is defined */
+#define SC_REF 0x0800U /* Symbol is referenced */
+
+#define SC_TYPE 0x1000U /* This is a type, struct, typedef, etc. */
+#define SC_STRUCT 0x1001U /* Struct or union */
+#define SC_SFLD 0x1002U /* Struct or union field */
+#define SC_TYPEDEF 0x1003U /* A typedef */
+
+#define SC_ZEROPAGE 0x8000U /* Symbol marked as zeropage */
+
+
+
+/* Symbol table entry */
+typedef struct SymEntry SymEntry;
+struct SymEntry {
+ SymEntry* NextHash; /* Next entry in hash list */
+ SymEntry* PrevSym; /* Previous symbol in dl list */
+ SymEntry* NextSym; /* Next symbol double linked list */
+ SymEntry* Link; /* General purpose single linked list */
+ struct SymTable* Owner; /* Symbol table the symbol is in */
+ unsigned Flags; /* Symbol flags */
+ type* Type; /* Symbol type */
+
+ /* Data that differs for the different symbol types */
+ union {
+
+ /* Offset for locals or struct members */
+ int Offs;
+
+ /* Label name for static symbols */
+ unsigned Label;
+
+ /* Value for enums */
+ int EnumVal;
+
+ /* Data for structs/unions */
+ struct {
+ struct SymTable* SymTab; /* Member symbol table */
+ unsigned Size; /* Size of the union/struct */
+ } S;
+
+ /* Data for functions */
+ struct FuncDesc* Func; /* Function descriptor */
+
+ } V;
+ char Name[1]; /* Name, dynamically allocated */
+};
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+SymEntry* NewSymEntry (const char* Name, unsigned Flags);
+/* Create a new symbol table with the given name */
+
+void FreeSymEntry (SymEntry* E);
+/* Free a symbol entry */
+
+void DumpSymEntry (FILE* F, const SymEntry* E);
+/* Dump the given symbol table entry to the file in readable form */
+
+int IsTypeDef (const SymEntry* E);
+/* Return true if the given entry is a typedef entry */
+
+void ChangeSymType (SymEntry* Entry, type* Type);
+/* Change the type of the given symbol */
+
+
+
+/* End of symentry.h */
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* symtab.c */
+/* */
+/* Symbol table management for the cc65 C compiler */
+/* */
+/* */
+/* */
+/* (C) 2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "asmcode.h"
+#include "asmlabel.h"
+#include "check.h"
+#include "codegen.h"
+#include "datatype.h"
+#include "declare.h"
+#include "error.h"
+#include "funcdesc.h"
+#include "global.h"
+#include "hashstr.h"
+#include "io.h"
+#include "mem.h"
+#include "symentry.h"
+#include "symtab.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* An empty symbol table */
+SymTable EmptySymTab = {
+ 0, /* PrevTab */
+ 0, /* SymHead */
+ 0, /* SymTail */
+ 0, /* SymCount */
+ 1, /* Size */
+ { 0 } /* Tab[1] */
+};
+
+/* Symbol table sizes */
+#define SYMTAB_SIZE_GLOBAL 211U
+#define SYMTAB_SIZE_FUNCTION 29U
+#define SYMTAB_SIZE_BLOCK 13U
+#define SYMTAB_SIZE_STRUCT 19U
+#define SYMTAB_SIZE_LABEL 7U
+
+/* Predefined lexical levels */
+#define LEX_LEVEL_GLOBAL 1U
+
+/* The current and root symbol tables */
+static unsigned LexicalLevel = 0; /* For safety checks */
+static SymTable* SymTab0 = 0;
+static SymTable* SymTab = 0;
+static SymTable* StructTab0 = 0;
+static SymTable* StructTab = 0;
+static SymTable* EnumTab0 = 0;
+static SymTable* EnumTab = 0;
+static SymTable* LabelTab = 0;
+
+
+
+/*****************************************************************************/
+/* struct SymTable */
+/*****************************************************************************/
+
+
+
+static SymTable* NewSymTable (unsigned Size)
+/* Create and return a symbol table for the given lexical level */
+{
+ unsigned I;
+
+ /* Allocate memory for the table */
+ SymTable* S = xmalloc (sizeof (SymTable) + (Size-1) * sizeof (SymEntry*));
+
+ /* Initialize the symbol table structure */
+ S->PrevTab = 0;
+ S->SymHead = 0;
+ S->SymTail = 0;
+ S->SymCount = 0;
+ S->Size = Size;
+ for (I = 0; I < Size; ++I) {
+ S->Tab[I] = 0;
+ }
+
+ /* Return the symbol table */
+ return S;
+}
+
+
+
+static void FreeSymTable (SymTable* S)
+/* Free the given symbo table including all symbols */
+{
+ /* Free all symbols */
+ SymEntry* Sym = S->SymHead;
+ while (Sym) {
+ SymEntry* NextSym = Sym->NextSym;
+ FreeSymEntry (Sym);
+ Sym = NextSym;
+ }
+
+ /* Free the table itself */
+ xfree (S);
+}
+
+
+
+/*****************************************************************************/
+/* Check symbols in a table */
+/*****************************************************************************/
+
+
+
+static void CheckSymTable (SymTable* Tab)
+/* Check a symbol table for open references, unused symbols ... */
+{
+ SymEntry* Entry = Tab->SymHead;
+ while (Entry) {
+
+ /* Get the storage flags for tne entry */
+ unsigned Flags = Entry->Flags;
+
+ /* Ignore typedef entries */
+ if ((Flags & SC_TYPEDEF) != SC_TYPEDEF) {
+
+ /* Check if the symbol is one with storage, and it if it was
+ * defined but not used.
+ */
+ if (((Flags & SC_AUTO) || (Flags & SC_STATIC)) && (Flags & SC_EXTERN) == 0) {
+ if ((Flags & SC_DEF) && !(Flags & SC_REF)) {
+ if (Flags & SC_PARAM) {
+ Warning (WARN_UNUSED_PARM, Entry->Name);
+ } else {
+ Warning (WARN_UNUSED_ITEM, Entry->Name);
+ }
+ }
+ }
+
+ /* If the entry is a label, check if it was defined in the function */
+ if (Flags & SC_LABEL) {
+ if ((Flags & SC_DEF) == 0) {
+ /* Undefined label */
+ Error (ERR_UNDEFINED_LABEL, Entry->Name);
+ } else if ((Flags & SC_REF) == 0) {
+ /* Defined but not used */
+ Warning (WARN_UNUSED_ITEM, Entry->Name);
+ }
+ }
+
+ }
+
+ /* Next entry */
+ Entry = Entry->NextSym;
+ }
+}
+
+
+
+/*****************************************************************************/
+/* Handling of lexical levels */
+/*****************************************************************************/
+
+
+
+void EnterGlobalLevel (void)
+/* Enter the program global lexical level */
+{
+ /* Safety */
+ PRECONDITION (++LexicalLevel == LEX_LEVEL_GLOBAL);
+
+ /* Create and assign the symbol table */
+ SymTab0 = SymTab = NewSymTable (SYMTAB_SIZE_GLOBAL);
+
+ /* Create and assign the struct table */
+ StructTab0 = StructTab = NewSymTable (SYMTAB_SIZE_GLOBAL);
+
+ /* Create and assign the enum table */
+ EnumTab0 = EnumTab = NewSymTable (SYMTAB_SIZE_GLOBAL);
+}
+
+
+
+void LeaveGlobalLevel (void)
+/* Leave the program global lexical level */
+{
+ /* Safety */
+ PRECONDITION (LexicalLevel-- == LEX_LEVEL_GLOBAL);
+
+ /* Check the tables */
+ CheckSymTable (SymTab0);
+
+ /* Dump the tables if requested */
+ if (Debug) {
+ PrintSymTable (SymTab0, stdout, "Global symbol table");
+ PrintSymTable (StructTab0, stdout, "Global struct table");
+ PrintSymTable (EnumTab0, stdout, "Global enum table");
+ }
+
+ /* Don't delete the symbol and struct tables! */
+ SymTab0 = SymTab = 0;
+ StructTab0 = StructTab = 0;
+ EnumTab0 = EnumTab = 0;
+}
+
+
+
+void EnterFunctionLevel (void)
+/* Enter function lexical level */
+{
+ SymTable* S;
+
+ /* New lexical level */
+ ++LexicalLevel;
+
+ /* Get a new symbol table and make it current */
+ S = NewSymTable (SYMTAB_SIZE_FUNCTION);
+ S->PrevTab = SymTab;
+ SymTab = S;
+
+ /* Get a new struct table and make it current */
+ S = NewSymTable (SYMTAB_SIZE_FUNCTION);
+ S->PrevTab = StructTab;
+ StructTab = S;
+
+ /* Get a new enum table and make it current */
+ S = NewSymTable (SYMTAB_SIZE_FUNCTION);
+ S->PrevTab = EnumTab;
+ EnumTab = S;
+
+ /* Create and assign a new label table */
+ LabelTab = NewSymTable (SYMTAB_SIZE_LABEL);
+}
+
+
+
+void RememberFunctionLevel (struct FuncDesc* F)
+/* Remember the symbol tables for the level and leave the level without checks */
+{
+ /* Leave the lexical level */
+ --LexicalLevel;
+
+ /* Remember the tables */
+ F->SymTab = SymTab;
+ F->StructTab = StructTab;
+ F->EnumTab = EnumTab;
+
+ /* Don't delete the tables */
+ SymTab = SymTab->PrevTab;
+ StructTab = StructTab->PrevTab;
+ EnumTab = EnumTab->PrevTab;
+}
+
+
+
+void ReenterFunctionLevel (struct FuncDesc* F)
+/* Reenter the function lexical level using the existing tables from F */
+{
+ /* New lexical level */
+ ++LexicalLevel;
+
+ /* Make the tables current again */
+ F->SymTab->PrevTab = SymTab;
+ SymTab = F->SymTab;
+
+ F->StructTab->PrevTab = StructTab;
+ StructTab = F->StructTab;
+
+ F->EnumTab->PrevTab = EnumTab;
+ EnumTab = F->EnumTab;
+
+ /* Create and assign a new label table */
+ LabelTab = NewSymTable (SYMTAB_SIZE_LABEL);
+}
+
+
+
+void LeaveFunctionLevel (void)
+/* Leave function lexical level */
+{
+ /* Leave the lexical level */
+ --LexicalLevel;
+
+ /* Check the tables */
+ CheckSymTable (SymTab);
+ CheckSymTable (LabelTab);
+
+ /* Drop the label table if it is empty */
+ if (LabelTab->SymCount == 0) {
+ FreeSymTable (LabelTab);
+ }
+
+ /* Don't delete the tables */
+ SymTab = SymTab->PrevTab;
+ StructTab = StructTab->PrevTab;
+ EnumTab = EnumTab->PrevTab;
+ LabelTab = 0;
+}
+
+
+
+void EnterBlockLevel (void)
+/* Enter a nested block in a function */
+{
+ SymTable* S;
+
+ /* New lexical level */
+ ++LexicalLevel;
+
+ /* Get a new symbol table and make it current */
+ S = NewSymTable (SYMTAB_SIZE_BLOCK);
+ S->PrevTab = SymTab;
+ SymTab = S;
+
+ /* Get a new struct table and make it current */
+ S = NewSymTable (SYMTAB_SIZE_BLOCK);
+ S->PrevTab = StructTab;
+ StructTab = S;
+
+ /* Get a new enum table and make it current */
+ S = NewSymTable (SYMTAB_SIZE_BLOCK);
+ S->PrevTab = EnumTab;
+ EnumTab = S;
+}
+
+
+
+void LeaveBlockLevel (void)
+/* Leave a nested block in a function */
+{
+ /* Leave the lexical level */
+ --LexicalLevel;
+
+ /* Check the tables */
+ CheckSymTable (SymTab);
+
+ /* Don't delete the tables */
+ SymTab = SymTab->PrevTab;
+ StructTab = StructTab->PrevTab;
+ EnumTab = EnumTab->PrevTab;
+}
+
+
+
+void EnterStructLevel (void)
+/* Enter a nested block for a struct definition */
+{
+ SymTable* S;
+
+ /* Get a new symbol table and make it current. Note: Structs and enums
+ * nested in struct scope are NOT local to the struct but visible in the
+ * outside scope. So we will NOT create a new struct or enum table.
+ */
+ S = NewSymTable (SYMTAB_SIZE_BLOCK);
+ S->PrevTab = SymTab;
+ SymTab = S;
+}
+
+
+
+void LeaveStructLevel (void)
+/* Leave a nested block for a struct definition */
+{
+ /* Don't delete the table */
+ SymTab = SymTab->PrevTab;
+}
+
+
+
+/*****************************************************************************/
+/* Find functions */
+/*****************************************************************************/
+
+
+
+static SymEntry* FindSymInTable (const SymTable* T, const char* Name, unsigned Hash)
+/* Search for an entry in one table */
+{
+ /* Get the start of the hash chain */
+ SymEntry* E = T->Tab [Hash % T->Size];
+ while (E) {
+ /* Compare the name */
+ if (strcmp (E->Name, Name) == 0) {
+ /* Found */
+ return E;
+ }
+ /* Not found, next entry in hash chain */
+ E = E->NextHash;
+ }
+
+ /* Not found */
+ return 0;
+}
+
+
+
+static SymEntry* FindSymInTree (const SymTable* Tab, const char* Name)
+/* Find the symbol with the given name in the table tree that starts with T */
+{
+ /* Get the hash over the name */
+ unsigned Hash = HashStr (Name);
+
+ /* Check all symbol tables for the symbol */
+ while (Tab) {
+ /* Try to find the symbol in this table */
+ SymEntry* E = FindSymInTable (Tab, Name, Hash);
+
+ /* Bail out if we found it */
+ if (E != 0) {
+ return E;
+ }
+
+ /* Repeat the search in the next higher lexical level */
+ Tab = Tab->PrevTab;
+ }
+
+ /* Not found */
+ return 0;
+}
+
+
+
+SymEntry* FindSym (const char* Name)
+/* Find the symbol with the given name */
+{
+ return FindSymInTree (SymTab, Name);
+}
+
+
+
+SymEntry* FindStructSym (const char* Name)
+/* Find the symbol with the given name in the struct table */
+{
+ return FindSymInTree (StructTab, Name);
+}
+
+
+
+SymEntry* FindEnumSym (const char* Name)
+/* Find the symbol with the given name in the enum table */
+{
+ return FindSymInTree (EnumTab, Name);
+}
+
+
+
+SymEntry* FindStructField (const type* Type, const char* Name)
+/* Find a struct field in the fields list */
+{
+ SymEntry* Field = 0;
+
+ /* The given type may actually be a pointer to struct */
+ if (Type[0] == T_PTR) {
+ ++Type;
+ }
+
+ /* Non-structs do not have any struct fields... */
+ if (IsStruct (Type)) {
+
+ const SymTable* Tab;
+
+ /* Get a pointer to the struct/union type */
+ const SymEntry* Struct = (const SymEntry*) Decode (Type+1);
+ CHECK (Struct != 0);
+
+ /* Get the field symbol table from the struct entry.
+ * Beware: The table may not exist.
+ */
+ Tab = Struct->V.S.SymTab;
+
+ /* Now search in the struct symbol table */
+ if (Tab) {
+ Field = FindSymInTable (Struct->V.S.SymTab, Name, HashStr (Name));
+ }
+ }
+
+ return Field;
+}
+
+
+
+/*****************************************************************************/
+/* Add stuff to the symbol table */
+/*****************************************************************************/
+
+
+
+static void AddSymEntry (SymTable* T, SymEntry* S)
+/* Add a symbol to a symbol table */
+{
+ /* Get the hash value for the name */
+ unsigned Hash = HashStr (S->Name) % T->Size;
+
+ /* Insert the symbol into the list of all symbols in this level */
+ if (T->SymTail) {
+ T->SymTail->NextSym = S;
+ }
+ S->PrevSym = T->SymTail;
+ T->SymTail = S;
+ if (T->SymHead == 0) {
+ /* First symbol */
+ T->SymHead = S;
+ }
+ T->SymCount++;
+
+ /* Insert the symbol into the hash chain */
+ S->NextHash = T->Tab[Hash];
+ T->Tab[Hash] = S;
+
+ /* Tell the symbol in which table it is */
+ S->Owner = T;
+}
+
+
+
+SymEntry* AddStructSym (const char* Name, unsigned Size, SymTable* Tab)
+/* Add a struct/union entry and return it */
+{
+ /* Do we have an entry with this name already? */
+ SymEntry* Entry = FindSymInTable (StructTab, Name, HashStr (Name));
+ if (Entry) {
+
+ /* We do have an entry. This may be a forward, so check it. */
+ if (Entry->Flags != SC_STRUCT) {
+ /* Existing symbol is not a struct */
+ Error (ERR_SYMBOL_KIND);
+ } else if (Size > 0 && Entry->V.S.Size > 0) {
+ /* Both structs are definitions. */
+ Error (ERR_MULTIPLE_DEFINITION, Name);
+ } else {
+ /* Define the struct size if it is given */
+ if (Size > 0) {
+ Entry->V.S.SymTab = Tab;
+ Entry->V.S.Size = Size;
+ }
+ }
+
+ } else {
+
+ /* Create a new entry */
+ Entry = NewSymEntry (Name, SC_STRUCT);
+
+ /* Set the struct data */
+ Entry->V.S.SymTab = Tab;
+ Entry->V.S.Size = Size;
+
+ /* Add it to the current table */
+ AddSymEntry (StructTab, Entry);
+ }
+
+ /* Return the entry */
+ return Entry;
+}
+
+
+
+SymEntry* AddEnumSym (const char* Name, int Val)
+/* Add an enum symbol to the symbol table and return it */
+{
+ /* Do we have an entry with this name already? */
+ SymEntry* Entry = FindSymInTable (SymTab, Name, HashStr (Name));
+ if (Entry) {
+ if (Entry->Flags != SC_ENUM) {
+ Error (ERR_SYMBOL_KIND);
+ } else {
+ Error (ERR_MULTIPLE_DEFINITION, Name);
+ }
+ return Entry;
+ }
+
+ /* Create a new entry */
+ Entry = NewSymEntry (Name, SC_ENUM);
+
+ /* Enum values are ints */
+ Entry->Type = TypeDup (type_int);
+
+ /* Set the enum data */
+ Entry->V.EnumVal = Val;
+
+ /* Add the entry to the symbol table */
+ AddSymEntry (SymTab, Entry);
+
+ /* Return the entry */
+ return Entry;
+}
+
+
+
+SymEntry* AddLabelSym (const char* Name, unsigned Flags)
+/* Add a goto label to the label table */
+{
+ /* Do we have an entry with this name already? */
+ SymEntry* Entry = FindSymInTable (LabelTab, Name, HashStr (Name));
+ if (Entry) {
+
+ if ((Entry->Flags & SC_DEF) != 0 && (Flags & SC_DEF) != 0) {
+ /* Trying to define the label more than once */
+ Error (ERR_MULTIPLE_DEFINITION, Name);
+ }
+ Entry->Flags |= Flags;
+
+ } else {
+
+ /* Create a new entry */
+ Entry = NewSymEntry (Name, SC_LABEL | Flags);
+
+ /* Set a new label number */
+ Entry->V.Label = GetLabel ();
+
+ /* Add the entry to the label table */
+ AddSymEntry (LabelTab, Entry);
+
+ }
+
+ /* Return the entry */
+ return Entry;
+}
+
+
+
+SymEntry* AddLocalSym (const char* Name, type* Type, unsigned Flags, int Offs)
+/* Add a local symbol and return the symbol entry */
+{
+ SymEntry* Entry;
+
+ /* Functions declared inside of functions do always have external linkage */
+ if (Type != 0 && IsFunc (Type)) {
+ if ((Flags & (SC_DEFAULT | SC_EXTERN)) == 0) {
+ Warning (WARN_FUNC_MUST_BE_EXTERN);
+ }
+ Flags = SC_EXTERN;
+ }
+
+ /* Do we have an entry with this name already? */
+ Entry = FindSymInTable (SymTab, Name, HashStr (Name));
+ if (Entry) {
+
+ /* We have a symbol with this name already */
+ Error (ERR_MULTIPLE_DEFINITION, Name);
+
+ } else {
+
+ /* Create a new entry */
+ Entry = NewSymEntry (Name, Flags);
+
+ /* Set the symbol attributes */
+ Entry->Type = TypeDup (Type);
+ Entry->V.Offs = Offs;
+
+ /* Add the entry to the symbol table */
+ AddSymEntry (SymTab, Entry);
+
+ }
+
+ /* Return the entry */
+ return Entry;
+}
+
+
+
+SymEntry* AddGlobalSym (const char* Name, type* Type, unsigned Flags)
+/* Add an external or global symbol to the symbol table and return the entry */
+{
+ /* Functions must be inserted in the global symbol table */
+ SymTable* Tab = IsFunc (Type)? SymTab0 : SymTab;
+
+ /* Do we have an entry with this name already? */
+ SymEntry* Entry = FindSymInTable (Tab, Name, HashStr (Name));
+ if (Entry) {
+
+ type* EType;
+
+ /* We have a symbol with this name already */
+ if (Entry->Flags & SC_TYPE) {
+ Error (ERR_MULTIPLE_DEFINITION, Name);
+ return Entry;
+ }
+
+ /* Get the type string of the existing symbol */
+ EType = Entry->Type;
+
+ /* If we are handling arrays, the old entry or the new entry may be an
+ * incomplete declaration. Accept this, and if the exsting entry is
+ * incomplete, complete it.
+ */
+ if (IsArray (Type) && IsArray (EType)) {
+
+ /* Get the array sizes */
+ unsigned Size = Decode (Type + 1);
+ unsigned ESize = Decode (EType + 1);
+
+ if ((Size != 0 && ESize != 0) ||
+ TypeCmp (Type+DECODE_SIZE+1, EType+DECODE_SIZE+1) != 0) {
+ /* Types not identical: Duplicate definition */
+ Error (ERR_MULTIPLE_DEFINITION, Name);
+ } else {
+ /* Check if we have a size in the existing definition */
+ if (ESize == 0) {
+ /* Existing, size not given, use size from new def */
+ Encode (EType + 1, Size);
+ }
+ }
+
+ } else {
+ /* New type must be identical */
+ if (!EqualTypes (EType, Type) != 0) {
+ Error (ERR_MULTIPLE_DEFINITION, Name);
+ }
+
+ /* In case of a function, use the new type descriptor, since it
+ * contains pointers to the new symbol tables that are needed if
+ * an actual function definition follows.
+ */
+ if (IsFunc (Type)) {
+ CopyEncode (Type+1, EType+1);
+ }
+ }
+
+ /* Add the new flags */
+ Entry->Flags |= Flags;
+
+ } else {
+
+ /* Create a new entry */
+ Entry = NewSymEntry (Name, Flags);
+
+ /* Set the symbol attributes */
+ Entry->Type = TypeDup (Type);
+
+ /* Add the entry to the symbol table */
+ AddSymEntry (Tab, Entry);
+ }
+
+ /* Return the entry */
+ return Entry;
+}
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+SymTable* GetSymTab (void)
+/* Return the current symbol table */
+{
+ return SymTab;
+}
+
+
+
+static int EqualSymTables (SymTable* Tab1, SymTable* Tab2)
+/* Compare two symbol tables. Return 1 if they are equal and 0 otherwise */
+{
+ /* Compare the parameter lists */
+ SymEntry* Sym1 = Tab1->SymHead;
+ SymEntry* Sym2 = Tab2->SymHead;
+
+ /* Compare the fields */
+ while (Sym1 && Sym2) {
+
+ /* Compare this field */
+ if (!EqualTypes (Sym1->Type, Sym2->Type)) {
+ /* Field types not equal */
+ return 0;
+ }
+
+ /* Get the pointers to the next fields */
+ Sym1 = Sym1->NextSym;
+ Sym2 = Sym2->NextSym;
+ }
+
+ /* Check both pointers against NULL to compare the field count */
+ return (Sym1 == 0 && Sym2 == 0);
+}
+
+
+
+int EqualTypes (const type* Type1, const type* Type2)
+/* Recursively compare two types. Return 1 if the types match, return 0
+ * otherwise.
+ */
+{
+ int v1, v2;
+ SymEntry* Sym1;
+ SymEntry* Sym2;
+ SymTable* Tab1;
+ SymTable* Tab2;
+ FuncDesc* F1;
+ FuncDesc* F2;
+
+
+ /* Shortcut here: If the pointers are identical, the types are identical */
+ if (Type1 == Type2) {
+ return 1;
+ }
+
+ /* Compare two types. Determine, where they differ */
+ while (*Type1 == *Type2 && *Type1 != T_END) {
+
+ switch (*Type1) {
+
+ case T_FUNC:
+ /* Compare the function descriptors */
+ F1 = DecodePtr (Type1+1);
+ F2 = DecodePtr (Type2+1);
+ if ((F1->Flags & ~FD_IMPLICIT) != (F2->Flags & ~FD_IMPLICIT)) {
+ /* Flags differ */
+ return 0;
+ }
+
+ /* Compare the parameter lists */
+ if (EqualSymTables (F1->SymTab, F2->SymTab) == 0 ||
+ EqualSymTables (F1->StructTab, F2->StructTab) == 0 ||
+ EqualSymTables (F1->EnumTab, F2->EnumTab) == 0) {
+ /* One of the tables is not identical */
+ return 0;
+ }
+
+ /* Skip the FuncDesc pointers to compare the return type */
+ Type1 += DECODE_SIZE;
+ Type2 += DECODE_SIZE;
+ break;
+
+ case T_ARRAY:
+ /* Check member count */
+ v1 = Decode (Type1+1);
+ v2 = Decode (Type2+1);
+ if (v1 != 0 && v2 != 0 && v1 != v2) {
+ /* Member count given but different */
+ return 0;
+ }
+ Type1 += DECODE_SIZE;
+ Type2 += DECODE_SIZE;
+ break;
+
+ case T_STRUCT:
+ case T_UNION:
+ /* Compare the fields recursively. To do that, we fetch the
+ * pointer to the struct definition from the type, and compare
+ * the fields.
+ */
+ Sym1 = DecodePtr (Type1+1);
+ Sym2 = DecodePtr (Type2+1);
+
+ /* Get the field tables from the struct entry */
+ Tab1 = Sym1->V.S.SymTab;
+ Tab2 = Sym2->V.S.SymTab;
+
+ /* One or both structs may be forward definitions. In this case,
+ * the symbol tables are both non existant. Assume that the
+ * structs are equal in this case.
+ */
+ if (Tab1 != 0 && Tab2 != 0) {
+
+ if (EqualSymTables (Tab1, Tab2) == 0) {
+ /* Field lists are not equal */
+ return 0;
+ }
+
+ }
+
+ /* Structs are equal */
+ Type1 += DECODE_SIZE;
+ Type2 += DECODE_SIZE;
+ break;
+ }
+ ++Type1;
+ ++Type2;
+ }
+
+ /* Done, types are equal */
+ return 1;
+}
+
+
+
+void MakeZPSym (const char* Name)
+/* Mark the given symbol as zero page symbol */
+{
+ /* Get the symbol table entry */
+ SymEntry* Entry = FindSymInTable (SymTab, Name, HashStr (Name));
+
+ /* Mark the symbol as zeropage */
+ if (Entry) {
+ Entry->Flags |= SC_ZEROPAGE;
+ } else {
+ Error (ERR_UNDEFINED_SYMBOL, Name);
+ }
+}
+
+
+
+void PrintSymTable (const SymTable* Tab, FILE* F, const char* Header, ...)
+/* Write the symbol table to the given file */
+{
+ unsigned Len;
+ const SymEntry* Entry;
+
+ /* Print the header */
+ va_list ap;
+ va_start (ap, Header);
+ fputc ('\n', F);
+ Len = vfprintf (F, Header, ap);
+ va_end (ap);
+ fputc ('\n', F);
+
+ /* Underline the header */
+ while (Len--) {
+ fputc ('=', F);
+ }
+ fputc ('\n', F);
+
+ /* Dump the table */
+ Entry = Tab->SymHead;
+ if (Entry == 0) {
+ fprintf (F, "(empty)\n");
+ } else {
+ while (Entry) {
+ DumpSymEntry (F, Entry);
+ Entry = Entry->NextSym;
+ }
+ }
+ fprintf (F, "\n\n\n");
+}
+
+
+
+void EmitExternals (void)
+/* Write import/export statements for external symbols */
+{
+ SymEntry* Entry;
+
+ AddEmptyLine ();
+
+ Entry = SymTab->SymHead;
+ while (Entry) {
+ unsigned Flags = Entry->Flags;
+ if (Flags & SC_EXTERN) {
+ /* Only defined or referenced externs */
+ if ((Flags & SC_REF) != 0 && (Flags & SC_DEF) == 0) {
+ /* An import */
+ g_defimport (Entry->Name, Flags & SC_ZEROPAGE);
+ } else if (Flags & SC_DEF) {
+ /* An export */
+ g_defexport (Entry->Name, Flags & SC_ZEROPAGE);
+ }
+ }
+ Entry = Entry->NextSym;
+ }
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* symtab.h */
+/* */
+/* Symbol table management for the cc65 C compiler */
+/* */
+/* */
+/* */
+/* (C) 2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef SYMTAB_H
+#define SYMTAB_H
+
+
+
+#include <stdio.h>
+
+#include "datatype.h"
+#include "symentry.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Symbol table */
+typedef struct SymTable SymTable;
+struct SymTable {
+ SymTable* PrevTab; /* Pointer to higher level symbol table */
+ SymEntry* SymHead; /* Double linked list of symbols */
+ SymEntry* SymTail; /* Double linked list of symbols */
+ unsigned SymCount; /* Count of symbols in this table */
+ unsigned Size; /* Size of table */
+ SymEntry* Tab[1]; /* Actual table, dynamically allocated */
+};
+
+/* An empty symbol table */
+extern SymTable EmptySymTab;
+
+/* Forwards */
+struct FuncDesc;
+
+
+
+/*****************************************************************************/
+/* Handling of lexical levels */
+/*****************************************************************************/
+
+
+
+void EnterGlobalLevel (void);
+/* Enter the program global lexical level */
+
+void LeaveGlobalLevel (void);
+/* Leave the program global lexical level */
+
+void EnterFunctionLevel (void);
+/* Enter function lexical level */
+
+void RememberFunctionLevel (struct FuncDesc* F);
+/* Remember the symbol tables for the level and leave the level without checks */
+
+void ReenterFunctionLevel (struct FuncDesc* F);
+/* Reenter the function lexical level using the existing tables from F */
+
+void LeaveFunctionLevel (void);
+/* Leave function lexical level */
+
+void EnterBlockLevel (void);
+/* Enter a nested block in a function */
+
+void LeaveBlockLevel (void);
+/* Leave a nested block in a function */
+
+void EnterStructLevel (void);
+/* Enter a nested block for a struct definition */
+
+void LeaveStructLevel (void);
+/* Leave a nested block for a struct definition */
+
+
+
+/*****************************************************************************/
+/* Find functions */
+/*****************************************************************************/
+
+
+
+SymEntry* FindSym (const char* Name);
+/* Find the symbol with the given name */
+
+SymEntry* FindStructSym (const char* Name);
+/* Find the symbol with the given name in the struct table */
+
+SymEntry* FindEnumSym (const char* Name);
+/* Find the symbol with the given name in the enum table */
+
+SymEntry* FindStructField (const type* TypeArray, const char* Name);
+/* Find a struct field in the fields list */
+
+
+
+/*****************************************************************************/
+/* Add stuff to the symbol table */
+/*****************************************************************************/
+
+
+
+SymEntry* AddStructSym (const char* Name, unsigned Size, SymTable* Tab);
+/* Add a struct/union entry and return it */
+
+SymEntry* AddEnumSym (const char* Name, int Val);
+/* Add an enum symbol to the symbol table and return it */
+
+SymEntry* AddLabelSym (const char* Name, unsigned Flags);
+/* Add a goto label to the symbol table */
+
+SymEntry* AddLocalSym (const char* Name, type* Type, unsigned Flags, int Offs);
+/* Add a local symbol and return the symbol entry */
+
+SymEntry* AddGlobalSym (const char* Name, type* Type, unsigned Flags);
+/* Add an external or global symbol to the symbol table and return the entry */
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+SymTable* GetSymTab (void);
+/* Return the current symbol table */
+
+int EqualTypes (const type* t1, const type* t2);
+/* Recursively compare two types. Return 1 if the types match, return 0
+ * otherwise.
+ */
+
+void MakeZPSym (const char* Name);
+/* Mark the given symbol as zero page symbol */
+
+void PrintSymTable (const SymTable* Tab, FILE* F, const char* Header, ...);
+/* Write the symbol table to the given file */
+
+void EmitExternals (void);
+/* Write import/export statements for external symbols */
+
+
+
+/* End of symtab.h */
+
+#endif
+
+
+
+
+
+
--- /dev/null
+/*
+ * util.c
+ *
+ * Ullrich von Bassewitz, 18.06.1998
+ */
+
+
+
+#include "util.h"
+
+
+
+/*****************************************************************************/
+/* data */
+/*****************************************************************************/
+
+
+
+
+
+
+/*****************************************************************************/
+/* code */
+/*****************************************************************************/
+
+
+
+int IsBlank (char c)
+/* Return true if c is a space, tab or newline */
+{
+ return (c == ' ' || c == '\t' || c == '\n');
+}
+
+
+
+int IsQuoteChar (char c)
+/* Return true if c is a single or double quote */
+{
+ return (c == '"' || c == '\'');
+}
+
+
+
+int powerof2 (unsigned long val)
+/* Return the exponent if val is a power of two. Return -1 if val is not a
+ * power of two.
+ */
+{
+ int i;
+ unsigned long mask;
+ mask = 0x0001;
+
+ for (i = 0; i < 32; ++i) {
+ if (val == mask) {
+ return i;
+ }
+ mask <<= 1;
+ }
+ return -1;
+}
+
+
+
--- /dev/null
+/*
+ * util.h
+ *
+ * Ullrich von Bassewitz, 18.06.1998
+ */
+
+
+
+#ifndef UTIL_H
+#define UTIL_H
+
+
+
+/*****************************************************************************/
+/* code */
+/*****************************************************************************/
+
+
+
+int IsBlank (char c);
+/* Return true if c is a space, tab or newline */
+
+int IsQuoteChar (char c);
+/* Return true if c is a single or double quote */
+
+int powerof2 (unsigned long val);
+/* Return the exponent if val is a power of two. Return -1 if val is not a
+ * power of two.
+ */
+
+
+
+/* End of util.h */
+
+#endif
+
+
+
--- /dev/null
+cl65
+cl65.exe
+.depend
--- /dev/null
+/*****************************************************************************/
+/* */
+/* global.c */
+/* */
+/* Error handling for the cl65 compile and link utility */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "global.h"
+#include "error.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Messages for internal compiler errors */
+const char _MsgCheckFailed [] =
+ "Check failed: `%s' (= %d), file `%s', line %u\n";
+const char _MsgPrecondition [] =
+ "Precondition violated: `%s' (= %d), file `%s', line %u\n";
+const char _MsgFail [] =
+ "%s, file `%s', line %u\n";
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void Warning (const char* Format, ...)
+/* Print a warning message */
+{
+ va_list ap;
+ va_start (ap, Format);
+ fprintf (stderr, "%s: ", ProgName);
+ vfprintf (stderr, Format, ap);
+ putc ('\n', stderr);
+ va_end (ap);
+}
+
+
+
+void Error (const char* Format, ...)
+/* Print an error message and die */
+{
+ va_list ap;
+ va_start (ap, Format);
+ fprintf (stderr, "%s: ", ProgName);
+ vfprintf (stderr, Format, ap);
+ putc ('\n', stderr);
+ va_end (ap);
+ exit (EXIT_FAILURE);
+}
+
+
+
+void Internal (const char* Format, ...)
+/* Print an internal error message and die */
+{
+ va_list ap;
+ va_start (ap, Format);
+ fprintf (stderr, "%s: Internal error: ", ProgName);
+ vfprintf (stderr, Format, ap);
+ putc ('\n', stderr);
+ va_end (ap);
+ exit (EXIT_FAILURE);
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* global.h */
+/* */
+/* Error handling for the cl65 compile and link utility */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef ERROR_H
+#define ERROR_H
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Messages for internal compiler errors */
+extern const char _MsgCheckFailed [];
+extern const char _MsgPrecondition [];
+extern const char _MsgFail [];
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void Warning (const char* Format, ...);
+/* Print a warning message */
+
+void Error (const char* Format, ...);
+/* Print an error message and die */
+
+void Internal (const char* Format, ...);
+/* Print an internal error message and die */
+
+#define CHECK(c) \
+ if (!(c)) \
+ Internal (_MsgCheckFailed, #c, c, __FILE__, __LINE__)
+
+#define PRECONDITION(c) \
+ if (!(c)) \
+ Internal (_MsgPrecondition, #c, c, __FILE__, __LINE__)
+
+#define FAIL(s) \
+ Internal (_MsgFail, s, __FILE__, __LINE__)
+
+
+
+/* End of error.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* global.c */
+/* */
+/* Global variables for the cl65 compile and link utility */
+/* */
+/* */
+/* */
+/* (C) 1999 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include "global.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+const char* ProgName = "cl65"; /* Program name */
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* global.h */
+/* */
+/* Global variables for the cl65 compile and link utility */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef GLOBAL_H
+#define GLOBAL_H
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+extern const char* ProgName; /* Program name */
+
+
+
+/* End of global.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* main.c */
+/* */
+/* Main module for the cl65 compile and link utility */
+/* */
+/* */
+/* */
+/* (C) 1999-2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#ifdef __WATCOMC__
+# include <process.h> /* DOS, OS/2 and Windows */
+#else
+# include "spawn.h" /* All others */
+#endif
+
+#include "../common/version.h"
+
+#include "global.h"
+#include "error.h"
+#include "mem.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Struct that describes a command */
+typedef struct CmdDesc_ CmdDesc;
+struct CmdDesc_ {
+ char* Name; /* The command name */
+
+ unsigned ArgCount; /* Count of arguments */
+ unsigned ArgMax; /* Maximum count of arguments */
+ char** Args; /* The arguments */
+
+ unsigned FileCount; /* Count of files to translate */
+ unsigned FileMax; /* Maximum count of files */
+ char** Files; /* The files */
+};
+
+/* Command descriptors for the different programs */
+static CmdDesc CC65 = { 0, 0, 0, 0, 0, 0, 0 };
+static CmdDesc CA65 = { 0, 0, 0, 0, 0, 0, 0 };
+static CmdDesc LD65 = { 0, 0, 0, 0, 0, 0, 0 };
+
+/* File types */
+enum {
+ FILETYPE_UNKNOWN,
+ FILETYPE_C,
+ FILETYPE_ASM,
+ FILETYPE_OBJ,
+ FILETYPE_LIB
+};
+
+/* Default file type, used if type unknown */
+static unsigned DefaultFileType = FILETYPE_UNKNOWN;
+
+/* Variables controlling the steps we're doing */
+static int DontLink = 0;
+static int DontAssemble = 0;
+
+/* The name of the output file, NULL if none given */
+static const char* OutputName = 0;
+
+/* The name of the linker configuration file if given */
+static const char* LinkerConfig = 0;
+
+/* The name of the first input file. This will be used to construct the
+ * executable file name if no explicit name is given.
+ */
+static const char* FirstInput = 0;
+
+/* The target system */
+enum {
+ TGT_UNKNOWN = -1,
+ TGT_NONE,
+ TGT_FIRSTREAL,
+ TGT_ATARI = TGT_FIRSTREAL,
+ TGT_C64,
+ TGT_C128,
+ TGT_ACE,
+ TGT_PLUS4,
+ TGT_CBM610,
+ TGT_PET,
+ TGT_NES,
+ TGT_APPLE2,
+ TGT_GEOS,
+ TGT_COUNT
+} Target = TGT_UNKNOWN;
+
+/* Names of the target systems sorted by target name */
+static const char* TargetNames [] = {
+ "none",
+ "atari",
+ "c64",
+ "c128",
+ "ace",
+ "plus4",
+ "cbm610",
+ "pet",
+ "nes",
+ "apple2",
+ "geos",
+};
+
+/* Name of the crt0 object file and the runtime library */
+static char* TargetCRT0 = 0;
+static char* TargetLib = 0;
+
+
+
+/*****************************************************************************/
+/* String handling */
+/*****************************************************************************/
+
+
+
+static const char* FindExt (const char* Name)
+/* Return a pointer to the file extension in Name or NULL if there is none */
+{
+ const char* S;
+
+ /* Get the length of the name */
+ unsigned Len = strlen (Name);
+ if (Len < 2) {
+ return 0;
+ }
+
+ /* Get a pointer to the last character */
+ S = Name + Len - 1;
+
+ /* Search for the dot, beware of subdirectories */
+ while (S >= Name && *S != '.' && *S != '\\' && *S != '/') {
+ --S;
+ }
+
+ /* Did we find an extension? */
+ if (*S == '.') {
+ return S;
+ } else {
+ return 0;
+ }
+}
+
+
+
+static char* ForceExt (const char* Name, const char* Ext)
+/* Return a new filename with the new extension */
+{
+ char* Out;
+ const char* P = FindExt (Name);
+ if (P == 0) {
+ /* No dot, add the extension */
+ Out = Xmalloc (strlen (Name) + strlen (Ext) + 1);
+ strcpy (Out, Name);
+ strcat (Out, Ext);
+ } else {
+ Out = Xmalloc (P - Name + strlen (Ext) + 1);
+ memcpy (Out, Name, P - Name);
+ strcpy (Out + (P - Name), Ext);
+ }
+ return Out;
+}
+
+
+
+/*****************************************************************************/
+/* Determine a file type */
+/*****************************************************************************/
+
+
+
+static unsigned GetFileType (const char* File)
+/* Determine the type of the given file */
+{
+ /* Table mapping extensions to file types */
+ static const struct {
+ const char* Ext;
+ unsigned Type;
+ } FileTypes [] = {
+ { ".c", FILETYPE_C },
+ { ".s", FILETYPE_ASM },
+ { ".asm", FILETYPE_ASM },
+ { ".o", FILETYPE_OBJ },
+ { ".obj", FILETYPE_OBJ },
+ { ".a", FILETYPE_LIB },
+ { ".lib", FILETYPE_LIB },
+ };
+
+ unsigned I;
+
+ /* Determine the file type by the extension */
+ const char* Ext = FindExt (File);
+
+ /* Do we have an extension? */
+ if (Ext == 0) {
+ return DefaultFileType;
+ }
+
+ /* Check for known extensions */
+ for (I = 0; I < sizeof (FileTypes) / sizeof (FileTypes [0]); ++I) {
+ if (strcmp (FileTypes [I].Ext, Ext) == 0) {
+ /* Found */
+ return FileTypes [I].Type;
+ }
+ }
+
+ /* Not found, return the default */
+ return DefaultFileType;
+}
+
+
+
+/*****************************************************************************/
+/* Command structure handling */
+/*****************************************************************************/
+
+
+
+static void CmdAddArg (CmdDesc* Cmd, const char* Arg)
+/* Add a new argument to the command */
+{
+ /* Expand the argument vector if needed */
+ if (Cmd->ArgCount == Cmd->ArgMax) {
+ unsigned NewMax = Cmd->ArgMax + 10;
+ char** NewArgs = Xmalloc (NewMax * sizeof (char*));
+ memcpy (NewArgs, Cmd->Args, Cmd->ArgMax * sizeof (char*));
+ Xfree (Cmd->Args);
+ Cmd->Args = NewArgs;
+ Cmd->ArgMax = NewMax;
+ }
+
+ /* Add a copy of the new argument, allow a NULL pointer */
+ if (Arg) {
+ Cmd->Args [Cmd->ArgCount++] = StrDup (Arg);
+ } else {
+ Cmd->Args [Cmd->ArgCount++] = 0;
+ }
+}
+
+
+
+static void CmdDelArgs (CmdDesc* Cmd, unsigned LastValid)
+/* Remove all arguments with an index greater than LastValid */
+{
+ while (Cmd->ArgCount > LastValid) {
+ Cmd->ArgCount--;
+ Xfree (Cmd->Args [Cmd->ArgCount]);
+ Cmd->Args [Cmd->ArgCount] = 0;
+ }
+}
+
+
+
+static void CmdAddFile (CmdDesc* Cmd, const char* File)
+/* Add a new file to the command */
+{
+ /* Expand the file vector if needed */
+ if (Cmd->FileCount == Cmd->FileMax) {
+ unsigned NewMax = Cmd->FileMax + 10;
+ char** NewFiles = Xmalloc (NewMax * sizeof (char*));
+ memcpy (NewFiles, Cmd->Files, Cmd->FileMax * sizeof (char*));
+ Xfree (Cmd->Files);
+ Cmd->Files = NewFiles;
+ Cmd->FileMax = NewMax;
+ }
+
+ /* Add a copy of the file name, allow a NULL pointer */
+ if (File) {
+ Cmd->Files [Cmd->FileCount++] = StrDup (File);
+ } else {
+ Cmd->Files [Cmd->FileCount++] = 0;
+ }
+}
+
+
+
+static void CmdInit (CmdDesc* Cmd, const char* Path)
+/* Initialize the command using the given path to the executable */
+{
+ /* Remember the command */
+ Cmd->Name = StrDup (Path);
+
+ /* Use the command name as first argument */
+ CmdAddArg (Cmd, Path);
+}
+
+
+
+static void CmdSetOutput (CmdDesc* Cmd, const char* File)
+/* Set the output file in a command desc */
+{
+ CmdAddArg (Cmd, "-o");
+ CmdAddArg (Cmd, File);
+}
+
+
+
+static void CmdSetTarget (CmdDesc* Cmd, int Target)
+/* Set the output file in a command desc */
+{
+ if (Target == TGT_UNKNOWN) {
+ /* Use C64 as default */
+ Target = TGT_C64;
+ }
+
+ if (Target != TGT_NONE) {
+ CmdAddArg (Cmd, "-t");
+ CmdAddArg (Cmd, TargetNames[Target]);
+ }
+}
+
+
+
+/*****************************************************************************/
+/* Target handling */
+/*****************************************************************************/
+
+
+
+static int MapTarget (const char* Name)
+/* Map a target name to a system code. Abort on errors */
+{
+ int I;
+
+ /* Check for a numeric target */
+ if (isdigit (*Name)) {
+ int Target = atoi (Name);
+ if (Target >= 0 && Target < TGT_COUNT) {
+ return Target;
+ }
+ }
+
+ /* Check for a target string */
+ for (I = 0; I < TGT_COUNT; ++I) {
+ if (strcmp (TargetNames [I], Name) == 0) {
+ return I;
+ }
+ }
+
+ /* Not found */
+ Error ("No such target system: `%s'", Name);
+ return -1; /* Not reached */
+}
+
+
+
+static void SetTargetFiles (void)
+/* Set the target system files */
+{
+ /* Determine the names of the default startup and library file */
+ if (Target >= TGT_FIRSTREAL) {
+
+ /* Get a pointer to the system name and its length */
+ const char* TargetName = TargetNames [Target];
+ unsigned TargetNameLen = strlen (TargetName);
+
+ /* Set the startup file */
+ TargetCRT0 = Xmalloc (TargetNameLen + 2 + 1);
+ strcpy (TargetCRT0, TargetName);
+ strcat (TargetCRT0, ".o");
+
+ /* Set the library file */
+ TargetLib = Xmalloc (TargetNameLen + 4 + 1);
+ strcpy (TargetLib, TargetName);
+ strcat (TargetLib, ".lib");
+
+ }
+}
+
+
+
+static void SetTargetByName (const char* Name)
+/* Set the target system by name */
+{
+ Target = MapTarget (Name);
+ SetTargetFiles ();
+}
+
+
+
+/*****************************************************************************/
+/* Subprocesses */
+/*****************************************************************************/
+
+
+
+static void ExecProgram (CmdDesc* Cmd)
+/* Execute a subprocess with the given name/parameters. Exit on errors. */
+{
+ /* Call the program */
+ int Status = spawnvp (P_WAIT, Cmd->Name, Cmd->Args);
+
+ /* Check the result code */
+ if (Status < 0) {
+ /* Error executing the program */
+ Error ("Cannot execute `%s': %s", Cmd->Name, strerror (errno));
+ } else if (Status != 0) {
+ /* Called program had an error */
+ exit (Status);
+ }
+}
+
+
+
+static void Link (void)
+/* Link the resulting executable */
+{
+ unsigned I;
+
+ /* If we have a linker config file given, set the linker config file.
+ * Otherwise set the target system.
+ */
+ if (LinkerConfig) {
+ CmdAddArg (&LD65, "-C");
+ CmdAddArg (&LD65, LinkerConfig);
+ } else {
+ if (Target == TGT_UNKNOWN) {
+ /* Use c64 instead */
+ Target = TGT_C64;
+ }
+ SetTargetFiles ();
+ CmdSetTarget (&LD65, Target);
+ }
+
+ /* Since linking is always the final step, if we have an output file name
+ * given, set it here. If we don't have an explicit output name given,
+ * try to build one from the name of the first input file.
+ */
+ if (OutputName) {
+
+ CmdAddArg (&LD65, "-o");
+ CmdAddArg (&LD65, OutputName);
+
+ } else if (FirstInput && FindExt (FirstInput)) { /* Only if ext present! */
+
+ char* Output = ForceExt (FirstInput, "");
+ CmdAddArg (&LD65, "-o");
+ CmdAddArg (&LD65, Output);
+ Xfree (Output);
+
+ }
+
+ /* If we have a startup file, add its name as a parameter */
+ if (TargetCRT0) {
+ CmdAddArg (&LD65, TargetCRT0);
+ }
+
+ /* Add all object files as parameters */
+ for (I = 0; I < LD65.FileCount; ++I) {
+ CmdAddArg (&LD65, LD65.Files [I]);
+ }
+
+ /* Add the system runtime library */
+ if (TargetLib) {
+ CmdAddArg (&LD65, TargetLib);
+ }
+
+ /* Terminate the argument list with a NULL pointer */
+ CmdAddArg (&LD65, 0);
+
+ /* Call the linker */
+ ExecProgram (&LD65);
+}
+
+
+
+static void Assemble (const char* File)
+/* Assemble the given file */
+{
+ /* Remember the current assembler argument count */
+ unsigned ArgCount = CA65.ArgCount;
+
+ /* If we won't link, this is the final step. In this case, set the
+ * output name.
+ */
+ if (DontLink && OutputName) {
+ CmdSetOutput (&CA65, OutputName);
+ } else {
+ /* The object file name will be the name of the source file
+ * with .s replaced by ".o". Add this file to the list of
+ * linker files.
+ */
+ char* ObjName = ForceExt (File, ".o");
+ CmdAddFile (&LD65, ObjName);
+ Xfree (ObjName);
+ }
+
+ /* Add the file as argument for the assembler */
+ CmdAddArg (&CA65, File);
+
+ /* Add a NULL pointer to terminate the argument list */
+ CmdAddArg (&CA65, 0);
+
+ /* Run the assembler */
+ ExecProgram (&CA65);
+
+ /* Remove the excess arguments */
+ CmdDelArgs (&CA65, ArgCount);
+}
+
+
+
+static void Compile (const char* File)
+/* Compile the given file */
+{
+ char* AsmName = 0;
+
+ /* Remember the current assembler argument count */
+ unsigned ArgCount = CC65.ArgCount;
+
+ /* Set the target system */
+ CmdSetTarget (&CC65, Target);
+
+ /* If we won't link, this is the final step. In this case, set the
+ * output name.
+ */
+ if (DontAssemble && OutputName) {
+ CmdSetOutput (&CC65, OutputName);
+ } else {
+ /* The assembler file name will be the name of the source file
+ * with .c replaced by ".s".
+ */
+ AsmName = ForceExt (File, ".s");
+ }
+
+ /* Add the file as argument for the compiler */
+ CmdAddArg (&CC65, File);
+
+ /* Add a NULL pointer to terminate the argument list */
+ CmdAddArg (&CC65, 0);
+
+ /* Run the compiler */
+ ExecProgram (&CC65);
+
+ /* Remove the excess arguments */
+ CmdDelArgs (&CC65, ArgCount);
+
+ /* If this is not the final step, assemble the generated file, then
+ * remove it
+ */
+ if (!DontAssemble) {
+ Assemble (AsmName);
+ if (remove (AsmName) < 0) {
+ Warning ("Cannot remove temporary file `%s': %s",
+ AsmName, strerror (errno));
+ }
+ Xfree (AsmName);
+ }
+}
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+static void Usage (void)
+/* Print usage information and exit */
+{
+ fprintf (stderr,
+ "Usage: %s [options] file\n"
+ "Options:\n"
+ "\t-A\t\tStrict ANSI mode\n"
+ "\t-C name\t\tUse linker config file\n"
+ "\t-Cl\t\tMake local variables static\n"
+ "\t-D sym[=defn]\tDefine a preprocessor symbol\n"
+ "\t-I path\t\tSet an include directory path\n"
+ "\t-Ln name\tCreate a VICE label file\n"
+ "\t-O\t\tOptimize code\n"
+ "\t-Oi\t\tOptimize code, inline functions\n"
+ "\t-Or\t\tOptimize code, honour the register keyword\n"
+ "\t-Os\t\tOptimize code, inline known C funtions\n"
+ "\t-S\t\tCompile but don't assemble and link\n"
+ "\t-V\t\tPrint the version number\n"
+ "\t-W\t\tSuppress warnings\n"
+ "\t-c\t\tCompiler and assemble but don't link\n"
+ "\t-d\t\tDebug mode\n"
+ "\t-g\t\tAdd debug info\n"
+ "\t-h\t\tHelp (this text)\n"
+ "\t-m name\t\tCreate a map file\n"
+ "\t-o name\t\tName the output file\n"
+ "\t-t system\tSet the target system\n"
+ "\t-v\t\tVerbose mode\n"
+ "\t-vm\t\tVerbose map file\n",
+ ProgName);
+}
+
+
+
+static const char* GetArg (int* ArgNum, char* argv [], unsigned Len)
+/* Get an option argument */
+{
+ const char* Arg = argv [*ArgNum];
+ if (Arg [Len] != '\0') {
+ /* Argument appended */
+ return Arg + Len;
+ } else {
+ /* Separate argument */
+ Arg = argv [*ArgNum + 1];
+ if (Arg == 0) {
+ /* End of arguments */
+ fprintf (stderr, "Option requires an argument: %s\n", argv [*ArgNum]);
+ exit (EXIT_FAILURE);
+ }
+ ++(*ArgNum);
+ return Arg;
+ }
+}
+
+
+
+static void ArgError (const char* Arg)
+/* Print an error about a wrong argument */
+{
+ Error ("Unknown option: `%s', use -h for help", Arg);
+}
+
+
+
+int main (int argc, char* argv [])
+/* Utility main program */
+{
+ int I;
+
+ /* Initialize the command descriptors */
+ CmdInit (&CC65, "cc65");
+ CmdInit (&CA65, "ca65");
+ CmdInit (&LD65, "ld65");
+
+ /* Check the parameters */
+ I = 1;
+ while (I < argc) {
+
+ /* Get the argument */
+ const char* Arg = argv [I];
+
+ /* Check for an option */
+ if (Arg [0] == '-') {
+
+ switch (Arg [1]) {
+
+ case 'A':
+ /* Strict ANSI mode (compiler) */
+ CmdAddArg (&CC65, "-A");
+ break;
+
+ case 'C':
+ if (Arg[2] == 'l' && Arg[3] == '\0') {
+ /* Make local variables static */
+ CmdAddArg (&CC65, "-Cl");
+ } else {
+ /* Specify linker config file */
+ LinkerConfig = GetArg (&I, argv, 2);
+ }
+ break;
+
+ case 'D':
+ /* Define a preprocessor symbol (compiler) */
+ CmdAddArg (&CC65, "-D");
+ CmdAddArg (&CC65, GetArg (&I, argv, 2));
+ break;
+
+ case 'I':
+ /* Include directory (compiler) */
+ CmdAddArg (&CC65, "-I");
+ CmdAddArg (&CC65, GetArg (&I, argv, 2));
+ break;
+
+ case 'L':
+ if (Arg[2] == 'n') {
+ /* VICE label file (linker) */
+ CmdAddArg (&LD65, "-Ln");
+ CmdAddArg (&LD65, GetArg (&I, argv, 3));
+ } else {
+ ArgError (Arg);
+ }
+ break;
+
+ case 'O':
+ /* Optimize code (compiler, also covers -Oi and others) */
+ CmdAddArg (&CC65, Arg);
+ break;
+
+ case 'S':
+ /* Dont assemble and link the created files */
+ DontLink = DontAssemble = 1;
+ break;
+
+ case 'T':
+ /* Include source as comment (compiler) */
+ CmdAddArg (&CC65, "-T");
+ break;
+
+ case 'V':
+ /* Print version number */
+ fprintf (stderr,
+ "cl65 V%u.%u.%u - (C) Copyright 1998-99 Ullrich von Bassewitz\n",
+ VER_MAJOR, VER_MINOR, VER_PATCH);
+ break;
+
+ case 'W':
+ /* Suppress warnings - compiler and assembler */
+ CmdAddArg (&CC65, "-W");
+ CmdAddArg (&CA65, "-W");
+ CmdAddArg (&CA65, "0");
+ break;
+
+ case 'c':
+ /* Don't link the resulting files */
+ DontLink = 1;
+ break;
+
+ case 'd':
+ /* Debug mode (compiler) */
+ CmdAddArg (&CC65, "-d");
+ break;
+
+ case 'g':
+ /* Debugging - add to compiler and assembler */
+ CmdAddArg (&CC65, "-g");
+ CmdAddArg (&CA65, "-g");
+ break;
+
+ case 'h':
+ case '?':
+ /* Print help - cl65 */
+ Usage ();
+ exit (EXIT_SUCCESS);
+ break;
+
+ case 'm':
+ /* Create a map file (linker) */
+ CmdAddArg (&LD65, "-m");
+ CmdAddArg (&LD65, GetArg (&I, argv, 2));
+ break;
+
+ case 'o':
+ /* Name the output file */
+ OutputName = GetArg (&I, argv, 2);
+ break;
+
+ case 't':
+ /* Set target system - compiler and linker */
+ SetTargetByName (GetArg (&I, argv, 2));
+ break;
+
+ case 'v':
+ if (Arg [2] == 'm') {
+ /* Verbose map file (linker) */
+ CmdAddArg (&LD65, "-vm");
+ } else {
+ /* Verbose mode (compiler, assembler, linker) */
+ CmdAddArg (&CC65, "-v");
+ CmdAddArg (&CA65, "-v");
+ CmdAddArg (&LD65, "-v");
+ }
+ break;
+
+ default:
+ ArgError (Arg);
+ }
+ } else {
+
+ /* Remember the first file name */
+ if (FirstInput == 0) {
+ FirstInput = Arg;
+ }
+
+ /* Determine the file type by the extension */
+ switch (GetFileType (Arg)) {
+
+ case FILETYPE_C:
+ /* Compile the file */
+ Compile (Arg);
+ break;
+
+ case FILETYPE_ASM:
+ /* Assemble the file */
+ if (!DontAssemble) {
+ Assemble (Arg);
+ }
+ break;
+
+ case FILETYPE_OBJ:
+ case FILETYPE_LIB:
+ /* Add to the linker files */
+ CmdAddFile (&LD65, Arg);
+ break;
+
+ default:
+ Error ("Don't know what to do with `%s'", Arg);
+
+ }
+
+ }
+
+ /* Next argument */
+ ++I;
+ }
+
+ /* Check if we had any input files */
+ if (FirstInput == 0) {
+ Warning ("No input files");
+ }
+
+ /* Link the given files if requested and if we have any */
+ if (DontLink == 0 && LD65.FileCount > 0) {
+ Link ();
+ }
+
+ /* Return an apropriate exit code */
+ return EXIT_SUCCESS;
+}
+
+
+
--- /dev/null
+#
+# Makefile for the cl65 compile&link utility
+#
+
+CC=gcc
+CFLAGS = -O2 -g -Wall
+LDFLAGS=
+
+OBJS = error.o \
+ global.o \
+ main.o \
+ mem.o \
+ spawn.o
+
+EXECS = cl65
+
+
+.PHONY: all
+ifeq (.depend,$(wildcard .depend))
+all : $(EXECS)
+include .depend
+else
+all: depend
+ @$(MAKE) -f make/gcc.mak all
+endif
+
+
+cl65: $(OBJS)
+ $(CC) $(LDFLAGS) -o cl65 $(CFLAGS) $(OBJS)
+
+clean:
+ rm -f *~ core
+
+zap: clean
+ rm -f *.o $(EXECS) .depend
+
+
+# ------------------------------------------------------------------------------
+# Make the dependencies
+
+.PHONY: depend dep
+depend dep: $(OBJS:.o=.c)
+ @echo "Creating dependency information"
+ $(CC) -MM $^ > .depend
+
+
+
--- /dev/null
+#
+# CL65 Makefile for the Watcom compiler
+#
+
+# ------------------------------------------------------------------------------
+# Generic stuff
+
+.AUTODEPEND
+.SUFFIXES .ASM .C .CC .CPP
+.SWAP
+
+AR = WLIB
+LD = WLINK
+
+!if !$d(TARGET)
+!if $d(__OS2__)
+TARGET = OS2
+!else
+TARGET = NT
+!endif
+!endif
+
+# target specific macros.
+!if $(TARGET)==OS2
+
+# --------------------- OS2 ---------------------
+SYSTEM = os2v2
+CC = WCC386
+CCCFG = -bt=$(TARGET) -d1 -onatx -zp4 -5 -zq -w2
+
+!elif $(TARGET)==DOS32
+
+# -------------------- DOS4G --------------------
+SYSTEM = dos4g
+CC = WCC386
+CCCFG = -bt=$(TARGET) -d1 -onatx -zp4 -5 -zq -w2
+
+!elif $(TARGET)==DOS
+
+# --------------------- DOS ---------------------
+SYSTEM = dos
+CC = WCC
+CCCFG = -bt=$(TARGET) -d1 -onatx -zp2 -2 -ml -zq -w2
+
+!elif $(TARGET)==NT
+
+# --------------------- NT ----------------------
+SYSTEM = nt
+CC = WCC386
+CCCFG = -bt=$(TARGET) -d1 -onatx -zp4 -5 -zq -w2
+
+!else
+!error
+!endif
+
+# ------------------------------------------------------------------------------
+# Implicit rules
+
+.c.obj:
+ $(CC) $(CCCFG) $<
+
+
+# ------------------------------------------------------------------------------
+# All OBJ files
+
+OBJS = error.obj \
+ global.obj \
+ main.obj \
+ mem.obj
+
+.PRECIOUS $(OBJS:.obj=.c)
+
+# ------------------------------------------------------------------------------
+# Main targets
+
+all: cl65
+
+cl65: cl65.exe
+
+
+# ------------------------------------------------------------------------------
+# Other targets
+
+
+cl65.exe: $(OBJS)
+ $(LD) system $(SYSTEM) @&&|
+DEBUG ALL
+OPTION QUIET
+NAME $<
+FILE error.obj
+FILE global.obj
+FILE main.obj
+FILE mem.obj
+|
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* mem.c */
+/* */
+/* Memory allocation for the cl65 compile and link utility */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "error.h"
+#include "mem.h"
+
+
+
+/*****************************************************************************/
+/* code */
+/*****************************************************************************/
+
+
+
+void* Xmalloc (size_t size)
+/* Allocate memory, check for out of memory condition. Do some debugging */
+{
+ void* p;
+
+ p = malloc (size);
+ if (p == 0 && size != 0) {
+ Error ("Out of memory");
+ }
+
+ /* Return a pointer to the block */
+ return p;
+}
+
+
+
+void Xfree (const void* block)
+/* Free the block, do some debugging */
+{
+ free ((void*) block);
+}
+
+
+
+char* StrDup (const char* s)
+/* Duplicate a string on the heap. The function checks for out of memory */
+{
+ unsigned len;
+
+ len = strlen (s) + 1;
+ return memcpy (Xmalloc (len), s, len);
+}
+
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* mem.h */
+/* */
+/* Memory allocation for the cl65 compile and link utility */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef MEM_H
+#define MEM_H
+
+
+
+#include <stddef.h>
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void* Xmalloc (size_t size);
+/* Allocate memory, check for out of memory condition. Do some debugging */
+
+void Xfree (const void* block);
+/* Free the block, do some debugging */
+
+char* StrDup (const char* s);
+/* Duplicate a string on the heap. The function checks for out of memory */
+
+
+
+/* End of mem.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* spawn.c */
+/* */
+/* Execute other external programs */
+/* */
+/* */
+/* */
+/* (C) 1999 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "error.h"
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+int spawnvp (int Mode, const char* File, char* const argv [])
+/* Execute the given program searching and wait til it terminates. The Mode
+ * argument is ignored (compatibility only). The result of the function is
+ * the return code of the program. The function will terminate the program
+ * on errors.
+ */
+{
+ int Status = 0;
+
+ /* Fork */
+ int pid = fork ();
+ if (pid < 0) {
+
+ /* Error forking */
+ Error ("Cannot fork: %s", strerror (errno));
+
+ } else if (pid == 0) {
+
+ /* The son - exec the program */
+ if (execvp (File, argv) < 0) {
+ Error ("Cannot exec `%s': %s", File, strerror (errno));
+ }
+
+ } else {
+
+ /* The father: Wait for the subprocess to terminate */
+ if (waitpid (pid, &Status, 0) < 0) {
+ Error ("Failure waiting for subprocess: %s", strerror (errno));
+ }
+
+ /* Examine the child status */
+ if (!WIFEXITED (Status)) {
+ Error ("Subprocess `%s' aborted by signal %d", File, WTERMSIG (Status));
+ }
+ }
+
+ /* Only the father goes here, we place a return here regardless of that
+ * to avoid compiler warnings.
+ */
+ return WEXITSTATUS (Status);
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* spawn.h */
+/* */
+/* Execute other external programs */
+/* */
+/* */
+/* */
+/* (C) 1999 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef SPAWN_H
+#define SPAWN_H
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Mode argument for spawn. This value is ignored by the function and only
+ * provided for DOS/Windows compatibility.
+ */
+#ifndef P_WAIT
+#define P_WAIT 0
+#endif
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+int spawnvp (int Mode, const char* File, char* const argv []);
+/* Execute the given program searching and wait til it terminates. The Mode
+ * argument is ignored (compatibility only). The result of the function is
+ * the return code of the program. The function will terminate the program
+ * on errors.
+ */
+
+
+
+/* End of spawn.h */
+#endif
+
+
+
--- /dev/null
+.depend
+common.o
+common.lib
--- /dev/null
+/*****************************************************************************/
+/* */
+/* bitops.c */
+/* */
+/* Single bit operations */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include "bitops.h"
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+unsigned BitFind (unsigned long Val)
+/* Find the first bit that is set in Val. Val must *not* be zero */
+{
+ unsigned long Mask;
+ unsigned Bit;
+
+ /* Search for the bits */
+ Mask = 1;
+ Bit = 0;
+ while (1) {
+ if (Val & Mask) {
+ return Bit;
+ }
+ Mask <<= 1;
+ ++Bit;
+ }
+}
+
+
+
+void BitSet (void* Data, unsigned Bit)
+/* Set a bit in a char array */
+{
+ /* Make a char pointer */
+ unsigned char* D = Data;
+
+ /* Set the bit */
+ D [Bit / 8] |= 0x01 << (Bit % 8);
+}
+
+
+
+void BitReset (void* Data, unsigned Bit)
+/* Reset a bit in a char array */
+{
+ /* Make a char pointer */
+ unsigned char* D = Data;
+
+ /* Set the bit */
+ D [Bit / 8] &= ~(0x01 << (Bit % 8));
+}
+
+
+
+int BitIsSet (void* Data, unsigned Bit)
+/* Check if a bit is set in a char array */
+{
+ /* Make a char pointer */
+ unsigned char* D = Data;
+
+ /* Check the bit state */
+ return (D [Bit / 8] & (0x01 << (Bit % 8))) != 0;
+}
+
+
+
+int BitIsReset (void* Data, unsigned Bit)
+/* Check if a bit is reset in a char array */
+{
+ /* Make a char pointer */
+ unsigned char* D = Data;
+
+ /* Check the bit state */
+ return (D [Bit / 8] & (0x01 << (Bit % 8))) == 0;
+}
+
+
+
+void BitMerge (void* Target, const void* Source, unsigned Size)
+/* Merge the bits of two char arrays (that is, do an or for the full array) */
+{
+ /* Make char arrays */
+ unsigned char* T = Target;
+ const unsigned char* S = Source;
+
+ /* Merge the arrays */
+ while (Size--) {
+ *T++ |= *S++;
+ }
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* bitops.h */
+/* */
+/* Single bit operations */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef BITOPS_H
+#define BITOPS_H
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+unsigned BitFind (unsigned long Val);
+/* Find the first bit that is set in Val. Val must *not* be zero */
+
+void BitSet (void* Data, unsigned Bit);
+/* Set a bit in a char array */
+
+void BitReset (void* Data, unsigned Bit);
+/* Reset a bit in a char array */
+
+int BitIsSet (void* Data, unsigned Bit);
+/* Check if a bit is set in a char array */
+
+int BitIsReset (void* Data, unsigned Bit);
+/* Check if a bit is reset in a char array */
+
+void BitMerge (void* Target, const void* Source, unsigned Size);
+/* Merge the bits of two char arrays (that is, do an or for the full array) */
+
+
+
+/* End of bitops.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* exprdefs.h */
+/* */
+/* Expression tree definitions */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef EXPRDEFS_H
+#define EXPRDEFS_H
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Expression type masks */
+#define EXPR_TYPEMASK 0xC0
+#define EXPR_BINARYNODE 0x00
+#define EXPR_UNARYNODE 0x40
+#define EXPR_LEAFNODE 0x80
+
+/* Type of expression nodes */
+#define EXPR_NULL 0x00 /* Internal error or NULL node */
+
+/* Leaf node codes */
+#define EXPR_LITERAL (EXPR_LEAFNODE | 0x01)
+#define EXPR_SYMBOL (EXPR_LEAFNODE | 0x02)
+#define EXPR_SEGMENT (EXPR_LEAFNODE | 0x03)
+#define EXPR_MEMAREA (EXPR_LEAFNODE | 0x04) /* Linker only */
+#define EXPR_ULABEL (EXPR_LEAFNODE | 0x05) /* Assembler only */
+
+/* Binary operations, left and right hand sides are valid */
+#define EXPR_PLUS (EXPR_BINARYNODE | 0x01)
+#define EXPR_MINUS (EXPR_BINARYNODE | 0x02)
+#define EXPR_MUL (EXPR_BINARYNODE | 0x03)
+#define EXPR_DIV (EXPR_BINARYNODE | 0x04)
+#define EXPR_MOD (EXPR_BINARYNODE | 0x05)
+#define EXPR_OR (EXPR_BINARYNODE | 0x06)
+#define EXPR_XOR (EXPR_BINARYNODE | 0x07)
+#define EXPR_AND (EXPR_BINARYNODE | 0x08)
+#define EXPR_SHL (EXPR_BINARYNODE | 0x09)
+#define EXPR_SHR (EXPR_BINARYNODE | 0x0A)
+#define EXPR_EQ (EXPR_BINARYNODE | 0x0B)
+#define EXPR_NE (EXPR_BINARYNODE | 0x0C)
+#define EXPR_LT (EXPR_BINARYNODE | 0x0D)
+#define EXPR_GT (EXPR_BINARYNODE | 0x0E)
+#define EXPR_LE (EXPR_BINARYNODE | 0x0F)
+#define EXPR_GE (EXPR_BINARYNODE | 0x10)
+#define EXPR_BAND (EXPR_BINARYNODE | 0x11)
+#define EXPR_BOR (EXPR_BINARYNODE | 0x12)
+#define EXPR_BXOR (EXPR_BINARYNODE | 0x13)
+
+/* Unary operations, right hand side is empty */
+#define EXPR_UNARY_MINUS (EXPR_UNARYNODE | 0x01)
+#define EXPR_NOT (EXPR_UNARYNODE | 0x02)
+#define EXPR_LOBYTE (EXPR_UNARYNODE | 0x03)
+#define EXPR_HIBYTE (EXPR_UNARYNODE | 0x04)
+#define EXPR_SWAP (EXPR_UNARYNODE | 0x05)
+#define EXPR_BNOT (EXPR_UNARYNODE | 0x06)
+
+
+
+/* The expression node itself */
+typedef struct ExprNode_ ExprNode;
+struct ExprNode_ {
+ unsigned char Op; /* Operand/Type */
+ ExprNode* Left; /* Left leaf */
+ ExprNode* Right; /* Right leaf */
+ struct ObjData_* Obj; /* Object file reference (linker) */
+ union {
+ long Val; /* If this is a value */
+ struct SymEntry_* Sym; /* If this is a symbol */
+ unsigned SegNum; /* If this is a segment */
+ unsigned ImpNum; /* If this is an import */
+ struct Memory_* MemArea; /* If this is a memory area */
+ } V;
+};
+
+
+
+/* Macros to determine the expression type */
+#define EXPR_IS_LEAF(Op) (((Op) & EXPR_TYPEMASK) == EXPR_LEAFNODE)
+#define EXPR_IS_UNARY(Op) (((Op) & EXPR_TYPEMASK) == EXPR_UNARYNODE)
+#define EXPR_IS_BINARY(OP) (((Op) & EXPR_TYPEMASK) == EXPR_BINARYNODE)
+
+
+
+/* End of exprdefs.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* filepos.h */
+/* */
+/* File position data structure */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef FILEPOS_H
+#define FILEPOS_H
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Size of position in file */
+#define POS_SIZE 5
+
+/* Type of a file position */
+typedef struct FilePos_ FilePos;
+struct FilePos_ {
+ unsigned long Line; /* Line */
+ unsigned char Col; /* Column */
+ unsigned char Name; /* File */
+};
+
+
+
+/* End of filepos.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* hashstr.c */
+/* */
+/* Hash function for strings */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+unsigned HashStr (const char* S)
+/* Return a hash value for the given string */
+{
+ unsigned L, H;
+
+ /* Do the hash */
+ H = L = 0;
+ while (*S) {
+ H = ((H << 3) ^ ((unsigned char) *S++)) + L++;
+ }
+ return H;
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* hashstr.h */
+/* */
+/* Hash function for strings */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef HASHSTR_H
+#define HASHSTR_H
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+unsigned HashStr (const char* S);
+/* Return a hash value for the given string */
+
+
+
+/* End of hashstr.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* libdefs.h */
+/* */
+/* Library file definitions */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef LIBDEFS_H
+#define LIBDEFS_H
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Defines for magic and version */
+#define LIB_MAGIC 0x7A55616E
+#define LIB_VERSION 0x0004
+
+/* Size of an library file header */
+#define LIB_HDR_SIZE 12
+
+
+
+/* Header structure for the library */
+typedef struct LibHeader_ LibHeader;
+struct LibHeader_ {
+ unsigned long Magic; /* 32: Magic number */
+ unsigned Version; /* 16: Version number */
+ unsigned Flags; /* 16: flags */
+ unsigned long IndexOffs; /* 32: Offset to directory */
+};
+
+
+
+/* End of libdefs.h */
+
+#endif
+
+
+
--- /dev/null
+#
+# gcc Makefile for the binutils common stuff
+#
+
+CFLAGS = -g -O2 -Wall
+CC = gcc
+LDFLAGS =
+LIB = common.a
+
+
+
+OBJS = bitops.o \
+ hashstr.o
+
+
+# ------------------------------------------------------------------------------
+# Dummy targets
+
+.PHONY: all
+ifeq (.depend,$(wildcard .depend))
+all: lib
+include .depend
+else
+all: depend
+ @$(MAKE) -f make/gcc.mak all
+endif
+
+.PHONY: lib
+lib: $(LIB)
+
+$(LIB): $(OBJS)
+ $(AR) rs $(LIB) $?
+
+clean:
+ rm -f *~ core *.map
+
+zap: clean
+ rm -f *.o $(LIB) .depend
+
+# ------------------------------------------------------------------------------
+# Make the dependencies
+
+.PHONY: depend dep
+depend dep: $(OBJS:.o=.c)
+ @echo "Creating dependency information"
+ $(CC) -MM $^ > .depend
+
+
--- /dev/null
+#
+# CC65 Makefile for the Watcom compiler
+#
+
+# ------------------------------------------------------------------------------
+# Generic stuff
+
+.AUTODEPEND
+.SUFFIXES .ASM .C .CC .CPP
+.SWAP
+
+AR = WLIB
+LD = WLINK
+
+LIB = common.lib
+
+!if !$d(TARGET)
+!if $d(__OS2__)
+TARGET = OS2
+!else
+TARGET = NT
+!endif
+!endif
+
+# target specific macros.
+!if $(TARGET)==OS2
+
+# --------------------- OS2 ---------------------
+SYSTEM = os2v2
+CC = WCC386
+CCCFG = -bt=$(TARGET) -d1 -onatx -zp4 -5 -zq -w2
+
+!elif $(TARGET)==DOS32
+
+# -------------------- DOS4G --------------------
+SYSTEM = dos4g
+CC = WCC386
+CCCFG = -bt=$(TARGET) -d1 -onatx -zp4 -5 -zq -w2
+
+!elif $(TARGET)==DOS
+
+# --------------------- DOS ---------------------
+SYSTEM = dos
+CC = WCC
+CCCFG = -bt=$(TARGET) -d1 -onatx -zp2 -2 -ml -zq -w2
+
+!elif $(TARGET)==NT
+
+# --------------------- NT ----------------------
+SYSTEM = nt
+CC = WCC386
+CCCFG = -bt=$(TARGET) -d1 -onatx -zp4 -5 -zq -w2
+
+!else
+!error
+!endif
+
+# ------------------------------------------------------------------------------
+# Implicit rules
+
+.c.obj:
+ $(CC) $(CCCFG) $<
+
+
+# ------------------------------------------------------------------------------
+# All library OBJ files
+
+OBJS = bitops.obj \
+ hashstr.obj \
+ wildargv.obj
+
+
+.PRECIOUS $(OBJS:.obj=.cc) $(LIB)
+
+# ------------------------------------------------------------------------------
+# Main targets
+
+all: lib
+
+lib: $(LIB)
+
+$(LIB): $(OBJS)
+ @echo Creating library...
+ &@$(AR) -q -b -P=32 $(LIB) +-$?
+ @echo Done!
+
+clean:
+ @if exist *.obj del *.obj
+ @if exist $(LIB) del $(LIB)
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* objdefs.h */
+/* */
+/* Object file definitions */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef OBJDEFS_H
+#define OBJDEFS_H
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Defines for magic and version */
+#define OBJ_MAGIC 0x616E7A55
+#define OBJ_VERSION 0x0005
+
+/* Size of an object file header */
+#define OBJ_HDR_SIZE 56
+
+/* Flag bits */
+#define OBJ_FLAGS_DBGINFO 0x0001 /* File has debug info */
+
+
+
+/* Header structure */
+typedef struct ObjHeader_ ObjHeader;
+struct ObjHeader_ {
+ unsigned long Magic; /* 32: Magic number */
+ unsigned Version; /* 16: Version number */
+ unsigned Flags; /* 16: flags */
+ unsigned long OptionOffs; /* 32: Offset to option table */
+ unsigned long OptionSize; /* 32: Size of options */
+ unsigned long FileOffs; /* 32: Offset to file table */
+ unsigned long FileSize; /* 32: Size of files */
+ unsigned long SegOffs; /* 32: Offset to segment table */
+ unsigned long SegSize; /* 32: Size of segment table */
+ unsigned long ImportOffs; /* 32: Offset to import list */
+ unsigned long ImportSize; /* 32: Size of import list */
+ unsigned long ExportOffs; /* 32: Offset to export list */
+ unsigned long ExportSize; /* 32: Size of export list */
+ unsigned long DbgSymOffs; /* 32: Offset to list of debug symbols */
+ unsigned long DbgSymSize; /* 32: Size of debug symbols */
+};
+
+
+
+/* End of objdefs.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* optdefs.h */
+/* */
+/* Definitions for object file options */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef OPTDEFS_H
+#define OPTDEFS_H
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Type of options */
+#define OPT_ARGMASK 0xC0 /* Mask for argument */
+#define OPT_ARGSTR 0x00 /* String argument */
+#define OPT_ARGNUM 0x40 /* Numerical argument */
+
+#define OPT_COMMENT (OPT_ARGSTR+0) /* Generic comment */
+#define OPT_AUTHOR (OPT_ARGSTR+1) /* Author specification */
+#define OPT_TRANSLATOR (OPT_ARGSTR+2) /* Translator specification */
+#define OPT_COMPILER (OPT_ARGSTR+3) /* Compiler specification */
+#define OPT_OS (OPT_ARGSTR+4) /* Operating system specification */
+
+#define OPT_DATETIME (OPT_ARGNUM+0) /* Date/time of translation */
+
+
+
+/* Structure to encode options */
+typedef struct Option_ Option;
+struct Option_ {
+ Option* Next; /* For list of options */
+ unsigned char Type; /* Type of option */
+ union {
+ const char* Str; /* String attribute */
+ unsigned long Val; /* Value attribute */
+ } V;
+};
+
+
+
+/* End of optdefs.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* segdefs.h */
+/* */
+/* Segment definitions for the bin65 binary utils */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef SEGDEFS_H
+#define SEGDEFS_H
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Available segment types */
+#define SEGTYPE_DEFAULT 0
+#define SEGTYPE_ABS 1
+#define SEGTYPE_ZP 2
+#define SEGTYPE_FAR 3
+
+/* Fragment types in the object file */
+#define FRAG_TYPEMASK 0x38 /* Mask the type of the fragment */
+#define FRAG_BYTEMASK 0x07 /* Mask for byte count */
+
+#define FRAG_LITERAL 0x00 /* Literal data */
+#define FRAG_LITERAL8 0x01 /* Literal data with 8 bit length */
+#define FRAG_LITERAL16 0x02 /* Literal data with 16 bit length */
+#define FRAG_LITERAL24 0x03 /* Literal data with 24 bit length */
+#define FRAG_LITERAL32 0x04 /* Literal data with 32 bit length */
+
+#define FRAG_EXPR 0x08 /* Expression */
+#define FRAG_EXPR8 0x09 /* 8 bit expression */
+#define FRAG_EXPR16 0x0A /* 16 bit expression */
+#define FRAG_EXPR24 0x0B /* 24 bit expression */
+#define FRAG_EXPR32 0x0C /* 32 bit expression */
+
+#define FRAG_SEXPR 0x10 /* Signed expression */
+#define FRAG_SEXPR8 0x11 /* 8 bit signed expression */
+#define FRAG_SEXPR16 0x12 /* 16 bit signed expression */
+#define FRAG_SEXPR24 0x13 /* 24 bit signed expression */
+#define FRAG_SEXPR32 0x14 /* 32 bit signed expression */
+
+#define FRAG_FILL 0x20 /* Fill bytes */
+
+
+/* End of segdefs.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* symdefs.h */
+/* */
+/* Symbol definitions for the bin65 binary utils */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef SYMDEFS_H
+#define SYMDEFS_H
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Object file tags for imports and exports */
+#define IMP_ABS 0x00 /* Import as normal value */
+#define IMP_ZP 0x01 /* Import as zero page symbol */
+
+#define EXP_ABS 0x00 /* Export as normal value */
+#define EXP_ZP 0x01 /* Export as zero page value */
+#define EXP_CONST 0x00 /* Mask bit for const values */
+#define EXP_EXPR 0x02 /* Mask bit for expr values */
+
+
+
+/* End of symdefs.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* version.h */
+/* */
+/* Version information for the cc65 compiler package */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef VERSION_H
+#define VERSION_H
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+#define VER_MAJOR 2U
+#define VER_MINOR 4U
+#define VER_PATCH 4U
+
+
+
+/* End of version.h */
+
+#endif
+
+
+
--- /dev/null
+#!/bin/sh
+
+# GEOS .cvt header generator...
+# it's a really quick and dirty hack ... big and ugly...
+
+# by Maciej 'YTM/Alliance' Witkowiak
+# 9/10.3.2000
+
+case "$1" in
+
+ *.res)
+
+#include resource file
+
+ . $1
+
+#test is arguments are really given, if not - set defaults
+
+# binary file type
+if [ -z "$progtype" ]; then progtype="APPLICATION"; fi
+
+# filenames
+if [ -z "$dosname" ]; then dosname="testapp" ; fi
+if [ -z "$dostype" ]; then dostype="USR" ; fi
+
+# date
+if [ -z "$year" ]; then year=`date +%y` ; fi
+if [ -z "$month" ]; then month=`date +%m` ; fi
+if [ -z "$day" ]; then day=`date +%e` ; fi
+if [ -z "$hour" ]; then hour=`date +%k` ; fi
+if [ -z "$minute" ]; then minute=`date +%M` ; fi
+
+# screenmode
+if [ -z "$screenmode" ]; then screenmode=0 ; fi
+
+# names
+if [ -z "$class" ]; then class="Programname"; fi
+if [ -z "$version" ]; then version="V1.0" ; fi
+if [ -z "$author" ]; then author="cc65"; fi
+if [ -z "$note" ]; then note="Program compiled with cc65 and GEOSLib."; fi
+
+# start generator
+
+cat << __END__
+
+; Maciej 'YTM/Alliance' Witkowiak
+; 28.02.2000
+
+; This is .cvt header for GEOS files, it is recognized by Convert v2.5 for GEOS
+; and Star Commander (when copying GEOS files to/from .d64 images)
+
+; currently only SEQUENTIAL structure is supported, no overlays
+
+; THIS IS GENERATED FILE, ANY CHANGES WILL BE LOST!!!
+
+ .segment "HEADER"
+
+;
+;filetypes
+; GEOS
+NOT_GEOS = 0
+BASIC = 1
+ASSEMBLY = 2
+DATA = 3
+SYSTEM = 4
+DESK_ACC = 5
+APPLICATION = 6
+APPL_DATA = 7
+FONT = 8
+PRINTER = 9
+INPUT_DEVICE = 10
+DISK_DEVICE = 11
+SYSTEM_BOOT = 12
+TEMPORARY = 13
+AUTO_EXEC = 14
+INPUT_128 = 15
+NUMFILETYPES = 16
+; structure
+SEQUENTIAL = 0
+VLIR = 1
+; DOS
+DEL = 0
+SEQ = 1
+PRG = 2
+USR = 3
+REL = 4
+CBM = 5
+
+__END__
+
+echo -e ProgType\\t\\t=\\t$progtype
+echo -e \\n\\t\\t.byte $dostype '| $80'\\t\\t'; DOS filetype'
+echo -e \\t\\t.word 0\\t\\t'; T&S, will be fixed by converter'
+echo $dosname | awk '
+{ len=length($0); printf "\t\t.byte %c%s%c\n", 34, substr($0,0,16), 34;
+ if (len<16) { len=15-len; printf "\t\t.byte $a0"
+ while (len>0) { printf ", $a0"; len-=1 } }
+ print ""
+ }'
+echo -e \\t\\t.word 0\\t\\t'; header T&S'
+echo -e \\t\\t.byte SEQUENTIAL
+echo -e \\t\\t.byte ProgType
+echo -e \\t\\t.byte $year
+echo -e \\t\\t.byte $month
+echo -e \\t\\t.byte $day
+echo -e \\t\\t.byte $hour
+echo -e \\t\\t.byte $minute
+echo -e \\n\\t\\t.word 0
+cat << __END__
+
+ .byte "PRG formatted GEOS file V1.0"
+ ; converter stamp
+ .res \$c4 ; some bytes are left
+
+ .byte 3, 21, 63 | \$80 ; icon picture header, 63 bytes follow
+
+ ;** hey, uberhacker! edit icon here!!! ;-))
+ .byte %11111111, %11111111, %11111111
+ .byte %10000000, %00000000, %00000001
+ .byte %10000000, %00000000, %00000001
+ .byte %10000000, %00000000, %00000001
+ .byte %10000000, %00000000, %00000001
+ .byte %10000000, %00000000, %00000001
+ .byte %10000000, %00000000, %00000001
+ .byte %10000000, %00000000, %00000001
+ .byte %10000000, %00000000, %00000001
+ .byte %10000000, %00000000, %00000001
+ .byte %10000000, %00000000, %00000001
+ .byte %10000000, %00000000, %00000001
+ .byte %10000000, %00000000, %00000001
+ .byte %10000000, %00000000, %00000001
+ .byte %10000000, %00000000, %00000001
+ .byte %10000000, %00000000, %00000001
+ .byte %10000000, %00000000, %00000001
+ .byte %10000000, %00000000, %00000001
+ .byte %10000000, %00000000, %00000001
+ .byte %10000000, %00000000, %00000001
+ .byte %11111111, %11111111, %11111111
+
+__END__
+
+echo -e \\n\\t\\t.byte $dostype '| $80'\\t\\t';DOS filetype again'
+
+cat << __END__
+ .byte ProgType ;again GEOS type
+ .byte SEQUENTIAL ;structure
+ .word \$0400 ;ProgStart
+ .word \$0400-1 ;ProgEnd (needs proper value for DESK_ACC)
+ .word \$0400 ;ProgExec
+__END__
+
+echo -e \\t\\t'; GEOS class (11 chars padded with spaces, terminated with space (12th))'
+echo $class | awk '
+{ len=length($0); printf "\t\t.byte %c%s%c\n", 34, substr($0,0,12), 34;
+ if (len<12) { len=11-len; printf "\t\t.byte $20"
+ while (len>0) { printf ", $20"; len-=1 } }
+ print ""
+ }'
+echo -e \\t\\t'; version info (4 characters)'
+echo -en \\t\\t.byte
+echo $version | awk '{ printf " %c%s%c\n", 34, substr($0,1,4), 34}'
+echo -e \\t\\t.byte 0\\t\\t\\t';string terminator'
+echo -e \\t\\t.word 0
+echo -e \\n\\t\\t.byte $screenmode\\t\\t\\t';40/80 columns capability'
+echo -e \\n\\t\\t'; author, up to 62 characters'
+echo $author | awk '
+{ printf "\t\t.byte %c%s%c\n\t\t.byte 0\n\t\t.res (63-%i)\n", 34, substr($0,0,62), 34, length($0)+1; }'
+echo -e \\n\\t\\t';note (up to 95 chars)'
+echo $note | awk '
+{ printf "\t\t.byte %c%s%c\n\t\t.byte 0\n\t\t.res (96-%i)\n", 34, substr($0,0,95), 34, length($0)+1; }'
+echo -e \\n\\n';end of .cvt header, real code follows'
+
+ ;;
+ *)
+echo "This is GEOSLib .cvt header generator by Maciej Witkowiak"
+echo "Usage:"
+echo " headergen resourcefile.res"
+echo
+echo "Contents of resource file are (case sensitive):"
+echo "dostype=[PRG,SEQ,USR]"
+echo "dosname=filename"
+echo "progtype=[APPLICATION,ASSEMBLY,DESK_ACC,PRINTER,INPUT_DEVICE,AUTO_EXEC,INPUT_128]"
+echo " currently only APPLICATION is supported"
+echo "year,month,date,hour,minute=XX - if not given current will be used"
+echo "screenmode=[0,64,128,192] -"
+echo " 0 - GEOS128 only 40 columns"
+echo " 64 - GEOS128 both 40/80 columns"
+echo " 128 - does not run under GEOS128"
+echo " 192 - GEOS128 only 80 columns"
+echo "class=Class - GEOS class name"
+echo "author=Author - author name"
+echo "note=Note - note field"
+echo
+echo "If any of those parameters is not given, default will be used"
+echo "Output should be redirected to a file e.g. cvthead.s"
+echo "compiled with ca65 and used in linking process as the first object file -"
+echo "even before crt0.o"
+ ;;
+esac
--- /dev/null
+.depend
+ld65
+*.map
+*.s
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* bin.c */
+/* */
+/* Module to handle the raw binary format */
+/* */
+/* */
+/* */
+/* (C) 1999-2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "global.h"
+#include "error.h"
+#include "mem.h"
+#include "fileio.h"
+#include "segments.h"
+#include "exports.h"
+#include "config.h"
+#include "expr.h"
+#include "bin.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+struct BinDesc_ {
+ unsigned Undef; /* Count of undefined externals */
+ FILE* F; /* Output file */
+ const char* Filename; /* Name of output file */
+};
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+BinDesc* NewBinDesc (void)
+/* Create a new binary format descriptor */
+{
+ /* Allocate memory for a new BinDesc struct */
+ BinDesc* D = Xmalloc (sizeof (BinDesc));
+
+ /* Initialize the fields */
+ D->Undef = 0;
+ D->F = 0;
+ D->Filename = 0;
+
+ /* Return the created struct */
+ return D;
+}
+
+
+
+void FreeBinDesc (BinDesc* D)
+/* Free a binary format descriptor */
+{
+ Xfree (D);
+}
+
+
+
+static unsigned BinWriteExpr (ExprNode* E, int Signed, unsigned Size,
+ unsigned long Offs, void* Data)
+/* Called from SegWrite for an expression. Evaluate the expression, check the
+ * range and write the expression value to the file.
+ */
+{
+ /* There's a predefined function to handle constant expressions */
+ return SegWriteConstExpr (((BinDesc*)Data)->F, E, Signed, Size);
+}
+
+
+
+static void BinWriteMem (BinDesc* D, Memory* M)
+/* Write the segments of one memory area to a file */
+{
+ /* Get the start address of this memory area */
+ unsigned long Addr = M->Start;
+
+ /* Get a pointer to the first segment node */
+ MemListNode* N = M->SegList;
+ while (N) {
+
+ int DoWrite;
+
+ /* Get the segment from the list node */
+ SegDesc* S = N->Seg;
+
+ /* Keep the user happy */
+ if (Verbose) {
+ printf (" Writing `%s'\n", S->Name);
+ }
+
+ /* Writes do only occur in the load area and not for BSS segments */
+ DoWrite = (S->Flags & SF_BSS) == 0 && /* No BSS segment */
+ S->Load == M && /* LOAD segment */
+ S->Seg->Dumped == 0; /* Not already written */
+
+ /* Check if we would need an alignment */
+ if (S->Seg->Align > S->Align) {
+ /* Segment itself requires larger alignment than configured
+ * in the linker.
+ */
+ Warning ("Segment `%s' in module `%s' requires larger alignment",
+ S->Name, S->Seg->AlignObj->Name);
+ }
+
+ /* Handle ALIGN and OFFSET/START */
+ if (S->Flags & SF_ALIGN) {
+ /* Align the address */
+ unsigned long Val, NewAddr;
+ Val = (0x01UL << S->Align) - 1;
+ NewAddr = (Addr + Val) & ~Val;
+ if (DoWrite) {
+ WriteMult (D->F, M->FillVal, NewAddr-Addr);
+ }
+ Addr = NewAddr;
+ /* Remember the fill value for the segment */
+ S->Seg->FillVal = M->FillVal;
+ } else if (S->Flags & (SF_OFFSET | SF_START)) {
+ unsigned long NewAddr = S->Addr;
+ if (S->Flags & SF_OFFSET) {
+ /* It's an offset, not a fixed address, make an address */
+ NewAddr += M->Start;
+ }
+ if (DoWrite) {
+ WriteMult (D->F, M->FillVal, NewAddr-Addr);
+ }
+ Addr = NewAddr;
+ }
+
+ /* Now write the segment to disk if it is not a BSS type segment and
+ * if the memory area is the load area.
+ */
+ if (DoWrite) {
+ SegWrite (D->F, S->Seg, BinWriteExpr, D);
+ } else if (M->Flags & MF_FILL) {
+ WriteMult (D->F, M->FillVal, S->Seg->Size);
+ }
+ S->Seg->Dumped = 1;
+
+ /* Calculate the new address */
+ Addr += S->Seg->Size;
+
+ /* Next segment node */
+ N = N->Next;
+ }
+
+ /* If a fill was requested, fill the remaining space */
+ if (M->Flags & MF_FILL) {
+ while (M->FillLevel < M->Size) {
+ Write8 (D->F, M->FillVal);
+ ++M->FillLevel;
+ }
+ }
+}
+
+
+
+static int BinUnresolved (const char* Name, void* D)
+/* Called if an unresolved symbol is encountered */
+{
+ /* Unresolved symbols are an error in binary format. Bump the counter
+ * and return zero telling the caller that the symbol is indeed
+ * unresolved.
+ */
+ ((BinDesc*) D)->Undef++;
+ return 0;
+}
+
+
+
+void BinWriteTarget (BinDesc* D, struct File_* F)
+/* Write a binary output file */
+{
+ Memory* M;
+
+ /* Place the filename in the control structure */
+ D->Filename = F->Name;
+
+ /* Check for unresolved symbols. The function BinUnresolved is called
+ * if we get an unresolved symbol.
+ */
+ D->Undef = 0; /* Reset the counter */
+ CheckExports (BinUnresolved, D);
+ if (D->Undef > 0) {
+ /* We had unresolved symbols, cannot create output file */
+ Error ("%u unresolved external(s) found - cannot create output file", D->Undef);
+ }
+
+ /* Open the file */
+ D->F = fopen (F->Name, "wb");
+ if (D->F == 0) {
+ Error ("Cannot open `%s': %s", F->Name, strerror (errno));
+ }
+
+ /* Keep the user happy */
+ if (Verbose) {
+ printf ("Opened `%s'...\n", F->Name);
+ }
+
+ /* Dump all memory areas */
+ M = F->MemList;
+ while (M) {
+ if (Verbose) {
+ printf (" Dumping `%s'\n", M->Name);
+ }
+ BinWriteMem (D, M);
+ M = M->FNext;
+ }
+
+ /* Close the file */
+ if (fclose (D->F) != 0) {
+ Error ("Cannot write to `%s': %s", F->Name, strerror (errno));
+ }
+
+ /* Reset the file and filename */
+ D->F = 0;
+ D->Filename = 0;
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* bin.h */
+/* */
+/* Module to handle the raw binary format */
+/* */
+/* */
+/* */
+/* (C) 1999 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef BIN_H
+#define BIN_H
+
+
+
+#include "config.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Structure describing the format */
+typedef struct BinDesc_ BinDesc;
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+BinDesc* NewBinDesc (void);
+/* Create a new binary format descriptor */
+
+void FreeBinDesc (BinDesc* D);
+/* Free a binary format descriptor */
+
+void BinWriteTarget (BinDesc* D, File* F);
+/* Write a binary output file */
+
+
+
+/* End of bin.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* binfmt.c */
+/* */
+/* Binary format definitions for the ld65 linker */
+/* */
+/* */
+/* */
+/* (C) 1999 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include "error.h"
+#include "binfmt.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Default format (depends on target system) */
+unsigned char DefaultBinFmt = BINFMT_BINARY;
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+int RelocatableBinFmt (unsigned Format)
+/* Return true if this is a relocatable format, return false otherwise */
+{
+ int Reloc = 0;
+
+ /* Resolve the default format */
+ if (Format == BINFMT_DEFAULT) {
+ Format = DefaultBinFmt;
+ }
+
+ /* Check the type */
+ switch (Format) {
+
+ case BINFMT_BINARY:
+ Reloc = 0;
+ break;
+
+ case BINFMT_O65:
+ Reloc = 1;
+ break;
+
+ default:
+ Internal ("Invalid format specifier: %u", Format);
+
+ }
+
+ /* Return the flag */
+ return Reloc;
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* binfmt.h */
+/* */
+/* Binary format definitions for the ld65 linker */
+/* */
+/* */
+/* */
+/* (C) 1999 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef BINFMT_H
+#define BINFMT_H
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Types of available output formats */
+#define BINFMT_DEFAULT 0 /* Default (binary) */
+#define BINFMT_BINARY 1 /* Straight binary format */
+#define BINFMT_O65 2 /* Andre Fachats o65 format */
+
+/* Default format (depends on target system) */
+extern unsigned char DefaultBinFmt;
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+int RelocatableBinFmt (unsigned Format);
+/* Return true if this is a relocatable format, return false otherwise */
+
+
+
+/* End of binfmt.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* config.c */
+/* */
+/* Target configuration file for the ld65 linker */
+/* */
+/* */
+/* */
+/* (C) 1998-2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "../common/bitops.h"
+
+#include "error.h"
+#include "mem.h"
+#include "global.h"
+#include "bin.h"
+#include "o65.h"
+#include "binfmt.h"
+#include "exports.h"
+#include "scanner.h"
+#include "config.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* File list */
+static File* FileList; /* Single linked list */
+static unsigned FileCount; /* Number of entries in the list */
+
+
+
+/* Memory list */
+static Memory* MemoryList; /* Single linked list */
+static Memory* MemoryLast; /* Last element in list */
+static unsigned MemoryCount; /* Number of entries in the list */
+
+/* Memory attributes */
+#define MA_START 0x0001
+#define MA_SIZE 0x0002
+#define MA_TYPE 0x0004
+#define MA_FILE 0x0008
+#define MA_DEFINE 0x0010
+#define MA_FILL 0x0020
+#define MA_FILLVAL 0x0040
+
+
+
+/* Segment list */
+SegDesc* SegDescList; /* Single linked list */
+unsigned SegDescCount; /* Number of entries in list */
+
+/* Segment attributes */
+#define SA_TYPE 0x0001
+#define SA_LOAD 0x0002
+#define SA_RUN 0x0004
+#define SA_ALIGN 0x0008
+#define SA_DEFINE 0x0010
+#define SA_OFFSET 0x0020
+#define SA_START 0x0040
+
+
+
+/* Descriptor holding information about the binary formats */
+static BinDesc* BinFmtDesc = 0;
+static O65Desc* O65FmtDesc = 0;
+
+/* Attributes for the o65 format */
+static unsigned O65Attr = 0;
+#define OA_OS 0x0001
+#define OA_TYPE 0x0002
+#define OA_VERSION 0x0004
+#define OA_OSVERSION 0x0008
+#define OA_TEXT 0x0010
+#define OA_DATA 0x0020
+#define OA_BSS 0x0040
+#define OA_ZP 0x0080
+
+
+
+/*****************************************************************************/
+/* Constructors/Destructors */
+/*****************************************************************************/
+
+
+
+static File* NewFile (const char* Name)
+/* Create a new file descriptor and insert it into the list */
+{
+ /* Get the length of the name */
+ unsigned Len = strlen (Name);
+
+ /* Allocate memory */
+ File* F = Xmalloc (sizeof (File) + Len);
+
+ /* Initialize the fields */
+ F->Flags = 0;
+ F->Format = BINFMT_DEFAULT;
+ F->MemList = 0;
+ F->MemLast = 0;
+ memcpy (F->Name, Name, Len);
+ F->Name [Len] = '\0';
+
+ /* Insert the struct into the list */
+ F->Next = FileList;
+ FileList = F;
+ ++FileCount;
+
+ /* ...and return it */
+ return F;
+}
+
+
+
+static Memory* NewMemory (const char* Name)
+/* Create a new memory section and insert it into the list */
+{
+ /* Get the length of the name */
+ unsigned Len = strlen (Name);
+
+ /* Check for duplicate names */
+ Memory* M = MemoryList;
+ while (M) {
+ if (strcmp (M->Name, Name) == 0) {
+ CfgError ("Memory area `%s' defined twice", Name);
+ break;
+ }
+ M = M->Next;
+ }
+
+ /* Allocate memory */
+ M = Xmalloc (sizeof (Memory) + Len);
+
+ /* Initialize the fields */
+ M->Next = 0;
+ M->FNext = 0;
+ M->Attr = 0;
+ M->Flags = 0;
+ M->Start = 0;
+ M->Size = 0;
+ M->FillLevel = 0;
+ M->FillVal = 0;
+ M->SegList = 0;
+ M->SegLast = 0;
+ M->F = 0;
+ memcpy (M->Name, Name, Len);
+ M->Name [Len] = '\0';
+
+ /* Insert the struct into the list */
+ if (MemoryLast == 0) {
+ /* First element */
+ MemoryList = M;
+ } else {
+ MemoryLast->Next = M;
+ }
+ MemoryLast = M;
+ ++MemoryCount;
+
+ /* ...and return it */
+ return M;
+}
+
+
+
+static SegDesc* NewSegDesc (const char* Name)
+/* Create a segment descriptor */
+{
+ Segment* Seg;
+
+ /* Get the length of the name */
+ unsigned Len = strlen (Name);
+
+ /* Check for duplicate names */
+ SegDesc* S = SegDescList;
+ while (S) {
+ if (strcmp (S->Name, Name) == 0) {
+ CfgError ("Segment `%s' defined twice", Name);
+ break;
+ }
+ S = S->Next;
+ }
+
+ /* Verify that the given segment does really exist */
+ Seg = SegFind (Name);
+ if (Seg == 0) {
+ CfgWarning ("Segment `%s' does not exist", Name);
+ }
+
+ /* Allocate memory */
+ S = Xmalloc (sizeof (SegDesc) + Len);
+
+ /* Initialize the fields */
+ S->Next = 0;
+ S->Seg = Seg;
+ S->Attr = 0;
+ S->Flags = 0;
+ S->Align = 0;
+ memcpy (S->Name, Name, Len);
+ S->Name [Len] = '\0';
+
+ /* ...and return it */
+ return S;
+}
+
+
+
+static void FreeSegDesc (SegDesc* S)
+/* Free a segment descriptor */
+{
+ Xfree (S);
+}
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+static void FlagAttr (unsigned* Flags, unsigned Mask, const char* Name)
+/* Check if the item is already defined. Print an error if so. If not, set
+ * the marker that we have a definition now.
+ */
+{
+ if (*Flags & Mask) {
+ CfgError ("%s is already defined", Name);
+ }
+ *Flags |= Mask;
+}
+
+
+
+static void AttrCheck (unsigned Attr, unsigned Mask, const char* Name)
+/* Check that a mandatory attribute was given */
+{
+ if ((Attr & Mask) == 0) {
+ CfgError ("%s attribute is missing", Name);
+ }
+}
+
+
+
+static File* FindFile (const char* Name)
+/* Find a file with a given name. */
+{
+ File* F = FileList;
+ while (F) {
+ if (strcmp (F->Name, Name) == 0) {
+ return F;
+ }
+ F = F->Next;
+ }
+ return 0;
+}
+
+
+
+static File* GetFile (const char* Name)
+/* Get a file entry with the given name. Create a new one if needed. */
+{
+ File* F = FindFile (Name);
+ if (F == 0) {
+ /* Create a new one */
+ F = NewFile (Name);
+ }
+ return F;
+}
+
+
+
+static void FileInsert (File* F, Memory* M)
+/* Insert the memory area into the files list */
+{
+ M->F = F;
+ if (F->MemList == 0) {
+ /* First entry */
+ F->MemList = M;
+ } else {
+ F->MemLast->FNext = M;
+ }
+ F->MemLast = M;
+}
+
+
+
+static void ParseMemory (void)
+/* Parse a MEMORY section */
+{
+ static const IdentTok Attributes [] = {
+ { "START", CFGTOK_START },
+ { "SIZE", CFGTOK_SIZE },
+ { "TYPE", CFGTOK_TYPE },
+ { "FILE", CFGTOK_FILE },
+ { "DEFINE", CFGTOK_DEFINE },
+ { "FILL", CFGTOK_FILL },
+ { "FILLVAL", CFGTOK_FILLVAL },
+ };
+ static const IdentTok Types [] = {
+ { "RO", CFGTOK_RO },
+ { "RW", CFGTOK_RW },
+ };
+
+ while (CfgTok == CFGTOK_IDENT) {
+
+ /* Create a new entry on the heap */
+ Memory* M = NewMemory (CfgSVal);
+
+ /* Skip the name and the following colon */
+ CfgNextTok ();
+ CfgConsumeColon ();
+
+ /* Read the attributes */
+ while (CfgTok == CFGTOK_IDENT) {
+
+ /* Map the identifier to a token */
+ unsigned AttrTok;
+ CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
+ AttrTok = CfgTok;
+
+ /* An optional assignment follows */
+ CfgNextTok ();
+ CfgOptionalAssign ();
+
+ /* Check which attribute was given */
+ switch (AttrTok) {
+
+ case CFGTOK_START:
+ FlagAttr (&M->Attr, MA_START, "START");
+ CfgAssureInt ();
+ M->Start = CfgIVal;
+ break;
+
+ case CFGTOK_SIZE:
+ FlagAttr (&M->Attr, MA_SIZE, "SIZE");
+ CfgAssureInt ();
+ M->Size = CfgIVal;
+ break;
+
+ case CFGTOK_TYPE:
+ FlagAttr (&M->Attr, MA_TYPE, "TYPE");
+ CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
+ if (CfgTok == CFGTOK_RO) {
+ M->Flags |= MF_RO;
+ }
+ break;
+
+ case CFGTOK_FILE:
+ FlagAttr (&M->Attr, MA_FILE, "FILE");
+ CfgAssureStr ();
+ /* Get the file entry and insert the memory area */
+ FileInsert (GetFile (CfgSVal), M);
+ break;
+
+ case CFGTOK_DEFINE:
+ FlagAttr (&M->Attr, MA_DEFINE, "DEFINE");
+ /* Map the token to a boolean */
+ CfgBoolToken ();
+ if (CfgTok == CFGTOK_TRUE) {
+ M->Flags |= MF_DEFINE;
+ }
+ break;
+
+ case CFGTOK_FILL:
+ FlagAttr (&M->Attr, MA_FILL, "FILL");
+ /* Map the token to a boolean */
+ CfgBoolToken ();
+ if (CfgTok == CFGTOK_TRUE) {
+ M->Flags |= MF_FILL;
+ }
+ break;
+
+ case CFGTOK_FILLVAL:
+ FlagAttr (&M->Attr, MA_FILLVAL, "FILLVAL");
+ CfgAssureInt ();
+ CfgRangeCheck (0, 0xFF);
+ M->FillVal = (unsigned char) CfgIVal;
+ break;
+
+ default:
+ FAIL ("Unexpected attribute token");
+
+ }
+
+ /* Skip the attribute value and an optional comma */
+ CfgNextTok ();
+ CfgOptionalComma ();
+ }
+
+ /* Skip the semicolon */
+ CfgConsumeSemi ();
+
+ /* Check for mandatory parameters */
+ AttrCheck (M->Attr, MA_START, "START");
+ AttrCheck (M->Attr, MA_SIZE, "SIZE");
+
+ /* If we don't have a file name for output given, use the default
+ * file name.
+ */
+ if ((M->Attr & MA_FILE) == 0) {
+ FileInsert (GetFile (OutputName), M);
+ }
+ }
+}
+
+
+
+static void ParseFiles (void)
+/* Parse a FILES section */
+{
+ static const IdentTok Attributes [] = {
+ { "FORMAT", CFGTOK_FORMAT },
+ };
+ static const IdentTok Formats [] = {
+ { "O65", CFGTOK_O65 },
+ { "BIN", CFGTOK_BIN },
+ { "BINARY", CFGTOK_BIN },
+ };
+
+
+ /* Parse all files */
+ while (CfgTok != CFGTOK_RCURLY) {
+
+ File* F;
+
+ /* We expect a string value here */
+ CfgAssureStr ();
+
+ /* Search for the file, it must exist */
+ F = FindFile (CfgSVal);
+ if (F == 0) {
+ CfgError ("No such file: `%s'", CfgSVal);
+ }
+
+ /* Skip the token and the following colon */
+ CfgNextTok ();
+ CfgConsumeColon ();
+
+ /* Read the attributes */
+ while (CfgTok == CFGTOK_IDENT) {
+
+ /* Map the identifier to a token */
+ unsigned AttrTok;
+ CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
+ AttrTok = CfgTok;
+
+ /* An optional assignment follows */
+ CfgNextTok ();
+ CfgOptionalAssign ();
+
+ /* Check which attribute was given */
+ switch (AttrTok) {
+
+ case CFGTOK_FORMAT:
+ if (F->Format != BINFMT_DEFAULT) {
+ /* We've set the format already! */
+ Error ("Cannot set a file format twice");
+ }
+ /* Read the format token */
+ CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
+ switch (CfgTok) {
+
+ case CFGTOK_BIN:
+ F->Format = BINFMT_BINARY;
+ break;
+
+ case CFGTOK_O65:
+ F->Format = BINFMT_O65;
+ break;
+
+ default:
+ Error ("Unexpected format token");
+ }
+ break;
+
+ default:
+ FAIL ("Unexpected attribute token");
+
+ }
+
+ /* Skip the attribute value and an optional comma */
+ CfgNextTok ();
+ CfgOptionalComma ();
+ }
+
+ /* Skip the semicolon */
+ CfgConsumeSemi ();
+
+ }
+}
+
+
+
+static Memory* CfgFindMemory (const char* Name)
+/* Find the memory are with the given name. Return NULL if not found */
+{
+ Memory* M = MemoryList;
+ while (M) {
+ if (strcmp (M->Name, Name) == 0) {
+ return M;
+ }
+ M = M->Next;
+ }
+ return 0;
+}
+
+
+
+static Memory* CfgGetMemory (const char* Name)
+/* Find the memory are with the given name. Print an error on an invalid name */
+{
+ Memory* M = CfgFindMemory (Name);
+ if (M == 0) {
+ CfgError ("Invalid memory area `%s'", Name);
+ }
+ return M;
+}
+
+
+
+static void SegDescInsert (SegDesc* S)
+/* Insert a segment descriptor into the list of segment descriptors */
+{
+ /* Insert the struct into the list */
+ S->Next = SegDescList;
+ SegDescList = S;
+ ++SegDescCount;
+}
+
+
+
+static void MemoryInsert (Memory* M, SegDesc* S)
+/* Insert the segment descriptor into the memory area list */
+{
+ /* Create a new node for the entry */
+ MemListNode* N = Xmalloc (sizeof (MemListNode));
+ N->Seg = S;
+ N->Next = 0;
+
+ if (M->SegLast == 0) {
+ /* First entry */
+ M->SegList = N;
+ } else {
+ M->SegLast->Next = N;
+ }
+ M->SegLast = N;
+}
+
+
+
+static void ParseSegments (void)
+/* Parse a SEGMENTS section */
+{
+ static const IdentTok Attributes [] = {
+ { "LOAD", CFGTOK_LOAD },
+ { "RUN", CFGTOK_RUN },
+ { "TYPE", CFGTOK_TYPE },
+ { "ALIGN", CFGTOK_ALIGN },
+ { "DEFINE", CFGTOK_DEFINE },
+ { "OFFSET", CFGTOK_OFFSET },
+ { "START", CFGTOK_START },
+ };
+ static const IdentTok Types [] = {
+ { "RO", CFGTOK_RO },
+ { "RW", CFGTOK_RW },
+ { "BSS", CFGTOK_BSS },
+ { "ZP", CFGTOK_ZP },
+ { "WP", CFGTOK_WPROT },
+ { "WPROT", CFGTOK_WPROT },
+ };
+
+ unsigned Count;
+
+ while (CfgTok == CFGTOK_IDENT) {
+
+ SegDesc* S;
+
+ /* Create a new entry on the heap */
+ S = NewSegDesc (CfgSVal);
+
+ /* Skip the name and the following colon */
+ CfgNextTok ();
+ CfgConsumeColon ();
+
+ /* Read the attributes */
+ while (CfgTok == CFGTOK_IDENT) {
+
+ /* Map the identifier to a token */
+ unsigned AttrTok;
+ CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
+ AttrTok = CfgTok;
+
+ /* An optional assignment follows */
+ CfgNextTok ();
+ CfgOptionalAssign ();
+
+ /* Check which attribute was given */
+ switch (AttrTok) {
+
+ case CFGTOK_LOAD:
+ FlagAttr (&S->Attr, SA_LOAD, "LOAD");
+ S->Load = CfgGetMemory (CfgSVal);
+ break;
+
+ case CFGTOK_RUN:
+ FlagAttr (&S->Attr, SA_RUN, "RUN");
+ S->Run = CfgGetMemory (CfgSVal);
+ break;
+
+ case CFGTOK_TYPE:
+ FlagAttr (&S->Attr, SA_TYPE, "TYPE");
+ CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
+ switch (CfgTok) {
+ case CFGTOK_RO: S->Flags |= SF_RO; break;
+ case CFGTOK_BSS: S->Flags |= SF_BSS; break;
+ case CFGTOK_ZP: S->Flags |= (SF_BSS | SF_ZP); break;
+ case CFGTOK_WPROT: S->Flags |= (SF_RO | SF_WPROT); break;
+ }
+ break;
+
+ case CFGTOK_ALIGN:
+ CfgAssureInt ();
+ FlagAttr (&S->Attr, SA_ALIGN, "ALIGN");
+ CfgRangeCheck (1, 0x10000);
+ S->Align = BitFind (CfgIVal);
+ if ((0x01UL << S->Align) != CfgIVal) {
+ CfgError ("Alignment must be a power of 2");
+ }
+ S->Flags |= SF_ALIGN;
+ break;
+
+ case CFGTOK_DEFINE:
+ FlagAttr (&S->Attr, SA_DEFINE, "DEFINE");
+ /* Map the token to a boolean */
+ CfgBoolToken ();
+ if (CfgTok == CFGTOK_TRUE) {
+ S->Flags |= SF_DEFINE;
+ }
+ break;
+
+ case CFGTOK_OFFSET:
+ CfgAssureInt ();
+ FlagAttr (&S->Attr, SA_OFFSET, "OFFSET");
+ CfgRangeCheck (1, 0x1000000);
+ S->Addr = CfgIVal;
+ S->Flags |= SF_OFFSET;
+ break;
+
+ case CFGTOK_START:
+ CfgAssureInt ();
+ FlagAttr (&S->Attr, SA_START, "START");
+ CfgRangeCheck (1, 0x1000000);
+ S->Addr = CfgIVal;
+ S->Flags |= SF_START;
+ break;
+
+ default:
+ FAIL ("Unexpected attribute token");
+
+ }
+
+ /* Skip the attribute value and an optional comma */
+ CfgNextTok ();
+ CfgOptionalComma ();
+ }
+
+ /* Skip the semicolon */
+ CfgConsumeSemi ();
+
+ /* Check for mandatory parameters */
+ AttrCheck (S->Attr, SA_LOAD, "LOAD");
+
+ /* Set defaults for stuff not given */
+ if ((S->Attr & SA_RUN) == 0) {
+ S->Attr |= SA_RUN;
+ S->Run = S->Load;
+ } else {
+ /* Both attributes given */
+ S->Flags |= SF_LOAD_AND_RUN;
+ }
+ if ((S->Attr & SA_ALIGN) == 0) {
+ S->Attr |= SA_ALIGN;
+ S->Align = 0;
+ }
+
+ /* If the segment is marked as BSS style, check that there's no
+ * initialized data in the segment.
+ */
+ if ((S->Flags & SF_BSS) != 0 && !IsBSSType (S->Seg)) {
+ Warning ("%s(%u): Segment with type `bss' contains initialized data",
+ CfgGetName (), CfgErrorLine);
+ }
+
+ /* Don't allow read/write data to be put into a readonly area */
+ if ((S->Flags & SF_RO) == 0) {
+ if (S->Run->Flags & MF_RO) {
+ CfgError ("Cannot put r/w segment `%s' in r/o memory area `%s'",
+ S->Name, S->Run->Name);
+ }
+ }
+
+ /* Only one of ALIGN, START and OFFSET may be used */
+ Count = ((S->Flags & SF_ALIGN) != 0) +
+ ((S->Flags & SF_OFFSET) != 0) +
+ ((S->Flags & SF_START) != 0);
+ if (Count > 1) {
+ CfgError ("Only one of ALIGN, START, OFFSET may be used");
+ }
+
+ /* If this segment does exist in any of the object files, insert the
+ * descriptor into the list of segment descriptors. Otherwise discard
+ * it silently, because the segment pointer in the descriptor is
+ * invalid.
+ */
+ if (S->Seg != 0) {
+ /* Insert the descriptor into the list of all descriptors */
+ SegDescInsert (S);
+ /* Insert the segment into the memory area list */
+ MemoryInsert (S->Run, S);
+ if ((S->Flags & SF_LOAD_AND_RUN) != 0) {
+ /* We have a separate RUN area given */
+ MemoryInsert (S->Load, S);
+ }
+ } else {
+ /* Segment does not exist, discard the descriptor */
+ FreeSegDesc (S);
+ }
+ }
+}
+
+
+
+static void ParseO65 (void)
+/* Parse the o65 format section */
+{
+ static const IdentTok Attributes [] = {
+ { "EXPORT", CFGTOK_EXPORT },
+ { "IMPORT", CFGTOK_IMPORT },
+ { "TYPE", CFGTOK_TYPE },
+ { "OS", CFGTOK_OS },
+ };
+ static const IdentTok Types [] = {
+ { "SMALL", CFGTOK_SMALL },
+ { "LARGE", CFGTOK_LARGE },
+ };
+ static const IdentTok OperatingSystems [] = {
+ { "LUNIX", CFGTOK_LUNIX },
+ { "OSA65", CFGTOK_OSA65 },
+ };
+
+ while (CfgTok == CFGTOK_IDENT) {
+
+ /* Map the identifier to a token */
+ unsigned AttrTok;
+ CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
+ AttrTok = CfgTok;
+
+ /* An optional assignment follows */
+ CfgNextTok ();
+ CfgOptionalAssign ();
+
+ /* Check which attribute was given */
+ switch (AttrTok) {
+
+ case CFGTOK_EXPORT:
+ /* We expect an identifier */
+ CfgAssureIdent ();
+ /* Check if we have this symbol defined already. The entry
+ * routine will check this also, but we get a more verbose
+ * error message when checking it here.
+ */
+ if (O65GetExport (O65FmtDesc, CfgSVal) != 0) {
+ CfgError ("Duplicate exported symbol: `%s'", CfgSVal);
+ }
+ /* Insert the symbol into the table */
+ O65SetExport (O65FmtDesc, CfgSVal);
+ break;
+
+ case CFGTOK_IMPORT:
+ /* We expect an identifier */
+ CfgAssureIdent ();
+ /* Check if we have this symbol defined already. The entry
+ * routine will check this also, but we get a more verbose
+ * error message when checking it here.
+ */
+ if (O65GetImport (O65FmtDesc, CfgSVal) != 0) {
+ CfgError ("Duplicate imported symbol: `%s'", CfgSVal);
+ }
+ /* Insert the symbol into the table */
+ O65SetImport (O65FmtDesc, CfgSVal);
+ break;
+
+ case CFGTOK_TYPE:
+ /* Cannot have this attribute twice */
+ FlagAttr (&O65Attr, OA_TYPE, "TYPE");
+ /* Get the type of the executable */
+ CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
+ switch (CfgTok) {
+
+ case CFGTOK_SMALL:
+ /* Default, nothing to do */
+ break;
+
+ case CFGTOK_LARGE:
+ O65SetLargeModel (O65FmtDesc);
+ break;
+
+ default:
+ Error ("Unexpected type token");
+ }
+ break;
+
+ case CFGTOK_OS:
+ /* Cannot use this attribute twice */
+ FlagAttr (&O65Attr, OA_OS, "OS");
+ /* Get the operating system */
+ CfgSpecialToken (OperatingSystems, ENTRY_COUNT (OperatingSystems), "OS type");
+ switch (CfgTok) {
+
+ case CFGTOK_LUNIX:
+ O65SetOS (O65FmtDesc, O65OS_LUNIX);
+ break;
+
+ case CFGTOK_OSA65:
+ O65SetOS (O65FmtDesc, O65OS_OSA65);
+ break;
+
+ default:
+ Error ("Unexpected OS token");
+ }
+ break;
+
+ default:
+ FAIL ("Unexpected attribute token");
+
+ }
+
+ /* Skip the attribute value and an optional comma */
+ CfgNextTok ();
+ CfgOptionalComma ();
+ }
+}
+
+
+
+static void ParseFormats (void)
+/* Parse a target format section */
+{
+ static const IdentTok Formats [] = {
+ { "O65", CFGTOK_O65 },
+ { "BIN", CFGTOK_BIN },
+ { "BINARY", CFGTOK_BIN },
+ };
+
+ while (CfgTok == CFGTOK_IDENT) {
+
+ /* Map the identifier to a token */
+ unsigned FormatTok;
+ CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
+ FormatTok = CfgTok;
+
+ /* Skip the name and the following colon */
+ CfgNextTok ();
+ CfgConsumeColon ();
+
+ /* Parse the format options */
+ switch (FormatTok) {
+
+ case CFGTOK_O65:
+ ParseO65 ();
+ break;
+
+ case CFGTOK_BIN:
+ /* No attribibutes available */
+ break;
+
+ default:
+ Error ("Unexpected format token");
+ }
+
+ /* Skip the semicolon */
+ CfgConsumeSemi ();
+ }
+}
+
+
+
+static void ParseConfig (void)
+/* Parse the config file */
+{
+ static const IdentTok BlockNames [] = {
+ { "MEMORY", CFGTOK_MEMORY },
+ { "FILES", CFGTOK_FILES },
+ { "SEGMENTS", CFGTOK_SEGMENTS },
+ { "FORMATS", CFGTOK_FORMATS },
+ };
+ unsigned BlockTok;
+
+ do {
+
+ /* Read the block ident */
+ CfgSpecialToken (BlockNames, ENTRY_COUNT (BlockNames), "Block identifier");
+ BlockTok = CfgTok;
+ CfgNextTok ();
+
+ /* Expected a curly brace */
+ CfgConsume (CFGTOK_LCURLY, "`{' expected");
+
+ /* Read the block */
+ switch (BlockTok) {
+
+ case CFGTOK_MEMORY:
+ ParseMemory ();
+ break;
+
+ case CFGTOK_FILES:
+ ParseFiles ();
+ break;
+
+ case CFGTOK_SEGMENTS:
+ ParseSegments ();
+ break;
+
+ case CFGTOK_FORMATS:
+ ParseFormats ();
+ break;
+
+ default:
+ FAIL ("Unexpected block token");
+
+ }
+
+ /* Skip closing brace */
+ CfgConsume (CFGTOK_RCURLY, "`}' expected");
+
+ } while (CfgTok != CFGTOK_EOF);
+}
+
+
+
+void CfgRead (void)
+/* Read the configuration */
+{
+ /* Create the descriptors for the binary formats */
+ BinFmtDesc = NewBinDesc ();
+ O65FmtDesc = NewO65Desc ();
+
+ /* If we have a config name given, open the file, otherwise we will read
+ * from a buffer.
+ */
+ CfgOpenInput ();
+
+ /* Parse the file */
+ ParseConfig ();
+
+ /* Close the input file */
+ CfgCloseInput ();
+}
+
+
+
+static void CreateRunDefines (Memory* M, SegDesc* S, unsigned long Addr)
+/* Create the defines for a RUN segment */
+{
+ char Buf [256];
+
+ sprintf (Buf, "__%s_RUN__", S->Name);
+ CreateMemExport (Buf, M, Addr - M->Start);
+ sprintf (Buf, "__%s_SIZE__", S->Name);
+ CreateConstExport (Buf, S->Seg->Size);
+ S->Flags |= SF_RUN_DEF;
+}
+
+
+
+static void CreateLoadDefines (Memory* M, SegDesc* S, unsigned long Addr)
+/* Create the defines for a LOAD segment */
+{
+ char Buf [256];
+
+ sprintf (Buf, "__%s_LOAD__", S->Name);
+ CreateMemExport (Buf, M, Addr - M->Start);
+ S->Flags |= SF_LOAD_DEF;
+}
+
+
+
+void CfgAssignSegments (void)
+/* Assign segments, define linker symbols where requested */
+{
+ /* Walk through each of the memory sections. Add up the sizes and check
+ * for an overflow of the section. Assign the start addresses of the
+ * segments while doing this.
+ */
+ Memory* M = MemoryList;
+ while (M) {
+
+ /* Get the start address of this memory area */
+ unsigned long Addr = M->Start;
+
+ /* Walk through the segments in this memory area */
+ MemListNode* N = M->SegList;
+ while (N) {
+
+ /* Get the segment from the node */
+ SegDesc* S = N->Seg;
+
+ /* Handle ALIGN and OFFSET/START */
+ if (S->Flags & SF_ALIGN) {
+ /* Align the address */
+ unsigned long Val = (0x01UL << S->Align) - 1;
+ Addr = (Addr + Val) & ~Val;
+ } else if (S->Flags & (SF_OFFSET | SF_START)) {
+ /* Give the segment a fixed starting address */
+ unsigned long NewAddr = S->Addr;
+ if (S->Flags & SF_OFFSET) {
+ /* An offset was given, no address, make an address */
+ NewAddr += M->Start;
+ }
+ if (Addr > NewAddr) {
+ /* Offset already too large */
+ if (S->Flags & SF_OFFSET) {
+ Error ("Offset too small in `%s', segment `%s'",
+ M->Name, S->Name);
+ } else {
+ Error ("Start address too low in `%s', segment `%s'",
+ M->Name, S->Name);
+ }
+ }
+ Addr = NewAddr;
+ }
+
+ /* If this is the run area, set the start address of this segment */
+ if (S->Run == M) {
+ S->Seg->PC = Addr;
+ }
+
+ /* Increment the fill level of the memory area and check for an
+ * overflow.
+ */
+ M->FillLevel = Addr + S->Seg->Size - M->Start;
+ if (M->FillLevel > M->Size) {
+ Error ("Memory area overflow in `%s', segment `%s' (%lu bytes)",
+ M->Name, S->Name, M->FillLevel - M->Size);
+ }
+
+ /* If requested, define symbols for the start and size of the
+ * segment.
+ */
+ if (S->Flags & SF_DEFINE) {
+ if ((S->Flags & SF_LOAD_AND_RUN) && S->Run == S->Load) {
+ /* RUN and LOAD given and in one memory area.
+ * Be careful: We will encounter this code twice, the
+ * first time when walking the RUN list, second time when
+ * walking the LOAD list. Be sure to define only the
+ * relevant symbols on each walk.
+ */
+ if (S->Load == M) {
+ if ((S->Flags & SF_LOAD_DEF) == 0) {
+ CreateLoadDefines (M, S, Addr);
+ } else {
+ CHECK ((S->Flags & SF_RUN_DEF) == 0);
+ CreateRunDefines (M, S, Addr);
+ }
+ }
+ } else {
+ /* RUN and LOAD in different memory areas, or RUN not
+ * given, so RUN defaults to LOAD. In the latter case, we
+ * have only one copy of the segment in the area.
+ */
+ if (S->Run == M) {
+ CreateRunDefines (M, S, Addr);
+ }
+ if (S->Load == M) {
+ CreateLoadDefines (M, S, Addr);
+ }
+ }
+ }
+
+ /* Calculate the new address */
+ Addr += S->Seg->Size;
+
+ /* Next segment */
+ N = N->Next;
+ }
+
+ /* If requested, define symbols for start and size of the memory area */
+ if (M->Flags & MF_DEFINE) {
+ char Buf [256];
+ sprintf (Buf, "__%s_START__", M->Name);
+ CreateMemExport (Buf, M, 0);
+ sprintf (Buf, "__%s_SIZE__", M->Name);
+ CreateConstExport (Buf, M->Size);
+ sprintf (Buf, "__%s_LAST__", M->Name);
+ CreateConstExport (Buf, M->FillLevel);
+ }
+
+ /* Next memory area */
+ M = M->Next;
+ }
+}
+
+
+
+void CfgWriteTarget (void)
+/* Write the target file(s) */
+{
+ Memory* M;
+
+ /* Walk through the files list */
+ File* F = FileList;
+ while (F) {
+ /* We don't need to look at files with no memory areas */
+ if (F->MemList) {
+
+ /* Is there an output file? */
+ if (strlen (F->Name) > 0) {
+
+ /* Assign a proper binary format */
+ if (F->Format == BINFMT_DEFAULT) {
+ F->Format = DefaultBinFmt;
+ }
+
+ /* Call the apropriate routine for the binary format */
+ switch (F->Format) {
+
+ case BINFMT_BINARY:
+ BinWriteTarget (BinFmtDesc, F);
+ break;
+
+ case BINFMT_O65:
+ O65WriteTarget (O65FmtDesc, F);
+ break;
+
+ default:
+ Internal ("Invalid binary format: %u", F->Format);
+
+ }
+
+ } else {
+
+ /* No output file. Walk through the list and mark all segments
+ * assigned to the memory areas in this file as dumped.
+ */
+ M = F->MemList;
+ while (M) {
+ /* Walk throught the segments */
+ MemListNode* N = M->SegList;
+ while (N) {
+ /* Mark the segment as dumped */
+ N->Seg->Seg->Dumped = 1;
+
+ /* Next segment node */
+ N = N->Next;
+ }
+ /* Next memory area */
+ M = M->FNext;
+ }
+ }
+ }
+
+ /* Next file */
+ F = F->Next;
+ }
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* config.h */
+/* */
+/* Target configuration file for the ld65 linker */
+/* */
+/* */
+/* */
+/* (C) 1998-2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef CONFIG_H
+#define CONFIG_H
+
+
+
+#include "segments.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* File list entry */
+typedef struct File_ File;
+struct File_ {
+ File* Next; /* Pointer to next entry in list */
+ unsigned Flags;
+ unsigned Format; /* Output format */
+ struct Memory_* MemList; /* List of memory areas in this file */
+ struct Memory_* MemLast; /* Last memory area in this file */
+ char Name [1]; /* Name of file */
+};
+
+/* Segment list node. Needed because there are two lists (RUN & LOAD) */
+typedef struct MemListNode_ MemListNode;
+struct MemListNode_ {
+ MemListNode* Next; /* Next entry */
+ struct SegDesc_* Seg; /* Segment */
+};
+
+/* Memory list entry */
+typedef struct Memory_ Memory;
+struct Memory_ {
+ Memory* Next; /* Pointer to next entry in list */
+ Memory* FNext; /* Next in file list */
+ unsigned Attr; /* Which values are valid? */
+ unsigned Flags; /* Set of bitmapped flags */
+ unsigned long Start; /* Start address */
+ unsigned long Size; /* Length of memory section */
+ unsigned long FillLevel; /* Actual fill level of segment */
+ unsigned char FillVal; /* Value used to fill rest of seg */
+ MemListNode* SegList; /* List of segments for this section */
+ MemListNode* SegLast; /* Last segment in this section */
+ File* F; /* File that contains the entry */
+ char Name [1]; /* Name of the memory section */
+};
+
+/* Segment descriptor entry */
+typedef struct SegDesc_ SegDesc;
+struct SegDesc_ {
+ SegDesc* Next; /* Pointer to next entry in list */
+ Segment* Seg; /* Pointer to segment structure */
+ unsigned Attr; /* Attributes for segment */
+ unsigned Flags; /* Set of bitmapped flags */
+ Memory* Load; /* Load memory section */
+ Memory* Run; /* Run memory section */
+ unsigned long Addr; /* Start address or offset into segment */
+ unsigned char Align; /* Alignment if given */
+ char Name [1]; /* Copy of name */
+};
+
+/* Segment list */
+extern SegDesc* SegDescList; /* Single linked list */
+extern unsigned SegDescCount; /* Number of entries in list */
+
+/* Memory flags */
+#define MF_DEFINE 0x0001 /* Define start and size */
+#define MF_FILL 0x0002 /* Fill segment */
+#define MF_RO 0x0004 /* Read only memory area */
+
+/* Segment flags */
+#define SF_RO 0x0001 /* Read only segment */
+#define SF_BSS 0x0002 /* Segment is BSS style segment */
+#define SF_ZP 0x0004 /* Zeropage segment (o65 only) */
+#define SF_WPROT 0x0008 /* Write protected segment */
+#define SF_DEFINE 0x0010 /* Define start and size */
+#define SF_ALIGN 0x0020 /* Align the segment */
+#define SF_OFFSET 0x0040 /* Segment has offset in memory */
+#define SF_START 0x0080 /* Segment has fixed start address */
+#define SF_LOAD_AND_RUN 0x1000 /* LOAD and RUN given */
+#define SF_RUN_DEF 0x2000 /* RUN symbols already defined */
+#define SF_LOAD_DEF 0x4000 /* LOAD symbols already defined */
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void CfgRead (void);
+/* Read the configuration */
+
+void CfgAssignSegments (void);
+/* Assign segments, define linker symbols where requested */
+
+void CfgWriteTarget (void);
+/* Write the target file(s) */
+
+
+
+/* End of config.h */
+
+#endif
+
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* dbgsyms.c */
+/* */
+/* Debug symbol handing for the ld65 linker */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <string.h>
+
+#include "../common/symdefs.h"
+
+#include "global.h"
+#include "mem.h"
+#include "error.h"
+#include "fileio.h"
+#include "objdata.h"
+#include "expr.h"
+#include "dbgsyms.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* We will collect all debug symbols in the following array and remove
+ * duplicates before outputing them.
+ */
+static DbgSym* DbgSymPool [256];
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+static DbgSym* NewDbgSym (unsigned char Type, const char* Name, ObjData* O)
+/* Create a new DbgSym and return it */
+{
+ /* Get the length of the symbol name */
+ unsigned Len = strlen (Name);
+
+ /* Allocate memory */
+ DbgSym* D = Xmalloc (sizeof (DbgSym) + Len);
+
+ /* Initialize the fields */
+ D->Next = 0;
+ D->Flags = 0;
+ D->Obj = O;
+ D->Expr = 0;
+ D->Type = Type;
+ memcpy (D->Name, Name, Len);
+ D->Name [Len] = '\0';
+
+ /* Return the new entry */
+ return D;
+}
+
+
+
+static DbgSym* GetDbgSym (DbgSym* D, long Val)
+/* Check if we find the same debug symbol in the table. If we find it, return
+ * a pointer to the other occurrence, if we didn't find it, return NULL.
+ */
+{
+ /* Create the hash. We hash over the symbol value */
+ unsigned Hash = ((Val >> 24) & 0xFF) ^
+ ((Val >> 16) & 0xFF) ^
+ ((Val >> 8) & 0xFF) ^
+ ((Val >> 0) & 0xFF);
+
+ /* Check for this symbol */
+ DbgSym* Sym = DbgSymPool [Hash];
+ while (Sym) {
+ /* Is this symbol identical? */
+ if (strcmp (Sym->Name, D->Name) == 0 && EqualExpr (Sym->Expr, D->Expr)) {
+ /* Found */
+ return Sym;
+ }
+
+ /* Next symbol */
+ Sym = Sym->Next;
+ }
+
+ /* This is the first symbol of it's kind */
+ return 0;
+}
+
+
+
+static void InsertDbgSym (DbgSym* D, long Val)
+/* Insert the symbol into the hashed symbol pool */
+{
+ /* Create the hash. We hash over the symbol value */
+ unsigned Hash = ((Val >> 24) & 0xFF) ^
+ ((Val >> 16) & 0xFF) ^
+ ((Val >> 8) & 0xFF) ^
+ ((Val >> 0) & 0xFF);
+
+ /* Insert the symbol */
+ D->Next = DbgSymPool [Hash];
+ DbgSymPool [Hash] = D;
+}
+
+
+
+DbgSym* ReadDbgSym (FILE* F, ObjData* O)
+/* Read a debug symbol from a file, insert and return it */
+{
+ unsigned char Type;
+ char Name [256];
+ DbgSym* D;
+
+ /* Read the type */
+ Type = Read8 (F);
+
+ /* Read the name */
+ ReadStr (F, Name);
+
+ /* Create a new export */
+ D = NewDbgSym (Type, Name, O);
+
+ /* Read the value */
+ if (Type & EXP_EXPR) {
+ D->Expr = ReadExpr (F, O);
+ } else {
+ D->Expr = LiteralExpr (Read32 (F), O);
+ }
+
+ /* Last is the file position where the definition was done */
+ ReadFilePos (F, &D->Pos);
+
+ /* Return the new DbgSym */
+ return D;
+}
+
+
+
+long GetDbgSymVal (DbgSym* D)
+/* Get the value of this symbol */
+{
+ CHECK (D->Expr != 0);
+ return GetExprVal (D->Expr);
+}
+
+
+
+void PrintDbgSymLabels (ObjData* O, FILE* F)
+/* Print the debug symbols in a VICE label file */
+{
+ unsigned I;
+
+ /* Walk through all debug symbols in this module */
+ for (I = 0; I < O->DbgSymCount; ++I) {
+
+ /* Get the next debug symbol */
+ DbgSym* D = O->DbgSyms [I];
+
+ /* Get the symbol value */
+ long Val = GetDbgSymVal (D);
+
+ /* Lookup this symbol in the table. If it is found in the table, it was
+ * already written to the file, so don't emit it twice. If it is not in
+ * the table, insert and output it.
+ */
+ if (GetDbgSym (D, Val) == 0) {
+
+ /* Emit the VICE label line */
+ fprintf (F, "al %06lX .%s\n", Val, D->Name);
+
+ /* Insert the symbol into the table */
+ InsertDbgSym (D, Val);
+ }
+ }
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* dbgsyms.h */
+/* */
+/* Debug symbol handing for the ld65 linker */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef DBGSYMS_H
+#define DBGSYMS_H
+
+
+
+#include <stdio.h>
+
+#include "../common/exprdefs.h"
+#include "../common/filepos.h"
+
+#include "objdata.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Debug symbol structure */
+typedef struct DbgSym_ DbgSym;
+struct DbgSym_ {
+ DbgSym* Next; /* Pool linear list link */
+ unsigned Flags; /* Generic flags */
+ ObjData* Obj; /* Object file that exports the name */
+ FilePos Pos; /* File position of definition */
+ ExprNode* Expr; /* Expression (0 if not def'd) */
+ unsigned char Type; /* Type of symbol */
+ char Name [1]; /* Name - dynamically allocated */
+};
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+DbgSym* ReadDbgSym (FILE* F, ObjData* Obj);
+/* Read a debug symbol from a file, insert and return it */
+
+long GetDbgSymVal (DbgSym* D);
+/* Get the value of this symbol */
+
+void PrintDbgSymLabels (ObjData* O, FILE* F);
+/* Print the debug symbols in a VICE label file */
+
+
+
+/* End of dbgsyms.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* global.c */
+/* */
+/* Error handling for the ld65 linker */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "error.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Messages for internal compiler errors */
+const char _MsgCheckFailed [] =
+ "Check failed: `%s' (= %d), file `%s', line %u\n";
+const char _MsgPrecondition [] =
+ "Precondition violated: `%s' (= %d), file `%s', line %u\n";
+const char _MsgFail [] =
+ "%s, file `%s', line %u\n";
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void Warning (const char* Format, ...)
+/* Print a warning message */
+{
+ va_list ap;
+ va_start (ap, Format);
+ fprintf (stderr, "Warning: ");
+ vfprintf (stderr, Format, ap);
+ putc ('\n', stderr);
+ va_end (ap);
+}
+
+
+
+void Error (const char* Format, ...)
+/* Print an error message and die */
+{
+ va_list ap;
+ va_start (ap, Format);
+ fprintf (stderr, "Error: ");
+ vfprintf (stderr, Format, ap);
+ putc ('\n', stderr);
+ va_end (ap);
+ exit (EXIT_FAILURE);
+}
+
+
+
+void Internal (const char* Format, ...)
+/* Print an internal error message and die */
+{
+ va_list ap;
+ va_start (ap, Format);
+ fprintf (stderr, "Internal error: ");
+ vfprintf (stderr, Format, ap);
+ putc ('\n', stderr);
+ va_end (ap);
+ exit (EXIT_FAILURE);
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* global.h */
+/* */
+/* Error handling for the ld65 linker */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef ERROR_H
+#define ERROR_H
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Messages for internal compiler errors */
+extern const char _MsgCheckFailed [];
+extern const char _MsgPrecondition [];
+extern const char _MsgFail [];
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void Warning (const char* Format, ...);
+/* Print a warning message */
+
+void Error (const char* Format, ...);
+/* Print an error message and die */
+
+void Internal (const char* Format, ...);
+/* Print an internal error message and die */
+
+#define CHECK(c) \
+ if (!(c)) \
+ Internal (_MsgCheckFailed, #c, c, __FILE__, __LINE__)
+
+#define PRECONDITION(c) \
+ if (!(c)) \
+ Internal (_MsgPrecondition, #c, c, __FILE__, __LINE__)
+
+#define FAIL(s) \
+ Internal (_MsgFail, s, __FILE__, __LINE__)
+
+
+
+/* End of error.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* exports.c */
+/* */
+/* Exports handing for the ld65 linker */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../common/symdefs.h"
+#include "../common/hashstr.h"
+
+#include "global.h"
+#include "mem.h"
+#include "error.h"
+#include "fileio.h"
+#include "objdata.h"
+#include "expr.h"
+#include "exports.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Hash table */
+#define HASHTAB_SIZE 4081
+static Export* HashTab [HASHTAB_SIZE];
+
+/* Import management variables */
+static unsigned ImpCount = 0; /* Import count */
+static unsigned ImpOpen = 0; /* Count of open imports */
+
+/* Export management variables */
+static unsigned ExpCount = 0; /* Export count */
+static Export** ExpPool = 0; /* Exports array */
+
+/* Defines for the flags in Export */
+#define EXP_USERMARK 0x0001
+
+
+
+/*****************************************************************************/
+/* Import handling */
+/*****************************************************************************/
+
+
+
+static Export* NewExport (unsigned char Type, const char* Name, ObjData* Obj);
+/* Create a new export and initialize it */
+
+
+
+static Import* NewImport (unsigned char Type, ObjData* Obj)
+/* Create a new import and initialize it */
+{
+ /* Allocate memory */
+ Import* I = Xmalloc (sizeof (Import));
+
+ /* Initialize the fields */
+ I->Next = 0;
+ I->Obj = Obj;
+ I->V.Name = 0;
+ I->Type = Type;
+
+ /* Return the new structure */
+ return I;
+}
+
+
+
+void InsertImport (Import* I)
+/* Insert an import into the table */
+{
+ Export* E;
+ unsigned HashVal;
+
+ /* As long as the import is not inserted, V.Name is valid */
+ const char* Name = I->V.Name;
+
+ /* Create a hash value for the given name */
+ HashVal = HashStr (Name) % HASHTAB_SIZE;
+
+ /* Search through the list in that slot and print matching duplicates */
+ if (HashTab [HashVal] == 0) {
+ /* The slot is empty, we need to insert a dummy export */
+ E = HashTab [HashVal] = NewExport (0, Name, 0);
+ ++ExpCount;
+ } else {
+ E = HashTab [HashVal];
+ while (1) {
+ if (strcmp (E->Name, Name) == 0) {
+ /* We have an entry, L points to it */
+ break;
+ }
+ if (E->Next == 0) {
+ /* End of list an entry not found, insert a dummy */
+ E->Next = NewExport (0, Name, 0);
+ E = E->Next; /* Point to dummy */
+ ++ExpCount; /* One export more */
+ break;
+ } else {
+ E = E->Next;
+ }
+ }
+ }
+
+ /* Ok, E now points to a valid exports entry for the given import. Insert
+ * the import into the imports list and update the counters.
+ */
+ I->V.Exp = E;
+ I->Next = E->ImpList;
+ E->ImpList = I;
+ E->ImpCount++;
+ ++ImpCount; /* Total import count */
+ if (E->Expr == 0) {
+ /* This is a dummy export */
+ ++ImpOpen;
+ }
+
+ /* Now free the name since it's no longer needed */
+ Xfree (Name);
+}
+
+
+
+Import* ReadImport (FILE* F, ObjData* Obj)
+/* Read an import from a file and return it */
+{
+ Import* I;
+
+ /* Read the import type and check it */
+ unsigned char Type = Read8 (F);
+ if (Type != IMP_ZP && Type != IMP_ABS) {
+ Error ("Unknown import type in module `%s': %02X", Obj->Name, Type);
+ }
+
+ /* Create a new import */
+ I = NewImport (Type, Obj);
+
+ /* Read the name */
+ I->V.Name = ReadMallocedStr (F);
+
+ /* Read the file position */
+ ReadFilePos (F, &I->Pos);
+
+ /* Return the new import */
+ return I;
+}
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+static Export* NewExport (unsigned char Type, const char* Name, ObjData* Obj)
+/* Create a new export and initialize it */
+{
+ /* Get the length of the symbol name */
+ unsigned Len = strlen (Name);
+
+ /* Allocate memory */
+ Export* E = Xmalloc (sizeof (Export) + Len);
+
+ /* Initialize the fields */
+ E->Next = 0;
+ E->Flags = 0;
+ E->Obj = Obj;
+ E->ImpCount = 0;
+ E->ImpList = 0;
+ E->Expr = 0;
+ E->Type = Type;
+ memcpy (E->Name, Name, Len);
+ E->Name [Len] = '\0';
+
+ /* Return the new entry */
+ return E;
+}
+
+
+
+void InsertExport (Export* E)
+/* Insert an exported identifier and check if it's already in the list */
+{
+ Export* L;
+ Export* Last;
+ Import* Imp;
+ unsigned HashVal;
+
+ /* Create a hash value for the given name */
+ HashVal = HashStr (E->Name) % HASHTAB_SIZE;
+
+ /* Search through the list in that slot */
+ if (HashTab [HashVal] == 0) {
+ /* The slot is empty */
+ HashTab [HashVal] = E;
+ ++ExpCount;
+ } else {
+
+ Last = 0;
+ L = HashTab [HashVal];
+ do {
+ if (strcmp (L->Name, E->Name) == 0) {
+ /* This may be an unresolved external */
+ if (L->Expr == 0) {
+
+ /* This *is* an unresolved external */
+ E->Next = L->Next;
+ E->ImpCount = L->ImpCount;
+ E->ImpList = L->ImpList;
+ if (Last) {
+ Last->Next = E;
+ } else {
+ HashTab [HashVal] = E;
+ }
+ ImpOpen -= E->ImpCount; /* Decrease open imports now */
+ Xfree (L);
+ /* We must run through the import list and change the
+ * export pointer now.
+ */
+ Imp = E->ImpList;
+ while (Imp) {
+ Imp->V.Exp = E;
+ Imp = Imp->Next;
+ }
+ } else {
+ /* Duplicate entry, ignore it */
+ Warning ("Duplicate external identifier: `%s'", L->Name);
+ }
+ return;
+ }
+ Last = L;
+ L = L->Next;
+
+ } while (L);
+
+ /* Insert export at end of queue */
+ Last->Next = E;
+ ++ExpCount;
+ }
+}
+
+
+
+Export* ReadExport (FILE* F, ObjData* O)
+/* Read an export from a file */
+{
+ unsigned char Type;
+ char Name [256];
+ Export* E;
+
+ /* Read the type */
+ Type = Read8 (F);
+
+ /* Read the name */
+ ReadStr (F, Name);
+
+ /* Create a new export */
+ E = NewExport (Type, Name, O);
+
+ /* Read the value */
+ if (Type & EXP_EXPR) {
+ E->Expr = ReadExpr (F, O);
+ } else {
+ E->Expr = LiteralExpr (Read32 (F), O);
+ }
+
+ /* Last is the file position where the definition was done */
+ ReadFilePos (F, &E->Pos);
+
+ /* Return the new export */
+ return E;
+}
+
+
+
+Export* CreateConstExport (const char* Name, long Value)
+/* Create an export for a literal date */
+{
+ /* Create a new export */
+ Export* E = NewExport (EXP_ABS, Name, 0);
+
+ /* Assign the value */
+ E->Expr = LiteralExpr (Value, 0);
+
+ /* Insert the export */
+ InsertExport (E);
+
+ /* Return the new export */
+ return E;
+}
+
+
+
+Export* CreateMemExport (const char* Name, Memory* Mem, unsigned long Offs)
+/* Create an relative export for a memory area offset */
+{
+ /* Create a new export */
+ Export* E = NewExport (EXP_ABS, Name, 0);
+
+ /* Assign the value */
+ E->Expr = MemExpr (Mem, Offs, 0);
+
+ /* Insert the export */
+ InsertExport (E);
+
+ /* Return the new export */
+ return E;
+}
+
+
+
+static Export* FindExport (const char* Name)
+/* Check for an identifier in the list. Return 0 if not found, otherwise
+ * return a pointer to the export.
+ */
+{
+ /* Get a pointer to the list with the symbols hash value */
+ Export* L = HashTab [HashStr (Name) % HASHTAB_SIZE];
+ while (L) {
+ /* Search through the list in that slot */
+ if (strcmp (L->Name, Name) == 0) {
+ /* Entry found */
+ return L;
+ }
+ L = L->Next;
+ }
+
+ /* Not found */
+ return 0;
+}
+
+
+
+int IsUnresolved (const char* Name)
+/* Check if this symbol is an unresolved export */
+{
+ /* Find the export */
+ Export* E = FindExport (Name);
+
+ /* Check if it's unresolved */
+ return E != 0 && E->Expr == 0;
+}
+
+
+
+int IsConstExport (const Export* E)
+/* Return true if the expression associated with this export is const */
+{
+ if (E->Expr == 0) {
+ /* External symbols cannot be const */
+ return 0;
+ } else {
+ return IsConstExpr (E->Expr);
+ }
+}
+
+
+
+long GetExportVal (const Export* E)
+/* Get the value of this export */
+{
+ if (E->Expr == 0) {
+ /* OOPS */
+ Internal ("`%s' is an undefined external", E->Name);
+ }
+ return GetExprVal (E->Expr);
+}
+
+
+
+static void CheckSymType (Export* E)
+/* Check the types for one export */
+{
+ /* External with matching imports */
+ Import* Imp = E->ImpList;
+ int ZP = (E->Type & EXP_ZP) != 0;
+ while (Imp) {
+ if (ZP != ((Imp->Type & IMP_ZP) != 0)) {
+ /* Export is ZP, import is abs or the other way round */
+ if (E->Obj) {
+ /* User defined export */
+ Warning ("Type mismatch for `%s', export in "
+ "%s(%lu), import in %s(%lu)",
+ E->Name, E->Obj->Files [Imp->Pos.Name],
+ E->Pos.Line, Imp->Obj->Files [Imp->Pos.Name],
+ Imp->Pos.Line);
+ } else {
+ /* Export created by the linker */
+ Warning ("Type mismatch for `%s', imported from %s(%lu)",
+ E->Name, Imp->Obj->Files [Imp->Pos.Name],
+ Imp->Pos.Line);
+ }
+ }
+ Imp = Imp->Next;
+ }
+}
+
+
+
+static void CheckSymTypes (void)
+/* Check for symbol tape mismatches */
+{
+ unsigned I;
+
+ /* Print all open imports */
+ for (I = 0; I < ExpCount; ++I) {
+ Export* E = ExpPool [I];
+ if (E->Expr != 0 && E->ImpCount > 0) {
+ /* External with matching imports */
+ CheckSymType (E);
+ }
+ }
+}
+
+
+
+static void PrintUnresolved (ExpCheckFunc F, void* Data)
+/* Print a list of unresolved symbols. On unresolved symbols, F is
+ * called (see the comments on ExpCheckFunc in the data section).
+ */
+{
+ unsigned I;
+
+ /* Print all open imports */
+ for (I = 0; I < ExpCount; ++I) {
+ Export* E = ExpPool [I];
+ if (E->Expr == 0 && E->ImpCount > 0 && F (E->Name, Data) == 0) {
+ /* Unresolved external */
+ Import* Imp = E->ImpList;
+ fprintf (stderr,
+ "Unresolved external `%s' referenced in:\n",
+ E->Name);
+ while (Imp) {
+ const char* Name = Imp->Obj->Files [Imp->Pos.Name];
+ fprintf (stderr, " %s(%lu)\n", Name, Imp->Pos.Line);
+ Imp = Imp->Next;
+ }
+ }
+ }
+}
+
+
+
+static int CmpExpName (const void* K1, const void* K2)
+/* Compare function for qsort */
+{
+ return strcmp ((*(Export**)K1)->Name, (*(Export**)K2)->Name);
+}
+
+
+
+static void CreateExportPool (void)
+/* Create an array with pointer to all exports */
+{
+ unsigned I, J;
+
+ /* Allocate memory */
+ if (ExpPool) {
+ Xfree (ExpPool);
+ }
+ ExpPool = Xmalloc (ExpCount * sizeof (Export*));
+
+ /* Walk through the list and insert the exports */
+ for (I = 0, J = 0; I < sizeof (HashTab) / sizeof (HashTab [0]); ++I) {
+ Export* E = HashTab [I];
+ while (E) {
+ CHECK (J < ExpCount);
+ ExpPool [J++] = E;
+ E = E->Next;
+ }
+ }
+
+ /* Sort them by name */
+ qsort (ExpPool, ExpCount, sizeof (Export*), CmpExpName);
+}
+
+
+
+void CheckExports (ExpCheckFunc F, void* Data)
+/* Check if there are any unresolved symbols. On unresolved symbols, F is
+ * called (see the comments on ExpCheckFunc in the data section).
+ */
+{
+ /* Create an export pool */
+ CreateExportPool ();
+
+ /* Check for symbol type mismatches */
+ CheckSymTypes ();
+
+ /* Check for unresolved externals (check here for special bin formats) */
+ if (ImpOpen != 0) {
+ /* Print all open imports */
+ PrintUnresolved (F, Data);
+ }
+}
+
+
+
+void PrintExportMap (FILE* F)
+/* Print an export map to the given file */
+{
+ unsigned I;
+ unsigned Count;
+
+ /* Print all exports */
+ Count = 0;
+ for (I = 0; I < ExpCount; ++I) {
+ Export* E = ExpPool [I];
+
+ /* Print unreferenced symbols only if explictly requested */
+ if (VerboseMap || E->ImpCount > 0) {
+ fprintf (F,
+ "%-25s %06lX %c%c ",
+ E->Name,
+ GetExportVal (E),
+ E->ImpCount? 'R' : ' ',
+ (E->Type & EXP_ZP)? 'Z' : ' ');
+ if (++Count == 2) {
+ Count = 0;
+ fprintf (F, "\n");
+ }
+ }
+ }
+ fprintf (F, "\n");
+}
+
+
+
+void PrintImportMap (FILE* F)
+/* Print an import map to the given file */
+{
+ unsigned I;
+ Import* Imp;
+
+ /* Loop over all exports */
+ for (I = 0; I < ExpCount; ++I) {
+
+ /* Get the export */
+ Export* Exp = ExpPool [I];
+
+ /* Print the symbol only if there are imports, or if a verbose map
+ * file is requested.
+ */
+ if (VerboseMap || Exp->ImpCount > 0) {
+
+ /* Get the name of the object file that exports the symbol.
+ * Beware: There may be no object file if the symbol is a linker
+ * generated symbol.
+ */
+ const char* ObjName = (Exp->Obj != 0)? Exp->Obj->Name : "linker generated";
+
+ /* Print the export */
+ fprintf (F,
+ "%s (%s):\n",
+ Exp->Name,
+ ObjName);
+
+ /* Print all imports for this symbol */
+ Imp = Exp->ImpList;
+ while (Imp) {
+
+ /* Print the import */
+ fprintf (F,
+ " %-25s %s(%lu)\n",
+ Imp->Obj->Name,
+ Imp->Obj->Files [Imp->Pos.Name],
+ Imp->Pos.Line);
+
+ /* Next import */
+ Imp = Imp->Next;
+ }
+ }
+ }
+ fprintf (F, "\n");
+}
+
+
+
+void PrintExportLabels (FILE* F)
+/* Print the exports in a VICE label file */
+{
+ unsigned I;
+
+ /* Print all exports */
+ for (I = 0; I < ExpCount; ++I) {
+ Export* E = ExpPool [I];
+ fprintf (F, "al %06lX .%s\n", GetExportVal (E), E->Name);
+ }
+}
+
+
+
+void MarkExport (Export* E)
+/* Mark the export */
+{
+ E->Flags |= EXP_USERMARK;
+}
+
+
+
+void UnmarkExport (Export* E)
+/* Remove the mark from the export */
+{
+ E->Flags &= ~EXP_USERMARK;
+}
+
+
+
+int ExportHasMark (Export* E)
+/* Return true if the export has a mark */
+{
+ return (E->Flags & EXP_USERMARK) != 0;
+}
+
+
+
+void CircularRefError (const Export* E)
+/* Print an error about a circular reference using to define the given export */
+{
+ Error ("Circular reference for symbol `%s', %s(%lu)",
+ E->Name, E->Obj->Files [E->Pos.Name], E->Pos.Line);
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* exports.h */
+/* */
+/* Exports handing for the ld65 linker */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef EXPORTS_H
+#define EXPORTS_H
+
+
+
+#include <stdio.h>
+
+#include "../common/exprdefs.h"
+#include "../common/filepos.h"
+
+#include "objdata.h"
+#include "config.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Import symbol structure */
+typedef struct Import_ Import;
+struct Import_ {
+ Import* Next; /* Single linked list */
+ ObjData* Obj; /* Object file that imports the name */
+ FilePos Pos; /* File position of reference */
+ union {
+ struct Export_* Exp; /* Matching export for this import */
+ const char* Name; /* Name if not in table */
+ } V;
+ unsigned char Type; /* Type of import */
+};
+
+
+
+/* Export symbol structure */
+typedef struct Export_ Export;
+struct Export_ {
+ Export* Next; /* Hash table link */
+ unsigned Flags; /* Generic flags */
+ ObjData* Obj; /* Object file that exports the name */
+ unsigned ImpCount; /* How many imports for this symbol? */
+ Import* ImpList; /* List of imports for this symbol */
+ FilePos Pos; /* File position of definition */
+ ExprNode* Expr; /* Expression (0 if not def'd) */
+ unsigned char Type; /* Type of export */
+ char Name [1]; /* Name - dynamically allocated */
+};
+
+
+
+/* Prototype of a function that is called if an undefined symbol is found. It
+ * may check if the symbol is an external symbol (for binary formats that
+ * support externals) and will return zero if the symbol could not be
+ * resolved, or a value != zero if the symbol could be resolved. The
+ * CheckExports routine will print out the missing symbol in the first case.
+ */
+typedef int (*ExpCheckFunc) (const char* Name, void* Data);
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+Import* ReadImport (FILE* F, ObjData* Obj);
+/* Read an import from a file and insert it into the table */
+
+void InsertImport (Import* I);
+/* Insert an import into the table */
+
+Export* ReadExport (FILE* F, ObjData* Obj);
+/* Read an export from a file */
+
+void InsertExport (Export* E);
+/* Insert an exported identifier and check if it's already in the list */
+
+Export* CreateConstExport (const char* Name, long Value);
+/* Create an export for a literal date */
+
+Export* CreateMemExport (const char* Name, Memory* Mem, unsigned long Offs);
+/* Create an relative export for a memory area offset */
+
+int IsUnresolved (const char* Name);
+/* Check if this symbol is an unresolved export */
+
+int IsConstExport (const Export* E);
+/* Return true if the expression associated with this export is const */
+
+long GetExportVal (const Export* E);
+/* Get the value of this export */
+
+void CheckExports (ExpCheckFunc F, void* Data);
+/* Check if there are any unresolved symbols. On unresolved symbols, F is
+ * called (see the comments on ExpCheckFunc in the data section).
+ */
+
+void PrintExportMap (FILE* F);
+/* Print an export map to the given file */
+
+void PrintImportMap (FILE* F);
+/* Print an import map to the given file */
+
+void PrintExportLabels (FILE* F);
+/* Print the exports in a VICE label file */
+
+void MarkExport (Export* E);
+/* Mark the export */
+
+void UnmarkExport (Export* E);
+/* Remove the mark from the export */
+
+int ExportHasMark (Export* E);
+/* Return true if the export has a mark */
+
+void CircularRefError (const Export* E);
+/* Print an error about a circular reference using to define the given export */
+
+
+
+/* End of exports.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* expr.c */
+/* */
+/* Expression evaluation for the ld65 linker */
+/* */
+/* */
+/* */
+/* (C) 1998-2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include "../common/exprdefs.h"
+
+#include "global.h"
+#include "error.h"
+#include "mem.h"
+#include "fileio.h"
+#include "segments.h"
+#include "expr.h"
+
+
+
+/*****************************************************************************/
+/* Helpers */
+/*****************************************************************************/
+
+
+
+static ExprNode* NewExprNode (ObjData* O)
+/* Create a new expression node */
+{
+ /* Allocate fresh memory */
+ ExprNode* N = Xmalloc (sizeof (ExprNode));
+ N->Op = EXPR_NULL;
+ N->Left = 0;
+ N->Right = 0;
+ N->Obj = O;
+ N->V.Val = 0;
+
+ return N;
+}
+
+
+
+static void FreeExprNode (ExprNode* E)
+/* Free a node */
+{
+ /* Free the memory */
+ Xfree (E);
+}
+
+
+
+/*****************************************************************************/
+/* Dump an expression tree on stdout for debugging */
+/*****************************************************************************/
+
+
+
+static void InternalDumpExpr (const ExprNode* Expr)
+/* Dump an expression in UPN */
+{
+ if (Expr == 0) {
+ return;
+ }
+ InternalDumpExpr (Expr->Left);
+ InternalDumpExpr (Expr->Right);
+
+ switch (Expr->Op) {
+
+ case EXPR_LITERAL:
+ printf (" $%04lX", Expr->V.Val & 0xFFFF);
+ break;
+
+ case EXPR_SYMBOL:
+ printf (" SYM");
+ break;
+
+ case EXPR_SEGMENT:
+ printf (" SEG");
+ break;
+
+ case EXPR_PLUS:
+ printf (" +");
+ break;
+
+ case EXPR_MINUS:
+ printf (" -");
+ break;
+
+ case EXPR_MUL:
+ printf (" *");
+ break;
+
+ case EXPR_DIV:
+ printf (" /");
+ break;
+
+ case EXPR_MOD:
+ printf (" %%");
+ break;
+
+ case EXPR_OR:
+ printf (" OR");
+ break;
+
+ case EXPR_XOR:
+ printf (" XOR");
+ break;
+
+ case EXPR_AND:
+ printf (" AND");
+ break;
+
+ case EXPR_SHL:
+ printf (" SHL");
+ break;
+
+ case EXPR_SHR:
+ printf (" SHR");
+ break;
+
+ case EXPR_EQ:
+ printf (" =");
+ break;
+
+ case EXPR_NE:
+ printf ("<>");
+ break;
+
+ case EXPR_LT:
+ printf (" <");
+ break;
+
+ case EXPR_GT:
+ printf (" >");
+ break;
+
+ case EXPR_UNARY_MINUS:
+ printf (" NEG");
+ break;
+
+ case EXPR_NOT:
+ printf (" ~");
+ break;
+
+ case EXPR_LOBYTE:
+ printf (" LO");
+ break;
+
+ case EXPR_HIBYTE:
+ printf (" HI");
+ break;
+
+ case EXPR_SWAP:
+ printf (" SWAP");
+ break;
+
+ case EXPR_BAND:
+ printf (" BOOL_AND");
+ break;
+
+ case EXPR_BOR:
+ printf (" BOOL_OR");
+ break;
+
+ case EXPR_BXOR:
+ printf (" BOOL_XOR");
+ break;
+
+ case EXPR_BNOT:
+ printf (" BOOL_NOT");
+ break;
+
+ default:
+ Internal ("Unknown Op type: %u", Expr->Op);
+
+ }
+}
+
+
+
+void DumpExpr (const ExprNode* Expr)
+/* Dump an expression tree to stdout */
+{
+ InternalDumpExpr (Expr);
+ printf ("\n");
+}
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void FreeExpr (ExprNode* Root)
+/* Free the expression, Root is pointing to. */
+{
+ if (Root) {
+ FreeExpr (Root->Left);
+ FreeExpr (Root->Right);
+ FreeExprNode (Root);
+ }
+}
+
+
+
+int IsConstExpr (ExprNode* Root)
+/* Return true if the given expression is a constant expression, that is, one
+ * with no references to external symbols.
+ */
+{
+ int Const;
+ Export* E;
+
+ if (EXPR_IS_LEAF (Root->Op)) {
+ switch (Root->Op) {
+
+ case EXPR_LITERAL:
+ return 1;
+
+ case EXPR_SYMBOL:
+ /* Get the referenced export */
+ E = GetExprExport (Root);
+ /* If this export has a mark set, we've already encountered it.
+ * This means that the export is used to define it's own value,
+ * which in turn means, that we have a circular reference.
+ */
+ if (ExportHasMark (E)) {
+ Error ("Circular reference for symbol `%s', %s(%u)",
+ E->Name, E->Obj->Files [E->Pos.Name], E->Pos.Line);
+ Const = 0;
+ } else {
+ MarkExport (E);
+ Const = IsConstExport (E);
+ UnmarkExport (E);
+ }
+ return Const;
+
+ default:
+ return 0;
+
+ }
+ } else if (EXPR_IS_UNARY (Root->Op)) {
+
+ return IsConstExpr (Root->Left);
+
+ } else {
+
+ /* We must handle shortcut boolean expressions here */
+ switch (Root->Op) {
+
+ case EXPR_BAND:
+ if (IsConstExpr (Root->Left)) {
+ /* lhs is const, if it is zero, don't eval right */
+ if (GetExprVal (Root->Left) == 0) {
+ return 1;
+ } else {
+ return IsConstExpr (Root->Right);
+ }
+ } else {
+ /* lhs not const --> tree not const */
+ return 0;
+ }
+ break;
+
+ case EXPR_BOR:
+ if (IsConstExpr (Root->Left)) {
+ /* lhs is const, if it is not zero, don't eval right */
+ if (GetExprVal (Root->Left) != 0) {
+ return 1;
+ } else {
+ return IsConstExpr (Root->Right);
+ }
+ } else {
+ /* lhs not const --> tree not const */
+ return 0;
+ }
+ break;
+
+ default:
+ /* All others are handled normal */
+ return IsConstExpr (Root->Left) && IsConstExpr (Root->Right);
+ }
+ }
+}
+
+
+
+Import* GetExprImport (ExprNode* Expr)
+/* Get the import data structure for a symbol expression node */
+{
+ /* Check that this is really a symbol */
+ PRECONDITION (Expr->Op == EXPR_SYMBOL);
+
+ /* Return the import */
+ return Expr->Obj->Imports [Expr->V.ImpNum];
+}
+
+
+
+Export* GetExprExport (ExprNode* Expr)
+/* Get the exported symbol for a symbol expression node */
+{
+ /* Check that this is really a symbol */
+ PRECONDITION (Expr->Op == EXPR_SYMBOL);
+
+ /* Return the export */
+ return Expr->Obj->Imports [Expr->V.ImpNum]->V.Exp;
+}
+
+
+
+Section* GetExprSection (ExprNode* Expr)
+/* Get the segment for a segment expression node */
+{
+ /* Check that this is really a segment node */
+ PRECONDITION (Expr->Op == EXPR_SEGMENT);
+
+ /* Return the export */
+ return Expr->Obj->Sections [Expr->V.SegNum];
+}
+
+
+
+long GetExprVal (ExprNode* Expr)
+/* Get the value of a constant expression */
+{
+ long Right, Left, Val;
+ Section* S;
+ Export* E;
+
+ switch (Expr->Op) {
+
+ case EXPR_LITERAL:
+ return Expr->V.Val;
+
+ case EXPR_SYMBOL:
+ /* Get the referenced export */
+ E = GetExprExport (Expr);
+ /* If this export has a mark set, we've already encountered it.
+ * This means that the export is used to define it's own value,
+ * which in turn means, that we have a circular reference.
+ */
+ if (ExportHasMark (E)) {
+ CircularRefError (E);
+ Val = 0;
+ } else {
+ MarkExport (E);
+ Val = GetExportVal (E);
+ UnmarkExport (E);
+ }
+ return Val;
+
+ case EXPR_SEGMENT:
+ S = GetExprSection (Expr);
+ return S->Offs + S->Seg->PC;
+
+ case EXPR_MEMAREA:
+ return Expr->V.MemArea->Start;
+
+ case EXPR_PLUS:
+ return GetExprVal (Expr->Left) + GetExprVal (Expr->Right);
+
+ case EXPR_MINUS:
+ return GetExprVal (Expr->Left) - GetExprVal (Expr->Right);
+
+ case EXPR_MUL:
+ return GetExprVal (Expr->Left) * GetExprVal (Expr->Right);
+
+ case EXPR_DIV:
+ Left = GetExprVal (Expr->Left);
+ Right = GetExprVal (Expr->Right);
+ if (Right == 0) {
+ Error ("Division by zero");
+ }
+ return Left / Right;
+
+ case EXPR_MOD:
+ Left = GetExprVal (Expr->Left);
+ Right = GetExprVal (Expr->Right);
+ if (Right == 0) {
+ Error ("Modulo operation with zero");
+ }
+ return Left % Right;
+
+ case EXPR_OR:
+ return GetExprVal (Expr->Left) | GetExprVal (Expr->Right);
+
+ case EXPR_XOR:
+ return GetExprVal (Expr->Left) ^ GetExprVal (Expr->Right);
+
+ case EXPR_AND:
+ return GetExprVal (Expr->Left) & GetExprVal (Expr->Right);
+
+ case EXPR_SHL:
+ return GetExprVal (Expr->Left) << GetExprVal (Expr->Right);
+
+ case EXPR_SHR:
+ return GetExprVal (Expr->Left) >> GetExprVal (Expr->Right);
+
+ case EXPR_EQ:
+ return (GetExprVal (Expr->Left) == GetExprVal (Expr->Right));
+
+ case EXPR_NE:
+ return (GetExprVal (Expr->Left) != GetExprVal (Expr->Right));
+
+ case EXPR_LT:
+ return (GetExprVal (Expr->Left) < GetExprVal (Expr->Right));
+
+ case EXPR_GT:
+ return (GetExprVal (Expr->Left) > GetExprVal (Expr->Right));
+
+ case EXPR_LE:
+ return (GetExprVal (Expr->Left) <= GetExprVal (Expr->Right));
+
+ case EXPR_GE:
+ return (GetExprVal (Expr->Left) >= GetExprVal (Expr->Right));
+
+ case EXPR_UNARY_MINUS:
+ return -GetExprVal (Expr->Left);
+
+ case EXPR_NOT:
+ return ~GetExprVal (Expr->Left);
+
+ case EXPR_LOBYTE:
+ return GetExprVal (Expr->Left) & 0xFF;
+
+ case EXPR_HIBYTE:
+ return (GetExprVal (Expr->Left) >> 8) & 0xFF;
+
+ case EXPR_SWAP:
+ Left = GetExprVal (Expr->Left);
+ return ((Left >> 8) & 0x00FF) | ((Left << 8) & 0xFF00);
+
+ case EXPR_BAND:
+ return GetExprVal (Expr->Left) && GetExprVal (Expr->Right);
+
+ case EXPR_BOR:
+ return GetExprVal (Expr->Left) || GetExprVal (Expr->Right);
+
+ case EXPR_BXOR:
+ return (GetExprVal (Expr->Left) != 0) ^ (GetExprVal (Expr->Right) != 0);
+
+ case EXPR_BNOT:
+ return !GetExprVal (Expr->Left);
+
+ default:
+ Internal ("Unknown expression Op type: %u", Expr->Op);
+ /* NOTREACHED */
+ return 0;
+ }
+}
+
+
+
+ExprNode* LiteralExpr (long Val, ObjData* O)
+/* Return an expression tree that encodes the given literal value */
+{
+ ExprNode* Expr = NewExprNode (O);
+ Expr->Op = EXPR_LITERAL;
+ Expr->V.Val = Val;
+ return Expr;
+}
+
+
+
+ExprNode* MemExpr (Memory* Mem, long Offs, ObjData* O)
+/* Return an expression tree that encodes an offset into the memory area */
+{
+ ExprNode* Root;
+
+ ExprNode* Expr = NewExprNode (O);
+ Expr->Op = EXPR_MEMAREA;
+ Expr->V.MemArea = Mem;
+
+ Root = NewExprNode (O);
+ Root->Op = EXPR_PLUS;
+ Root->Left = Expr;
+ Root->Right = LiteralExpr (Offs, O);
+
+ return Root;
+}
+
+
+
+ExprNode* ReadExpr (FILE* F, ObjData* O)
+/* Read an expression from the given file */
+{
+ ExprNode* Expr;
+
+ /* Read the node tag and handle NULL nodes */
+ unsigned char Op = Read8 (F);
+ if (Op == EXPR_NULL) {
+ return 0;
+ }
+
+ /* Create a new node */
+ Expr = NewExprNode (O);
+ Expr->Op = Op;
+
+ /* Check the tag and handle the different expression types */
+ if (EXPR_IS_LEAF (Op)) {
+ switch (Op) {
+
+ case EXPR_LITERAL:
+ Expr->V.Val = Read32Signed (F);
+ break;
+
+ case EXPR_SYMBOL:
+ /* Read the import number */
+ Expr->V.ImpNum = Read16 (F);
+ break;
+
+ case EXPR_SEGMENT:
+ /* Read the segment number */
+ Expr->V.SegNum = Read8 (F);
+ break;
+
+ default:
+ Error ("Invalid expression op: %02X", Op);
+
+ }
+
+ } else {
+
+ /* Not a leaf node */
+ Expr->Left = ReadExpr (F, O);
+ Expr->Right = ReadExpr (F, O);
+
+ }
+
+ /* Return the tree */
+ return Expr;
+}
+
+
+
+int EqualExpr (ExprNode* E1, ExprNode* E2)
+/* Check if two expressions are identical. */
+{
+ /* If one pointer is NULL, both must be NULL */
+ if ((E1 == 0) ^ (E2 == 0)) {
+ return 0;
+ }
+ if (E1 == 0) {
+ return 1;
+ }
+
+ /* Both pointers not NULL, check OP */
+ if (E1->Op != E2->Op) {
+ return 0;
+ }
+
+ /* OPs are identical, check data for leafs, or subtrees */
+ switch (E1->Op) {
+
+ case EXPR_LITERAL:
+ /* Value must be identical */
+ return (E1->V.Val == E2->V.Val);
+
+ case EXPR_SYMBOL:
+ /* Import number must be identical */
+ return (E1->V.ImpNum == E2->V.ImpNum);
+
+ case EXPR_SEGMENT:
+ /* Segment number must be identical */
+ return (E1->V.SegNum == E2->V.SegNum);
+
+ case EXPR_MEMAREA:
+ /* Memory area must be identical */
+ return (E1->V.MemArea == E2->V.MemArea);
+
+ default:
+ /* Not a leaf node */
+ return EqualExpr (E1->Left, E2->Left) && EqualExpr (E1->Right, E2->Right);
+ }
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* expr.h */
+/* */
+/* Expression evaluation for the ld65 linker */
+/* */
+/* */
+/* */
+/* (C) 1998-2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef EXPR_H
+#define EXPR_H
+
+
+
+#include "../common/exprdefs.h"
+
+#include "objdata.h"
+#include "exports.h"
+#include "config.h"
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void FreeExpr (ExprNode* Root);
+/* Free the expression tree, Root is pointing to. */
+
+int IsConstExpr (ExprNode* Root);
+/* Return true if the given expression is a constant expression, that is, one
+ * with no references to external symbols.
+ */
+
+Import* GetExprImport (ExprNode* Expr);
+/* Get the import data structure for a symbol expression node */
+
+Export* GetExprExport (ExprNode* Expr);
+/* Get the exported symbol for a symbol expression node */
+
+Section* GetExprSection (ExprNode* Expr);
+/* Get the segment for a segment expression node */
+
+long GetExprVal (ExprNode* Expr);
+/* Get the value of a constant expression */
+
+ExprNode* LiteralExpr (long Val, ObjData* O);
+/* Return an expression tree that encodes the given literal value */
+
+ExprNode* MemExpr (Memory* Mem, long Offs, ObjData* O);
+/* Return an expression tree that encodes an offset into the memory area */
+
+void DumpExpr (const ExprNode* Expr);
+/* Dump an expression tree to stdout */
+
+ExprNode* ReadExpr (FILE* F, ObjData* O);
+/* Read an expression from the given file */
+
+int EqualExpr (ExprNode* E1, ExprNode* E2);
+/* Check if two expressions are identical. */
+
+
+
+/* End of expr.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* extsyms.c */
+/* */
+/* Handle program external symbols for relocatable output formats */
+/* */
+/* */
+/* */
+/* (C) 1999 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <string.h>
+
+#include "../common/hashstr.h"
+
+#include "mem.h"
+#include "error.h"
+#include "extsyms.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Structure holding an external symbol */
+struct ExtSym_ {
+ ExtSym* List; /* Next entry in list of all symbols */
+ ExtSym* Next; /* Next entry in hash list */
+ unsigned Flags; /* Generic flags */
+ unsigned Num; /* Number of external symbol */
+ char Name [1]; /* Name - dynamically allocated */
+};
+
+/* External symbol table structure */
+#define HASHTAB_SIZE 53
+struct ExtSymTab_ {
+ ExtSym* Root; /* List of symbols */
+ ExtSym* Last; /* Pointer to last symbol */
+ unsigned Count; /* Number of symbols */
+ ExtSym* HashTab [HASHTAB_SIZE];
+};
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+ExtSym* NewExtSym (ExtSymTab* Tab, const char* Name)
+/* Create a new external symbol and insert it into the table */
+{
+ /* Get the hash value of the string */
+ unsigned Hash = HashStr (Name) % HASHTAB_SIZE;
+
+ /* Get the length of the name */
+ unsigned Len = strlen (Name);
+
+ /* Check for duplicates */
+ ExtSym* E = GetExtSym (Tab, Name); /* Don't care about duplicate hash here... */
+ if (E != 0) {
+ /* We do already have a symbol with this name */
+ Error ("Duplicate external symbol `%s'", Name);
+ }
+
+ /* Allocate memory for the structure */
+ E = Xmalloc (sizeof (ExtSym) + Len);
+
+ /* Initialize the structure */
+ E->List = 0;
+ E->Flags = 0;
+ E->Num = Tab->Count;
+ memcpy (E->Name, Name, Len+1);
+
+ /* Insert the entry into the list of all symbols */
+ if (Tab->Last == 0) {
+ /* List is empty */
+ Tab->Root = E;
+ } else {
+ /* List not empty */
+ Tab->Last->List = E;
+ }
+ Tab->Last = E;
+ Tab->Count++;
+
+ /* Insert the symbol into the hash table */
+ E->Next = Tab->HashTab [Hash];
+ Tab->HashTab [Hash] = E;
+
+ /* Done, return the created entry */
+ return E;
+}
+
+
+
+static void FreeExtSym (ExtSym* E)
+/* Free an external symbol structure. Will not unlink the entry, so internal
+ * use only.
+ */
+{
+ Xfree (E);
+}
+
+
+
+ExtSymTab* NewExtSymTab (void)
+/* Create a new external symbol table */
+{
+ unsigned I;
+
+ /* Allocate memory */
+ ExtSymTab* Tab = Xmalloc (sizeof (ExtSymTab));
+
+ /* Initialize the fields */
+ Tab->Root = 0;
+ Tab->Last = 0;
+ Tab->Count = 0;
+ for (I = 0; I < HASHTAB_SIZE; ++I) {
+ Tab->HashTab [I] = 0;
+ }
+
+ /* Done, return the hash table */
+ return Tab;
+}
+
+
+
+void FreeExtSymTab (ExtSymTab* Tab)
+/* Free an external symbol structure */
+{
+ /* Free all entries */
+ while (Tab->Root) {
+ ExtSym* E = Tab->Root;
+ Tab->Root = E->Next;
+ FreeExtSym (E);
+ }
+
+ /* Free the struct itself */
+ Xfree (Tab);
+}
+
+
+
+ExtSym* GetExtSym (const ExtSymTab* Tab, const char* Name)
+/* Return the entry for the external symbol with the given name. Return NULL
+ * if there is no such symbol.
+ */
+{
+ /* Hash the name */
+ unsigned Hash = HashStr (Name) % HASHTAB_SIZE;
+
+ /* Check the linked list */
+ ExtSym* E = Tab->HashTab [Hash];
+ while (E) {
+ if (strcmp (E->Name, Name) == 0) {
+ /* Found it */
+ break;
+ }
+ E = E->Next;
+ }
+
+ /* Return the symbol we found */
+ return E;
+}
+
+
+
+unsigned ExtSymCount (const ExtSymTab* Tab)
+/* Return the number of symbols in the table */
+{
+ return Tab->Count;
+}
+
+
+
+const ExtSym* ExtSymList (const ExtSymTab* Tab)
+/* Return the start of the symbol list sorted by symbol number. Call
+ * ExtSymNext for the next symbol.
+ */
+{
+ return Tab->Root;
+}
+
+
+
+unsigned ExtSymNum (const ExtSym* E)
+/* Return the number of an external symbol */
+{
+ return E->Num;
+}
+
+
+
+const char* ExtSymName (const ExtSym* E)
+/* Return the symbol name */
+{
+ return E->Name;
+}
+
+
+
+const ExtSym* ExtSymNext (const ExtSym* E)
+/* Return the next symbol in the list */
+{
+ return E->Next;
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* extsyms.h */
+/* */
+/* Handle program external symbols for relocatable output formats */
+/* */
+/* */
+/* */
+/* (C) 1999 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef EXTSYMS_H
+#define EXTSYMS_H
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Forward decl for structure holding an external symbol */
+typedef struct ExtSym_ ExtSym;
+
+/* External symbol table structure */
+typedef struct ExtSymTab_ ExtSymTab;
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+ExtSym* NewExtSym (ExtSymTab* Tab, const char* Name);
+/* Create a new external symbol and insert it into the list */
+
+ExtSymTab* NewExtSymTab (void);
+/* Create a new external symbol table */
+
+void FreeExtSymTab (ExtSymTab* Tab);
+/* Free an external symbol structure */
+
+ExtSym* GetExtSym (const ExtSymTab* Tab, const char* Name);
+/* Return the entry for the external symbol with the given name. Return NULL
+ * if there is no such symbol.
+ */
+
+unsigned ExtSymCount (const ExtSymTab* Tab);
+/* Return the number of symbols in the table */
+
+const ExtSym* ExtSymList (const ExtSymTab* Tab);
+/* Return the start of the symbol list sorted by symbol number. Call
+ * ExtSymNext for the next symbol.
+ */
+
+unsigned ExtSymNum (const ExtSym* E);
+/* Return the number of an external symbol */
+
+const char* ExtSymName (const ExtSym* E);
+/* Return the symbol name */
+
+const ExtSym* ExtSymNext (const ExtSym* E);
+/* Return the next symbol in the list */
+
+
+
+/* End of extsyms.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* fileio.c */
+/* */
+/* File I/O for the ld65 linker */
+/* */
+/* */
+/* */
+/* (C) 1998-2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <string.h>
+
+#include "error.h"
+#include "mem.h"
+#include "fileio.h"
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void Write8 (FILE* F, unsigned char Val)
+/* Write an 8 bit value to the file */
+{
+ if (putc (Val, F) == EOF) {
+ Error ("Write error (disk full?)");
+ }
+}
+
+
+
+void Write16 (FILE* F, unsigned Val)
+/* Write a 16 bit value to the file */
+{
+ Write8 (F, (unsigned char) Val);
+ Write8 (F, (unsigned char) (Val >> 8));
+}
+
+
+
+void Write24 (FILE* F, unsigned long Val)
+/* Write a 24 bit value to the file */
+{
+ Write8 (F, (unsigned char) Val);
+ Write8 (F, (unsigned char) (Val >> 8));
+ Write8 (F, (unsigned char) (Val >> 16));
+}
+
+
+
+void Write32 (FILE* F, unsigned long Val)
+/* Write a 32 bit value to the file */
+{
+ Write8 (F, (unsigned char) Val);
+ Write8 (F, (unsigned char) (Val >> 8));
+ Write8 (F, (unsigned char) (Val >> 16));
+ Write8 (F, (unsigned char) (Val >> 24));
+}
+
+
+
+void WriteVal (FILE* F, unsigned long Val, unsigned Size)
+/* Write a value of the given size to the output file */
+{
+ switch (Size) {
+
+ case 1:
+ Write8 (F, Val);
+ break;
+
+ case 2:
+ Write16 (F, Val);
+ break;
+
+ case 3:
+ Write24 (F, Val);
+ break;
+
+ case 4:
+ Write32 (F, Val);
+ break;
+
+ default:
+ Internal ("WriteVal: Invalid size: %u", Size);
+
+ }
+}
+
+
+
+void WriteStr (FILE* F, const char* S)
+/* Write a string to the file */
+{
+ unsigned Len = strlen (S);
+ if (Len > 255) {
+ Internal ("String too long");
+ }
+ Write8 (F, (unsigned char) Len);
+ WriteData (F, S, Len);
+}
+
+
+
+void WriteData (FILE* F, const void* Data, unsigned Size)
+/* Write data to the file */
+{
+ if (fwrite (Data, 1, Size, F) != Size) {
+ Error ("Write error (disk full?)");
+ }
+}
+
+
+
+void WriteMult (FILE* F, unsigned char Val, unsigned long Count)
+/* Write one byte several times to the file */
+{
+ while (Count--) {
+ Write8 (F, Val);
+ }
+}
+
+
+
+unsigned Read8 (FILE* F)
+/* Read an 8 bit value from the file */
+{
+ int C = getc (F);
+ if (C == EOF) {
+ Error ("Read error (file corrupt?)");
+ }
+ return C;
+}
+
+
+
+unsigned Read16 (FILE* F)
+/* Read a 16 bit value from the file */
+{
+ unsigned Lo = Read8 (F);
+ unsigned Hi = Read8 (F);
+ return (Hi << 8) | Lo;
+}
+
+
+
+unsigned long Read24 (FILE* F)
+/* Read a 24 bit value from the file */
+{
+ unsigned long Lo = Read16 (F);
+ unsigned long Hi = Read8 (F);
+ return (Hi << 16) | Lo;
+}
+
+
+
+unsigned long Read32 (FILE* F)
+/* Read a 32 bit value from the file */
+{
+ unsigned long Lo = Read16 (F);
+ unsigned long Hi = Read16 (F);
+ return (Hi << 16) | Lo;
+}
+
+
+
+long Read32Signed (FILE* F)
+/* Read a 32 bit value from the file. Sign extend the value. */
+{
+ /* Read a 32 bit value */
+ unsigned long V = Read32 (F);
+
+ /* Sign extend the value */
+ if (V & 0x80000000UL) {
+ /* Signed value */
+ V |= ~0xFFFFFFFFUL;
+ }
+
+ /* Return it as a long */
+ return (long) V;
+}
+
+
+
+char* ReadStr (FILE* F, char* Str)
+/* Read a string from the file. Str must hold 256 chars at max */
+{
+ /* Read the length byte */
+ unsigned Len = Read8 (F);
+
+ /* Read the string itself */
+ ReadData (F, Str, Len);
+
+ /* Terminate the string and return it */
+ Str [Len] = '\0';
+ return Str;
+}
+
+
+
+char* ReadMallocedStr (FILE* F)
+/* Read a string from the file into a malloced area */
+{
+ /* Read the length byte */
+ unsigned Len = Read8 (F);
+
+ /* Allocate memory */
+ char* Str = Xmalloc (Len + 1);
+
+ /* Read the string itself */
+ ReadData (F, Str, Len);
+
+ /* Terminate the string and return it */
+ Str [Len] = '\0';
+ return Str;
+}
+
+
+
+FilePos* ReadFilePos (FILE* F, FilePos* Pos)
+/* Read a file position from the file */
+{
+ /* The line number is encoded as 24 bit value to save some space */
+ Pos->Line = Read24 (F);
+ Pos->Col = Read8 (F);
+ Pos->Name = Read8 (F);
+ return Pos;
+}
+
+
+
+void* ReadData (FILE* F, void* Data, unsigned Size)
+/* Read data from the file */
+{
+ if (fread (Data, 1, Size, F) != Size) {
+ Error ("Read error (file corrupt?)");
+ }
+ return Data;
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* fileio.h */
+/* */
+/* File I/O for the ld65 linker */
+/* */
+/* */
+/* */
+/* (C) 1998-2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef FILEIO_H
+#define FILEIO_H
+
+
+
+#include <stdio.h>
+
+#include "../common/filepos.h"
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void Write8 (FILE* F, unsigned char Val);
+/* Write an 8 bit value to the file */
+
+void Write16 (FILE* F, unsigned Val);
+/* Write a 16 bit value to the file */
+
+void Write24 (FILE* F, unsigned long Val);
+/* Write a 24 bit value to the file */
+
+void Write32 (FILE* F, unsigned long Val);
+/* Write a 32 bit value to the file */
+
+void WriteVal (FILE* F, unsigned long Val, unsigned Size);
+/* Write a value of the given size to the output file */
+
+void WriteStr (FILE* F, const char* S);
+/* Write a string to the file */
+
+void WriteData (FILE* F, const void* Data, unsigned Size);
+/* Write data to the file */
+
+void WriteMult (FILE* F, unsigned char Val, unsigned long Count);
+/* Write one byte several times to the file */
+
+unsigned Read8 (FILE* F);
+/* Read an 8 bit value from the file */
+
+unsigned Read16 (FILE* F);
+/* Read a 16 bit value from the file */
+
+unsigned long Read24 (FILE* F);
+/* Read a 24 bit value from the file */
+
+unsigned long Read32 (FILE* F);
+/* Read a 32 bit value from the file */
+
+long Read32Signed (FILE* F);
+/* Read a 32 bit value from the file. Sign extend the value. */
+
+char* ReadStr (FILE* F, char* Str);
+/* Read a string from the file. Str must hold 256 chars at max */
+
+char* ReadMallocedStr (FILE* F);
+/* Read a string from the file into a malloced area */
+
+FilePos* ReadFilePos (FILE* F, FilePos* Pos);
+/* Read a file position from the file */
+
+void* ReadData (FILE* F, void* Data, unsigned Size);
+/* Read data from the file */
+
+
+
+/* End of fileio.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* global.c */
+/* */
+/* Global variables for the ld65 linker */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include "global.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+const char* ProgName = "ld65"; /* Program name */
+
+const char* OutputName = "a.out"; /* Name of output file */
+
+unsigned long StartAddr = 0x200; /* Start address */
+
+unsigned char Verbose = 0; /* Verbose operation flag */
+unsigned char VerboseMap = 0; /* Verbose map file */
+const char* MapFileName = 0; /* Name of the map file */
+const char* LabelFileName = 0; /* Name of the label file */
+unsigned char WProtSegs = 0; /* Mark write protected segments */
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* global.h */
+/* */
+/* Global variables for the ld65 linker */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef GLOBAL_H
+#define GLOBAL_H
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+extern const char* ProgName; /* Program name */
+
+extern const char* OutputName; /* Name of output file */
+
+extern unsigned long StartAddr; /* Start address */
+
+extern unsigned char Verbose; /* Verbose operation flag */
+extern unsigned char VerboseMap; /* Verbose map file */
+extern const char* MapFileName; /* Name of the map file */
+extern const char* LabelFileName; /* Name of the label file */
+extern unsigned char WProtSegs; /* Mark write protected segments */
+
+
+
+/* End of global.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* library.c */
+/* */
+/* Library data structures and helpers for the ld65 linker */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "../common/objdefs.h"
+#include "../common/libdefs.h"
+#include "../common/symdefs.h"
+#include "../common/exprdefs.h"
+#include "../common/filepos.h"
+
+#include "mem.h"
+#include "error.h"
+#include "fileio.h"
+#include "objdata.h"
+#include "objfile.h"
+#include "exports.h"
+#include "library.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Library data */
+static FILE* Lib = 0;
+static char* LibName = 0;
+static unsigned ModuleCount = 0;
+static ObjData** Index = 0;
+
+
+
+/*****************************************************************************/
+/* Reading file data structures */
+/*****************************************************************************/
+
+
+
+static void LibReadObjHeader (ObjData* O)
+/* Read the header of the object file checking the signature */
+{
+ O->Header.Magic = Read32 (Lib);
+ if (O->Header.Magic != OBJ_MAGIC) {
+ Error ("Object file `%s' in library `%s' is invalid", O->Name, LibName);
+ }
+ O->Header.Version = Read16 (Lib);
+ if (O->Header.Version != OBJ_VERSION) {
+ Error ("Object file `%s' in library `%s' has wrong version",
+ O->Name, LibName);
+ }
+ O->Header.Flags = Read16 (Lib);
+ O->Header.OptionOffs = Read32 (Lib);
+ O->Header.OptionSize = Read32 (Lib);
+ O->Header.FileOffs = Read32 (Lib);
+ O->Header.FileSize = Read32 (Lib);
+ O->Header.SegOffs = Read32 (Lib);
+ O->Header.SegSize = Read32 (Lib);
+ O->Header.ImportOffs = Read32 (Lib);
+ O->Header.ImportSize = Read32 (Lib);
+ O->Header.ExportOffs = Read32 (Lib);
+ O->Header.ExportSize = Read32 (Lib);
+ O->Header.DbgSymOffs = Read32 (Lib);
+ O->Header.DbgSymSize = Read32 (Lib);
+}
+
+
+
+static ObjData* ReadIndexEntry (void)
+/* Read one entry in the index */
+{
+ unsigned I;
+
+ /* Create a new entry and insert it into the list */
+ ObjData* O = NewObjData ();
+
+ /* Module name/flags/MTime/Start/Size */
+ O->Name = ReadMallocedStr (Lib);
+ O->Flags = Read16 (Lib);
+ Read32 (Lib); /* Skip MTime */
+ O->Start = Read32 (Lib);
+ Read32 (Lib); /* Skip Size */
+
+ /* Skip the export size, then read the exports */
+ Read16 (Lib);
+ O->ExportCount = Read16 (Lib);
+ O->Exports = Xmalloc (O->ExportCount * sizeof (Export*));
+ for (I = 0; I < O->ExportCount; ++I) {
+ O->Exports [I] = ReadExport (Lib, O);
+ }
+
+ /* Skip the import size, then read the imports */
+ Read16 (Lib);
+ O->ImportCount = Read16 (Lib);
+ O->Imports = Xmalloc (O->ImportCount * sizeof (Import*));
+ for (I = 0; I < O->ImportCount; ++I) {
+ O->Imports [I] = ReadImport (Lib, O);
+ }
+
+ /* Done */
+ return O;
+}
+
+
+
+static void ReadIndex (void)
+/* Read the index of a library file */
+{
+ unsigned I;
+
+ /* Read the object file count and allocate memory */
+ ModuleCount = Read16 (Lib);
+ Index = Xmalloc (ModuleCount * sizeof (ObjData*));
+
+ /* Read all entries in the index */
+ for (I = 0; I < ModuleCount; ++I) {
+ Index [I] = ReadIndexEntry ();
+ }
+}
+
+
+
+/*****************************************************************************/
+/* High level stuff */
+/*****************************************************************************/
+
+
+
+static void LibCheckExports (ObjData* O)
+/* Check if the exports from this file can satisfy any import requests. If so,
+ * insert the imports and exports from this file and mark the file as added.
+ */
+{
+ unsigned I;
+
+ /* Check all exports */
+ for (I = 0; I < O->ExportCount; ++I) {
+ if (IsUnresolved (O->Exports [I]->Name)) {
+ /* We need this module */
+ O->Flags |= OBJ_REF;
+ break;
+ }
+ }
+
+ /* If we need this module, insert the imports and exports */
+ if (O->Flags & OBJ_REF) {
+ /* Insert the exports */
+ for (I = 0; I < O->ExportCount; ++I) {
+ InsertExport (O->Exports [I]);
+ }
+ /* Insert the imports */
+ for (I = 0; I < O->ImportCount; ++I) {
+ InsertImport (O->Imports [I]);
+ }
+ }
+}
+
+
+
+void LibAdd (FILE* F, const char* Name)
+/* Add files from the library to the list if there are references that could
+ * be satisfied.
+ */
+{
+ int Add;
+ unsigned I;
+ LibHeader Header;
+
+ /* Store the parameters, so they're visible for other routines */
+ Lib = F;
+ LibName = StrDup (Name);
+
+ /* Read the remaining header fields (magic is already read) */
+ Header.Magic = LIB_MAGIC;
+ Header.Version = Read16 (Lib);
+ if (Header.Version != LIB_VERSION) {
+ Error ("Wrong data version in `%s'", Name);
+ }
+ Header.Flags = Read16 (Lib);
+ Header.IndexOffs = Read32 (Lib);
+
+ /* Seek to the index position and read the index */
+ fseek (Lib, Header.IndexOffs, SEEK_SET);
+ ReadIndex ();
+
+ /* Walk through all library modules and check for each module if there
+ * are unresolved externals in existing modules that may be resolved
+ * by adding the module. Repeat this step until no more object files
+ * were added.
+ */
+ do {
+ Add = 0;
+ for (I = 0; I < ModuleCount; ++I) {
+ ObjData* O = Index [I];
+ if ((O->Flags & OBJ_REF) == 0) {
+ LibCheckExports (O);
+ if (O->Flags & OBJ_REF) {
+ /* The routine added the file */
+ Add = 1;
+ }
+ }
+ }
+ } while (Add);
+
+ /* Add the files list and sections for all requested modules */
+ for (I = 0; I < ModuleCount; ++I) {
+ ObjData* O = Index [I];
+ if (O->Flags & OBJ_REF) {
+
+ /* Seek to the start of the object file and read the header */
+ fseek (Lib, O->Start, SEEK_SET);
+ LibReadObjHeader (O);
+
+ /* Seek to the start of the files list and read the files list */
+ fseek (Lib, O->Start + O->Header.FileOffs, SEEK_SET);
+ ObjReadFiles (Lib, O);
+
+ /* Seek to the start of the segment list and read the segments */
+ fseek (Lib, O->Start + O->Header.SegOffs, SEEK_SET);
+ ObjReadSections (Lib, O);
+
+ /* Seek to the start of the debug info and read the debug info */
+ fseek (Lib, O->Start + O->Header.DbgSymOffs, SEEK_SET);
+ ObjReadDbgSyms (Lib, O);
+
+ /* We have the data now */
+ O->Flags |= OBJ_HAVEDATA;
+
+ }
+
+ /* Add a pointer to the library name */
+ O->LibName = LibName;
+ }
+
+ /* Done. Close the file, release allocated memory */
+ fclose (F);
+ Xfree (Index);
+ Lib = 0;
+ LibName = 0;
+ ModuleCount = 0;
+ Index = 0;
+}
+
+
+
+
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* library.h */
+/* */
+/* Library data structures and helpers for the ld65 linker */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef LIBRARY_H
+#define LIBRARY_H
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void LibAdd (FILE* F, const char* Name);
+/* Add files from the library to the list if there are references that could
+ * be satisfied.
+ */
+
+
+
+/* End of library.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* main.c */
+/* */
+/* Main program for the ld65 linker */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "../common/libdefs.h"
+#include "../common/objdefs.h"
+#include "../common/version.h"
+
+#include "global.h"
+#include "error.h"
+#include "mem.h"
+#include "target.h"
+#include "fileio.h"
+#include "scanner.h"
+#include "config.h"
+#include "objfile.h"
+#include "library.h"
+#include "exports.h"
+#include "segments.h"
+#include "mapfile.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+static unsigned ObjFiles = 0; /* Count of object files linked */
+static unsigned LibFiles = 0; /* Count of library files linked */
+static const char* LibPath = 0; /* Search path for modules */
+static unsigned LibPathLen = 0; /* Length of LibPath */
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+static void Usage (void)
+/* Print usage information and exit */
+{
+ fprintf (stderr,
+ "Usage: %s [options] module ...\n"
+ "Options are:\n"
+ "\t-m name\t\tCreate a map file\n"
+ "\t-o name\t\tName the default output file\n"
+ "\t-t type\t\tType of target system\n"
+ "\t-v\t\tVerbose mode\n"
+ "\t-vm\t\tVerbose map file\n"
+ "\t-C name\t\tUse linker config file\n"
+ "\t-Ln name\tCreate a VICE label file\n"
+ "\t-Lp\t\tMark write protected segments as such (VICE)\n"
+ "\t-S addr\t\tSet the default start address\n"
+ "\t-V\t\tPrint linker version\n",
+ ProgName);
+ exit (EXIT_FAILURE);
+}
+
+
+
+static void UnknownOption (const char* Arg)
+/* Print an error about an unknown option. Print usage information and exit */
+{
+ fprintf (stderr, "Unknown option: %s\n", Arg);
+ Usage ();
+}
+
+
+
+static void InvNumber (const char* Arg)
+/* Print an error about an unknown option. Print usage information and exit */
+{
+ fprintf (stderr, "Invalid number given in argument: %s\n", Arg);
+ Usage ();
+}
+
+
+
+static unsigned long CvtNumber (const char* Arg, const char* Number)
+/* Convert a number from a string. Allow '$' and '0x' prefixes for hex
+ * numbers.
+ */
+{
+ unsigned long Val;
+
+ /* Convert */
+ if (*Number == '$') {
+ ++Number;
+ if (sscanf (Number, "%lx", &Val) != 1) {
+ InvNumber (Arg);
+ }
+ } else {
+ if (sscanf (Number, "%li", (long*)&Val) != 1) {
+ InvNumber (Arg);
+ }
+ }
+
+ /* Return the result */
+ return Val;
+}
+
+
+
+static const char* GetArg (int* ArgNum, char* argv [], unsigned Len)
+/* Get an option argument */
+{
+ const char* Arg = argv [*ArgNum];
+ if (Arg [Len] != '\0') {
+ /* Argument appended */
+ return Arg + Len;
+ } else {
+ /* Separate argument */
+ Arg = argv [*ArgNum + 1];
+ if (Arg == 0) {
+ /* End of arguments */
+ fprintf (stderr, "Option requires an argument: %s\n", argv [*ArgNum]);
+ exit (EXIT_FAILURE);
+ }
+ ++(*ArgNum);
+ return Arg;
+ }
+}
+
+
+
+static void LongOption (int* Arg, char* argv [])
+/* Handle a long command line option */
+{
+ /* For now ... */
+ UnknownOption (argv [*Arg]);
+}
+
+
+
+static int HasPath (const char* Name)
+/* Check if the given Name has a path component */
+{
+ return strchr (Name, '/') != 0 || strchr (Name, '\\') != 0;
+}
+
+
+
+static void LinkFile (const char* Name)
+/* Handle one file */
+{
+ unsigned long Magic;
+ unsigned Len;
+ char* NewName = 0;
+
+ /* Try to open the file */
+ FILE* F = fopen (Name, "rb");
+ if (F == 0) {
+ /* We couldn't open the file. If the name doesn't have a path, and we
+ * have a search path given, try the name with the search path
+ * prepended.
+ */
+ if (LibPathLen > 0 && !HasPath (Name)) {
+ /* Allocate memory. Account for the trailing zero, and for a
+ * path separator character eventually needed.
+ */
+ Len = LibPathLen;
+ NewName = Xmalloc (strlen (Name) + Len + 2);
+ /* Build the new name */
+ memcpy (NewName, LibPath, Len);
+ if (NewName [Len-1] != '/' && NewName [Len-1] != '\\') {
+ /* We need an additional path separator */
+ NewName [Len++] = '/';
+ }
+ strcpy (NewName + Len, Name);
+
+ /* Now try to open the new file */
+ F = fopen (NewName, "rb");
+ }
+
+ if (F == 0) {
+ Error ("Cannot open `%s': %s", Name, strerror (errno));
+ }
+ }
+
+ /* Read the magic word */
+ Magic = Read32 (F);
+
+ /* Do we know this type of file? */
+ switch (Magic) {
+
+ case OBJ_MAGIC:
+ ObjAdd (F, Name);
+ ++ObjFiles;
+ break;
+
+ case LIB_MAGIC:
+ LibAdd (F, Name);
+ ++LibFiles;
+ break;
+
+ default:
+ fclose (F);
+ Error ("File `%s' has unknown type", Name);
+
+ }
+
+ /* If we have allocated memory, free it here. Note: Memory will not always
+ * be freed if we run into an error, but that's no problem. Adding more
+ * code to work around it will use more memory than the chunk that's lost.
+ */
+ Xfree (NewName);
+}
+
+
+
+int main (int argc, char* argv [])
+/* Assembler main program */
+{
+ int I;
+
+ /* Evaluate the CC65_LIB environment variable */
+ LibPath = getenv ("CC65_LIB");
+ if (LibPath == 0) {
+ /* Use some default path */
+#ifdef CC65_LIB
+ LibPath = CC65_LIB;
+#else
+ LibPath = "/usr/lib/cc65/lib/";
+#endif
+ }
+ LibPathLen = strlen (LibPath);
+
+ /* Check the parameters */
+ I = 1;
+ while (I < argc) {
+
+ /* Get the argument */
+ const char* Arg = argv [I];
+
+ /* Check for an option */
+ if (Arg [0] == '-') {
+
+ /* An option */
+ switch (Arg [1]) {
+
+ case '-':
+ LongOption (&I, argv);
+ break;
+
+ case 'm':
+ MapFileName = GetArg (&I, argv, 2);
+ break;
+
+ case 'o':
+ OutputName = GetArg (&I, argv, 2);
+ break;
+
+ case 't':
+ if (CfgAvail ()) {
+ Error ("Cannot use -C/-t twice");
+ }
+ TgtSet (GetArg (&I, argv, 2));
+ break;
+
+ case 'v':
+ switch (Arg [2]) {
+ case 'm': VerboseMap = 1; break;
+ case '\0': ++Verbose; break;
+ default: UnknownOption (Arg);
+ }
+ break;
+
+ case 'C':
+ if (CfgAvail ()) {
+ Error ("Cannot use -C/-t twice");
+ }
+ CfgSetName (GetArg (&I, argv, 2));
+ break;
+
+ case 'L':
+ switch (Arg [2]) {
+ case 'n': LabelFileName = GetArg (&I, argv, 3); break;
+ case 'p': WProtSegs = 1; break;
+ default: UnknownOption (Arg);
+ }
+ break;
+
+ case 'S':
+ StartAddr = CvtNumber (Arg, GetArg (&I, argv, 2));
+ break;
+
+ case 'V':
+ fprintf (stderr,
+ "ld65 V%u.%u.%u - (C) Copyright 1998-2000 Ullrich von Bassewitz\n",
+ VER_MAJOR, VER_MINOR, VER_PATCH);
+ break;
+
+ default:
+ UnknownOption (Arg);
+ break;
+ }
+
+ } else {
+
+ /* A filename */
+ LinkFile (Arg);
+
+ }
+
+ /* Next argument */
+ ++I;
+ }
+
+ /* Check if we had any object files */
+ if (ObjFiles == 0) {
+ fprintf (stderr, "No object files to link\n");
+ Usage ();
+ }
+
+ /* Check if we have a valid configuration */
+ if (!CfgAvail ()) {
+ fprintf (stderr, "Memory configuration missing\n");
+ Usage ();
+ }
+
+ /* Read the config file */
+ CfgRead ();
+
+ /* Assign start addresses for the segments, define linker symbols */
+ CfgAssignSegments ();
+
+ /* Create the output file */
+ CfgWriteTarget ();
+
+ /* Check for segments not written to the output file */
+ CheckSegments ();
+
+ /* If requested, create a map file and a label file for VICE */
+ if (MapFileName) {
+ CreateMapFile ();
+ }
+ if (LabelFileName) {
+ CreateLabelFile ();
+ }
+
+ /* Dump the data for debugging */
+ if (Verbose > 1) {
+ SegDump ();
+ }
+
+ /* Return an apropriate exit code */
+ return EXIT_SUCCESS;
+}
+
+
+
--- /dev/null
+#
+# gcc Makefile for ld65
+#
+
+# Default for the compiler lib search path as compiler define
+CDEFS=-DCC65_LIB=\"/usr/lib/cc65/lib/\"
+CFLAGS = -g -O2 -Wall $(CDEFS)
+CC=gcc
+LDFLAGS=
+
+OBJS = bin.o \
+ binfmt.o \
+ config.o \
+ dbgsyms.o \
+ error.o \
+ exports.o \
+ expr.o \
+ extsyms.o \
+ fileio.o \
+ global.o \
+ library.o \
+ main.o \
+ mapfile.o \
+ mem.o \
+ o65.o \
+ objdata.o \
+ objfile.o \
+ scanner.o \
+ segments.o \
+ target.o
+
+LIBS = ../common/common.a
+
+
+EXECS = ld65
+
+.PHONY: all
+ifeq (.depend,$(wildcard .depend))
+all : $(EXECS)
+include .depend
+else
+all: depend
+ @$(MAKE) -f make/gcc.mak all
+endif
+
+
+
+ld65: $(OBJS) $(LIBS)
+ $(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS)
+
+clean:
+ rm -f *~ core *.map
+
+zap: clean
+ rm -f *.o $(EXECS) .depend
+
+
+# ------------------------------------------------------------------------------
+# Make the dependencies
+
+.PHONY: depend dep
+depend dep: $(OBJS:.o=.c)
+ @echo "Creating dependency information"
+ $(CC) -MM $^ > .depend
+
+
--- /dev/null
+#
+# ld65 Makefile for the Watcom compiler
+#
+
+# ------------------------------------------------------------------------------
+# Generic stuff
+
+.AUTODEPEND
+.SUFFIXES .ASM .C .CC .CPP
+.SWAP
+
+AR = WLIB
+LD = WLINK
+
+!if !$d(TARGET)
+!if $d(__OS2__)
+TARGET = OS2
+!else
+TARGET = NT
+!endif
+!endif
+
+# target specific macros.
+!if $(TARGET)==OS2
+
+# --------------------- OS2 ---------------------
+SYSTEM = os2v2
+CC = WCC386
+CCCFG = -bt=$(TARGET) -d1 -onatx -zp4 -5 -zq -w2
+
+!elif $(TARGET)==DOS32
+
+# -------------------- DOS4G --------------------
+SYSTEM = dos4g
+CC = WCC386
+CCCFG = -bt=$(TARGET) -d1 -onatx -zp4 -5 -zq -w2
+
+!elif $(TARGET)==DOS
+
+# --------------------- DOS ---------------------
+SYSTEM = dos
+CC = WCC
+CCCFG = -bt=$(TARGET) -d1 -onatx -zp2 -2 -ml -zq -w2
+
+!elif $(TARGET)==NT
+
+# --------------------- NT ----------------------
+SYSTEM = nt
+CC = WCC386
+CCCFG = -bt=$(TARGET) -d1 -onatx -zp4 -5 -zq -w2
+
+!else
+!error
+!endif
+
+# ------------------------------------------------------------------------------
+# Implicit rules
+
+.c.obj:
+ $(CC) $(CCCFG) $<
+
+
+# ------------------------------------------------------------------------------
+# All OBJ files
+
+OBJS = bin.obj \
+ binfmt.obj \
+ config.obj \
+ dbgsyms.obj \
+ error.obj \
+ exports.obj \
+ expr.obj \
+ extsyms.obj \
+ fileio.obj \
+ global.obj \
+ library.obj \
+ main.obj \
+ mapfile.obj \
+ mem.obj \
+ o65.obj \
+ objdata.obj \
+ objfile.obj \
+ scanner.obj \
+ segments.obj \
+ target.obj
+
+LIBS = ..\common\common.lib
+
+
+# ------------------------------------------------------------------------------
+# Main targets
+
+all: ld65
+
+ld65: ld65.exe
+
+
+# ------------------------------------------------------------------------------
+# Other targets
+
+
+ld65.exe: $(OBJS) $(LIBS)
+ $(LD) system $(SYSTEM) @&&|
+DEBUG ALL
+OPTION QUIET
+NAME $<
+FILE bin.obj
+FILE binfmt.obj
+FILE config.obj
+FILE dbgsyms.obj
+FILE error.obj
+FILE exports.obj
+FILE expr.obj
+FILE extsyms.obj
+FILE fileio.obj
+FILE global.obj
+FILE library.obj
+FILE main.obj
+FILE mapfile.obj
+FILE mem.obj
+FILE o65.obj
+FILE objdata.obj
+FILE objfile.obj
+FILE scanner.obj
+FILE segments.obj
+FILE target.obj
+LIBRARY ..\common\common.lib
+|
+
+clean:
+ @if exist *.obj del *.obj
+ @if exist *.obj del ld65.exe
+
+strip:
+ @-wstrip ld65.exe
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* mapfile.c */
+/* */
+/* Map file creation for the ld65 linker */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "global.h"
+#include "error.h"
+#include "objdata.h"
+#include "segments.h"
+#include "dbgsyms.h"
+#include "exports.h"
+#include "config.h"
+#include "mapfile.h"
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void CreateMapFile (void)
+/* Create a map file */
+{
+ ObjData* O;
+ unsigned I;
+
+ /* Open the map file */
+ FILE* F = fopen (MapFileName, "w");
+ if (F == 0) {
+ Error ("Cannot create map file `%s': %s", MapFileName, strerror (errno));
+ }
+
+ /* Write a modules list */
+ fprintf (F, "Modules list:\n"
+ "-------------\n");
+ O = ObjRoot;
+ while (O) {
+ if (O->Flags & OBJ_HAVEDATA) {
+ /* We've linked this module */
+ if (O->LibName) {
+ /* The file is from a library */
+ fprintf (F, "%s(%s):\n", O->LibName, O->Name);
+ } else {
+ fprintf (F, "%s:\n", O->Name);
+ }
+ for (I = 0; I < O->SectionCount; ++I) {
+ const Section* S = O->Sections [I];
+ /* Don't include zero sized sections if not explicitly
+ * requested
+ */
+ if (VerboseMap || S->Size > 0) {
+ fprintf (F, " %-15s Offs = %06lX Size = %06lX\n",
+ S->Seg->Name, S->Offs, S->Size);
+ }
+ }
+ }
+ O = O->Next;
+ }
+
+ /* Write the segment list */
+ fprintf (F, "\n\n"
+ "Segment list:\n"
+ "-------------\n");
+ PrintSegmentMap (F);
+
+ /* Write the exports list */
+ fprintf (F, "\n\n"
+ "Exports list:\n"
+ "-------------\n");
+ PrintExportMap (F);
+
+ /* Write the imports list */
+ fprintf (F, "\n\n"
+ "Imports list:\n"
+ "-------------\n");
+ PrintImportMap (F);
+
+ /* Close the file */
+ if (fclose (F) != 0) {
+ Error ("Error closing map file `%s': %s", MapFileName, strerror (errno));
+ }
+}
+
+
+
+void CreateLabelFile (void)
+/* Create a label file */
+{
+ ObjData* O;
+
+ /* Open the map file */
+ FILE* F = fopen (LabelFileName, "w");
+ if (F == 0) {
+ Error ("Cannot create label file `%s': %s", LabelFileName, strerror (errno));
+ }
+
+ /* Print the labels for the export symbols */
+ PrintExportLabels (F);
+
+ /* Print debug symbols from all modules we have linked into the output file */
+ O = ObjRoot;
+ while (O) {
+ if (O->Flags & OBJ_HAVEDATA) {
+ /* We've linked this module */
+ PrintDbgSymLabels (O, F);
+
+ }
+ O = O->Next;
+ }
+
+ /* If we should mark write protected areas as such, do it */
+ if (WProtSegs) {
+ SegDesc* S = SegDescList;
+ while (S) {
+ /* Is this segment write protected and contains data? */
+ if (S->Flags & SF_WPROT && S->Seg->Size > 0) {
+ /* Write protect the memory area in VICE */
+ fprintf (F, "wp %04lX %04lX\n",
+ S->Seg->PC,
+ S->Seg->PC + S->Seg->Size - 1);
+ }
+ /* Next segment */
+ S = S->Next;
+ }
+ }
+
+ /* Close the file */
+ if (fclose (F) != 0) {
+ Error ("Error closing map file `%s': %s", LabelFileName, strerror (errno));
+ }
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* mapfile.h */
+/* */
+/* Map file creation for the ld65 linker */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef MAPFILE_H
+#define MAPFILE_H
+
+
+
+#include <stdio.h>
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void CreateMapFile (void);
+/* Create a map file */
+
+void CreateLabelFile (void);
+/* Create a label file */
+
+
+
+/* End of mapfile.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* mem.c */
+/* */
+/* Memory allocation for the ld65 linker */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "error.h"
+#include "mem.h"
+
+
+
+/*****************************************************************************/
+/* code */
+/*****************************************************************************/
+
+
+
+void* Xmalloc (size_t size)
+/* Allocate memory, check for out of memory condition. Do some debugging */
+{
+ void* p;
+
+ p = malloc (size);
+ if (p == 0 && size != 0) {
+ Error ("Out of memory");
+ }
+
+ /* Return a pointer to the block */
+ return p;
+}
+
+
+
+void Xfree (const void* block)
+/* Free the block, do some debugging */
+{
+ free ((void*) block);
+}
+
+
+
+char* StrDup (const char* s)
+/* Duplicate a string on the heap. The function checks for out of memory */
+{
+ unsigned len;
+
+ len = strlen (s) + 1;
+ return memcpy (Xmalloc (len), s, len);
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* mem.h */
+/* */
+/* Memory allocation for the ld65 linker */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef MEM_H
+#define MEM_H
+
+
+
+#include <stddef.h>
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void* Xmalloc (size_t size);
+/* Allocate memory, check for out of memory condition. Do some debugging */
+
+void Xfree (const void* block);
+/* Free the block, do some debugging */
+
+char* StrDup (const char* s);
+/* Duplicate a string on the heap. The function checks for out of memory */
+
+
+
+/* End of mem.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* o65.c */
+/* */
+/* Module to handle the o65 binary format */
+/* */
+/* */
+/* */
+/* (C) 1999 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+
+#include "../common/version.h"
+
+#include "global.h"
+#include "error.h"
+#include "mem.h"
+#include "fileio.h"
+#include "exports.h"
+#include "expr.h"
+#include "o65.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Header mode bits */
+#define MF_SIZE_32BIT 0x2000 /* All size words are 32bit */
+#define MF_CPU_816 0x8000 /* Executable is for 65816 */
+
+/* The four o65 segment types. Note: These values are identical to the values
+ * needed for the segmentID in the o65 spec.
+ */
+#define O65SEG_UNDEF 0x00
+#define O65SEG_ABS 0x01
+#define O65SEG_TEXT 0x02
+#define O65SEG_DATA 0x03
+#define O65SEG_BSS 0x04
+#define O65SEG_ZP 0x05
+
+/* Relocation type codes for the o65 format */
+#define O65RELOC_WORD 0x80
+#define O65RELOC_HIGH 0x40
+#define O65RELOC_LOW 0x20
+#define O65RELOC_SEGADR 0xc0
+#define O65RELOC_SEG 0xa0
+
+/* O65 executable file header */
+typedef struct O65Header_ O65Header;
+struct O65Header_ {
+ unsigned Version; /* Version number for o65 format */
+ unsigned Mode; /* Mode word */
+ unsigned long TextBase; /* Base address of text segment */
+ unsigned long TextSize; /* Size of text segment */
+ unsigned long DataBase; /* Base of data segment */
+ unsigned long DataSize; /* Size of data segment */
+ unsigned long BssBase; /* Base of bss segment */
+ unsigned long BssSize; /* Size of bss segment */
+ unsigned long ZPBase; /* Base of zeropage segment */
+ unsigned long ZPSize; /* Size of zeropage segment */
+ unsigned long StackSize; /* Requested stack size */
+};
+
+/* An o65 option */
+typedef struct O65Option_ O65Option;
+struct O65Option_ {
+ O65Option* Next; /* Next in option list */
+ unsigned char Type; /* Type of option */
+ unsigned char Len; /* Data length */
+ unsigned char Data [1]; /* Data, dynamically allocated */
+};
+
+/* A o65 relocation table */
+#define RELOC_BLOCKSIZE 4096
+typedef struct O65RelocTab_ O65RelocTab;
+struct O65RelocTab_ {
+ unsigned Size; /* Size of the table */
+ unsigned Fill; /* Amount used */
+ unsigned char* Buf; /* Buffer, dynamically allocated */
+};
+
+/* Structure describing the format */
+struct O65Desc_ {
+ O65Header Header; /* File header */
+ O65Option* Options; /* List of file options */
+ ExtSymTab* Exports; /* Table with exported symbols */
+ ExtSymTab* Imports; /* Table with imported symbols */
+ unsigned Undef; /* Count of undefined symbols */
+ FILE* F; /* The file we're writing to */
+ char* Filename; /* Name of the output file */
+ O65RelocTab* TextReloc; /* Relocation table for text segment */
+ O65RelocTab* DataReloc; /* Relocation table for data segment */
+
+ unsigned TextCount; /* Number of segments assigned to .text */
+ SegDesc** TextSeg; /* Array of text segments */
+ unsigned DataCount; /* Number of segments assigned to .data */
+ SegDesc** DataSeg; /* Array of data segments */
+ unsigned BssCount; /* Number of segments assigned to .bss */
+ SegDesc** BssSeg; /* Array of bss segments */
+ unsigned ZPCount; /* Number of segments assigned to .zp */
+ SegDesc** ZPSeg; /* Array of zp segments */
+
+ /* Temporary data for writing segments */
+ unsigned long SegSize;
+ O65RelocTab* CurReloc;
+ long LastOffs;
+};
+
+/* Structure for parsing expression trees */
+typedef struct ExprDesc_ ExprDesc;
+struct ExprDesc_ {
+ O65Desc* D; /* File format descriptor */
+ long Val; /* The offset value */
+ int TooComplex; /* Expression too complex */
+ Section* SegRef; /* Section referenced if any */
+ ExtSym* ExtRef; /* External reference if any */
+};
+
+
+
+/*****************************************************************************/
+/* Helper functions */
+/*****************************************************************************/
+
+
+
+static void WriteSize (const O65Desc* D, unsigned long Val)
+/* Write a "size" word to the file */
+{
+ if (D->Header.Mode & MF_SIZE_32BIT) {
+ Write32 (D->F, Val);
+ } else {
+ Write16 (D->F, (unsigned) Val);
+ }
+}
+
+
+
+static unsigned O65SegType (const SegDesc* S)
+/* Map our own segment types into something o65 compatible */
+{
+ /* Check the segment type. Readonly segments are assign to the o65
+ * text segment, writeable segments that contain data are assigned
+ * to data, bss and zp segments are handled respectively.
+ * Beware: Zeropage segments have the SF_BSS flag set, so be sure
+ * to check SF_ZP first.
+ */
+ if (S->Flags & SF_RO) {
+ return O65SEG_TEXT;
+ } else if (S->Flags & SF_ZP) {
+ return O65SEG_ZP;
+ } else if (S->Flags & SF_BSS) {
+ return O65SEG_BSS;
+ } else {
+ return O65SEG_DATA;
+ }
+}
+
+
+
+/*****************************************************************************/
+/* Expression handling */
+/*****************************************************************************/
+
+
+
+static void O65ParseExpr (ExprNode* Expr, ExprDesc* D, int Sign)
+/* Extract and evaluate all constant factors in an subtree that has only
+ * additions and subtractions. If anything other than additions and
+ * subtractions are found, D->TooComplex is set to true.
+ */
+{
+ Export* E;
+
+ switch (Expr->Op) {
+
+ case EXPR_LITERAL:
+ if (Sign < 0) {
+ D->Val -= Expr->V.Val;
+ } else {
+ D->Val += Expr->V.Val;
+ }
+ break;
+
+ case EXPR_SYMBOL:
+ /* Get the referenced Export */
+ E = GetExprExport (Expr);
+ /* If this export has a mark set, we've already encountered it.
+ * This means that the export is used to define it's own value,
+ * which in turn means, that we have a circular reference.
+ */
+ if (ExportHasMark (E)) {
+ CircularRefError (E);
+ } else if (E->Expr == 0) {
+ /* Dummy export, must be an o65 imported symbol */
+ ExtSym* S = O65GetImport (D->D, E->Name);
+ CHECK (S != 0);
+ if (D->ExtRef) {
+ /* We cannot have more than one external reference in o65 */
+ D->TooComplex = 1;
+ } else {
+ /* Remember the external reference */
+ D->ExtRef = S;
+ }
+ } else {
+ MarkExport (E);
+ O65ParseExpr (E->Expr, D, Sign);
+ UnmarkExport (E);
+ }
+ break;
+
+ case EXPR_SEGMENT:
+ if (D->SegRef) {
+ /* We cannot handle more than one segment reference in o65 */
+ D->TooComplex = 1;
+ } else {
+ /* Remember the segment reference */
+ D->SegRef = GetExprSection (Expr);
+ }
+ break;
+
+ case EXPR_PLUS:
+ O65ParseExpr (Expr->Left, D, Sign);
+ O65ParseExpr (Expr->Right, D, Sign);
+ break;
+
+ case EXPR_MINUS:
+ O65ParseExpr (Expr->Left, D, Sign);
+ O65ParseExpr (Expr->Right, D, -Sign);
+ break;
+
+ default:
+ /* Expression contains illegal operators */
+ D->TooComplex = 1;
+ break;
+
+ }
+}
+
+
+
+/*****************************************************************************/
+/* Relocation tables */
+/*****************************************************************************/
+
+
+
+static O65RelocTab* NewO65RelocTab (void)
+/* Create a new relocation table */
+{
+ /* Allocate a new structure */
+ O65RelocTab* R = Xmalloc (sizeof (O65RelocTab));
+
+ /* Initialize the data */
+ R->Size = RELOC_BLOCKSIZE;
+ R->Fill = 0;
+ R->Buf = Xmalloc (RELOC_BLOCKSIZE);
+
+ /* Return the created struct */
+ return R;
+}
+
+
+
+static void FreeO65RelocTab (O65RelocTab* R)
+/* Free a relocation table */
+{
+ Xfree (R->Buf);
+ Xfree (R);
+}
+
+
+
+static void O65RelocPutByte (O65RelocTab* R, unsigned char B)
+/* Put the byte into the relocation table */
+{
+ /* Do we have enough space in the buffer? */
+ if (R->Fill == R->Size) {
+ /* We need to grow the buffer */
+ unsigned char* NewBuf = Xmalloc (R->Size + RELOC_BLOCKSIZE);
+ memcpy (NewBuf, R->Buf, R->Size);
+ Xfree (R->Buf);
+ R->Buf = NewBuf;
+ }
+
+ /* Put the byte into the buffer */
+ R->Buf [R->Fill++] = B;
+}
+
+
+
+static void O65RelocPutWord (O65RelocTab* R, unsigned W)
+/* Put a word into the relocation table */
+{
+ O65RelocPutByte (R, W);
+ O65RelocPutByte (R, W >> 8);
+}
+
+
+
+static void O65WriteReloc (O65RelocTab* R, FILE* F)
+/* Write the relocation table to the given file */
+{
+ WriteData (F, R->Buf, R->Fill);
+}
+
+
+
+/*****************************************************************************/
+/* Option handling */
+/*****************************************************************************/
+
+
+
+static O65Option* NewO65Option (unsigned Type, const void* Data, unsigned DataLen)
+/* Allocate and initialize a new option struct */
+{
+ O65Option* O;
+
+ /* Check the length */
+ CHECK (DataLen <= 253);
+
+ /* Allocate memory */
+ O = Xmalloc (sizeof (O65Option) - 1 + DataLen);
+
+ /* Initialize the structure */
+ O->Next = 0;
+ O->Type = Type;
+ O->Len = DataLen;
+ memcpy (O->Data, Data, DataLen);
+
+ /* Return the created struct */
+ return O;
+}
+
+
+
+static void FreeO65Option (O65Option* O)
+/* Free an O65Option struct */
+{
+ Xfree (O);
+}
+
+
+
+/*****************************************************************************/
+/* Subroutines to write o65 sections */
+/*****************************************************************************/
+
+
+
+static void O65WriteHeader (O65Desc* D)
+/* Write the header of the executable to the given file */
+{
+ static unsigned char Trailer [5] = {
+ 0x01, 0x00, 0x6F, 0x36, 0x35
+ };
+
+ O65Option* O;
+
+
+ /* Write the fixed header */
+ WriteData (D->F, Trailer, sizeof (Trailer));
+ Write8 (D->F, D->Header.Version);
+ Write16 (D->F, D->Header.Mode);
+ WriteSize (D, D->Header.TextBase);
+ WriteSize (D, D->Header.TextSize);
+ WriteSize (D, D->Header.DataBase);
+ WriteSize (D, D->Header.DataSize);
+ WriteSize (D, D->Header.BssBase);
+ WriteSize (D, D->Header.BssSize);
+ WriteSize (D, D->Header.ZPBase);
+ WriteSize (D, D->Header.ZPSize);
+ WriteSize (D, D->Header.StackSize);
+
+ /* Write the options */
+ O = D->Options;
+ while (O) {
+ Write8 (D->F, O->Len + 2); /* Account for len and type bytes */
+ Write8 (D->F, O->Type);
+ if (O->Len) {
+ WriteData (D->F, O->Data, O->Len);
+ }
+ O = O->Next;
+ }
+
+ /* Write the end-of-options byte */
+ Write8 (D->F, 0);
+}
+
+
+
+static unsigned O65WriteExpr (ExprNode* E, int Signed, unsigned Size,
+ unsigned long Offs, void* Data)
+/* Called from SegWrite for an expression. Evaluate the expression, check the
+ * range and write the expression value to the file, update the relocation
+ * table.
+ */
+{
+ long Diff;
+ long BinVal;
+ ExprNode* Expr;
+ ExprDesc ED;
+ unsigned char RelocType;
+
+ /* Cast the Data pointer to its real type, an O65Desc */
+ O65Desc* D = (O65Desc*) Data;
+
+ /* Check for a constant expression */
+ if (IsConstExpr (E)) {
+ /* Write out the constant expression */
+ return SegWriteConstExpr (((O65Desc*)Data)->F, E, Signed, Size);
+ }
+
+ /* We have a relocatable expression that needs a relocation table entry.
+ * Calculate the number of bytes between this entry and the last one, and
+ * setup all necessary intermediate bytes in the relocation table.
+ */
+ Offs += D->SegSize; /* Calulate full offset */
+ Diff = ((long) Offs) - D->LastOffs;
+ while (Diff > 0xFE) {
+ O65RelocPutByte (D->CurReloc, 0xFF);
+ Diff -= 0xFE;
+ }
+ O65RelocPutByte (D->CurReloc, Diff);
+
+ /* Remember this offset for the next time */
+ D->LastOffs = Offs;
+
+ /* Determine the expression to relocate */
+ Expr = E;
+ if (E->Op == EXPR_LOBYTE || E->Op == EXPR_HIBYTE) {
+ /* Use the real expression */
+ Expr = E->Left;
+ }
+
+ /* Initialize the descriptor for expression parsing */
+ ED.D = D;
+ ED.Val = 0;
+ ED.TooComplex = 0;
+ ED.SegRef = 0;
+ ED.ExtRef = 0;
+
+ /* Recursively collect information about this expression */
+ O65ParseExpr (Expr, &ED, 1);
+
+ /* We cannot handle both, an imported symbol and a segment ref */
+ if (ED.SegRef != 0 && ED.ExtRef != 0) {
+ ED.TooComplex = 1;
+ }
+
+ /* Bail out if we cannot handle the expression */
+ if (ED.TooComplex) {
+ return SEG_EXPR_TOO_COMPLEX;
+ }
+
+ /* Safety: Check that we are really referencing a symbol or a segment */
+ CHECK (ED.SegRef != 0 || ED.ExtRef != 0);
+
+ /* Write out the offset that goes into the segment. */
+ BinVal = ED.Val;
+ if (E->Op == EXPR_LOBYTE) {
+ BinVal &= 0x00FF;
+ } else if (E->Op == EXPR_HIBYTE) {
+ BinVal = (BinVal >> 8) & 0x00FF;
+ }
+ WriteVal (D->F, BinVal, Size);
+
+ /* Determine the actual type of relocation entry needed from the
+ * information gathered about the expression.
+ */
+ if (E->Op == EXPR_LOBYTE) {
+ RelocType = O65RELOC_LOW;
+ } else if (E->Op == EXPR_HIBYTE) {
+ RelocType = O65RELOC_HIGH;
+ } else {
+ switch (Size) {
+
+ case 1:
+ RelocType = O65RELOC_LOW;
+ break;
+
+ case 2:
+ RelocType = O65RELOC_WORD;
+ break;
+
+ case 3:
+ RelocType = O65RELOC_SEGADR;
+ break;
+
+ case 4:
+ /* 4 byte expression not supported by o65 */
+ return SEG_EXPR_TOO_COMPLEX;
+
+ default:
+ Internal ("O65WriteExpr: Invalid expression size: %u", Size);
+ RelocType = 0; /* Avoid gcc warnings */
+ }
+ }
+
+ /* Determine which segment we're referencing */
+ if (ED.ExtRef) {
+ /* Imported symbol */
+ RelocType |= O65SEG_UNDEF;
+ O65RelocPutByte (D->CurReloc, RelocType);
+ /* Put the number of the imported symbol into the table */
+ O65RelocPutWord (D->CurReloc, ExtSymNum (ED.ExtRef));
+ } else {
+ /* Segment reference */
+
+
+
+ }
+
+ /* Success */
+ return SEG_EXPR_OK;
+}
+
+
+
+static void O65WriteSeg (O65Desc* D, SegDesc** Seg, unsigned Count, int DoWrite)
+/* Write one segment to the o65 output file */
+{
+ SegDesc* S;
+ unsigned I;
+
+ /* Initialize variables */
+ D->SegSize = 0;
+ D->LastOffs = -1;
+
+ /* Write out all segments */
+ for (I = 0; I < Count; ++I) {
+
+ /* Get the segment from the list node */
+ S = Seg [I];
+
+ /* Keep the user happy */
+ if (Verbose) {
+ printf (" Writing `%s'\n", S->Name);
+ }
+
+ /* Write this segment */
+ if (DoWrite) {
+ SegWrite (D->F, S->Seg, O65WriteExpr, D);
+ }
+
+ /* Mark the segment as dumped */
+ S->Seg->Dumped = 1;
+
+ /* Calculate the total size */
+ D->SegSize += S->Seg->Size;
+ }
+
+ /* Terminate the relocation table for the this segment */
+ if (D->CurReloc) {
+ O65RelocPutByte (D->CurReloc, 0);
+ }
+
+ /* Check the size of the segment for overflow */
+ if ((D->Header.Mode & MF_SIZE_32BIT) == 0 && D->SegSize > 0xFFFF) {
+ Error ("Segment overflow in file `%s'", D->Filename);
+ }
+
+}
+
+
+
+static void O65WriteTextSeg (O65Desc* D, Memory* M)
+/* Write the code segment to the o65 output file */
+{
+ /* Initialize variables */
+ D->CurReloc = D->TextReloc;
+
+ /* Dump all text segments */
+ O65WriteSeg (D, D->TextSeg, D->TextCount, 1);
+
+ /* Set the size of the segment */
+ D->Header.TextSize = D->SegSize;
+}
+
+
+
+static void O65WriteDataSeg (O65Desc* D, Memory* M)
+/* Write the data segment to the o65 output file */
+{
+ /* Initialize variables */
+ D->CurReloc = D->DataReloc;
+
+ /* Dump all data segments */
+ O65WriteSeg (D, D->DataSeg, D->DataCount, 1);
+
+ /* Set the size of the segment */
+ D->Header.DataSize = D->SegSize;
+}
+
+
+
+static void O65WriteBssSeg (O65Desc* D, Memory* M)
+/* "Write" the bss segments to the o65 output file. This will only update
+ * the relevant header fields.
+ */
+{
+ /* Initialize variables */
+ D->CurReloc = 0;
+
+ /* Dump all data segments */
+ O65WriteSeg (D, D->BssSeg, D->BssCount, 0);
+
+ /* Set the size of the segment */
+ D->Header.BssSize = D->SegSize;
+}
+
+
+
+static void O65WriteZPSeg (O65Desc* D, Memory* M)
+/* "Write" the zeropage segments to the o65 output file. This will only update
+ * the relevant header fields.
+ */
+{
+ /* Initialize variables */
+ D->CurReloc = 0;
+
+ /* Dump all data segments */
+ O65WriteSeg (D, D->ZPSeg, D->ZPCount, 0);
+
+ /* Set the size of the segment */
+ D->Header.ZPSize = D->SegSize;
+}
+
+
+
+static void O65WriteImports (O65Desc* D)
+/* Write the list of imported symbols to the O65 file */
+{
+ const ExtSym* E;
+
+ /* Write the number of external symbols */
+ WriteSize (D, ExtSymCount (D->Imports));
+
+ /* Write out the symbol names, zero terminated */
+ E = ExtSymList (D->Imports);
+ while (E) {
+ /* Get the name */
+ const char* Name = ExtSymName (E);
+ /* And write it to the output file */
+ WriteData (D->F, Name, strlen (Name) + 1);
+ /* Next symbol */
+ E = ExtSymNext (E);
+ }
+}
+
+
+
+static void O65WriteTextReloc (O65Desc* D)
+/* Write the relocation for the text segment to the output file */
+{
+ O65WriteReloc (D->TextReloc, D->F);
+}
+
+
+
+static void O65WriteDataReloc (O65Desc* D)
+/* Write the relocation for the data segment to the output file */
+{
+ O65WriteReloc (D->DataReloc, D->F);
+}
+
+
+
+static void O65WriteExports (O65Desc* D)
+/* Write the list of exports */
+{
+ /* For now... */
+ WriteSize (D, 0);
+}
+
+
+
+/*****************************************************************************/
+/* Public code */
+/*****************************************************************************/
+
+
+
+O65Desc* NewO65Desc (void)
+/* Create, initialize and return a new O65 descriptor struct */
+{
+ /* Allocate a new structure */
+ O65Desc* D = Xmalloc (sizeof (O65Desc));
+
+ /* Initialize the header */
+ D->Header.Version = 0;
+ D->Header.Mode = 0;
+ D->Header.TextBase = 0;
+ D->Header.TextSize = 0;
+ D->Header.DataBase = 0;
+ D->Header.DataSize = 0;
+ D->Header.BssBase = 0;
+ D->Header.BssSize = 0;
+ D->Header.ZPBase = 0;
+ D->Header.ZPSize = 0;
+ D->Header.StackSize = 0; /* Let OS choose a good value */
+
+ /* Initialize other data */
+ D->Options = 0;
+ D->Exports = NewExtSymTab ();
+ D->Imports = NewExtSymTab ();
+ D->Undef = 0;
+ D->F = 0;
+ D->Filename = 0;
+ D->TextReloc = NewO65RelocTab ();
+ D->DataReloc = NewO65RelocTab ();
+ D->TextCount = 0;
+ D->TextSeg = 0;
+ D->DataCount = 0;
+ D->DataSeg = 0;
+ D->BssCount = 0;
+ D->BssSeg = 0;
+ D->ZPCount = 0;
+ D->ZPSeg = 0;
+
+ /* Return the created struct */
+ return D;
+}
+
+
+
+void FreeO65Desc (O65Desc* D)
+/* Delete the descriptor struct with cleanup */
+{
+ /* Free the segment arrays */
+ Xfree (D->ZPSeg);
+ Xfree (D->BssSeg);
+ Xfree (D->DataSeg);
+ Xfree (D->TextSeg);
+
+ /* Free the relocation tables */
+ FreeO65RelocTab (D->DataReloc);
+ FreeO65RelocTab (D->TextReloc);
+
+ /* Free the option list */
+ while (D->Options) {
+ O65Option* O = D->Options;
+ D->Options = D->Options->Next;
+ FreeO65Option (O);
+ }
+
+ /* Free the external symbol tables */
+ FreeExtSymTab (D->Exports);
+ FreeExtSymTab (D->Imports);
+
+ /* Free the struct itself */
+ Xfree (D);
+}
+
+
+
+void O65Set816 (O65Desc* D)
+/* Enable 816 mode */
+{
+ D->Header.Mode |= MF_CPU_816;
+}
+
+
+
+void O65SetLargeModel (O65Desc* D)
+/* Enable a large memory model executable */
+{
+ D->Header.Mode |= MF_SIZE_32BIT;
+}
+
+
+
+void O65SetAlignment (O65Desc* D, unsigned Align)
+/* Set the executable alignment */
+{
+ /* Remove all alignment bits from the mode word */
+ D->Header.Mode &= ~0x0003;
+
+ /* Set the alignment bits */
+ switch (Align) {
+ case 1: break;
+ case 2: D->Header.Mode |= 0x01; break;
+ case 4: D->Header.Mode |= 0x02; break;
+ case 256: D->Header.Mode |= 0x03; break;
+ default: Error ("Invalid alignment for O65 format: %u", Align);
+ }
+}
+
+
+
+void O65SetOption (O65Desc* D, unsigned Type, const void* Data, unsigned DataLen)
+/* Set an o65 header option */
+{
+ /* Create a new option structure */
+ O65Option* O = NewO65Option (Type, Data, DataLen);
+
+ /* Insert it into the linked list */
+ O->Next = D->Options;
+ D->Options = O;
+}
+
+
+
+void O65SetOS (O65Desc* D, unsigned OS)
+/* Set an option describing the target operating system */
+{
+ static const unsigned char OSA65 [2] = { O65OS_OSA65, 0 };
+ static const unsigned char Lunix [2] = { O65OS_LUNIX, 0 };
+
+ /* Write the correct option */
+ switch (OS) {
+
+ case O65OS_OSA65:
+ O65SetOption (D, O65OPT_OS, OSA65, sizeof (OSA65));
+ break;
+
+ case O65OS_LUNIX:
+ O65SetOption (D, O65OPT_OS, Lunix, sizeof (Lunix));
+ break;
+
+ default:
+ Internal ("Trying to set invalid O65 operating system: %u", OS);
+
+ }
+}
+
+
+
+ExtSym* O65GetImport (O65Desc* D, const char* Ident)
+/* Return the imported symbol or NULL if not found */
+{
+ /* Retrieve the symbol from the table */
+ return GetExtSym (D->Imports, Ident);
+}
+
+
+
+void O65SetImport (O65Desc* D, const char* Ident)
+/* Set an imported identifier */
+{
+ /* Insert the entry into the table */
+ NewExtSym (D->Imports, Ident);
+}
+
+
+
+ExtSym* O65GetExport (O65Desc* D, const char* Ident)
+/* Return the exported symbol or NULL if not found */
+{
+ /* Retrieve the symbol from the table */
+ return GetExtSym (D->Exports, Ident);
+}
+
+
+
+void O65SetExport (O65Desc* D, const char* Ident)
+/* Set an exported identifier */
+{
+ /* Insert the entry into the table */
+ NewExtSym (D->Exports, Ident);
+}
+
+
+
+static void O65SetupSegments (O65Desc* D, Memory* M)
+/* Setup segment assignments */
+{
+ MemListNode* N;
+ SegDesc* S;
+ unsigned TextIdx, DataIdx, BssIdx, ZPIdx;
+
+ /* Initialize the counters */
+ D->TextCount = 0;
+ D->DataCount = 0;
+ D->BssCount = 0;
+ D->ZPCount = 0;
+
+ /* Walk through the memory list and count the segment types */
+ N = M->SegList;
+ while (N) {
+
+ /* Get the segment from the list node */
+ S = N->Seg;
+
+ /* Check the segment type. */
+ switch (O65SegType (S)) {
+ case O65SEG_TEXT: D->TextCount++; break;
+ case O65SEG_DATA: D->DataCount++; break;
+ case O65SEG_BSS: D->BssCount++; break;
+ case O65SEG_ZP: D->ZPCount++; break;
+ default: Internal ("Invalid return from O65SegType");
+ }
+
+ /* Next segment node */
+ N = N->Next;
+ }
+
+ /* Allocate memory according to the numbers */
+ D->TextSeg = Xmalloc (D->TextCount * sizeof (SegDesc*));
+ D->DataSeg = Xmalloc (D->DataCount * sizeof (SegDesc*));
+ D->BssSeg = Xmalloc (D->BssCount * sizeof (SegDesc*));
+ D->ZPSeg = Xmalloc (D->ZPCount * sizeof (SegDesc*));
+
+ /* Walk again through the list and setup the segment arrays */
+ TextIdx = DataIdx = BssIdx = ZPIdx = 0;
+ N = M->SegList;
+ while (N) {
+
+ /* Get the segment from the list node */
+ S = N->Seg;
+
+ /* Check the segment type. */
+ switch (O65SegType (S)) {
+ case O65SEG_TEXT: D->TextSeg [TextIdx++] = S; break;
+ case O65SEG_DATA: D->DataSeg [DataIdx++] = S; break;
+ case O65SEG_BSS: D->BssSeg [BssIdx++] = S; break;
+ case O65SEG_ZP: D->ZPSeg [ZPIdx++] = S; break;
+ default: Internal ("Invalid return from O65SegType");
+ }
+
+ /* Next segment node */
+ N = N->Next;
+ }
+}
+
+
+
+static int O65Unresolved (const char* Name, void* D)
+/* Called if an unresolved symbol is encountered */
+{
+ /* Check if the symbol is an imported o65 symbol */
+ if (O65GetImport (D, Name) != 0) {
+ /* This is an external symbol, relax... */
+ return 1;
+ } else {
+ /* This is actually an unresolved external. Bump the counter */
+ ((O65Desc*) D)->Undef++;
+ return 0;
+ }
+}
+
+
+
+void O65WriteTarget (O65Desc* D, File* F)
+/* Write an o65 output file */
+{
+ Memory* M;
+ char OptBuf [256]; /* Buffer for option strings */
+ time_t T;
+
+ /* Place the filename in the control structure */
+ D->Filename = F->Name;
+
+ /* The o65 format uses only one memory area per file. Check that. */
+ M = F->MemList;
+ if (M->Next != 0) {
+ Warning ("Cannot handle more than one memory area for o65 format");
+ }
+
+ /* Check for unresolved symbols. The function O65Unresolved is called
+ * if we get an unresolved symbol.
+ */
+ D->Undef = 0; /* Reset the counter */
+ CheckExports (O65Unresolved, D);
+ if (D->Undef > 0) {
+ /* We had unresolved symbols, cannot create output file */
+ Error ("%u unresolved external(s) found - cannot create output file", D->Undef);
+ }
+
+ /* Setup the segment arrays */
+ O65SetupSegments (D, M);
+
+ /* Open the file */
+ D->F = fopen (F->Name, "wb");
+ if (D->F == 0) {
+ Error ("Cannot open `%s': %s", F->Name, strerror (errno));
+ }
+
+ /* Keep the user happy */
+ if (Verbose) {
+ printf ("Opened `%s'...\n", F->Name);
+ }
+
+ /* Define some more options: A timestamp and the linker version */
+ T = time (0);
+ strcpy (OptBuf, ctime (&T));
+ O65SetOption (D, O65OPT_TIMESTAMP, OptBuf, strlen (OptBuf) + 1);
+ sprintf (OptBuf, "ld65 V%u.%u.%u", VER_MAJOR, VER_MINOR, VER_PATCH);
+ O65SetOption (D, O65OPT_ASM, OptBuf, strlen (OptBuf) + 1);
+
+ /* Write the header */
+ O65WriteHeader (D);
+
+ /* Write the text segment */
+ O65WriteTextSeg (D, M);
+
+ /* Write the data segment */
+ O65WriteDataSeg (D, M);
+
+ /* "Write" the bss segments */
+ O65WriteBssSeg (D, M);
+
+ /* "Write" the zeropage segments */
+ O65WriteZPSeg (D, M);
+
+ /* Write the undefined references list */
+ O65WriteImports (D);
+
+ /* Write the text segment relocation table */
+ O65WriteTextReloc (D);
+
+ /* Write the data segment relocation table */
+ O65WriteDataReloc (D);
+
+ /* Write the list of exports */
+ O65WriteExports (D);
+
+ /* Seek back to the start and write the updated header */
+ fseek (D->F, 0, SEEK_SET);
+ O65WriteHeader (D);
+
+ /* Close the file */
+ if (fclose (D->F) != 0) {
+ Error ("Cannot write to `%s': %s", F->Name, strerror (errno));
+ }
+
+ /* Reset the file and filename */
+ D->F = 0;
+ D->Filename = 0;
+}
+
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* o65.h */
+/* */
+/* Module to handle the o65 binary format */
+/* */
+/* */
+/* */
+/* (C) 1999 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef O65_H
+#define O65_H
+
+
+
+#include <stdio.h>
+
+#include "extsyms.h"
+#include "config.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Structure describing the format */
+typedef struct O65Desc_ O65Desc;
+
+/* Option tags */
+#define O65OPT_FILENAME 0
+#define O65OPT_OS 1
+#define O65OPT_ASM 2
+#define O65OPT_AUTHOR 3
+#define O65OPT_TIMESTAMP 4
+
+/* Operating system codes for O65OPT_OS */
+#define O65OS_OSA65 1
+#define O65OS_LUNIX 2
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+O65Desc* NewO65Desc (void);
+/* Create, initialize and return a new O65 descriptor struct */
+
+void FreeO65Desc (O65Desc* D);
+/* Delete the descriptor struct with cleanup */
+
+void O65Set816 (O65Desc* D);
+/* Enable 816 mode */
+
+void O65SetLargeModel (O65Desc* D);
+/* Enable a large memory model executable */
+
+void O65SetAlignment (O65Desc* D, unsigned Align);
+/* Set the executable alignment */
+
+void O65SetOption (O65Desc* D, unsigned Type, const void* Data, unsigned DataLen);
+/* Set an o65 header option */
+
+void O65SetOS (O65Desc* D, unsigned OS);
+/* Set an option describing the target operating system */
+
+ExtSym* O65GetImport (O65Desc* D, const char* Ident);
+/* Return the imported symbol or NULL if not found */
+
+void O65SetImport (O65Desc* D, const char* Ident);
+/* Set an imported identifier */
+
+ExtSym* O65GetExport (O65Desc* D, const char* Ident);
+/* Return the exported symbol or NULL if not found */
+
+void O65SetExport (O65Desc* D, const char* Ident);
+/* Set an exported identifier */
+
+void O65WriteTarget (O65Desc* D, File* F);
+/* Write an o65 output file */
+
+
+
+/* End of o65.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* objdata.c */
+/* */
+/* Handling object file data for the ld65 linker */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <string.h>
+
+#include "mem.h"
+#include "error.h"
+#include "objdata.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Object data list management */
+unsigned ObjCount = 0; /* Count of object files in the list */
+ObjData* ObjRoot = 0; /* List of object files */
+ObjData* ObjLast = 0; /* Last entry in list */
+ObjData** ObjPool = 0; /* Object files as array */
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+ObjData* NewObjData (void)
+/* Allocate a new structure on the heap, insert it into the list, return it */
+{
+ /* Allocate memory */
+ ObjData* O = Xmalloc (sizeof (ObjData));
+
+ /* Initialize the data */
+ O->Next = 0;
+ O->Name = 0;
+ O->LibName = 0;
+ O->Flags = 0;
+ O->Start = 0;
+ O->ExportCount = 0;
+ O->Exports = 0;
+ O->ImportCount = 0;
+ O->Imports = 0;
+ O->DbgSymCount = 0;
+ O->DbgSyms = 0;
+
+ /* Link it into the list */
+ if (ObjLast) {
+ ObjLast->Next = O;
+ ObjLast = O;
+ } else {
+ /* First entry */
+ ObjRoot = ObjLast = O;
+ }
+
+ /* One object file more now */
+ ++ObjCount;
+
+ /* Return the new entry */
+ return O;
+}
+
+
+
+void FreeObjData (ObjData* O)
+/* Free a complete struct */
+{
+ Xfree (O->Name);
+ Xfree (O->Imports);
+ Xfree (O->Exports);
+ Xfree (O->DbgSyms);
+ Xfree (O);
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* objdata.h */
+/* */
+/* Handling object file data for the ld65 linker */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef OBJDATA_H
+#define OBJDATA_H
+
+
+
+#include "../common/objdefs.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Values for the Flags field */
+#define OBJ_REF 0x0001 /* We have a reference to this file */
+#define OBJ_HAVEDATA 0x0002 /* We have this object file already */
+#define OBJ_MARKED 0x0004 /* Generic marker bit */
+
+
+/* Internal structure holding object file data */
+typedef struct ObjData_ ObjData;
+struct ObjData_ {
+ ObjData* Next; /* Linked list of all objects */
+ char* Name; /* Module name */
+ char* LibName; /* Name of library */
+ ObjHeader Header; /* Header of file */
+ unsigned long Start; /* Start offset of data in library */
+ unsigned Flags;
+ unsigned FileCount; /* Input file count */
+ char** Files; /* List of input files */
+ unsigned SectionCount; /* Count of sections in this object */
+ struct Section_** Sections; /* List of all sections */
+ unsigned ExportCount; /* Count of exports */
+ struct Export_** Exports; /* List of all exports */
+ unsigned ImportCount; /* Count of imports */
+ struct Import_** Imports; /* List of all imports */
+ unsigned DbgSymCount; /* Count of debug symbols */
+ struct DbgSym_** DbgSyms; /* List of debug symbols */
+};
+
+
+
+/* Object data list management */
+extern unsigned ObjCount; /* Count of files in the list */
+extern ObjData* ObjRoot; /* List of object files */
+extern ObjData* ObjLast; /* Last entry in list */
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+ObjData* NewObjData (void);
+/* Allocate a new structure on the heap, insert it into the list, return it */
+
+void FreeObjData (ObjData* O);
+/* Free a complete struct */
+
+
+
+/* End of objdata.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* objfile.c */
+/* */
+/* Object file handling for the ld65 linker */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/stat.h>
+
+#include "error.h"
+#include "mem.h"
+#include "objdata.h"
+#include "fileio.h"
+#include "segments.h"
+#include "exports.h"
+#include "dbgsyms.h"
+#include "objfile.h"
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+static const char* GetModule (const char* Name)
+/* Get a module name from the file name */
+{
+ /* Make a module name from the file name */
+ const char* Module = Name + strlen (Name);
+ while (Module > Name) {
+ --Module;
+ if (*Module == '/' || *Module == '\\') {
+ ++Module;
+ break;
+ }
+ }
+ if (*Module == 0) {
+ Error ("Cannot make module name from `%s'", Name);
+ }
+ return Module;
+}
+
+
+
+static void ObjReadHeader (FILE* Obj, ObjHeader* H, const char* Name)
+/* Read the header of the object file checking the signature */
+{
+ H->Version = Read16 (Obj);
+ if (H->Version != OBJ_VERSION) {
+ Error ("Object file `%s' has wrong version", Name);
+ }
+ H->Flags = Read16 (Obj);
+ H->OptionOffs = Read32 (Obj);
+ H->OptionSize = Read32 (Obj);
+ H->FileOffs = Read32 (Obj);
+ H->FileSize = Read32 (Obj);
+ H->SegOffs = Read32 (Obj);
+ H->SegSize = Read32 (Obj);
+ H->ImportOffs = Read32 (Obj);
+ H->ImportSize = Read32 (Obj);
+ H->ExportOffs = Read32 (Obj);
+ H->ExportSize = Read32 (Obj);
+ H->DbgSymOffs = Read32 (Obj);
+ H->DbgSymSize = Read32 (Obj);
+}
+
+
+
+void ObjReadFiles (FILE* F, ObjData* O)
+/* Read the files list from a file at the current position */
+{
+ unsigned I;
+
+ O->FileCount = Read8 (F);
+ O->Files = Xmalloc (O->FileCount * sizeof (char*));
+ for (I = 0; I < O->FileCount; ++I) {
+ /* Skip MTime and size */
+ Read32 (F);
+ Read32 (F);
+ /* Read the filename */
+ O->Files [I] = ReadMallocedStr (F);
+ }
+}
+
+
+
+void ObjReadImports (FILE* F, ObjData* O)
+/* Read the imports from a file at the current position */
+{
+ unsigned I;
+
+ O->ImportCount = Read16 (F);
+ O->Imports = Xmalloc (O->ImportCount * sizeof (Import*));
+ for (I = 0; I < O->ImportCount; ++I) {
+ O->Imports [I] = ReadImport (F, O);
+ InsertImport (O->Imports [I]);
+ }
+}
+
+
+
+void ObjReadExports (FILE* F, ObjData* O)
+/* Read the exports from a file at the current position */
+{
+ unsigned I;
+
+ O->ExportCount = Read16 (F);
+ O->Exports = Xmalloc (O->ExportCount * sizeof (Export*));
+ for (I = 0; I < O->ExportCount; ++I) {
+ O->Exports [I] = ReadExport (F, O);
+ InsertExport (O->Exports [I]);
+ }
+}
+
+
+
+void ObjReadDbgSyms (FILE* F, ObjData* O)
+/* Read the debug symbols from a file at the current position */
+{
+ unsigned I;
+
+ O->DbgSymCount = Read16 (F);
+ O->DbgSyms = Xmalloc (O->DbgSymCount * sizeof (DbgSym*));
+ for (I = 0; I < O->DbgSymCount; ++I) {
+ O->DbgSyms [I] = ReadDbgSym (F, O);
+ }
+}
+
+
+
+void ObjReadSections (FILE* F, ObjData* O)
+/* Read the section data from a file at the current position */
+{
+ unsigned I;
+
+ O->SectionCount = Read8 (F);
+ O->Sections = Xmalloc (O->SectionCount * sizeof (Section*));
+ for (I = 0; I < O->SectionCount; ++I) {
+ O->Sections [I] = ReadSection (F, O);
+ }
+}
+
+
+
+void ObjAdd (FILE* Obj, const char* Name)
+/* Add an object file to the module list */
+{
+ /* Create a new structure for the object file data */
+ ObjData* O = NewObjData ();
+
+ /* The magic was already read and checked, so set it in the header */
+ O->Header.Magic = OBJ_MAGIC;
+
+ /* Read and check the header */
+ ObjReadHeader (Obj, &O->Header, Name);
+
+ /* Initialize the object module data structure */
+ O->Name = StrDup (GetModule (Name));
+ O->Flags = OBJ_HAVEDATA;
+
+ /* Read the files list from the object file */
+ fseek (Obj, O->Header.FileOffs, SEEK_SET);
+ ObjReadFiles (Obj, O);
+
+ /* Read the imports list from the object file */
+ fseek (Obj, O->Header.ImportOffs, SEEK_SET);
+ ObjReadImports (Obj, O);
+
+ /* Read the object file exports and insert them into the exports list */
+ fseek (Obj, O->Header.ExportOffs, SEEK_SET);
+ ObjReadExports (Obj, O);
+
+ /* Read the object debug symbols from the object file */
+ fseek (Obj, O->Header.DbgSymOffs, SEEK_SET);
+ ObjReadDbgSyms (Obj, O);
+
+ /* Read the segment list from the object file. This must be last, since
+ * the expressions stored in the code may reference segments or imported
+ * symbols.
+ */
+ fseek (Obj, O->Header.SegOffs, SEEK_SET);
+ ObjReadSections (Obj, O);
+
+ /* Mark this object file as needed */
+ O->Flags |= OBJ_REF | OBJ_HAVEDATA;
+
+ /* Done, close the file (we read it only, so no error check) */
+ fclose (Obj);
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* objfile.h */
+/* */
+/* Object file handling for the ld65 linker */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef OBJFILE_H
+#define OBJFILE_H
+
+
+
+#include <stdio.h>
+
+#include "../common/objdefs.h"
+
+#include "objdata.h"
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void ObjReadFiles (FILE* F, ObjData* O);
+/* Read the files list from a file at the current position */
+
+void ObjReadImports (FILE* F, ObjData* O);
+/* Read the imports from a file at the current position */
+
+void ObjReadExports (FILE* F, ObjData* O);
+/* Read the exports from a file at the current position */
+
+void ObjReadDbgSyms (FILE* F, ObjData* O);
+/* Read the debug symbols from a file at the current position */
+
+void ObjReadSections (FILE* F, ObjData* O);
+/* Read the section data from a file at the current position */
+
+void ObjAdd (FILE* F, const char* Name);
+/* Add an object file to the module list */
+
+
+
+/* End of objfile.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* scanner.c */
+/* */
+/* Configuration file scanner for the ld65 linker */
+/* */
+/* */
+/* */
+/* (C) 1998-2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "global.h"
+#include "error.h"
+#include "scanner.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Current token and attributes */
+unsigned CfgTok;
+char CfgSVal [CFG_MAX_IDENT_LEN+1];
+unsigned long CfgIVal;
+
+/* Error location */
+unsigned CfgErrorLine;
+unsigned CfgErrorCol;
+
+/* Input sources for the configuration */
+static const char* CfgName = 0;
+static const char* CfgBuf = 0;
+
+/* Other input stuff */
+static int C = ' ';
+static unsigned InputLine = 1;
+static unsigned InputCol = 0;
+static FILE* InputFile = 0;
+
+
+
+/*****************************************************************************/
+/* Error handling */
+/*****************************************************************************/
+
+
+
+void CfgWarning (const char* Format, ...)
+/* Print a warning message adding file name and line number of the config file */
+{
+ char Buf [512];
+ va_list ap;
+ va_start (ap, Format);
+#ifdef __WATCOMC__
+ _vbprintf (Buf, sizeof (Buf), Format, ap);
+#else
+ vsnprintf (Buf, sizeof (Buf), Format, ap);
+#endif
+ Warning ("%s(%u): %s", CfgName, CfgErrorLine, Buf);
+}
+
+
+
+void CfgError (const char* Format, ...)
+/* Print an error message adding file name and line number of the config file */
+{
+ char Buf [512];
+ va_list ap;
+ va_start (ap, Format);
+#ifdef __WATCOMC__
+ _vbprintf (Buf, sizeof (Buf), Format, ap);
+#else
+ vsnprintf (Buf, sizeof (Buf), Format, ap);
+#endif
+ Error ("%s(%u): %s", CfgName, CfgErrorLine, Buf);
+}
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+static void NextChar (void)
+/* Read the next character from the input file */
+{
+ if (CfgBuf) {
+ /* Read from buffer */
+ C = (unsigned char)(*CfgBuf);
+ if (C == 0) {
+ C = EOF;
+ } else {
+ ++CfgBuf;
+ }
+ } else {
+ /* Read from the file */
+ C = getc (InputFile);
+ }
+
+ /* Count columns */
+ if (C != EOF) {
+ ++InputCol;
+ }
+
+ /* Count lines */
+ if (C == '\n') {
+ ++InputLine;
+ InputCol = 0;
+ }
+}
+
+
+
+static unsigned DigitVal (int C)
+/* Return the value for a numeric digit */
+{
+ if (isdigit (C)) {
+ return C - '0';
+ } else {
+ return toupper (C) - 'A' + 10;
+ }
+}
+
+
+
+void CfgNextTok (void)
+/* Read the next token from the input stream */
+{
+ unsigned I;
+
+
+Again:
+ /* Skip whitespace */
+ while (isspace (C)) {
+ NextChar ();
+ }
+
+ /* Remember the current position */
+ CfgErrorLine = InputLine;
+ CfgErrorCol = InputCol;
+
+ /* Identifier? */
+ if (C == '_' || isalpha (C)) {
+
+ /* Read the identifier */
+ I = 0;
+ while (C == '_' || isalnum (C)) {
+ if (I < CFG_MAX_IDENT_LEN) {
+ CfgSVal [I++] = C;
+ }
+ NextChar ();
+ }
+ CfgSVal [I] = '\0';
+ CfgTok = CFGTOK_IDENT;
+ return;
+ }
+
+ /* Hex number? */
+ if (C == '$') {
+ NextChar ();
+ if (!isxdigit (C)) {
+ Error ("%s(%u): Hex digit expected", CfgName, InputLine);
+ }
+ CfgIVal = 0;
+ while (isxdigit (C)) {
+ CfgIVal = CfgIVal * 16 + DigitVal (C);
+ NextChar ();
+ }
+ CfgTok = CFGTOK_INTCON;
+ return;
+ }
+
+ /* Decimal number? */
+ if (isdigit (C)) {
+ CfgIVal = 0;
+ while (isdigit (C)) {
+ CfgIVal = CfgIVal * 10 + DigitVal (C);
+ NextChar ();
+ }
+ CfgTok = CFGTOK_INTCON;
+ return;
+ }
+
+ /* Other characters */
+ switch (C) {
+
+ case '{':
+ NextChar ();
+ CfgTok = CFGTOK_LCURLY;
+ break;
+
+ case '}':
+ NextChar ();
+ CfgTok = CFGTOK_RCURLY;
+ break;
+
+ case ';':
+ NextChar ();
+ CfgTok = CFGTOK_SEMI;
+ break;
+
+ case '.':
+ NextChar ();
+ CfgTok = CFGTOK_DOT;
+ break;
+
+ case ',':
+ NextChar ();
+ CfgTok = CFGTOK_COMMA;
+ break;
+
+ case '=':
+ NextChar ();
+ CfgTok = CFGTOK_EQ;
+ break;
+
+ case ':':
+ NextChar ();
+ CfgTok = CFGTOK_COLON;
+ break;
+
+ case '\"':
+ NextChar ();
+ I = 0;
+ while (C != '\"') {
+ if (C == EOF || C == '\n') {
+ Error ("%s(%u): Unterminated string", CfgName, InputLine);
+ }
+ if (I < CFG_MAX_IDENT_LEN) {
+ CfgSVal [I++] = C;
+ }
+ NextChar ();
+ }
+ NextChar ();
+ CfgSVal [I] = '\0';
+ CfgTok = CFGTOK_STRCON;
+ break;
+
+ case '#':
+ /* Comment */
+ while (C != '\n' && C != EOF) {
+ NextChar ();
+ }
+ if (C != EOF) {
+ goto Again;
+ }
+ CfgTok = CFGTOK_EOF;
+ break;
+
+ case '%':
+ NextChar ();
+ switch (C) {
+
+ case 'O':
+ NextChar ();
+ if (OutputName) {
+ strncpy (CfgSVal, OutputName, CFG_MAX_IDENT_LEN);
+ CfgSVal [CFG_MAX_IDENT_LEN] = '\0';
+ } else {
+ CfgSVal [0] = '\0';
+ }
+ CfgTok = CFGTOK_STRCON;
+ break;
+
+ case 'S':
+ NextChar ();
+ CfgIVal = StartAddr;
+ CfgTok = CFGTOK_INTCON;
+ break;
+
+ default:
+ CfgError ("Invalid format specification");
+ }
+ break;
+
+ case EOF:
+ CfgTok = CFGTOK_EOF;
+ break;
+
+ default:
+ Error ("%s(%u): Invalid character `%c'", CfgName, InputLine, C);
+
+ }
+}
+
+
+
+void CfgConsume (unsigned T, const char* Msg)
+/* Skip a token, print an error message if not found */
+{
+ if (CfgTok != T) {
+ CfgError (Msg);
+ }
+ CfgNextTok ();
+}
+
+
+
+void CfgConsumeSemi (void)
+/* Consume a semicolon */
+{
+ CfgConsume (CFGTOK_SEMI, "`;' expected");
+}
+
+
+
+void CfgConsumeColon (void)
+/* Consume a colon */
+{
+ CfgConsume (CFGTOK_COLON, "`:' expected");
+}
+
+
+
+void CfgOptionalComma (void)
+/* Consume a comma if there is one */
+{
+ if (CfgTok == CFGTOK_COMMA) {
+ CfgNextTok ();
+ }
+}
+
+
+
+void CfgOptionalAssign (void)
+/* Consume an equal sign if there is one */
+{
+ if (CfgTok == CFGTOK_EQ) {
+ CfgNextTok ();
+ }
+}
+
+
+
+void CfgAssureInt (void)
+/* Make sure the next token is an integer */
+{
+ if (CfgTok != CFGTOK_INTCON) {
+ CfgError ("Integer constant expected");
+ }
+}
+
+
+
+void CfgAssureStr (void)
+/* Make sure the next token is a string constant */
+{
+ if (CfgTok != CFGTOK_STRCON) {
+ CfgError ("String constant expected");
+ }
+}
+
+
+
+void CfgAssureIdent (void)
+/* Make sure the next token is an identifier */
+{
+ if (CfgTok != CFGTOK_IDENT) {
+ CfgError ("Identifier expected");
+ }
+}
+
+
+
+void CfgRangeCheck (unsigned long Lo, unsigned long Hi)
+/* Check the range of CfgIVal */
+{
+ if (CfgIVal < Lo || CfgIVal > Hi) {
+ CfgError ("Range error");
+ }
+}
+
+
+
+void CfgSpecialToken (const IdentTok* Table, unsigned Size, const char* Name)
+/* Map an identifier to one of the special tokens in the table */
+{
+ unsigned I;
+
+ /* We need an identifier */
+ if (CfgTok == CFGTOK_IDENT) {
+
+ /* Make it upper case */
+ I = 0;
+ while (CfgSVal [I]) {
+ CfgSVal [I] = toupper (CfgSVal [I]);
+ ++I;
+ }
+
+ /* Linear search */
+ for (I = 0; I < Size; ++I) {
+ if (strcmp (CfgSVal, Table [I].Ident) == 0) {
+ CfgTok = Table [I].Tok;
+ return;
+ }
+ }
+
+ }
+
+ /* Not found or no identifier */
+ Error ("%s(%u): %s expected", CfgName, InputLine, Name);
+}
+
+
+
+void CfgBoolToken (void)
+/* Map an identifier or integer to a boolean token */
+{
+ static const IdentTok Booleans [] = {
+ { "YES", CFGTOK_TRUE },
+ { "NO", CFGTOK_FALSE },
+ { "TRUE", CFGTOK_TRUE },
+ { "FALSE", CFGTOK_FALSE },
+ };
+
+ /* If we have an identifier, map it to a boolean token */
+ if (CfgTok == CFGTOK_IDENT) {
+ CfgSpecialToken (Booleans, ENTRY_COUNT (Booleans), "Boolean");
+ } else {
+ /* We expected an integer here */
+ if (CfgTok != CFGTOK_INTCON) {
+ CfgError ("Boolean value expected");
+ }
+ CfgTok = (CfgIVal == 0)? CFGTOK_FALSE : CFGTOK_TRUE;
+ }
+}
+
+
+
+void CfgSetName (const char* Name)
+/* Set a name for a config file */
+{
+ CfgName = Name;
+}
+
+
+
+const char* CfgGetName (void)
+/* Get the name of the config file */
+{
+ return CfgName? CfgName : "";
+}
+
+
+
+void CfgSetBuf (const char* Buf)
+/* Set a memory buffer for the config */
+{
+ CfgBuf = Buf;
+}
+
+
+
+int CfgAvail (void)
+/* Return true if we have a configuration available */
+{
+ return CfgName != 0 || CfgBuf != 0;
+}
+
+
+
+void CfgOpenInput (void)
+/* Open the input file if we have one */
+{
+ /* If we have a config name given, open the file, otherwise we will read
+ * from a buffer.
+ */
+ if (!CfgBuf) {
+
+ /* Open the file */
+ InputFile = fopen (CfgName, "r");
+ if (InputFile == 0) {
+ Error ("Cannot open `%s': %s", CfgName, strerror (errno));
+ }
+
+ }
+
+ /* Initialize variables */
+ C = ' ';
+ InputLine = 1;
+ InputCol = 0;
+
+ /* Start the ball rolling ... */
+ CfgNextTok ();
+}
+
+
+
+void CfgCloseInput (void)
+/* Close the input file if we have one */
+{
+ /* Close the input file if we had one */
+ if (InputFile) {
+ (void) fclose (InputFile);
+ InputFile = 0;
+ }
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* scanner.h */
+/* */
+/* Configuration file scanner for the ld65 linker */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef SCANNER_H
+#define SCANNER_H
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Config file tokens */
+#define CFGTOK_NONE 0
+#define CFGTOK_INTCON 1
+#define CFGTOK_STRCON 2
+#define CFGTOK_IDENT 3
+#define CFGTOK_LCURLY 4
+#define CFGTOK_RCURLY 5
+#define CFGTOK_SEMI 6
+#define CFGTOK_COMMA 7
+#define CFGTOK_EQ 8
+#define CFGTOK_COLON 9
+#define CFGTOK_DOT 10
+#define CFGTOK_EOF 11
+
+/* Special identifiers */
+#define CFGTOK_MEMORY 20
+#define CFGTOK_FILES 21
+#define CFGTOK_SEGMENTS 22
+#define CFGTOK_FORMATS 23
+
+#define CFGTOK_START 30
+#define CFGTOK_SIZE 31
+#define CFGTOK_TYPE 32
+#define CFGTOK_FILE 33
+#define CFGTOK_DEFINE 34
+#define CFGTOK_FILL 35
+#define CFGTOK_FILLVAL 36
+#define CFGTOK_EXPORT 37
+#define CFGTOK_IMPORT 38
+#define CFGTOK_OS 39
+#define CFGTOK_FORMAT 40
+
+#define CFGTOK_LOAD 50
+#define CFGTOK_RUN 51
+#define CFGTOK_ALIGN 52
+#define CFGTOK_OFFSET 53
+
+#define CFGTOK_RO 60
+#define CFGTOK_RW 61
+#define CFGTOK_BSS 62
+#define CFGTOK_ZP 63
+#define CFGTOK_WPROT 64
+
+#define CFGTOK_O65 70
+#define CFGTOK_BIN 71
+
+#define CFGTOK_SMALL 80
+#define CFGTOK_LARGE 81
+
+#define CFGTOK_TRUE 90
+#define CFGTOK_FALSE 91
+
+#define CFGTOK_LUNIX 100
+#define CFGTOK_OSA65 101
+
+
+
+/* Mapping table entry, special identifier --> token */
+typedef struct IdentTok_ IdentTok;
+struct IdentTok_ {
+ const char* Ident; /* Identifier */
+ unsigned Tok; /* Token for identifier */
+};
+#define ENTRY_COUNT(s) (sizeof (s) / sizeof (s [0]))
+
+
+
+/* Current token and attributes */
+#define CFG_MAX_IDENT_LEN 255
+extern unsigned CfgTok;
+extern char CfgSVal [CFG_MAX_IDENT_LEN+1];
+extern unsigned long CfgIVal;
+
+/* Error location */
+extern unsigned CfgErrorLine;
+extern unsigned CfgErrorCol;
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void CfgWarning (const char* Format, ...);
+/* Print a warning message adding file name and line number of the config file */
+
+void CfgError (const char* Format, ...);
+/* Print an error message adding file name and line number of the config file */
+
+void CfgNextTok (void);
+/* Read the next token from the input stream */
+
+void CfgConsume (unsigned T, const char* Msg);
+/* Skip a token, print an error message if not found */
+
+void CfgConsumeSemi (void);
+/* Consume a semicolon */
+
+void CfgConsumeColon (void);
+/* Consume a colon */
+
+void CfgOptionalComma (void);
+/* Consume a comma if there is one */
+
+void CfgOptionalAssign (void);
+/* Consume an equal sign if there is one */
+
+void CfgAssureInt (void);
+/* Make sure the next token is an integer */
+
+void CfgAssureStr (void);
+/* Make sure the next token is a string constant */
+
+void CfgAssureIdent (void);
+/* Make sure the next token is an identifier */
+
+void CfgRangeCheck (unsigned long Lo, unsigned long Hi);
+/* Check the range of CfgIVal */
+
+void CfgSpecialToken (const IdentTok* Table, unsigned Size, const char* Name);
+/* Map an identifier to one of the special tokens in the table */
+
+void CfgBoolToken (void);
+/* Map an identifier or integer to a boolean token */
+
+void CfgSetName (const char* Name);
+/* Set a name for a config file */
+
+const char* CfgGetName (void);
+/* Get the name of the config file */
+
+void CfgSetBuf (const char* Buf);
+/* Set a memory buffer for the config */
+
+int CfgAvail (void);
+/* Return true if we have a configuration available */
+
+void CfgOpenInput (void);
+/* Open the input file if we have one */
+
+void CfgCloseInput (void);
+/* Close the input file if we have one */
+
+
+
+/* End of scanner.h */
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* segments.c */
+/* */
+/* Segment handling for the ld65 linker */
+/* */
+/* */
+/* */
+/* (C) 1998-2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "../common/exprdefs.h"
+#include "../common/symdefs.h"
+#include "../common/segdefs.h"
+#include "../common/hashstr.h"
+
+#include "mem.h"
+#include "global.h"
+#include "error.h"
+#include "fileio.h"
+#include "expr.h"
+#include "segments.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Fragment structure */
+typedef struct Fragment_ Fragment;
+struct Fragment_ {
+ Fragment* Next; /* Next fragment in list */
+ ObjData* Obj; /* Source of fragment */
+ unsigned long Size; /* Size of data/expression */
+ ExprNode* Expr; /* Expression if FRAG_EXPR */
+ FilePos Pos; /* File position in source */
+ unsigned char Type; /* Type of fragment */
+ unsigned char LitBuf [1]; /* Dynamically alloc'ed literal buffer */
+};
+
+
+
+/* Hash table */
+#define HASHTAB_SIZE 253
+static Segment* HashTab [HASHTAB_SIZE];
+
+static unsigned SegCount = 0; /* Segment count */
+static Segment* SegRoot = 0; /* List of all segments */
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+static Fragment* NewFragment (unsigned char Type, unsigned long Size, Section* S)
+/* Create a new fragment and insert it into the segment S */
+{
+ /* Allocate memory */
+ Fragment* F = Xmalloc (sizeof (Fragment) - 1 + Size); /* Portable? */
+
+ /* Initialize the data */
+ F->Next = 0;
+ F->Obj = 0;
+ F->Size = Size;
+ F->Expr = 0;
+ F->Type = Type;
+
+ /* Insert the code fragment into the segment */
+ if (S->FragRoot == 0) {
+ /* First fragment */
+ S->FragRoot = F;
+ } else {
+ S->FragLast->Next = F;
+ }
+ S->FragLast = F;
+ S->Size += Size;
+
+ /* Return the new fragment */
+ return F;
+}
+
+
+
+static Segment* NewSegment (const char* Name, unsigned char Type)
+/* Create a new segment and initialize it */
+{
+ /* Get the length of the symbol name */
+ unsigned Len = strlen (Name);
+
+ /* Allocate memory */
+ Segment* S = Xmalloc (sizeof (Segment) + Len);
+
+ /* Initialize the fields */
+ S->Next = 0;
+ S->SecRoot = 0;
+ S->SecLast = 0;
+ S->PC = 0;
+ S->Size = 0;
+ S->AlignObj = 0;
+ S->Align = 0;
+ S->FillVal = 0;
+ S->Type = Type;
+ S->Dumped = 0;
+ memcpy (S->Name, Name, Len);
+ S->Name [Len] = '\0';
+
+ /* Insert the segment into the segment list */
+ S->List = SegRoot;
+ SegRoot = S;
+ ++SegCount;
+
+ /* Return the new entry */
+ return S;
+}
+
+
+
+static Section* NewSection (Segment* Seg, unsigned char Align, unsigned char Type)
+/* Create a new section for the given segment */
+{
+ unsigned long V;
+
+
+ /* Allocate memory */
+ Section* S = Xmalloc (sizeof (Segment));
+
+ /* Initialize the data */
+ S->Next = 0;
+ S->Seg = Seg;
+ S->FragRoot = 0;
+ S->FragLast = 0;
+ S->Size = 0;
+ S->Align = Align;
+ S->Type = Type;
+
+ /* Calculate the alignment bytes needed for the section */
+ V = (0x01UL << S->Align) - 1;
+ S->Fill = ((Seg->Size + V) & ~V) - Seg->Size;
+
+ /* Adjust the segment size and set the section offset */
+ Seg->Size += S->Fill;
+ S->Offs = Seg->Size; /* Current size is offset */
+
+ /* Insert the section into the segment */
+ if (Seg->SecRoot == 0) {
+ /* First section in this segment */
+ Seg->SecRoot = S;
+ } else {
+ Seg->SecLast->Next = S;
+ }
+ Seg->SecLast = S;
+
+ /* Return the struct */
+ return S;
+}
+
+
+
+static Segment* SegFindInternal (const char* Name, unsigned HashVal)
+/* Try to find the segment with the given name, return a pointer to the
+ * segment structure, or 0 if not found.
+ */
+{
+ Segment* S = HashTab [HashVal];
+ while (S) {
+ if (strcmp (Name, S->Name) == 0) {
+ /* Found */
+ break;
+ }
+ S = S->Next;
+ }
+ /* Not found */
+ return S;
+}
+
+
+
+Section* ReadSection (FILE* F, ObjData* O)
+/* Read a section from a file */
+{
+ unsigned HashVal;
+ char Name [256];
+ unsigned long Size;
+ unsigned char Align;
+ unsigned char Type;
+ Segment* S;
+ Section* Sec;
+
+ /* Read the name */
+ ReadStr (F, Name);
+
+ /* Read the size */
+ Size = Read32 (F);
+
+ /* Read the alignment */
+ Align = Read8 (F);
+
+ /* Read the segment type */
+ Type = Read8 (F);
+
+ /* Print some data */
+ if (Verbose > 1) {
+ printf ("Module `%s': Found segment `%s', size = %lu, align = %u, type = %u\n",
+ O->Name, Name, Size, Align, Type);
+ }
+
+ /* Create a hash over the name and try to locate the segment in the table */
+ HashVal = HashStr (Name) % HASHTAB_SIZE;
+ S = SegFindInternal (Name, HashVal);
+
+ /* If we don't have that segment already, allocate it using the type of
+ * the first section.
+ */
+ if (S == 0) {
+ /* Create a new segment and insert it */
+ S = NewSegment (Name, Type);
+ S->Next = HashTab [HashVal];
+ HashTab [HashVal] = S;
+ }
+
+ /* Allocate the section we will return later */
+ Sec = NewSection (S, Align, Type);
+
+ /* Check if the section has the same type as the segment */
+ if (Sec->Type != S->Type) {
+ /* OOPS */
+ Error ("Module `%s': Type mismatch for segment `%s'", O->Name, S->Name);
+ }
+
+ /* Set up the minimum segment alignment */
+ if (Sec->Align > S->Align) {
+ /* Section needs larger alignment, use this one */
+ S->Align = Sec->Align;
+ S->AlignObj = O;
+ }
+
+ /* Start reading fragments from the file and insert them into the section . */
+ while (Size) {
+
+ Fragment* Frag;
+
+ /* Read the fragment type */
+ unsigned char Type = Read8 (F);
+
+ /* Handle the different fragment types */
+ switch (Type) {
+
+ case FRAG_LITERAL8:
+ Frag = NewFragment (FRAG_LITERAL, Read8 (F), Sec);
+ break;
+
+ case FRAG_LITERAL16:
+ Frag = NewFragment (FRAG_LITERAL, Read16 (F), Sec);
+ break;
+
+ case FRAG_LITERAL24:
+ Frag = NewFragment (FRAG_LITERAL, Read24 (F), Sec);
+ break;
+
+ case FRAG_LITERAL32:
+ Frag = NewFragment (FRAG_LITERAL, Read32 (F), Sec);
+ break;
+
+ case FRAG_EXPR8:
+ case FRAG_EXPR16:
+ case FRAG_EXPR24:
+ case FRAG_EXPR32:
+ case FRAG_SEXPR8:
+ case FRAG_SEXPR16:
+ case FRAG_SEXPR24:
+ case FRAG_SEXPR32:
+ Frag = NewFragment (Type & FRAG_TYPEMASK, Type & FRAG_BYTEMASK, Sec);
+ break;
+
+ case FRAG_FILL:
+ /* Will allocate memory, but we don't care... */
+ Frag = NewFragment (FRAG_FILL, Read16 (F), Sec);
+ break;
+
+ default:
+ Error ("Unknown fragment type in module `%s', segment `%s': %02X",
+ O->Name, S->Name, Type);
+ /* NOTREACHED */
+ return 0;
+ }
+
+ /* Now read the fragment data */
+ switch (Frag->Type) {
+
+ case FRAG_LITERAL:
+ /* Literal data */
+ ReadData (F, Frag->LitBuf, Frag->Size);
+ break;
+
+ case FRAG_EXPR:
+ case FRAG_SEXPR:
+ /* An expression */
+ Frag->Expr = ReadExpr (F, O);
+ break;
+
+ }
+
+ /* Read the file position of the fragment */
+ ReadFilePos (F, &Frag->Pos);
+
+ /* Remember the module we had this fragment from */
+ Frag->Obj = O;
+
+ /* Next one */
+ CHECK (Size >= Frag->Size);
+ Size -= Frag->Size;
+ }
+
+ /* Increment the segment size by the section size */
+ S->Size += Sec->Size;
+
+ /* Return the section */
+ return Sec;
+}
+
+
+
+Segment* SegFind (const char* Name)
+/* Return the given segment or NULL if not found. */
+{
+ return SegFindInternal (Name, HashStr (Name) % HASHTAB_SIZE);
+}
+
+
+
+int IsBSSType (Segment* S)
+/* Check if the given segment is a BSS style segment, that is, it does not
+ * contain non-zero data.
+ */
+{
+ /* Loop over all sections */
+ Section* Sec = S->SecRoot;
+ while (Sec) {
+ /* Loop over all fragments */
+ Fragment* F = Sec->FragRoot;
+ while (F) {
+ if (F->Type == FRAG_LITERAL) {
+ unsigned char* Data = F->LitBuf;
+ unsigned long Count = F->Size;
+ while (Count--) {
+ if (*Data++ != 0) {
+ return 0;
+ }
+ }
+ } else if (F->Type == FRAG_EXPR || F->Type == FRAG_SEXPR) {
+ if (GetExprVal (F->Expr) != 0) {
+ return 0;
+ }
+ }
+ F = F->Next;
+ }
+ Sec = Sec->Next;
+ }
+ return 1;
+}
+
+
+
+void SegDump (void)
+/* Dump the segments and it's contents */
+{
+ unsigned I;
+ unsigned long Count;
+ unsigned char* Data;
+
+ Segment* Seg = SegRoot;
+ while (Seg) {
+ Section* S = Seg->SecRoot;
+ printf ("Segment: %s (%lu)\n", Seg->Name, Seg->Size);
+ while (S) {
+ Fragment* F = S->FragRoot;
+ printf (" Section:\n");
+ while (F) {
+ switch (F->Type) {
+
+ case FRAG_LITERAL:
+ printf (" Literal (%lu bytes):", F->Size);
+ Count = F->Size;
+ Data = F->LitBuf;
+ I = 100;
+ while (Count--) {
+ if (I > 75) {
+ printf ("\n ");
+ I = 3;
+ }
+ printf (" %02X", *Data++);
+ I += 3;
+ }
+ printf ("\n");
+ break;
+
+ case FRAG_EXPR:
+ printf (" Expression (%lu bytes):\n", F->Size);
+ printf (" ");
+ DumpExpr (F->Expr);
+ break;
+
+ case FRAG_SEXPR:
+ printf (" Signed expression (%lu bytes):\n", F->Size);
+ printf (" ");
+ DumpExpr (F->Expr);
+ break;
+
+ case FRAG_FILL:
+ printf (" Empty space (%lu bytes)\n", F->Size);
+ break;
+
+ default:
+ Internal ("Invalid fragment type: %02X", F->Type);
+ }
+ F = F->Next;
+ }
+ S = S->Next;
+ }
+ Seg = Seg->List;
+ }
+}
+
+
+
+unsigned SegWriteConstExpr (FILE* F, ExprNode* E, int Signed, unsigned Size)
+/* Write a supposedly constant expression to the target file. Do a range
+ * check and return one of the SEG_EXPR_xxx codes.
+ */
+{
+ static const unsigned long U_HighRange [4] = {
+ 0x000000FF, 0x0000FFFF, 0x00FFFFFF, 0xFFFFFFFF
+ };
+ static const long S_HighRange [4] = {
+ 0x0000007F, 0x00007FFF, 0x007FFFFF, 0x7FFFFFFF
+ };
+ static const long S_LowRange [4] = {
+ 0xFFFFFF80, 0xFFFF8000, 0xFF800000, 0x80000000
+ };
+
+
+ /* Get the expression value */
+ long Val = GetExprVal (E);
+
+ /* Check the size */
+ CHECK (Size >= 1 && Size <= 4);
+
+ /* Check for a range error */
+ if (Signed) {
+ if (Val > S_HighRange [Size-1] || Val < S_LowRange [Size-1]) {
+ /* Range error */
+ return SEG_EXPR_RANGE_ERROR;
+ }
+ } else {
+ if (((unsigned long)Val) > U_HighRange [Size-1]) {
+ /* Range error */
+ return SEG_EXPR_RANGE_ERROR;
+ }
+ }
+
+ /* Write the value to the file */
+ WriteVal (F, Val, Size);
+
+ /* Success */
+ return SEG_EXPR_OK;
+}
+
+
+
+void SegWrite (FILE* Tgt, Segment* S, SegWriteFunc F, void* Data)
+/* Write the data from the given segment to a file. For expressions, F is
+ * called (see description of SegWriteFunc above).
+ */
+{
+ int Sign;
+ unsigned long Offs = 0;
+
+ /* Loop over all sections in this segment */
+ Section* Sec = S->SecRoot;
+ while (Sec) {
+ Fragment* Frag;
+
+ /* If we have fill bytes, write them now */
+ WriteMult (Tgt, S->FillVal, Sec->Fill);
+
+ /* Loop over all fragments in this section */
+ Frag = Sec->FragRoot;
+ while (Frag) {
+
+ switch (Frag->Type) {
+
+ case FRAG_LITERAL:
+ WriteData (Tgt, Frag->LitBuf, Frag->Size);
+ break;
+
+ case FRAG_EXPR:
+ case FRAG_SEXPR:
+ Sign = (Frag->Type == FRAG_SEXPR);
+ /* Call the users function and evaluate the result */
+ switch (F (Frag->Expr, Sign, Frag->Size, Offs, Data)) {
+
+ case SEG_EXPR_OK:
+ break;
+
+ case SEG_EXPR_RANGE_ERROR:
+ Error ("Range error in module `%s', line %lu",
+ Frag->Obj->Files [Frag->Pos.Name], Frag->Pos.Line);
+ break;
+
+ case SEG_EXPR_TOO_COMPLEX:
+ Error ("Expression too complex in module `%s', line %lu",
+ Frag->Obj->Files [Frag->Pos.Name], Frag->Pos.Line);
+ break;
+
+ default:
+ Internal ("Invalid return code from SegWriteFunc");
+ }
+ break;
+
+ case FRAG_FILL:
+ WriteMult (Tgt, S->FillVal, Frag->Size);
+ break;
+
+ default:
+ Internal ("Invalid fragment type: %02X", Frag->Type);
+ }
+
+ /* Update the offset */
+ Offs += Frag->Size;
+
+ /* Next fragment */
+ Frag = Frag->Next;
+ }
+
+ /* Next section */
+ Sec = Sec->Next;
+ }
+}
+
+
+
+static int CmpSegStart (const void* K1, const void* K2)
+/* Compare function for qsort */
+{
+ /* Get the real segment pointers */
+ const Segment* S1 = *(const Segment**)K1;
+ const Segment* S2 = *(const Segment**)K2;
+
+ /* Compare the start addresses */
+ if (S1->PC > S2->PC) {
+ return 1;
+ } else if (S1->PC < S2->PC) {
+ return -1;
+ } else {
+ /* Sort segments with equal starts by name */
+ return strcmp (S1->Name, S2->Name);
+ }
+}
+
+
+
+void PrintSegmentMap (FILE* F)
+/* Print a segment map to the given file */
+{
+ unsigned I;
+ Segment* S;
+ Segment** SegPool;
+
+ /* Allocate memory for the segment pool */
+ SegPool = Xmalloc (SegCount * sizeof (Segment*));
+
+ /* Collect pointers to the segments */
+ I = 0;
+ S = SegRoot;
+ while (S) {
+
+ /* Check the count for safety */
+ CHECK (I < SegCount);
+
+ /* Remember the pointer */
+ SegPool [I] = S;
+
+ /* Follow the linked list */
+ S = S->List;
+
+ /* Next array index */
+ ++I;
+ }
+ CHECK (I == SegCount);
+
+ /* Sort the array by increasing start addresses */
+ qsort (SegPool, SegCount, sizeof (Segment*), CmpSegStart);
+
+ /* Print a header */
+ fprintf (F, "Name Start End Size\n"
+ "--------------------------------------------\n");
+
+ /* Print the segments */
+ for (I = 0; I < SegCount; ++I) {
+
+ /* Get a pointer to the segment */
+ S = SegPool [I];
+
+ /* Print empty segments only if explicitly requested */
+ if (VerboseMap || S->Size > 0) {
+ /* Print the segment data */
+ fprintf (F, "%-20s %06lX %06lX %06lX\n",
+ S->Name, S->PC, S->PC + S->Size, S->Size);
+ }
+ }
+
+ /* Free the segment pool */
+ Xfree (SegPool);
+}
+
+
+
+void CheckSegments (void)
+/* Walk through the segment list and check if there are segments that were
+ * not written to the output file. Output an error if this is the case.
+ */
+{
+ Segment* S = SegRoot;
+ while (S) {
+ if (S->Size > 0 && S->Dumped == 0) {
+ Error ("Missing memory area assignment for segment `%s'", S->Name);
+ }
+ S = S->List;
+ }
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* segments.h */
+/* */
+/* Segment handling for the ld65 linker */
+/* */
+/* */
+/* */
+/* (C) 1998-2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef SEGMENTS_H
+#define SEGMENTS_H
+
+
+
+#include <stdio.h>
+
+#include "../common/exprdefs.h"
+
+#include "objdata.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Forward for the section structure (a section is a part of a segment) */
+typedef struct Section_ Section;
+
+/* Segment structure */
+typedef struct Segment_ Segment;
+struct Segment_ {
+ Segment* Next; /* Hash list */
+ Segment* List; /* List of all segments */
+ Section* SecRoot; /* Section list */
+ Section* SecLast; /* Pointer to last section */
+ unsigned long PC; /* PC were this segment is located */
+ unsigned long Size; /* Size of data so far */
+ ObjData* AlignObj; /* Module that requested the alignment */
+ unsigned char Align; /* Alignment needed */
+ unsigned char FillVal; /* Value to use for fill bytes */
+ unsigned char Type; /* Type of segment */
+ char Dumped; /* Did we dump this segment? */
+ char Name [1]; /* Name, dynamically allocated */
+};
+
+
+
+/* Section structure (a section is a part of a segment) */
+struct Section_ {
+ Section* Next; /* List of sections in a segment */
+ Segment* Seg; /* Segment that contains the section */
+ struct Fragment_* FragRoot; /* Fragment list */
+ struct Fragment_* FragLast; /* Pointer to last fragment */
+ unsigned long Offs; /* Offset into the segment */
+ unsigned long Size; /* Size of the section */
+ unsigned char Align; /* Alignment */
+ unsigned char Fill; /* Fill bytes for alignment */
+ unsigned char Type; /* Type of segment */
+};
+
+
+
+/* Prototype for a function that is used to write expressions to the target
+ * file (used in SegWrite). It returns one of the following values:
+ */
+#define SEG_EXPR_OK 0 /* Ok */
+#define SEG_EXPR_RANGE_ERROR 1 /* Range error */
+#define SEG_EXPR_TOO_COMPLEX 2 /* Expression too complex */
+
+typedef unsigned (*SegWriteFunc) (ExprNode* E, /* The expression to write */
+ int Signed, /* Signed expression? */
+ unsigned Size, /* Size (=range) */
+ unsigned long Offs, /* File offset */
+ void* Data); /* Callers data */
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+Section* ReadSection (FILE* F, ObjData* O);
+/* Read a section from a file */
+
+Segment* SegFind (const char* Name);
+/* Return the given segment or NULL if not found. */
+
+int IsBSSType (Segment* S);
+/* Check if the given segment is a BSS style segment, that is, it does not
+ * contain non-zero data.
+ */
+
+void SegDump (void);
+/* Dump the segments and it's contents */
+
+unsigned SegWriteConstExpr (FILE* F, ExprNode* E, int Signed, unsigned Size);
+/* Write a supposedly constant expression to the target file. Do a range
+ * check and return one of the SEG_EXPR_xxx codes.
+ */
+
+void SegWrite (FILE* Tgt, Segment* S, SegWriteFunc F, void* Data);
+/* Write the data from the given segment to a file. For expressions, F is
+ * called (see description of SegWriteFunc above).
+ */
+
+void PrintSegmentMap (FILE* F);
+/* Print a segment map to the given file */
+
+void CheckSegments (void);
+/* Walk through the segment list and check if there are segments that were
+ * not written to the output file. Output an error if this is the case.
+ */
+
+
+
+/* End of segments.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* target.c */
+/* */
+/* Target system support for the ld65 linker */
+/* */
+/* */
+/* */
+/* (C) 1998-2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "error.h"
+#include "global.h"
+#include "binfmt.h"
+#include "scanner.h"
+#include "config.h"
+#include "target.h"
+
+
+
+/*****************************************************************************/
+/* Target configurations */
+/*****************************************************************************/
+
+
+
+static const char CfgNone [] =
+ "MEMORY {"
+ "RAM: start = %S, size = $10000, file = %O;"
+ "}"
+ "SEGMENTS {"
+ "CODE: load = RAM, type = rw;"
+ "RODATA: load = RAM, type = rw;"
+ "DATA: load = RAM, type = rw;"
+ "BSS: load = RAM, type = bss, define = yes;"
+ "}";
+
+static const char CfgAtari [] =
+ "MEMORY {"
+ "HEADER: start = $0000, size = $6, file = %O;"
+ "RAM: start = $1F00, size = $6100, file = %O;"
+ "}"
+ "SEGMENTS {"
+ "EXEHDR: load = HEADER, type = wprot;"
+ "CODE: load = RAM, type = wprot, define = yes;"
+ "RODATA: load = RAM, type = wprot;"
+ "DATA: load = RAM, type = rw;"
+ "BSS: load = RAM, type = bss, define = yes;"
+ "AUTOSTRT: load = RAM, type = wprot;"
+ "}";
+
+static const char CfgC64 [] =
+ "MEMORY {"
+ "RAM: start = $7FF, size = $c801, file = %O;"
+ "}"
+ "SEGMENTS {"
+ "CODE: load = RAM, type = wprot;"
+ "RODATA: load = RAM, type = wprot;"
+ "DATA: load = RAM, type = rw;"
+ "BSS: load = RAM, type = bss, define = yes;"
+ "}";
+
+static const char CfgC128 [] =
+ "MEMORY {"
+ "RAM: start = $1bff, size = $a401, file = %O;"
+ "}"
+ "SEGMENTS {"
+ "CODE: load = RAM, type = wprot;"
+ "RODATA: load = RAM, type = wprot;"
+ "DATA: load = RAM, type = rw;"
+ "BSS: load = RAM, type = bss, define = yes;"
+ "}";
+
+static const char CfgAce [] =
+ "";
+
+static const char CfgPlus4 [] =
+ "MEMORY {"
+ "RAM: start = $0fff, size = $7001, file = %O;"
+ "}"
+ "SEGMENTS {"
+ "CODE: load = RAM, type = wprot;"
+ "RODATA: load = RAM, type = wprot;"
+ "DATA: load = RAM, type = rw;"
+ "BSS: load = RAM, type = bss, define = yes;"
+ "}";
+
+static const char CfgCBM610 [] =
+ "MEMORY {"
+ "RAM: start = $0001, size = $FFF0, file = %O;"
+ "}"
+ "SEGMENTS {"
+ "CODE: load = RAM, type = wprot;"
+ "RODATA: load = RAM, type = wprot;"
+ "DATA: load = RAM, type = rw;"
+ "BSS: load = RAM, type = bss, define = yes;"
+ "}";
+
+static const char CfgPET [] =
+ "MEMORY {"
+ "RAM: start = $03FF, size = $7BFF, file = %O;"
+ "}"
+ "SEGMENTS {"
+ "CODE: load = RAM, type = wprot;"
+ "RODATA: load = RAM, type = wprot;"
+ "DATA: load = RAM, type = rw;"
+ "BSS: load = RAM, type = bss, define = yes;"
+ "}";
+
+static const char CfgNES [] =
+ "MEMORY {"
+ "RAM: start = $0200, size = $0600, file = \"\";"
+ "ROM: start = $8000, size = $8000, file = %O;"
+ "}"
+ "SEGMENTS {"
+ "CODE: load = ROM, type = ro;"
+ "RODATA: load = ROM, type = ro;"
+ "DATA: load = ROM, run = RAM, type = rw, define = yes;"
+ "BSS: load = RAM, type = bss, define = yes;"
+ "VECTORS: load = ROM, type = ro, start = $FFFA;"
+ "}";
+
+static const char CfgLunix [] =
+ "MEMORY {"
+ "COMBINED: start = $0000, size = $FFFF, file = %O;"
+ "ZEROPAGE: start = $0000, size = $0100, file = %O;"
+ "}"
+ "SEGMENTS {"
+ "CODE: load = COMBINED, type = wprot;"
+ "RODATA: load = COMBINED, type = wprot;"
+ "DATA: load = COMBINED, type = rw, define = yes;"
+ "BSS: load = COMBINED, type = bss, define = yes;"
+ "ZEROPAGE: load = ZEROPAGE, type = zp;"
+ "}"
+ "FILES {"
+ "%O: format = o65;"
+ "}"
+ "FORMATS {"
+ "o65: os = lunix, type = small,"
+ "extsym = \"LUNIXKERNAL\", extsym = \"LIB6502\";"
+ "}";
+
+static const char CfgOSA65 [] =
+ "MEMORY {"
+ "COMBINED: start = $0000, size = $FFFF, file = %O;"
+ "ZEROPAGE: start = $0000, size = $0100, file = %O;"
+ "}"
+ "SEGMENTS {"
+ "CODE: load = COMBINED, type = wprot;"
+ "RODATA: load = COMBINED, type = wprot;"
+ "DATA: load = COMBINED, type = rw, define = yes;"
+ "BSS: load = COMBINED, type = bss, define = yes;"
+ "ZEROPAGE: load = ZEROPAGE, type = zp;"
+ "}"
+ "FILES {"
+ "%O: format = o65;"
+ "}"
+ "FORMATS {"
+ "o65: os = osa65, type = small,"
+ "extsym = \"OSA2KERNAL\", extsym = \"LIB6502\";"
+ "}";
+
+static const char CfgApple2 [] =
+ "MEMORY {"
+ "RAM: start = $800, size = $8E00, file = %O;"
+ "}"
+ "SEGMENTS { "
+ "CODE: load = RAM, type = ro;"
+ "RODATA: load = RAM, type = ro;"
+ "DATA: load = RAM, type = rw;"
+ "BSS: load = RAM, type = bss, define = yes;"
+ "}";
+
+static const char CfgGeos [] =
+ "MEMORY {"
+ "HEADER: start = $204, size = 508, file = %O;"
+ "RAM: start = $400, size = $7C00, file = %O;"
+ "}"
+ "SEGMENTS { "
+ "HEADER: load = HEADER, type = ro;"
+ "CODE: load = RAM, type = ro;"
+ "RODATA: load = RAM, type = ro;"
+ "DATA: load = RAM, type = rw;"
+ "BSS: load = RAM, type = bss, define = yes;"
+ "}";
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Supported systems */
+#define TGT_NONE 0
+#define TGT_ATARI 1 /* Atari 8 bit machines */
+#define TGT_C64 2
+#define TGT_C128 3
+#define TGT_ACE 4
+#define TGT_PLUS4 5
+#define TGT_CBM610 6 /* CBM 600/700 family */
+#define TGT_PET 7 /* CBM PET family */
+#define TGT_NES 8 /* Nintendo Entertainment System */
+#define TGT_LUNIX 9
+#define TGT_OSA65 10
+#define TGT_APPLE2 11
+#define TGT_GEOS 12
+#define TGT_COUNT 13 /* Count of supported systems */
+
+
+
+/* Structure describing a target */
+typedef struct TargetCfg_ TargetCfg;
+struct TargetCfg_ {
+ const char* Name; /* Name of the system */
+ unsigned char BinFmt; /* Default binary format for the target */
+ const char* Cfg; /* Pointer to configuration */
+};
+
+static const TargetCfg Targets [TGT_COUNT] = {
+ { "none", BINFMT_BINARY, CfgNone },
+ { "atari", BINFMT_BINARY, CfgAtari },
+ { "c64", BINFMT_BINARY, CfgC64 },
+ { "c128", BINFMT_BINARY, CfgC128 },
+ { "ace", BINFMT_BINARY, CfgAce },
+ { "plus4", BINFMT_BINARY, CfgPlus4 },
+ { "cbm610", BINFMT_BINARY, CfgCBM610 },
+ { "pet", BINFMT_BINARY, CfgPET },
+ { "nes", BINFMT_BINARY, CfgNES },
+ { "lunix", BINFMT_O65, CfgLunix },
+ { "osa65", BINFMT_O65, CfgOSA65 },
+ { "apple2", BINFMT_BINARY, CfgApple2 },
+ { "geos", BINFMT_BINARY, CfgGeos },
+};
+
+/* Selected target system type */
+static const TargetCfg* Target;
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+static int StrICmp (const char* S1, const char* S2)
+/* Compare two strings case insensitive */
+{
+ int Diff = 0;
+ while (1) {
+ Diff = tolower (*S1) - tolower (*S2);
+ if (Diff != 0 || *S1 == '\0') {
+ return Diff;
+ }
+ ++S1;
+ ++S2;
+ }
+}
+
+
+
+static int TgtMap (const char* Name)
+/* Map a target name to a system code. Return -1 in case of an error */
+{
+ unsigned I;
+
+ /* Check for a numeric target */
+ if (isdigit (*Name)) {
+ int Target = atoi (Name);
+ if (Target >= 0 && Target < TGT_COUNT) {
+ return Target;
+ }
+ }
+
+ /* Check for a target string */
+ for (I = 0; I < TGT_COUNT; ++I) {
+ if (StrICmp (Targets [I].Name, Name) == 0) {
+ return I;
+ }
+ }
+
+ /* Not found */
+ return -1;
+}
+
+
+
+void TgtSet (const char* T)
+/* Set the target system, initialize internal stuff for this target */
+{
+ /* Map the target to a number */
+ int TgtNum = TgtMap (T);
+ if (TgtNum == -1) {
+ Error ("Invalid target system: %s", T);
+ }
+ Target = &Targets [TgtNum];
+
+ /* Set the target data */
+ DefaultBinFmt = Target->BinFmt;
+ CfgSetBuf (Target->Cfg);
+}
+
+
+
+void TgtPrintList (FILE* F)
+/* Print a list of the available target systems */
+{
+ unsigned I;
+
+ /* Print a header */
+ fprintf (F, "Available targets:\n");
+
+ /* Print a list of the target systems */
+ for (I = 0; I < TGT_COUNT; ++I) {
+ fprintf (F, " %s\n", Targets [I].Name);
+ }
+}
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* target.h */
+/* */
+/* Target system support for the ld65 linker */
+/* */
+/* */
+/* */
+/* (C) 1998-2000 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef TARGET_H
+#define TARGET_H
+
+
+
+#include <stdio.h>
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void TgtSet (const char* T);
+/* Set the target system, initialize internal stuff for this target */
+
+void TgtPrintList (FILE* F);
+/* Print a list of the available target systems */
+
+
+
+/* End of target.h */
+
+#endif
+
+
+
--- /dev/null
+/*****************************************************************************/
+/* */
+/* version.h */
+/* */
+/* Version information for the ld65 linker */
+/* */
+/* */
+/* */
+/* (C) 1998 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@musoftware.de */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef VERSION_H
+#define VERSION_H
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+#define VER_MAJOR 2U
+#define VER_MINOR 4U
+#define VER_PATCH 0U
+
+
+
+/* End of version.h */
+
+#endif
+
+
+
--- /dev/null
+#
+# gcc Makefile for the program sources
+#
+
+CFLAGS = -g -O2 -Wall
+CC = gcc
+LDFLAGS =
+
+SUBDIRS = \
+ common \
+ ar65 \
+ ca65 \
+ cc65 \
+ cl65 \
+ ld65
+
+.PHONY: all
+all:
+ for i in $(SUBDIRS); do $(MAKE) -C $$i -f make/gcc.mak all; done
+
+.PHONY: dist
+dist:
+ for i in $(SUBDIRS); do $(MAKE) -C $$i -f make/gcc.mak dist; done
+
+.PHONY: clean
+clean:
+ for i in $(SUBDIRS); do $(MAKE) -C $$i -f make/gcc.mak clean; done
+
+.PHONY: zap
+zap:
+ for i in $(SUBDIRS); do $(MAKE) -C $$i -f make/gcc.mak zap; done
+
--- /dev/null
+#
+# Watcom Makefile for the cc65 binutils
+#
+
+SUBDIRS = \
+ common \
+ ar65 \
+ ca65 \
+ ld65
+
+all:
+ cd common
+ make -f make\watcom.mak
+ cd ..\ar65
+ make -f make\watcom.mak
+ cd ..\ca65
+ make -f make\watcom.mak
+ cd ..\ld65
+ make -f make\watcom.mak
+ cd ..
+
+clean:
+ cd common
+ make -f make\watcom.mak clean
+ cd ..\ar65
+ make -f make\watcom.mak clean
+ cd ..\ca65
+ make -f make\watcom.mak clean
+ cd ..\ld65
+ make -f make\watcom.mak clean
+ cd ..
+
+strip:
+ @cd ar65
+ @-make -f make\watcom.mak strip
+ @cd ..\ca65
+ @-make -f make\watcom.mak strip
+ @cd ..\ld65
+ @-make -f make\watcom.mak strip
+ @cd ..
+
+
--- /dev/null
+#define hash_hash # ## #
+#define mkstr(a) # a
+#define in_between(a) mkstr(a)
+#define join(c, d) in_between(c hash_hash d)
+
+char p[] = join(x, y); // Comment
--- /dev/null
+#define x 3
+#define f(a) f(x * (a))
+#undef x
+#define x 2
+#define g f
+#define z z[0]
+#define h g(~
+#define m(a) a(w)
+#define w 0,1
+#define t(a) a
+#define p() int
+#define q(x) x
+#define r(x,y) x ## y
+#define str(x) # x
+
+f(y+1) + f(f(z)) % t(t(g) (0) + t)(1);
+g(x+(3,4)-w) | h 5) & m(f)^m(m);
+p() i[q()] = { q(1), r(2,3), r(4,), r(,5), r(,) };
+char c[2][6] = { str(hello), str() };
--- /dev/null
+#define str(s) # s
+#define xstr(s) str(s)
+#define debug(s, t) printf("x" # s "= %d, x" # t "= %s", \
+ x ## s, x ## t)
+#define INCFILE(n) vers ## n // Comment
+#define glue(a,b) a ## b
+#define xglue(a,b) glue(a,b)
+#define HIGHLOW "hello"
+#define LOW LOW ", world"
+
+debug (1, 2);
+fputs (str (strncmp("abc\0d", "abc", '\4') // Comment
+ == 0) str (: @\n), s);
+glue (HIGH, LOW);
+xglue (HIGH, LOW);
+
--- /dev/null
+#define t(x,y,z) x ## y ## z
+int j[] = { t(1,2,3), t(,4,5), t(6,,7), t(8,9,),
+ t(10,,), t(,11,), t(,,12), t(,,) };
--- /dev/null
+#include <stdio.h>
+
+int main (void)
+{
+ int C;
+ while ((C = getchar ()) != EOF) {
+ if (C == 0x9B) {
+ putchar ('\n');
+ } else if (C == 0x7F) {
+ putchar ('\t');
+ } else {
+ putchar (C);
+ }
+ }
+ return 0;
+}
+