<pending: tabularise these features, this is unreadeble>
SDCC is a Free ware, retargettable, optimizing ANSI-C compiler
by Sandeep Dutta designed for 8 bit Microprocessors. The
current version targets Intel MCS51 based Microprocessors(8051,8052,
etc), Zilog Z80 based MCUs, and the Dallas 80C390 MCS51 variant. It
can be retargetted for other microprocessors, support for PIC, AVR
and 186 is under development. The entire source code for the compiler
is distributed under GPL. SDCC uses ASXXXX & ASLINK, a Freeware,
retargettable assembler & linker. SDCC has extensive language extensions
suitable for utilizing various microcontrollers underlying hardware
effectively. In addition to the MCU specific optimizations SDCC also
does a host of standard optimizations like global sub expression
elimination, loop optimizations (loop invariant, strength reduction
of induction variables and loop reversing), constant folding & propagation,
copy propagation, dead code elimination and jumptables for 'switch'
statements. For the back-end SDCC uses a global register allocation
scheme which should be well suited for other 8 bit MCUs. The peep
hole optimizer uses a rule based substitution mechanism which is MCU
dependent. Supported data-types are char (8 bits, 1 byte), short
and int (16 bits, 2 bytes), long (32 bit, 4 bytes) and float
(4 byte IEEE). The compiler also allows inline assembler code
to be embedded anywhere in a function. In addition routines developed
in assembly can also be called. SDCC also provides an option to report
the relative complexity of a function, these functions can then be
further optimized, or hand coded in assembly if needed. SDCC also
comes with a companion source level debugger SDCDB, the debugger currently
uses ucSim a freeware simulator for 8051 and other micro-controllers.
The latest version can be downloaded from http://sdcc.sourceforge.net/
.
All packages used in this compiler system are opensource and freeware; source code for all the sub-packages (asxxxx assembler/linker, pre-processor) is distributed with the package. This documentation is maintained using a freeware word processor (LYX).
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2, or (at your option)
any later version. This program is distributed in the hope that it
will be useful, but WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
the GNU General Public License for more details. You should have received
a copy of the GNU General Public License along with this program;
if not, write to the Free Software Foundation, 59 Temple Place - Suite
330, Boston, MA 02111-1307, USA. In other words, you are welcome to
use, share and improve this program. You are forbidden to forbid anyone
else to use, share and improve what you give them. Help stamp out
software-hoarding!
<pending: add a link to gnu>
Throughout this manual, we will use the following convention. Commands you have to type in are printed in "sans serif". Code samples are printed in typewriter font. Interesting items and new terms are printed in italicised type.
This version has numerous bug fixes comperated with the previous version.
But we also introduced some incompatibilaties with older versions.
Not just for the fun of it, but to make the compiler more stable,
efficient and ANSI compliant.
short char
directory structure (2.7)
vararg pars expl int unless casted
never had a regextend
no -noreparms anymore
more?
What do you need before you start installation of SDCC? A computer, and a desire to compute. The preferred method of installation is to compile SDCC from source using GNU GCC and make. For Windows some pre-compiled binary distributions are available for your convenience. You should have some experience with command line tools and compiler use.
The SDCC home page at http://sdcc.sourceforge.net/ is a great place to find distribution sets. You can also find links to the user mailing lists that offer help or discuss SDCC with other SDCC users. Web links to other SDCC related sites can also be found here. This document can be found in the DOC directory of the source package as a text or HTML file. Some of the other tools (simulator and assembler) included with SDCC contain their own documentation and can be found in the source distribution. If you want the latest unreleased software, the complete source package is available directly by anonymous CVS on cvs.sdcc.sourceforge.net.
<pending: is this complete? where is borland, mingw>
For installation under Windows you first need to pick between a pre-compiled
binary package, or installing the source package along with the Cygwin
package. The binary package is the quickest to install, while the
Cygwin package includes all of the open source power tools used to
compile the complete SDCC source package in the Windows environment.
If you are not familiar with the Unix command line environment, you
may want to read the section on additional information for Windows
users prior to your initial installation.
The first thing you should do after installing your SDCC compiler
is to see if it runs. Type "sdcc -version"
at the prompt, and the program should run and tell you the version.
If it doesn't run, or gives a message about not finding sdcc program,
then you need to check over your installation. Make sure that the
sdcc bin directory is in your executable search path defined by the
PATH environment setting (see the Trouble-shooting section for suggestions).
Make sure that the sdcc program is in the bin folder, if not perhaps
something did not install correctly.
SDCC binaries are commonly installed in a directory arrangement like
this:
/usr/local/bin | Holds executables(sdcc, s51, aslink, ...) |
/usr/local/share/sdcc/lib | Holds common C libraries |
/usr/local/share/sdcc/include | Holds common C header files |
The default installation assumes the libraries and header files are located at ``/usr/local/share/sdcc/lib'' and ``/usr/local/share/sdcc/include''. An alternative is to specify these locations as compiler options like this: "sdcc -L /usr/local/sdcc/lib/small -I /usr/local/sdcc/include test.c".
A thing to try is starting from scratch by unpacking the .tgz source
package again in an empty directory. Confure it again and build like:
make 2SPMamp;>1 | tee make.log
After this you can review the make.log file to locate the problem.
Or a relevant part of this be attached to an email that could be helpful
when requesting help from the mailing list.
The ''./configure'' command is a script that analyzes your system and performs some configuration to ensure the source package compiles on your system. It will take a few minutes to run, and will compile a few tests to determine what compiler features are installed.
This runs the GNU make tool, which automatically compiles all the source packages into the final installed binary executables.
This will install the compiler, other executables and libraries in to the appropriate system directories. The default is to copy the executables to /usr/local/bin and the libraries and header files to /usr/local/share/sdcc/lib and /usr/local/share/sdcc/include.
<pending: is this up to date?>
The standard method of installing on a Unix system involves compiling
the source package. This is easily done under Unix, but under Windows
it can be a more difficult process. The Cygwin is a large package
to download, and the compilation runs considerably slower under Windows
due to the overhead of the Cygwin tool set. An alternative is to install
a pre-compiled Windows binary package. There are various trade-offs
between each of these methods.
The Cygwin package allows a Windows user to run a Unix command line interface (bash shell) and also implements a Unix like file system on top of Windows. Included are many of the famous GNU software development tools which can augment the SDCC compiler.This is great if you have some experience with Unix command line tools and file system conventions, if not you may find it easier to start by installing a binary Windows package. The binary packages work with the Windows file system conventions.
SDCC is typically distributed as a tarred/gzipped file (.tgz). This is a packed file similar to a .zip file. Cygwin includes the tools you will need to unpack the SDCC distribution (tar and gzip). To unpack it, simply follow the instructions under the Linux/Unix install section. Before you do this you need to learn how to start a cygwin shell and some of the basic commands used to move files, change directory, run commands and so on. The change directory command is ``cd'', the move command is ``mv''. To print the current working directory, type ``pwd''. To make a directory, use ``mkdir''.
There are some basic differences between Unix and Windows file systems you should understand. When you type in directory paths, Unix and the Cygwin bash prompt uses forward slashes '/' between directories while Windows traditionally uses '\' backward slashes. So when you work at the Cygwin bash prompt, you will need to use the forward '/' slashes. Unix does not have a concept of drive letters, such as ``c:``, instead all files systems attach and appear as directories.
If you use the pre-compiled binaries, the install directories for the libraries and header files may need to be specified on the sdcc command line like this: "sdcc -L c:\usr\local\sdcc\lib\small -I c:\usr\local\sdcc\include test.c" if you are running outside of a Unix bash shell.
If you have successfully installed and compiled SDCC with the Cygwin package, it is possible to compile into native .exe files by using the additional makefiles included for this purpose. For example, with the Borland 32-bit compiler you would run "make -f Makefile.bcc". A command line version of the Borland 32-bit compiler can be downloaded from the Inprise web site.
The ``configure'' command has several options. The most commonly
used option is -prefix=<directory name>, where <directory name> is
the final location for the sdcc executables and libraries, (default
location is /usr/local). The installation process will create the
following directory structure under the <directory name> specified
(if they do not already exist).
bin/ - binary exectables (add to PATH environment variable)
bin/share/
bin/share/sdcc/include/ - include header files
bin/share/sdcc/lib/
bin/share/sdcc/lib/small/ - Object & library files for small model
library
bin/share/sdcc/lib/large/ - Object & library files for large model
library
bin/share/sdcc/lib/ds390/ - Object & library files forDS80C390 library
The command ''./configure -prefix=/usr/local''
will configure the compiler to be installed in directory /usr/local/bin.
SDCC is not just a compiler, but a collection of tools by various developers. These include linkers, assemblers, simulators and other components. Here is a summary of some of the components. Note that the included simulator and assembler have separate documentation which you can find in the source package in their respective directories. As SDCC grows to include support for other processors, other packages from various developers are included and may have their own sets of documentation.
You might want to look at the various executables which are installed
in the bin directory. At the time of this writing, we find the following
programs:
<pending: tabularize this>
sdcc - The compiler.
sdcpp - The C preprocessor.
asx8051 - The assembler for 8051 type processors.
as-z80, as-gbz80 - The Z80 and GameBoy Z80 assemblers.
aslink -The linker for 8051 type processors.
link-z80, link-gbz80 - The Z80 and GameBoy Z80 linkers.
s51 - The ucSim 8051 simulator.
sdcdb - The source debugger.
packihx - A tool to pack Intel hex files.
As development for other processors proceeds, this list will expand
to include executables to support processors like AVR, PIC, etc.
This is the actual compiler, it in turn uses the c-preprocessor and invokes the assembler and linkage editor.
The preprocessor is a modified version of the GNU preprocessor. The C preprocessor is used to pull in #include sources, process #ifdef statements, #defines and so on.
This is retargettable assembler & linkage editor, it was developed by Alan Baldwin. John Hartman created the version for 8051, and I (Sandeep) have made some enhancements and bug fixes for it to work properly with the SDCC.
S51 is a freeware, opensource simulator developed by Daniel Drotos (mailto:drdani@mazsola.iit.uni-miskolc.hu). The simulator is built as part of the build process. For more information visit Daniel's website at: http://mazsola.iit.uni-miskolc.hu/ drdani/embedded/s51 .
Sdcdb is the companion source level debugger. The current version of the debugger uses Daniel's Simulator S51, but can be easily changed to use other simulators.
For single source file 8051 projects the process is very simple. Compile
your programs with the following command "sdcc
sourcefile.c". This will compile, assemble and link your
source file. Output files are as follows
sourcefile.asm - Assembler source file created by the compiler
sourcefile.lst - Assembler listing file created by the Assembler
sourcefile.rst - Assembler listing file updated with linkedit information,
created by linkage editor
sourcefile.sym - symbol listing for the sourcefile, created by the
assembler
sourcefile.rel - Object file created by the assembler, input to Linkage
editor
sourcefile.map - The memory map for the load module, created by the
Linker
sourcefile.ihx - The load module in Intel hex format (you can select
the Motorola S19 format with -out-fmt-s19)
sourcefile.cdb - An optional file (with -debug) containing debug
information
SDCC can compile only ONE file at a time. Let us for example assume
that you have a project containing the following files:
foo1.c (contains some functions)
foo2.c (contains some more functions)
foomain.c (contains more functions and the function main)
The first two files will need to be compiled separately with the commands:
sdcc -c foo1.c
sdcc -c foo2.c
Then compile the source file containing the main() function
and link the files together with the following command:
sdcc foomain.c foo1.rel foo2.rel
Alternatively, foomain.c can be separately compiled as well:
sdcc -c foomain.c
sdcc foomain.rel foo1.rel foo2.rel
The file containing the main() function MUST
be the FIRST file specified in the command line, since the
linkage editor processes file in the order they are presented to it.
Some reusable routines may be compiled into a library, see the documentation
for the assembler and linkage editor (which are in <installdir>/share/sdcc/doc)
for how to create a .lib library file. Libraries created in
this manner can be included in the command line. Make sure you include
the -L <library-path> option to tell the linker where to look for
these files if they are not in the current directory. Here is an example,
assuming you have the source file foomain.c and a library foolib.lib
in the directory mylib (if that is not the same as your current
project):
sdcc foomain.c foolib.lib -L mylib
Note here that mylib must be an absolute path name.
The most efficient way to use libraries is to keep seperate modules
in seperate source files. The lib file now should name all the modules.rel
files. For an example see the standard library file libsdcc.lib
in the directory <installdir>/share/lib/small.
The following options are provided for the purpose of retargetting and debugging the compiler. These provided a means to dump the intermediate code (iCode) generated by the compiler in human readable form at various stages of the compilation process.
In addition to the ANSI storage classes SDCC allows the following MCS51 specific storage classes.
Variables declared with this storage class will be placed in the extern
RAM. This is the default storage class for Large Memory model,
e.g.:
xdata unsigned char xduc;
This is the default storage class for Small Memory model.
Variables declared with this storage class will be allocated in the
internal RAM, e.g.:
data int iramdata;
Variables declared with this storage class will be allocated into
the indirectly addressable portion of the internal ram of a 8051,
e.g.:
idata int idi;
This is a data-type and a storage class specifier. When a variable
is declared as a bit, it is allocated into the bit addressable memory
of 8051, e.g.:
bit iFlag;
Like the bit keyword, sfr / sbit signifies both a data-type
and storage class, they are used to describe the special function
registers and special bit variables of a 8051, eg:
sfr at 0x80 P0; /* special function register P0 at location
0x80 */
sbit at 0xd7 CY; /* CY (Carry Flag) */
SDCC allows (via language extensions) pointers to explicitly point
to any of the memory spaces of the 8051. In addition to the explicit
pointers, the compiler also allows a _generic class of pointers
which can be used to point to any of the memory spaces.
Pointer declaration examples:
/* pointer physically in xternal ram pointing to object
in internal ram */
data unsigned char * xdata p;
/* pointer physically in code rom pointing to data in xdata
space */
xdata unsigned char * code p;
/* pointer physically in code space pointing to data in
code space */
code unsigned char * code p;
/* the folowing is a generic pointer physically located
in xdata space */
char * xdata p;
Well you get the idea.
For compatibility with the previous version of the compiler,
the following syntax for pointer declaration is still supported but
will disappear int the near future.
unsigned char _xdata *ucxdp; /* pointer to data
in external ram */
unsigned char _data *ucdp ; /* pointer to data
in internal ram */
unsigned char _code *uccp ; /* pointer to data
in R/O code space */
unsigned char _idata *uccp; /* pointer to upper
128 bytes of ram */
All unqualified pointers are treated as 3-byte (4-byte for the ds390)
generic pointers. These type of pointers can also to be explicitly
declared.
unsigned char _generic *ucgp;
The highest order byte of the generic pointers contains the
data space information. Assembler support routines are called whenever
data is stored or retrieved using generic pointers. These are
useful for developing reusable library routines. Explicitly specifying
the pointer type will generate the most efficient code. Pointers declared
using a mixture of OLD and NEW style could have unpredictable results.
Automatic (local) variables and parameters to functions can either be placed on the stack or in data-space. The default action of the compiler is to place these variables in the internal RAM (for small model) or external RAM (for Large model). This in fact makes them static so by default functions are non-reentrant.
They can be placed on the stack either by using the -stack-auto
compiler option or by using the reentrant keyword in the function
declaration, e.g.:
unsigned char foo(char i) reentrant
{
...
}
Since stack space on 8051 is limited, the reentrant keyword
or the -stack-auto option should be used sparingly. Note that
the reentrant keyword just means that the parameters & local variables
will be allocated to the stack, it does not mean that the function
is register bank independent.
Local variables can be assigned storage classes and absolute addresses,
e.g.:
unsigned char foo() {
xdata unsigned char i;
bit bvar;
data at 0x31 unsiged char j;
...
}
In the above example the variable i will be allocated in the
external ram, bvar in bit addressable space and j in
internal ram. When compiled with -stack-auto or when a function
is declared as reentrant this can only be done for static variables.
Parameters however are not allowed any storage class, (storage classes for parameters will be ignored), their allocation is governed by the memory model in use, and the reentrancy options.
For non-reentrant functions SDCC will try to reduce internal ram space usage by overlaying parameters and local variables of a function (if possible). Parameters and local variables of a function will be allocated to an overlayable segment if the function has no other function calls and the function is non-reentrant and the memory model is small. If an explicit storage class is specified for a local variable, it will NOT be overlayed.
Note that the compiler (not the linkage editor) makes the decision for overlaying the data items. Functions that are called from an interrupt service routine should be preceded by a #pragma NOOVERLAY if they are not reentrant.
Also note that the compiler does not do any processing of inline assembler code, so the compiler might incorrectly assign local variables and parameters of a function into the overlay segment if the inline assembler code calls other c-functions that might use the overlay. In that case the #pragma NOOVERLAY should be used.
Parameters and Local variables of functions that contain 16 or 32
bit multiplication or division will NOT be overlayed since these are
implemented using external functions, e.g.:
#pragma SAVE
#pragma NOOVERLAY
void set_error(unsigned char errcd)
{
P3 = errcd;
}
#pragma RESTORE
void some_isr () interrupt 2 using 1
{
...
set_error(10);
...
}
In the above example the parameter errcd for the function set_error
would be assigned to the overlayable segment if the #pragma NOOVERLAY
was not present, this could cause unpredictable runtime behavior when
called from an ISR. The #pragma NOOVERLAY ensures that the parameters
and local variables for the function are NOT overlayed.
SDCC allows interrupt service routines to be coded in C, with some
extended keywords.
void timer_isr (void) interrupt 2 using 1
{
..
}
The number following the interrupt keyword is the interrupt
number this routine will service. The compiler will insert a call
to this routine in the interrupt vector table for the interrupt number
specified. The using keyword is used to tell the compiler to
use the specified register bank (8051 specific) when generating code
for this function. Note that when some function is called from an
interrupt service routine it should be preceded by a #pragma NOOVERLAY
if it is not reentrant. A special note here, int (16 bit) and long
(32 bit) integer division, multiplication & modulus operations are
implemented using external support routines developed in ANSI-C, if
an interrupt service routine needs to do any of these operations then
the support routines (as mentioned in a following section) will have
to be recompiled using the -stack-auto option and the source
file will need to be compiled using the -int-long-rent compiler
option.
If you have multiple source files in your project, interrupt service routines can be present in any of them, but a prototype of the isr MUST be present or included in the file that contains the function main.
Interrupt Numbers and the corresponding address & descriptions for
the Standard 8051 are listed below. SDCC will automatically adjust
the interrupt vector table to the maximum interrupt number specified.
Interrupt # | Description | Vector Address |
0 | External 0 | 0x0003 |
1 | Timer 0 | 0x000B |
2 | External 1 | 0x0013 |
3 | Timer 1 | 0x001B |
4 | Serial | 0x0023 |
If the interrupt service routine is defined to be using a specific register bank then only a, b & dptr are save and restored, if such an interrupt service routine calls another function (using another register bank) then the entire register bank of the called function will be saved on the stack. This scheme is recommended for larger interrupt service routines.
Calling other functions from an interrupt service routine is not recommended,
avoid it if possible.
Also see the _naked modifier.
A special keyword may be associated with a function declaring it as
critical. SDCC will generate code to disable all interrupts
upon entry to a critical function and enable them back before returning.
Note that nesting critical functions may cause unpredictable results.
int foo () critical
{
...
...
}
The critical attribute maybe used with other attributes like reentrant.
A special keyword may be associated with a function declaring it as
_naked. The _naked function modifier attribute prevents
the compiler from generating prologue and epilogue code for that function.
This means that the user is entirely responsible for such things as
saving any registers that may need to be preserved, selecting the
proper register bank, generating the return instruction at
the end, etc. Practically, this means that the contents of the function
must be written in inline assembler. This is particularly useful for
interrupt functions, which can have a large (and often unnecessary)
prologue/epilogue. For example, compare the code generated by these
two functions:
data unsigned char counter;
void simpleInterrupt(void) interrupt 1
{
counter++;
}
void nakedInterrupt(void) interrupt 2 _naked
{
_asm
inc _counter
reti ; MUST explicitly include ret in _naked
function.
_endasm;
}
For an 8051 target, the generated simpleInterrupt looks like:
_simpleIterrupt:
push acc
push b
push dpl
push dph
push psw
mov psw,#0x00
inc _counter
pop psw
pop dph
pop dpl
pop b
pop acc
reti
whereas nakedInterrupt looks like:
_nakedInterrupt:
inc _counter
reti ; MUST explicitly include ret(i) in _naked
function.
While there is nothing preventing you from writing C code inside a
_naked function, there are many ways to shoot yourself in the foot
doing this, and is is recommended that you stick to inline assembler.
The using attribute (which tells the compiler to use a register bank other than the default bank zero) should only be applied to interrupt functions (see note 1 below). This will in most circumstances make the generated ISR code more efficient since it will not have to save registers on the stack.
The using attribute will have no effect on the generated code
for a non-interrupt function (but may occasionally be useful
anyway1).
(pending: I don't think this has been done yet)
An interrupt function using a non-zero bank will assume that it can trash that register bank, and will not save it. Since high-priority interrupts can interrupt low-priority ones on the 8051 and friends, this means that if a high-priority ISR using a particular bank occurs while processing a low-priority ISR using the same bank, terrible and bad things can happen. To prevent this, no single register bank should be used by both a high priority and a low priority ISR. This is probably most easily done by having all high priority ISRs use one bank and all low priority ISRs use another. If you have an ISR which can change priority at runtime, you're on your own: I suggest using the default bank zero and taking the small performance hit.
It is most efficient if your ISR calls no other functions. If your ISR must call other functions, it is most efficient if those functions use the same bank as the ISR (see note 1 below); the next best is if the called functions use bank zero. It is very inefficient to call a function using a different, non-zero bank from an ISR.
Data items can be assigned an absolute address with the at <address>
keyword, in addition to a storage class, e.g.:
xdata at 0x8000 unsigned char PORTA_8255 ;
In the above example the PORTA_8255 will be allocated to the location
0x8000 of the external ram. Note that this feature is provided to
give the programmer access to memory mapped devices attached
to the controller. The compiler does not actually reserve any space
for variables declared in this way (they are implemented with an equate
in the assembler). Thus it is left to the programmer to make sure
there are no overlaps with other variables that are declared without
the absolute address. The assembler listing file (.lst) and the linker
output files (.rst) and (.map) are a good places to look for such
overlaps.
Absolute address can be specified for variables in all storage classes,
e.g.:
bit at 0x02 bvar;
The above example will allocate the variable at offset 0x02 in the
bit-addressable space. There is no real advantage to assigning absolute
addresses to variables in this manner, unless you want strict control
over all the variables allocated.
The compiler inserts a call to the C routine _sdcc__external__startup() at the start of the CODE area. This routine is in the runtime library. By default this routine returns 0, if this routine returns a non-zero value, the static & global variable initialization will be skipped and the function main will be invoked Other wise static & global variables will be initialized before the function main is invoked. You could add a _sdcc__external__startup() routine to your program to override the default if you need to setup hardware or perform some other critical operation prior to static & global variable initialization.
SDCC allows the use of in-line assembler with a few restriction as
regards labels. All labels defined within inline assembler code has
to be of the form nnnnn$ where nnnn is a number less than
100 (which implies a limit of utmost 100 inline assembler labels per
function). It is strongly recommended that each assembly
instruction (including labels) be placed in a separate line (as the
example shows). When the -peep-asm command line option is
used, the inline assembler code will be passed through the peephole
optimizer. This might cause some unexpected changes in the inline
assembler code. Please go throught the peephole optimizer rules defined
in file SDCCpeeph.def carefully before using this option.
_asm
mov b,#10
00001$:
djnz b,00001$
_endasm ;
The inline assembler code can contain any valid code understood by
the assembler, this includes any assembler directives and comment
lines. The compiler does not do any validation of the code within
the _asm ... _endasm; keyword pair.
Inline assembler code cannot reference any C-Labels, however it can
reference labels defined by the inline assembler, e.g.:
foo() {
/* some c code */
_asm
; some assembler code
ljmp $0003
_endasm;
/* some more c code */
clabel: /* inline assembler cannot reference this label
*/
_asm
$0003: ;label (can be reference by inline assembler
only)
_endasm ;
/* some more c code */
}
In other words inline assembly code can access labels defined in inline
assembly within the scope of the funtion.
The same goes the other way, ie. labels defines in inline assembly CANNOT be accessed by C statements.
For signed & unsigned int (16 bit) and long (32 bit) variables, division,
multiplication and modulus operations are implemented by support routines.
These support routines are all developed in ANSI-C to facilitate porting
to other MCUs, although some model specific assembler optimations
are used. The following files contain the described routine, all of
them can be found in <installdir>/share/sdcc/lib.
<pending: tabularise this>
_mulsint.c - signed 16 bit multiplication (calls _muluint)
_muluint.c - unsigned 16 bit multiplication
_divsint.c - signed 16 bit division (calls _divuint)
_divuint.c - unsigned 16 bit division
_modsint.c - signed 16 bit modulus (call _moduint)
_moduint.c - unsigned 16 bit modulus
_mulslong.c - signed 32 bit multiplication (calls _mululong)
_mululong.c - unsigned32 bit multiplication
_divslong.c - signed 32 division (calls _divulong)
_divulong.c - unsigned 32 division
_modslong.c - signed 32 bit modulus (calls _modulong)
_modulong.c - unsigned 32 bit modulus
Since they are compiled as non-reentrant, interrupt service
routines should not do any of the above operations. If this is unavoidable
then the above routines will need to be compiled with the -stack-auto
option, after which the source program will have to be compiled with
-int-long-rent option.
SDCC supports IEEE (single precision 4bytes) floating point numbers.The
floating point support routines are derived from gcc's floatlib.c
and consists of the following routines:
<pending: tabularise this>
_fsadd.c - add floating point numbers
_fssub.c - subtract floating point numbers
_fsdiv.c - divide floating point numbers
_fsmul.c - multiply floating point numbers
_fs2uchar.c - convert floating point to unsigned char
_fs2char.c - convert floating point to signed char
_fs2uint.c - convert floating point to unsigned int
_fs2int.c - convert floating point to signed int
_fs2ulong.c - convert floating point to unsigned long
_fs2long.c - convert floating point to signed long
_uchar2fs.c - convert unsigned char to floating point
_char2fs.c - convert char to floating point number
_uint2fs.c - convert unsigned int to floating point
_int2fs.c - convert int to floating point numbers
_ulong2fs.c - convert unsigned long to floating point number
_long2fs.c - convert long to floating point number
Note if all these routines are used simultaneously the data space
might overflow. For serious floating point usage it is strongly recommended
that the large model be used.
SDCC allows two memory models for MCS51 code, small and large. Modules compiled with different memory models should never be combined together or the results would be unpredictable. The library routines supplied with the compiler are compiled as both small and large. The compiled library modules are contained in seperate directories as small and large so that you can link to either set.
When the large model is used all variables declared without a storage class will be allocated into the external ram, this includes all parameters and local variables (for non-reentrant functions). When the small model is used variables without storage class are allocated in the internal ram.
Judicious usage of the processor specific storage classes and the 'reentrant' function type will yield much more efficient code, than using the large model. Several optimizations are disabled when the program is compiled using the large model, it is therefore strongly recommdended that the small model be used unless absolutely required.
The only model supported is Flat 24. This generates code for the 24
bit contiguous addressing mode of the Dallas DS80C390 part. In this
mode, up to four meg of external RAM or code space can be directly
addressed. See the data sheets at www.dalsemi.com for further information
on this part.
In older versions of the compiler, this option was used with the MCS51
code generator (-mmcs51). Now, however, the '390 has it's own
code generator, selected by the -mds390 switch.
Note that the compiler does not generate any code to place the processor
into 24 bitmode (although tinibios in the ds390 libraries will
do that for you). If you don't use tinibios, the boot loader
or similar code must ensure that the processor is in 24 bit contiguous
addressing mode before calling the SDCC startup code.
Like the -model-large option, variables will by default be
placed into the XDATA segment.
Segments may be placed anywhere in the 4 meg address space using the
usual -*-loc options. Note that if any segments are located above
64K, the -r flag must be passed to the linker to generate the proper
segment relocations, and the Intel HEX output format must be used.
The -r flag can be passed to the linker by using the option -Wl-r
on the sdcc command line. However, currently the linker can not handle
code segments > 64k.
The compiler creates the following #defines.
SDCC performs a host of standard optimizations in addition to some MCU specific optimizations.
The compiler does local and global common subexpression elimination,
e.g.:
i = x + y + 1;
j = x + y;
will be translated to
iTemp = x + y
i = iTemp + 1
j = iTemp
Some subexpressions are not as obvious as the above example, e.g.:
a->b[i].c = 10;
a->b[i].d = 11;
In this case the address arithmetic a->b[i] will be computed only
once; the equivalent code in C would be.
iTemp = a->b[i];
iTemp.c = 10;
iTemp.d = 11;
The compiler will try to keep these temporary variables in registers.
int global;
void f () {
int i;
i = 1; /* dead store */
global = 1; /* dead store */
global = 2;
return;
global = 3; /* unreachable */
}
will be changed to
int global; void f ()
{
global = 2;
return;
}
int f() {
int i, j;
i = 10;
j = i;
return j;
}
will be changed to
int f() {
int i,j;
i = 10;
j = 10;
return 10;
}
Note: the dead stores created by this copy propagation will be eliminated
by dead-code elimination.
Two types of loop optimizations are done by SDCC loop invariant lifting
and strength reduction of loop induction variables. In addition to
the strength reduction the optimizer marks the induction variables
and the register allocator tries to keep the induction variables in
registers for the duration of the loop. Because of this preference
of the register allocator, loop induction optimization causes an increase
in register pressure, which may cause unwanted spilling of other temporary
variables into the stack / data space. The compiler will generate
a warning message when it is forced to allocate extra space either
on the stack or data space. If this extra space allocation is undesirable
then induction optimization can be eliminated either for the entire
source file (with -noinduction option) or for a given function only
using #pragma NOINDUCTION.
Loop Invariant:
for (i = 0 ; i < 100 ; i ++)
f += k + l;
changed to
itemp = k + l;
for (i = 0; i < 100; i++)
f += itemp;
As mentioned previously some loop invariants are not as apparent,
all static address computations are also moved out of the loop.
Strength Reduction, this optimization substitutes an expression by
a cheaper expression:
for (i=0;i < 100; i++)
ar[i*5] = i*3;
changed to
itemp1 = 0;
itemp2 = 0;
for (i=0;i< 100;i++) {
ar[itemp1] = itemp2;
itemp1 += 5;
itemp2 += 3;
}
The more expensive multiplication is changed to a less expensive addition.
This optimization is done to reduce the overhead of checking loop boundaries for every iteration. Some simple loops can be reversed and implemented using a ``decrement and jump if not zero'' instruction. SDCC checks for the following criterion to determine if a loop is reversible (note: more sophisticated compilers use data-dependency analysis to make this determination, SDCC uses a more simple minded analysis).
SDCC does numerous algebraic simplifications, the following is a small
sub-set of these optimizations.
i = j + 0 ; /* changed to */ i = j;
i /= 2; /* changed to */ i >>= 1;
i = j - j ; /* changed to */ i = 0;
i = j / 1 ; /* changed to */ i = j;
Note the subexpressions given above are generally introduced by macro
expansions or as a result of copy/constant propagation.
SDCC changes switch statements to jump tables when the following conditions are true.
Bit shifting is one of the most frequently used operation in embedded
programming. SDCC tries to implement bit-shift operations in the most
efficient way possible, e.g.:
unsigned char i;
...
i>>= 4;
...
generates the following code:
mov a,_i
swap a
anl a,#0x0f
mov _i,a
In general SDCC will never setup a loop if the shift count is known.
Another example:
unsigned int i;
...
i >>= 9;
...
will generate:
mov a,(_i + 1)
mov (_i + 1),#0x00
clr c
rrc a
mov _i,a
Note that SDCC stores numbers in little-endian format (i.e. lowest
order first).
A special case of the bit-shift operation is bit rotation, SDCC recognizes
the following expression to be a left bit-rotation:
unsigned char i;
...
i = ((i << 1) | (i >>
7));
...
will generate the following code:
mov a,_i
rl a
mov _i,a
SDCC uses pattern matching on the parse tree to determine this operation.Variations
of this case will also be recognized as bit-rotation, i.e.:
i = ((i >> 7) | (i <<
1)); /* left-bit rotation */
It is frequently required to obtain the highest order bit of an integral
type (long, int, short or char types). SDCC recognizes the following
expression to yield the highest order bit and generates optimized
code for it, e.g.:
unsigned int gint;
foo () {
unsigned char hob;
...
hob = (gint >> 15) & 1;
..
}
will generate the following code:
61
; hob.c 7
000A E5*01 62
mov a,(_gint + 1)
000C 33 63
rlc a
000D E4 64
clr a
000E 13 65
rrc a
000F F5*02 66
mov _foo_hob_1_1,a
Variations of this case however will not be recognized. It
is a standard C expression, so I heartily recommend this be the only
way to get the highest order bit, (it is portable). Of course it will
be recognized even if it is embedded in other expressions, e.g.:
xyz = gint + ((gint >> 15) & 1);
will still be recognized.
The compiler uses a rule based, pattern matching and re-writing mechanism
for peep-hole optimization. It is inspired by copt a peep-hole
optimizer by Christopher W. Fraser (cwfraser@microsoft.com). A default
set of rules are compiled into the compiler, additional rules may
be added with the -peep-file <filename> option. The rule language
is best illustrated with examples.
replace {
mov %1,a
mov a,%1
} by {
mov %1,a
}
The above rule will change the following assembly sequence:
mov r1,a
mov a,r1
to
mov r1,a
Note: All occurrences of a %n (pattern variable) must denote
the same string. With the above rule, the assembly sequence:
mov r1,a
mov a,r2
will remain unmodified.
Other special case optimizations may be added by the user (via -peep-file
option). E.g. some variants of the 8051 MCU allow only ajmp
and acall. The following two rules will change all ljmp
and lcall to ajmp and acall
replace { lcall %1 } by { acall %1 }
replace { ljmp %1 } by { ajmp %1 }
The inline-assembler code is also passed through the peep hole
optimizer, thus the peephole optimizer can also be used as an assembly
level macro expander. The rules themselves are MCU dependent whereas
the rule language infra-structure is MCU independent. Peephole optimization
rules for other MCU can be easily programmed using the rule language.
The syntax for a rule is as follows:
rule := replace [ restart ] '{' <assembly sequence> '\n'
'}' by '{' '\n'
<assembly
sequence> '\n'
'}' [if <functionName>
] '\n'
<assembly sequence> := assembly instruction (each instruction including
labels must be on a separate line).
The optimizer will apply to the rules one by one from the top in the
sequence of their appearance, it will terminate when all rules are
exhausted. If the 'restart' option is specified, then the optimizer
will start matching the rules again from the top, this option for
a rule is expensive (performance), it is intended to be used in situations
where a transformation will trigger the same rule again. A good example
of this the following rule:
replace restart {
pop %1
push %1 } by {
; nop
}
Note that the replace pattern cannot be a blank, but can be a comment
line. Without the 'restart' option only the inner most 'pop' 'push'
pair would be eliminated, i.e.:
pop ar1
pop ar2
push ar2
push ar1
would result in:
pop ar1
; nop
push ar1
with the restart option the rule will be applied again to the
resulting code and then all the pop-push pairs will be eliminated
to yield:
; nop
; nop
A conditional function can be attached to a rule. Attaching rules
are somewhat more involved, let me illustrate this with an example.
replace {
ljmp %5
%2:} by {
sjmp %5
%2:} if labelInRange
The optimizer does a look-up of a function name table defined in function
callFuncByName in the source file SDCCpeeph.c, with the name
labelInRange. If it finds a corresponding entry the function
is called. Note there can be no parameters specified for these functions,
in this case the use of %5 is crucial, since the function
labelInRange expects to find the label in that particular variable
(the hash table containing the variable bindings is passed as a parameter).
If you want to code more such functions, take a close look at the
function labelInRange and the calling mechanism in source file SDCCpeeph.c.
I know this whole thing is a little kludgey, but maybe some day we
will have some better means. If you are looking at this file, you
will also see the default rules that are compiled into the compiler,
you can add your own rules in the default set there if you get tired
of specifying the -peep-file option.
<pending: this is as far as I got>
SDCC supports the following #pragma directives. This directives are applicable only at a function level.
eg
#pragma SAVE /* save the current settings */
#pragma NOGCSE /* turnoff global subexpression elimination */
#pragma NOINDUCTION /* turn off induction optimizations */
int foo ()
{
...
/* large code */
...
}
#pragma RESTORE /* turn the optimizations back on */
The compiler will generate a warning message when extra space is allocated. It is strongly recommended that the SAVE and RESTORE pragma's be used when changing options for a function.
The following library routines are provided for your convenience.
stdio.h - Contains the following functions printf & sprintf these routines are developed by Martijn van Balen <balen@natlab.research.philips.com>.
%[flags][width][b|B|l|L]type
flags: - left justify output in
specified field width
+ prefix output with
+/- sign if output is signed type
space prefix output with a
blank if it's a signed positive value
width: specifies minimum number
of characters outputted for numbers
or strings.
- For numbers,
spaces are added on the left when needed.
If width starts
with a zero character, zeroes and used
instead of
spaces.
- For strings,
spaces are are added on the left or right (when
flag '-' is
used) when needed.
b/B: byte argument (used
by d, u, o, x, X)
l/L: long argument (used
by d, u, o, x, X)
type: d decimal number
u unsigned decimal
number
o unsigned octal number
x unsigned hexadecimal
number (0-9, a-f)
X unsigned hexadecimal
number (0-9, A-F)
c character
s string (generic pointer)
p generic pointer (I:data/idata,
C:code, X:xdata, P:paged)
f float (still to be
implemented)
Also contains a very simple version of printf (printf_small). This simplified version of printf supports only the following formats.
format output type argument-type
%d decimal short/int
%ld decimal long
%hd decimal char
%x hexadecimal short/int
%lx hexadecimal long
%hx hexadecimal char
%o octal short/int
%lo octal long
%ho octal char
%c character char
%s character _generic pointer
The routine is very stack intesive, -stack-after-data parameter should be used when using this routine, the routine also takes about 1K of code space. It also expects an external function named putchar(char) to be present (this can be changed). When using the %s format the string / pointer should be cast to a generic pointer. eg.
printf_small(``my str %s, my int %d\n'',(char _generic *)mystr,myint);
va_list, va_start, va_arg, va_end.
atoi, atol.
strcpy, strncpy, strcat, strncat, strcmp, strncmp, strchr, strrchr, strspn, strcspn, strpbrk, strstr, strlen, strtok, memcpy, memcmp, memset.
iscntrl, isdigit, isgraph, islower, isupper, isprint, ispunct, isspace, isxdigit, isalnum, isalpha.
//Example:
// #define DYNAMIC_MEMORY_SIZE 0x2000
// .....
// unsigned char xdata dynamic_memory_pool[DYNAMIC_MEMORY_SIZE];
// unsigned char xdata * current_buffer;
// .....
// void main(void)
// {
// ...
// init_dynamic_memory(dynamic_memory_pool,DYNAMIC_MEMORY_SIZE);
// //Now it's possible to use malloc.
// ...
// current_buffer = malloc(0x100);
//
Have not had time to do the more involved routines like printf, will get to them shortly.
By default the compiler uses the global registers ``DPL,DPH,B,ACC'' to pass the first parameter to a routine, the second parameter onwards is either allocated on the stack (for reentrant routines or -stack-auto is used) or in the internal / external ram (depending on the memory model).
In the following example the function cfunc calls an assembler routine asm_func, which takes two parameters.
extern int asm_func(unsigned char, unsigned char);
int c_func (unsigned char i, unsigned char j)
{
return asm_func(i,j);
}
int main()
{
return c_func(10,9);
}
The corresponding assembler function is:-
.globl _asm_func_PARM_2
.globl _asm_func
.area OSEG
_asm_func_PARM_2: .ds 1
.area CSEG
_asm_func:
mov a,dpl
add a,_asm_func_PARM_2
mov dpl,a
mov dpl,#0x00
ret
Note here that the return values are placed in 'dpl' - One byte return value, 'dpl' LSB & 'dph' MSB for two byte values. 'dpl', 'dph' and 'b' for three byte values (generic pointers) and 'dpl','dph','b' & 'acc' for four byte values.
The parameter naming convention is _<function_name>_PARM_<n>, where n is the parameter number starting from 1, and counting from the left. The first parameter is passed in ``dpl'' for One bye parameter, ``dptr'' if two bytes, ``b,dptr'' for three bytes and ``acc,b,dptr'' for four bytes, the varaible name for the second parameter will be _<function_name>_PARM_2.
Assemble the assembler routine with the following command.
asx8051 -losg asmfunc.asm
Then compile and link the assembler routine to the C source file with the following command,
sdcc cfunc.c asmfunc.rel
In this case the second parameter onwards will be passed on the stack, the parameters are pushed from right to left i.e. after the call the left most parameter will be on the top of the stack. Here is an example.
extern int asm_func(unsigned char, unsigned char);
int c_func (unsigned char i, unsigned char j) reentrant
{
return asm_func(i,j);
}
int main()
{
return c_func(10,9);
}
The corresponding assembler routine is.
.globl _asm_func
_asm_func:
push _bp
mov _bp,sp
mov r2,dpl
mov a,_bp
clr c
add a,#0xfd
mov r0,a
add a,#0xfc
mov r1,a
mov a,@r0
add a,r2
mov dpl,a
mov dph,#0x00
mov sp,_bp
pop _bp
ret
The compiling and linking procedure remains the same, however note the extra entry & exit linkage required for the assembler code, _bp is the stack frame pointer and is used to compute the offset into the stack for parameters and local variables.
The external stack is located at the start of the external ram segment, and is 256 bytes in size. When -xstack option is used to compile the program, the parameters and local variables of all reentrant functions are allocated in this area. This option is provided for programs with large stack space requirements. When used with the -stack-auto option, all parameters and local variables are allocated on the external stack (note support libraries will need to be recompiled with the same options).
The compiler outputs the higher order address byte of the external ram segment into PORT P2, therefore when using the External Stack option, this port MAY NOT be used by the application program.
Deviations from the compliancy.
eg
struct s foo1 (struct s parms) /* is invalid in SDCC although allowed
in ANSI */
{
struct s rets;
...
return rets;/* is invalid in SDCC although allowed in ANSI */
}
int (*foo)();
Cyclomatic complexity of a function is defined as the number of independent paths the program can take during execution of the function. This is an important number since it defines the number test cases you have to generate to validate the function. The accepted industry standard for complexity number is 10, if the cyclomatic complexity reported by SDCC exceeds 10 you should think about simplification of the function logic.
Note that the complexity level is not related to the number of lines of code in a function. Large functions can have low complexity, and small functions can have large complexity levels. SDCC uses the following formula to compute the complexity.
complexity = (number of edges in control flow graph) -
(number of nodes in control flow graph) + 2;
Having said that the industry standard is 10, you should be aware that in some cases it may unavoidable to have a complexity level of less than 10. For example if you have switch statement with more than 10 case labels, each case label adds one to the complexity level. The complexity level is by no means an absolute measure of the algorithmic complexity of the function, it does however provide a good starting point for which functions you might look at for further optimization.
Here are a few guide-lines that will help the compiler generate more efficient code, some of the tips are specific to this compiler others are generally good programming practice.
foobar(unsigned int p1, unsigned char ch)
{
unsigned char ch1 = p1 % ch ;
....
}
For the modulus operation the variable ch will be promoted to unsigned int first then the modulus operation will be performed (this will lead to a call to a support routine). If the code is changed to
foobar(unsigned int p1, unsigned char ch)
{
unsigned char ch1 = (unsigned char)p1 % ch ;
....
}
It would substantially reduce the code generated (future versions of the compiler will be smart enough to detect such optimization oppurtunities).
The 8051 family of micro controller have a minimum of 128 bytes of internal memory which is structured as follows
- Bytes 00-1F - 32 bytes to hold up to 4 banks of the registers R7 to R7
- Bytes 20-2F - 16 bytes to hold 128 bit variables and
- Bytes 30-7F - 60 bytes for general purpose use.
Normally the SDCC compiler will only utilise the first bank of registers, but it is possible to specify that other banks of registers should be used in interrupt routines. By default, the compiler will place the stack after the last bank of used registers, i.e. if the first 2 banks of registers are used, it will position the base of the internal stack at address 16 (0X10). This implies that as the stack grows, it will use up the remaining register banks, and the 16 bytes used by the 128 bit variables, and 60 bytes for general purpose use.
By default, the compiler uses the 60 general purpose bytes to hold "near data". The compiler/optimiser may also declare some Local Variables in this area to hold local data.
If any of the 128 bit variables are used, or near data is being used then care needs to be taken to ensure that the stack does not grow so much that it starts to over write either your bit variables or "near data". There is no runtime checking to prevent this from happening.
The amount of stack being used is affected by the use of the "internal stack" to save registers before a subroutine call is made, - -stack-auto will declare parameters and local variables on the stack - the number of nested subroutines.
If you detect that the stack is over writing you data, then the following can be done. -xstack will cause an external stack to be used for saving registers and (if -stack-auto is being used) storing parameters and local variables. However this will produce more and code which will be slower to execute.
-stack-loc will allow you specify the start of the stack, i.e. you could start it after any data in the general purpose area. However this may waste the memory not used by the register banks and if the size of the "near data" increases, it may creep into the bottom of the stack.
-stack-after-data, similar to the -stack-loc, but it automatically places the stack after the end of the "near data". Again this could waste any spare register space.
-data-loc allows you to specify the start address of the near data. This could be used to move the "near data" further away from the stack giving it more room to grow. This will only work if no bit variables are being used and the stack can grow to use the bit variable space.
Conclusion.
If you find that the stack is over writing your bit variables or "near data" then the approach which best utilised the internal memory is to position the "near data" after the last bank of used registers or, if you use bit variables, after the last bit variable by using the -data-loc, e.g. if two register banks are being used and no data variables, -data-loc 16, and - use the -stack-after-data option.
If bit variables are being used, another method would be to try and squeeze the data area in the unused register banks if it will fit, and start the stack after the last bit variable.
The issues for retargetting the compiler are far too numerous to be covered by this document. What follows is a brief description of each of the seven phases of the compiler and its MCU dependency.
SDCC is distributed with a source level debugger. The debugger uses a command line interface, the command repertoire of the debugger has been kept as close to gdb (the GNU debugger) as possible. The configuration and build process is part of the standard compiler installation, which also builds and installs the debugger in the target directory specified during configuration. The debugger allows you debug BOTH at the C source and at the ASM source level.
The -debug option must be specified for all files for which debug information is to be generated. The complier generates a .cdb file for each of these files. The linker updates the .cdb file with the address information. This .cdb is used by the debugger.
When the -debug option is specified the compiler generates extra symbol information some of which are put into the the assembler source and some are put into the .cdb file, the linker updates the .cdb file with the address information for the symbols. The debugger reads the symbolic information generated by the compiler & the address information generated by the linker. It uses the SIMULATOR (Daniel's S51) to execute the program, the program execution is controlled by the debugger. When a command is issued for the debugger, it translates it into appropriate commands for the simulator.
The debugger can be started using the following command line. (Assume the file you are debugging has
the file name foo).
>sdcdb foo
The debugger will look for the following files.
As mention earlier the command interface for the debugger has been deliberately kept as close the GNU debugger gdb, as possible, this will help int integration with existing graphical user interfaces (like ddd, xxgdb or xemacs) existing for the GNU debugger.
Set breakpoint at specified line or function.
sdcdb>break 100
sdcdb>break foo.c:100
sdcdb>break funcfoo
sdcdb>break foo.c:funcfoo
Clear breakpoint at specified line or function.
sdcdb>clear 100
sdcdb>clear foo.c:100
sdcdb>clear funcfoo
sdcdb>clear foo.c:funcfoo
Continue program being debugged, after breakpoint.
Execute till the end of the current function.
Delete breakpoint number 'n'. If used without any option clear ALL user defined break points.
Step program until it reaches a different source line.
Step program, proceeding through subroutine calls.
Start debugged program.
Print type information of the variable.
print value of variable.
load the given file name. Note this is an alternate method of loading file for debugging.
print information about current frame.
Toggle between C source & assembly source.
Send the string following '!' to the simulator, the simulator response is displayed. Note the debugger does not interpret the command being sent to the simulator, so if a command like 'go' is sent the debugger can loose its execution context and may display incorrect values.
"Watch me now. Iam going Down. My name is Bobby Brown"
Two files are (in emacs lisp) are provided for the interfacing with XEmacs, sdcdb.el and sdcdbsrc.el. These two files can be found in the $(prefix)/bin directory after the installation is complete. These files need to be loaded into XEmacs for the interface to work, this can be done at XEmacs startup time by inserting the following into your '.xemacs' file (which can be found in your HOME directory) (load-file sdcdbsrc.el) [ .xemacs is a lisp file so the () around the command is REQUIRED), the files can also be loaded dynamically while XEmacs is running, set the environment variable 'EMACSLOADPATH' to the installation bin directory [$(prefix)/bin], then enter the following command ESC-x load-file sdcdbsrc. To start the interface enter the following command ESC-x sdcdbsrc, you will prompted to enter the file name to be debugged.
The command line options that are passed to the simulator directly are bound to default values in the file sdcdbsrc.el the variables are listed below these values maybe changed as required.
;; Current Listing ::
;;key binding Comment
;;-- ---- ----
;;
;; n sdcdb-next-from-src SDCDB
next command
;; b sdcdb-back-from-src SDCDB
back command
;; c sdcdb-cont-from-src SDCDB
continue command
;; s sdcdb-step-from-src SDCDB
step command
;; ? sdcdb-whatis-c-sexp SDCDB
ptypecommand for data at
;;
buffer point
;; x sdcdbsrc-delete SDCDB
Delete all breakpoints if no arg
;; given
or delete arg (C-u arg x)
;; m sdcdbsrc-frame SDCDB
Display current frame if no arg,
;; given
or display frame arg
;; buffer
point
;; ! sdcdbsrc-goto-sdcdb Goto
the SDCDB output buffer
;; p sdcdb-print-c-sexp SDCDB
print command for data at
;;
buffer point
;; g sdcdbsrc-goto-sdcdb Goto
the SDCDB output buffer
;; t sdcdbsrc-mode Toggles
Sdcdbsrc mode (turns it off)
;;
;; C-c C-f sdcdb-finish-from-src SDCDB
finish command
;;
;; C-x SPC sdcdb-break Set
break for line with point
;; ESC t sdcdbsrc-mode Toggle
Sdcdbsrc mode
;; ESC m sdcdbsrc-srcmode
Toggle list mode
;;
SDCC can target both the Zilog Z80 and the Nintendo Gameboy's Z80-like gbz80. The port is incomplete - long support is incomplete (mul, div and mod are unimplimented), and both float and bitfield support is missing, but apart from that the code generated is correct.
As always, the code is the authoritave reference - see z80/ralloc.c and z80/gen.c. The stack frame is similar to that generated by the IAR Z80 compiler. IX is used as the base pointer, HL is used as a temporary register, and BC and DE are available for holding varibles. IY is currently unusued. Return values are stored in HL. One bad side effect of using IX as the base pointer is that a functions stack frame is limited to 127 bytes - this will be fixed in a later version.
SDCC has grown to be large project, the compiler alone (without the Assembler Package, Preprocessor) is about 40,000 lines of code (blank stripped). The open source nature of this project is a key to its continued growth and support. You gain the benefit and support of many active software developers and end users. Is SDCC perfect? No, that's why we need your help. The developers take pride in fixing reported bugs. You can help by reporting the bugs and helping other SDCC users. There are lots of ways to contribute, and we encourage you to take part in making SDCC a great software package.
Send an email to the mailing list at 'user-sdcc@sdcc.sourceforge.net' or 'devel-sdcc@sdcc.sourceforge.net'. Bugs will be fixed ASAP. When reporting a bug, it is very useful to include a small test program which reproduces the problem. If you can isolate the problem by looking at the generated assembly code, this can be very helpful. Compiling your program with the -dumpall option can sometimes be useful in locating optimization problems.
Sandeep Dutta(sandeep.dutta@usa.net) - SDCC, the compiler, MCS51 code
generator, Debugger, AVR port
Alan Baldwin (baldwin@shop-pdp.kent.edu) - Initial version of ASXXXX
& ASLINK.
John Hartman (jhartman@compuserve.com) - Porting ASXXX & ASLINK for
8051
Dmitry S. Obukhov (dso@usa.net) - malloc & serial i/o routines.
Daniel Drotos <drdani@mazsola.iit.uni-miskolc.hu> - for his Freeware
simulator
Malini Dutta(malini_dutta@hotmail.com) - my wife for her patience
and support.
Unknown - for the GNU C - preprocessor.
Michael Hope - The Z80 and Z80GB port, 186 development
Kevin Vigor - The DS390 port.
Johan Knol - DS390/TINI libs, lots of fixes and enhancements.
Scott Datallo - PIC port.
(Thanks to all the other volunteer developers who have helped with
coding, testing, web-page creation, distribution sets, etc. You know
who you are :-)
This document initially written by Sandeep Dutta
All product names mentioned herein may be trademarks of their respective companies.
This document was generated using the LaTeX2HTML translator Version 2K.1beta (1.47)
Copyright © 1993, 1994, 1995, 1996,
Nikos Drakos,
Computer Based Learning Unit, University of Leeds.
Copyright © 1997, 1998, 1999,
Ross Moore,
Mathematics Department, Macquarie University, Sydney.
The command line arguments were:
latex2html -no_subdir -split 0 -show_section_numbers /tmp/lyx_tmpdir1913F54AWM/lyx_tmpbuf1913544rwj/SDCCUdoc.tex
The translation was initiated by Karl Bongers on 2001-07-05