This commit was generated by cvs2svn to compensate for changes in r2,
which included commits to RCS files with non-trunk default branches. git-svn-id: svn://svn.cc65.org/cc65/trunk@3 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
11
doc/BUGS
Normal file
11
doc/BUGS
Normal file
@@ -0,0 +1,11 @@
|
||||
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.
|
||||
|
||||
62
doc/CREDITS
Normal file
62
doc/CREDITS
Normal file
@@ -0,0 +1,62 @@
|
||||
|
||||
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.
|
||||
|
||||
|
||||
152
doc/ar65.txt
Normal file
152
doc/ar65.txt
Normal file
@@ -0,0 +1,152 @@
|
||||
|
||||
|
||||
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.
|
||||
|
||||
|
||||
|
||||
1903
doc/ca65.txt
Normal file
1903
doc/ca65.txt
Normal file
File diff suppressed because it is too large
Load Diff
600
doc/cc65.txt
Normal file
600
doc/cc65.txt
Normal file
@@ -0,0 +1,600 @@
|
||||
|
||||
|
||||
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.
|
||||
|
||||
|
||||
|
||||
183
doc/cl65.txt
Normal file
183
doc/cl65.txt
Normal file
@@ -0,0 +1,183 @@
|
||||
|
||||
|
||||
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.
|
||||
|
||||
|
||||
|
||||
340
doc/coding.txt
Normal file
340
doc/coding.txt
Normal file
@@ -0,0 +1,340 @@
|
||||
|
||||
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.
|
||||
|
||||
|
||||
|
||||
159
doc/compile.txt
Normal file
159
doc/compile.txt
Normal file
@@ -0,0 +1,159 @@
|
||||
|
||||
|
||||
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.
|
||||
|
||||
|
||||
151
doc/debugging.txt
Normal file
151
doc/debugging.txt
Normal file
@@ -0,0 +1,151 @@
|
||||
|
||||
|
||||
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.
|
||||
|
||||
185
doc/internal.doc
Normal file
185
doc/internal.doc
Normal file
@@ -0,0 +1,185 @@
|
||||
|
||||
|
||||
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.
|
||||
|
||||
|
||||
|
||||
206
doc/intro.txt
Normal file
206
doc/intro.txt
Normal file
@@ -0,0 +1,206 @@
|
||||
|
||||
|
||||
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.
|
||||
|
||||
|
||||
|
||||
|
||||
655
doc/ld65.txt
Normal file
655
doc/ld65.txt
Normal file
@@ -0,0 +1,655 @@
|
||||
|
||||
|
||||
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.
|
||||
|
||||
|
||||
|
||||
|
||||
235
doc/library.txt
Normal file
235
doc/library.txt
Normal file
@@ -0,0 +1,235 @@
|
||||
|
||||
|
||||
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.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
511
doc/newvers.txt
Normal file
511
doc/newvers.txt
Normal file
@@ -0,0 +1,511 @@
|
||||
|
||||
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.
|
||||
|
||||
|
||||
|
||||
|
||||
34
doc/readme.1st
Normal file
34
doc/readme.1st
Normal file
@@ -0,0 +1,34 @@
|
||||
|
||||
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
|
||||
|
||||
|
||||
31
doc/readme.txt
Normal file
31
doc/readme.txt
Normal file
@@ -0,0 +1,31 @@
|
||||
|
||||
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.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user