Transputer backend overview --------------------------- Transputer backend is not part of GCC distribution yet; instead, it is available as a patch against the "official" GCC 2.7.2 distribution (gcc-2.7.2.tar.gz). It allows one to build a cross compiler that runs on a host capable of running GCC in general and produces transputer assembly language output. Features and peculiarities ~~~~~~~~~~~~~~~~~~~~~~~~~~ * SUPPORTED: code generation for most (all?) 32-bit transputers (t800, t805, t425, t9000, t450) * SUPPORTED: asm_operands. * SUPPORTED: floating point instructions. However, no attempt is made to optimize ALU and FPU operation overlapping. * UNSUPPORTED: debugging info output. Just not ripe enough for now. * UNSUPPORTED: nested functions (GNU extension to C). You can work around this limitation by using a preprocessor macro instead. * if you want code quality to be any decent, compile with -O. That's because reload pass cannot do well for transputer without register life info. Run-time models supported ~~~~~~~~~~~~~~~~~~~~~~~~~ There are currently two of them. The first (generic) one is a home-made model, hardly corresponding to any other model in existence. In this model, no static chain is passed in function call; instead, global data are addressed relative to program counter (Iptr). First three words of function arguments are passed on integer register stack. The benefits of this model are compact function prologues and cheap function calls; on the other hand, it leaves no way to implement a stack expansion scheme. The binary tools (assembler, linker, etc.) for use with this model are now available. Check , or . Some libraries are available too -- thanks to Roman Pozlevich The second model (Expert) is compatible with the one used by ACE Expert compilers in the Parix OS. The description of the model can be found in the Parix documentation. The two models are very different, and hopefully solve most problems that might arise when porting GCC to other transputer-based platforms. Transputer-specific compiler options ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -mt800, -mt805, -mt425, -mt9000, -mt450 Run-time selection of target CPU type. Default is the processor type you give to configure when building the compiler. -mfpu, -mno-fpu -mfpentry, -mno-fpentry -mfpge, -mno-fpge -mpop, -mno-pop -mgtu, -mno-gtu -msixteen, -mno-sixteen -mxtend, -mno-xtend -mslmul, -mno-slmul Switches that enable/disable use of certain CPU capabilities. Each of the -mtNNN target CPU selection options actually works by setting certain combination of these. Hope you don't want to fiddle with them; but if you do, search config/t800.h for their meaning. -mshort16, -mshort32 Size for the "short int" type in bits. Default is 16 on transputers that have support for 16-bit memory access (ls/ss), 32 on transputers that don't have it. Specifying -mshort16 in the latter case results in implementation of halfword stores using shift and byte store instructions. Random examples of inline assembly usage ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ get_timer () { int tmp; asm volatile ("ldtimer" : "=a" (tmp) : /* no inputs */ ); return tmp; } This asm takes no inputs, and pushes one word of result onto the integer reg-stack, according to the `a' constraint. Constraint letters meaning: a,b,c Areg,Breg,Creg respectively t,v,u FAreg, FBreg, FCreg respectively P popped input constraint modifier. Example 2. void outword (unsigned word, unsigned chan) { asm volatile ("outword" : /* no outputs */ : "bP" (chan), "aP" (word) : "Areg", "Breg", "Creg", "FAreg", "FBreg", "FCreg", "Wreg[0]"); } This asm consumes two inputs which come in Areg and Breg. The modifier constraint `P' indicates that the input is popped off the stack by the asm. The clobber section indicates that the asm clobbers all stack registers. "Wreg[0]" in the clobber section indicates that this asm destroys the value of the word at the top of workspace. Note that "Wreg[0]" is just an identifier; you cannot write, say, "Wreg[1]" here. Note that popping constraint is not a substitute for a clobber; thus, following asm would not reflect the fact that all registers are clobbered by this asm (and so is incorrect): void outword (unsigned word, unsigned chan) { asm volatile ("outword" : /* no outputs */ : "bP" (chan), "aP" (word) : "Creg", "FAreg", "FBreg", "FCreg", "Wreg[0]"); } Example 3. float square_root (float x) { register float tmp; asm ("fpusqrtfirst\n\t" "fpusqrtstep\n\t" "fpusqrtstep\n\t" "fpusqrtlast" : "=t" (tmp) : "tP" (x) : "FBreg", "FCreg"); return tmp; } This asm pops its input off floating reg-stack, and pushes the result back onto the floating reg-stack. Example 4, from real life static inline int lit_load_in_byte (void) { int tmp = 0; extern int boot_link_in; asm volatile ("in" : /* no outputs */ : "cP" (&tmp), "bP" (boot_link_in), "aP" (1) : "Areg", "Breg", "Creg", "FAreg", "FBreg", "FCreg", "memory"); return tmp; } Here the asm inputs a byte from a link whose address is stored in `boot_link_in'. Note that this asm has no explicit outputs, but puts its result into memory (the `tmp' variable) as a side-effect. You have to explicitly tell the compiler that the asm modifies memory; that's what the "memory" in the clobber section of the asm is for. Without it, the optimiser would rightfully optimize this function to always return 0. Note that the order of input operands in asms matters: supplying the operands in reverse order (Creg, Breg, Areg), as in the above asm, tends to give better code. One more example, making use of local temporary variable (from Roman Pozlevich, ): int *alt (int* first, ...) { int *res, **ptr; __asm__ __volatile__ ( " alt \n\t" " ldlp %w2; stl %w1 \n\t" "0: \n\t" " ldl %w1; ldnl 0; cj 1f \n\t" " ldl %w1; ldnl 0; ldc 1; enbc \n\t" " ldl %w1; ldnlp 1; stl %w1 \n\t" " ldc 0; cj 0b \n\t" "1: \n\t" " altwt \n\t" " ldlp %w2; stl %w1 \n\t" "0: \n\t" " ldl %w1; ldnl 0; cj 1f \n\t" " ldl %w1; ldnl 0; dup; ldc 1; rev; disc \n\t" " eqc 0; cj 1f \n\t" " ldl %w1; ldnlp 1; stl %w1 \n\t" " ldc 0; cj 0b \n\t" "1: \n\t" " ldl 0 \n\t" : "=a" (res) : "m" (ptr), "m" (first) : "Breg", "Creg", "FAreg", "FBreg", "FCreg", "Wreg[0]" ); return res; } You most likely don't want to understand what this code is doing, but note the use of "m" constraint for local variables, and the use of "%wN" to obtain stack offset in words for Nth operand of the asm. Where to get T800 patches ~~~~~~~~~~~~~~~~~~~~~~~~~ The most recent version is always at ftp://ftp.botik.ru/pub/local/gcc-t800/gcc-2.7.2 The port as a diff against gcc-2.7.2 is in the file gcc-2.7.2-t800.NNN.dif.gz, where NNN is the alpha release number. You most probably want to pick the largest numbered one. patchNNN.gz contains patches from alpha release MMM to alpha release NNN, where MMM=NNN-1. changesNNN contain a short overview of the changes. You can also find gcc-t800 at the mirror in UK: ftp://unix.hensa.ac.uk/pub/parallel/transputer/software/compilers/gcc/pereslavl/ http://www.hensa.ac.uk/parallel/transputer/software/compilers/gcc/pereslavl/ Feedback ~~~~~~~~ Please e-mail bug reports to me at . DO NOT send any bug reports for gcc-t800 to the GNU bug-gcc list where GCC bugs normally go; gcc-t800 is not yet an official part of GCC. There is a (mostly inactive) mailing list for gcc-t800: . If you want to subscribe to the list, send e-mail with a line like this: subscribe to . Installation ~~~~~~~~~~~~ (1) Apply T800 patches to the stock GCC distribution: cd gcc-2.7.2 gzip -dc gcc-2.7.2-t800.12.dif.gz | patch -p1 (2) Configure the sources for the target of your choice. Example 1: configure for `generic' model. This is what you need if you are going to use gcc-t800 with TTOOLS. ./configure --target=t800 Note: this chooses t800 as the default CPU type. You can however use the compiler thus built for other cpu types by running `gcc -mt425', for example. Example 2: configure for `expert' model ./configure --target=t800-parix Example 3: configure for `expert' model, install in a private directory rather than in /usr/local ./configure --target=t800-parix --prefix=$(HOME)/usr (3) If you are impatient and want to try it out quickly, do make LANGUAGES=c CC=gcc cc1 cc1 -O pself.c more pself.s (4) Follow the normal procedure for building and installing a cross compiler, described in INSTALL. In short, the following might work: make LANGUAGES=c CC=gcc make install While making, you will see warnings about `-g' and `-g1' options being unsupported by the compiler -- indeed, debugging info output is not yet supported. Ignore the warnings. Acknowledgements ~~~~~~~~~~~~~~~~ FSF people provided the World with the GNU C Compiler. Sergei Abramov enabled me to work on this port. Kriton Kyrimis of High Performance Computing Laboratory, Athens, inspired the port to Parix/GCel, and helped to work on it. This work was in part supported by INTAS--International Association for the promotion of cooperation with scientists from the independent states of the former Soviet Union; grant # INTAS-93-0972 Dave Beckett easies life to the downloaders of the package by mirroring gcc-t800 and TTOOLS at unix.hensa.ac.uk. Thanks to all. $Revision: 1.17 $