The GNU C4x-Tools are a suite of programs for compiling, assembling, linking, running, and debugging programs for the TMS320C3x and TMS320C4x Digital Signal Processors (DSP)s.
Here's the ubiquitous hello world program written in C:
#include <stdio.h>
int main(int argc, char **argv)
{
printf("Hello world!\n");
return 0;
}
and here is a simple Makefile to build this program for a C30 target system:
hello.out: hello.c c4x-gcc -m30 -msmall -g -Wall -O2 -o $ $^ clean: -rm -f *.o *.out *.s *.i *~
where
c4x-gcc
-m30
-msmall
-g
-Wall
-O2
Saving the example program as a file called `hello.c' and then running `make' will generate an executable file `hello.out' that can be loaded and run on a C30 target system.
Running this executable file is more difficult. Somehow it needs to be loaded into the memory of the target system and have control passed to it. With many target systems the program will require to be programmed into EPROM, however for the moment, let's consider a target system with a host interface that allows the program to be downloaded to the target system for the host computer (this may be via a serial interface, shared memory, an ethernet connection, etc.). The C4x-Tools program to download and run a program is `c4x-run', and this can be invoked as:
$ c4x-run hello.out
Note that in many cases this program will not print anything since most embedded systems do not have an output screen on which the message can be displayed. However, some embedded operating systems will provide a means to output the message to a host system (see ???).
To compile a program for the C30 or C40 it is necessary to invoke GCC as
a cross-compiler (since the generated code will not run on the system
that runs the compiler). This can be achieved by invoking the driver
`gcc' with the -b c4x option:
$ gcc -bc4x hello.c
However, it is sometimes necessary to specify the version number
-V version if the native GCC compiler and the C4x cross compiler
are different versions of `gcc'. An alternative approach is to
invoke the c4x cross compiler specifically, for example:
$ c4x-gcc hello.c
Note that `/usr/bin/gcc' is a generic driver which uses the
`-b TARGET' switch (and `-V VERSION' switch) to look up the
actual compiler for the desired target (and version),
`/usr/lib/gcc-lib/TARGET/VERSION/cc1'. Thus many different
versions of GCC can coexist for different targets. The default options
are supplied from a specs file,
`/usr/lib/gcc-lib/TARGET/VERSION/specs'. Give the -v switch
to GCC to see which specs file it uses (and what other files it
uses). If your prefix used for compilation is not `/usr', the above
paths change accordingly.
These `-m' options are defined for the C4x:
-m30 -mc30
-m40 -mc40
-mbig-memory
-mbig
-msmall-memory
-msmall
-mbk
-mno-bk
-mdb
-mno-db
-mdp-isr-reload
-mparanoid
-mmpyi
-mno-mpyi
-mfast-fix
-mno-fast-fix
-mrptb
-mno-rptb
-mrpts=count
-mno-rpts
-mloop-unsigned
-mno-loop-unsigned
-mti
-mregparm
-mmemparm
-mparallel-insns
-mno-parallel-insns
-mparallel-mpy
-mno-parallel-mpy
-mparallel-insns is also specified. These instructions have
tight register constraints which can pessimize the code generation
of large functions.
-maliases
-mno-aliases
_C3x, _TMS320C3x
_C30, _TMS320C30
_C31, _TMS320C31
_C32, _TMS320C32
_C4x, _TMS320C4x
_C40, _TMS320C40
_C44, _TMS320C44
_REGPARM
_BIGMODEL
The program `gcc' (or `c4x-gcc') is just a driver program that
invokes the C preprocessor `cpp', the C compiler `c4x-cc1',
the assembler `c4x-as', and the linker `c4x-ld' in turn. The
behaviour of the `gcc' driver is controlled by a `specs' file
which can be determined by running `gcc' with a -v option,
for example:
$ c4x-gcc -v hello.c Reading specs from /usr/lib/gcc-lib/c4x/egcs-2.93.15/specs gcc version egcs-2.93.15 19990404 (gcc2 ss-980929 experimental)
Note that there is a different `specs' file for every version of each cross compiler installed on the system. You can ignore the contents of these files since you should never need to modify them.
The -v (verbose) option to `gcc' can also be used to see
what actions the `gcc' driver performs and where it looks for
files.
$ c4x-gcc -v -m30 -msmall -O2 hello.c -o hello.out Reading specs from /usr/lib/gcc-lib/c4x/egcs-2.93.15/specs gcc version egcs-2.93.15 19990404 (gcc2 ss-980929 experimental) /usr/lib/gcc-lib/c4x/egcs-2.93.15/cpp -lang-c -v -undef -D__GNUC__=2 \ -D__GNUC_MINOR__=93 -D__OPTIMIZE__ -D_TMS320C3x -D_C3x -D_TMS320C30 \ -D_C30 -D_REGPARM -U_BIGMODEL hello.c /tmp/ccAFdaaa.i GNU CPP version egcs-2.93.15 19990404 (gcc2 ss-980929 experimental) \ (TMS320C[34]x, TI syntax) #include "..." search starts here: #include <...> search starts here: /usr/lib/gcc-lib/c4x/egcs-2.93.15/include /usr/lib/gcc-lib/c4x/egcs-2.93.15/../../../../c4x/include End of search list. The following default directories have been omitted from the search path: /usr/lib/gcc-lib/c4x/egcs-2.93.15/../../../../include/g++-2 /usr/lib/gcc-lib/c4x/egcs-2.93.15/../../../../c4x/sys-include End of omitted list. /usr/lib/gcc-lib/c4x/egcs-2.93.15/cc1 /tmp/ccAFdaaa.i -quiet -dumpbase \ hello.c -m30 -msmall -O2 -version -o /tmp/cc0ahaaa.s GNU C version egcs-2.93.15 19990404 (gcc2 ss-980929 experimental) (c4x) \ compiled by GNU C version 2.7.2.3. /usr/c4x/bin/as -m30 -r -s -o /tmp/ccqGkaaa.o /tmp/cc0ahaaa.s /usr/lib/gcc-lib/c4x/egcs-2.93.15/collect2 --architecture c3x -o hello.out \ /usr/c4x/lib/crt0_3sr.o -L/usr/lib/gcc-lib/c4x/egcs-2.93.15/c3x/small \ -L/usr/lib/gcc-lib/c4x/egcs-2.93.15 -L/usr/c4x/lib /tmp/ccqGkaaa.o -lgcc -lc -lgcc
Looking at this output, it can be seen that `gcc' runs the C preprocessor `cpp' on the source file `hello.c' (specifying a number of macro definitions indicating which CPU model to generate code for, etc.). Note that `cpp' prints out the directories where it searches for header files to include.
The resultant temporary file output by `cpp' is then passed to the C cross compiler `cc1' which converts the preprocessed source code into assembler code that is stored in another temporary file that gets passed to the assembler `as'. This then generates a temporary object file that is linked with the system libraries by `ld'. Note that usually `ld' is a link to a program `collect2' which handles grouping of constructor functions for C++.
One aspect that confuses newcomers to these tools is that there are often two copies of each of the tools, eg, `/usr/bin/c4x-as' and `/usr/c4x/bin/as'. The former is usually invoked from a shell command while the latter is usually invoked from the `gcc' driver.
EGCS supports the C, C++, Objective C, Chill, Java, and Fortran 77 (g77) programming languages. However, Fortran currently won't work as a cross-compiler, Java is awaiting run-time libraries, and I haven't tried Objective C and Chill (an embedded systems language) with the C4x back-end. Front-end patches are also available for Pascal (gpc) and Ada95 (gnat) although I haven't tried these with the C4x back-end either (I've heard of an existence of a Modula-2 front end and several other front ends for more esoteric languages).
The code generated by GCC can be examined by using the compiler
option -S. This will stop the `gcc' driver from assembling
and linking the generated code. Alternatively, the option
--save-temps can be used to prevent GCC from deleting all
its temporary intermediate files.
Wherever possible, GCC tries to emit the low overhead looping
instructions RPTB/RPTS and DB to speed up the execution of
loops.
The generation of parallel instructions is often foiled if GCC detects
the presence of a possible memory alias. Whereas Fortran assumes that a
programmer will not call a function with aliased arrays, C does not make
this assumption and has to assume the worst (the restrict
qualifier in the forthcoming new C standard will help here).
If you know that your functions are never called with aliased pointers,
you can use the compiler option -fargument-noalias. Most of the
time this shouldn't cause any trouble. However, problems can occur with
routines such as when the pointers a and b point to the
same array, as with the following example:
void foo(double *a, double *b, double c, int size)
{
int i;
a[0] = b[0];
for (i = 1; i < size; i++)
a[i] = a[i - 1] + b[i] * c;
}
When compiled with gcc -bc4x -O2 -S, `gcc' generates:
addi3 -2,r1,rc
rptb L7-1
L5:
mpyf3 f2,*ar0++,f0
addf3 f0,*-ar2(1),f0
stf f0,*ar2++
L7:
while gcc -bc4x -O2 -fargument-noalias -S generates:
addi3 -3,r2,rc
mpyf3 f1,*ar0++,f0
cmpi3 0,rc
blt L7
rptb L7-1
L5:
mpyf3 f1,*ar0++,f0
|| addf3 f0,*-ar2(1),f3
stf f3,*ar2++
L7:
addf3 f0,*-ar2(1),f3
stf f3,*ar2++
Note that if ar0 and ar2 are pointing to the same array at
the start of this code snippet, then the MPY||ADD instruction
will load the old value at ar0 but not the new value that is to stored
at the end of the loop.
Similar problems can occur with the following program if called as
fcopy1(foo + 1, foo, 128)
where
float fcopy1(float *a, float *b, int size)
{
int i;
for (i = 0; i < size; i++)
a[i] = b[i];
return 1;
}
The GNU assembler for the c4x is `c4x-as' and this can be invoked to assemble assembler code into an object file.
The linking of object files into an executable is performed by the program `c4x-ld', although this is usually invoked through the GCC driver `gcc'.
To be able to create an executable, `c4x-ld' requires a number of files:
_start and needs to transfer
control to the operating system (if present) or to call the bootstrap
routine which sets up the target system and calls the function
main.
-T option.
The default script resides in `/usr/c4x/lib/ldscripts'.
Optionally other libraries may be required such as the math library
`libm.a' for operations such as sqrt and pow.
The default linker script is `/usr/c4x/lib/ldscripts/c4xcoff.x'. It
defines where all the program sections are to reside in memory. This
linker script includes one non-standard program section .comms
which is a piece of shared memory that my operating system using to
communicate to the host PC. The other program sections are:
.bss
.data
.const
.cinit
.text
.init
.fini
.ctors
.dtors
.stack
.sysmem
malloc).
The default linker script assumes that there is sufficient contiguous
memory starting from address 0 to accomodate the desired program. Note
that the .bss and .const (and .data if it is used)
sections must be contiguous for the small memory model and their
combined size must fit within a 64k page.
OUTPUT_FORMAT("coff-c4x")
SEARCH_DIR(/usr/c4x/lib);
ENTRY(_start)
__SYSMEM_SIZE = DEFINED(__SYSMEM_SIZE) ? __SYSMEM_SIZE : 0x4000;
__STACK_SIZE = DEFINED(__STACK_SIZE) ? __STACK_SIZE : 0x1000;
SECTIONS
{
.comms 64 : {
*(.comms)
}
.bss SIZEOF(.comms) + ADDR(.comms) : {
.bss = .;
*(.bss)
*(COMMON)
end = .;
_end = end;
}
.data SIZEOF(.bss) + ADDR(.bss) :
{
.data = .;
*(.data)
edata = .;
}
.const SIZEOF(.data) + ADDR(.data) :
{
*(.const)
}
.cinit SIZEOF(.const) + ADDR(.const) :
{
cinit = .;
*(.cinit)
}
.text SIZEOF(.cinit) + ADDR(.cinit) : {
.text = .;
*(.init)
*(.text)
___CTOR_LIST__ = .;
LONG(___CTOR_END__ - ___CTOR_LIST__ - 2)
*(.ctors)
LONG(0);
___CTOR_END__ = .;
___DTOR_LIST__ = .;
LONG(___DTOR_END__ - ___DTOR_LIST__ - 2)
*(.dtors)
LONG(0)
___DTOR_END__ = .;
*(.fini)
etext = .;
_etext = etext;
}
.stack SIZEOF(.text) + ADDR(.text) :
{
*(.stack)
. = . + __STACK_SIZE;
}
.sysmem SIZEOF(.stack) + ADDR(.stack) :
{
*(.sysmem)
}
.heap SIZEOF(.sysmem) + ADDR(.sysmem) :
{
. += __SYSMEM_SIZE - SIZEOF(.sysmem);
}
.stab 0 (NOLOAD) :
{
[ .stab ]
}
.stabstr 0 (NOLOAD) :
{
[ .stabstr ]
}
/* The TI tools sets cinit to -1 if the ram model is used. */
cinit = SIZEOF(.cinit) ? cinit : -1;
}
The following symbols are defined by this script (using the same definitions as the TI tools):
.bss Begin of .bss section.
end End of .bss section.
.data Begin of .data section.
edata End of .data section.
.text Begin of .text section.
etext End of .text section.
.cinit Begin of .cinit section.
The contents of object files can be dumped in a variety of formats using
`c4x-objdump'. For example, the option -d can be used to
dump the disassembled contents of the object file.
$ c4x-objdump -d hello.out hello.out: file format coff-c4x Disassembly of section .text: 0000919d <_start> br 000091de <_c_int00> 0000919e <_main> call 000091d8 <___main> 0000919f <_main+1> addi 1,sp 000091a0 <_main+2> ldiu sp,ar0 000091a1 <_main+3> addi 1,ar0 000091a2 <_main+4> ldiu @000085ea <edata+7>,rs 000091a3 <_main+5> sti rs,*-ar0(1) 000091a4 <_main+6> call 0000b520 <_printf> 000091a5 <_main+7> ldiu 0,r0 000091a6 <_main+8> addi -1,sp 000091a7 <_main+9> retsu 000091a8 <___do_global_dtors> push ar4 000091a9 <___do_global_dtors+1> ldiu @000085eb <.const>,ar1 000091aa <___do_global_dtors+2> ldiu *ar1,ar0 000091ab <___do_global_dtors+3> ldi *ar0,r0 000091ac <___do_global_dtors+4> beqd 000091bb <.ef> 000091ad <___do_global_dtors+5> ldiu ar1,ar4 000091ae <___do_global_dtors+6> nop r0
For further information about `c4x-objdump', see the generic `objdump' info pages.
The symbol table can be stripped from an object file using `c4x-strip'. This can make the executable file size much smaller and thus save disk space. However, this won't reduce the memory requirements of the program and will make the program difficult to debug.
The size of the main program sections can be displayed with `c4x-size', for example:
$ c4x-size hello.out text data bss dec hex filename 10788 3485 54208 68481 10b81 hello.out
Symbols within object files can be examined with `c4x-nm', for example:
$ c4x-nm hello.o
00000000 b .bss
00000000 ? .const
00000000 d .data
00000000 t .text
U ___main
00000000 T _main
U _printf
00000000 d data_sec
00000000 t gcc2_compiled.
Library files can be created with the archiver `c4x-ar'.
For further information about `c4x-ar', see the generic `ar' info pages.
An index can be added to the library archive using `c4x-ranlib'.
$ c4x-gdb hello.out (gdb) target c4x
Currently there are no freely available C and math libraries for the C30 or C40 DSPs. Texas Instruments sells these libraries with their compiler (they are not particularly well written but work tolerably well) and this is what I currently use. However, I cannot redistribute it. The alternatives are targetting the GNU C library (glibc) or newlib (from Cygnus Solutions) to the C30/C40. I would recommend the latter since it has been used for a number of embedded processors and is a much more simple library than glibc.
If you use the Texas Instruments C library (`rts30.lib' or `rts40.lib'), you will have to assemble a small file `crt0.s'...
This is a target system dependent operation. There is a generic loader program `c4x-load' that can be used to download an executable file and this is configurable to support different target systems. An example of its use is:
$ c4x-load hello.out
Another generic program `c4x-reset' can be use to reset the target system.
The installation of egcs can be achieved along the following lines:
$ tar xvfz egcs-ss-xxxxx.tgz
$ mkdir egcs-obj $ cd egcs-obj
$ ../egcs/configure --target=c4x --prefix=/usr(Note that if you want GCC installed in `/usr/local/lib/lib-gcc', then use
--prefix=/usr/local which is the default.)
$ make LANGUAGES="c c++"(Note that just typing
make will fail when trying to build the
libraries `libchill,' `libf2c', and `libobjc' for the
languages Chill, Fortran, and Objective C respectively. It will also
fail when checking for the executable suffix unless you have a C
run-time start up file `crt0_4br.o' somewhere accessible.)
$ make install LANGUAGES="c c++"
The compiler can be tested using the `dejagnu' testing harness. This can be installed as follows:
$ ln -s dejagnu-xxx/dejagnu egcs/dejagnu
$ ln -s dejagnu-xxx/tcl egcs/tcl $ ln -s dejagnu-xxx/expect egcs/expect
make check to see if dejagnu runs. It will bleat
that the target board is not defined but it should run the gcc c-torture
compilation tests using unix.exp.
$ make check
DEJAGNU environment variable
to it.
$ export DEJAGNU=~/site.expwhere an example `site.def' file is:
case "$target_triplet" in {
{ "c4x-*" } {
# set target_list { c4x-sim30 c4x-dspt30 }
set target_list { c4x-sim30 }
}
}
This document was generated on 15 April 1999 using the texi2html translator version 1.51a.