TIGCC Tools Suite - HowTo's | (c) TI-Chess Team
Convert Functions To Binary C Arrays | Anno Domini 2000

All informations below are given with courtesy of Zeljko Juric, the author of the TIGCC Standard Library, who worked out the concept.

## Introduction

> If you examine the TIGCC standard library headerfiles you will find some strange looking definitions like:

>     //---------------------------------------------------------
>     // sample taken from sprites.h (TIGCC standard library 2.1)
>     //---------------------------------------------------------
>     #define Sprite8 ((void(*)(int,int,int,char*,void*,int))(int[]){0x48E7, \
>       0x1E00,0x322F,20,0x226F,26,0x3C2F,34,0x302F,22,0xC1FC,30,0x3040,0xD1EF,30, \
>       0x3001,0xE640,0x280,0,-2,0xD1C0,0x241,15,0x7018,0x9041,0x342F,24,0x5342, \
>       0xC42,-1,0x673E,0x4241,0x3A00,0x48C5,0x7800,0x7600,0x1219,0xC46,2,0x6614, \
>       0x3001,0x4640,0x240,255,0x3800,0x2004,0xEBA8,0x4680,0xC190,0x6010,0x3601, \
>       0x2003,0xEBA8,0x4A46,0x6604,0xB190,0x6002,0x8190,0x41E8,30,0x51CA,0xFFCE, \
>       0x4CDF,0x78,0x4E75})

> These macros encapsulate the binary (compiled) code of a function in a really smart way. Due to the fact that till today the TIGCC programming environment cannot handle compile time libraries the above macros are the only way to include just the really used functions into a final binary.

> Zeljko Juric has explained the necessity of these array definitions this way:

> > I have very strong reasons for usage of (very awkward) casting arrays to functions. Namely, such definitions allow that a function which is not called in the program will not be included in the program, and a function which is called more than once will be included just once. The first property would not be true if a function is implemented "normally" function in the header file, and the second property would not be true if a function is implemented as a smart inline macro. In "normal" C compilers, such problems are solved using an external library of object files which contain implementations of all functions, and they would be linked with the program when necessary. But note that TI-GCC linker does not support external libraries of object files, so for a while, such "cryptic" definitions are the only solution!

> The original code of the Sprite8 function looks like this:

>     //------------------------------------------------------------
>     // sample taken from file sources (TIGCC standard library 2.1)
>     // which is located in the include directory
>     //------------------------------------------------------------
>     void Sprite8(int x,int y,int h,unsigned char *sprite,void *buff,int mode)
>     {
>       long addr=(long)buff+30*y+((x>>3)&0xfffe),d1;
>       unsigned int cnt=24-(x&15),data;
>       for(;h--;addr+=30)
>         {
>           data=*sprite++;
>           if(mode==SPRT_AND) *(long*)addr&=~((long)(~data&0xff)<<cnt);
>           else
>             {
>               d1=(long)data<<cnt;
>               if(mode==SPRT_XOR) *(long*)addr^=d1;
>               else *(long*)addr|=d1;
>             }
>         }
>     }

## Conversion Steps

> To convert the above sourcecode to a binary data array is quite simple. The headerfile all.h from the TIGCC Standard Library contains the following undocumented macro (yeah, not only TI deals with undocumented features ;-):

>     #define __MARK(s) asm(".ascii \"" #s "\"");

> This macro inserts a given string somewhere into the code which is very useful for our task.
> Now let us write a tiny program which contains the sprite function instrumented with this macro:

>     //---------------------------------------------
>     // put this code in a file called function.c
>     //---------------------------------------------
>     #include <nostub.h>
>     #include <all.h>

>     int _ti89; // we need just the TI89 version, because the code is calc-independed

>     __MARK(STARTFCT)
>     void Sprite8(int x,int y,int h,unsigned char *sprite,void *buff,int mode)
>     {
>       long addr=(long)buff+30*y+((x>>3)&0xfffe),d1;
>       unsigned int cnt=24-(x&15),data;
>       for(;h--;addr+=30)
>         {
>           data=*sprite++;
>           if(mode==SPRT_AND) *(long*)addr&=~((long)(~data&0xff)<<cnt);
>           else
>             {
>               d1=(long)data<<cnt;
>               if(mode==SPRT_XOR) *(long*)addr^=d1;
>               else *(long*)addr|=d1;
>             }
>         }
>     }
>     __MARK(ENDS_FCT)

>     void main() {}

> In this tiny program the function gets encapsulated with two strings, one at each end. To prevent the compiler from inserting filler bytes for alignment we use in both cases strings of length 8 !

> Now compile the program with: tigcc -O2 function.c This will give us the binary file function.89z. To extract the function from the executable you can use the ttextract utility from the TIGCC tools suite. If you call it with: "ttextract function.89z function.bin STARTFCT ENDS_FCT" it will extract the function code to file function.bin.
> As last step we have to convert function.bin into a data array which can be used within C source codes. This job can be done with utility ttbin2hex like this: "ttbin2hex -b2 function.bin function.txt".
> That's it. File function.txt contains now the C array data of function Sprite8 which can be used to generate the macro.
> How to encapsulate this data into the above macro should be obviously.

> NOTE:
> Under some circumstances the compiler puts data between the start mark and the real start of the function (normally additional string data). Check the binary extraction with the TIGCC Tools Suite disassembler (ttdasm) if you face any problems. Using the function to another place within your code may help.

Thomas Nussbaumer Graz,Austria 29/09/2000