How to make a "NoStub" (kernel-less) program


  
"NoStub" programs are programs which don't need any kernels like DoorsOS, Universal OS, TeOS, PlusShell etc. for the execution (note that this does not imply that they can not work under DoorsOS etc.). Starting from release 2.2 of TIGCCLIB, the TIGCC produces a "NoStub" program by default (there is no need for including nostub.h header file before including any other header files from this library as in releases of TIGCCLIB prior 2.2; this will be explain in more details below). As this release of the library is highly ANSI-compatible, the first example will be the classic Kernighan & Ritchie "Hello world" example (slightly modified, to include clearing the screen and waiting for the keypress):
#define SAVE_SCREEN         // this directive forces saving/restoring the screen

#include <stdio.h>          // standard ANSI C input/output support
#include <kbd.h>            // keyboard handling support, needed for ngetchx

int _ti89, _ti92plus;       // produce both .89z and .9xz files

void _main (void)           // main entry point is function _main
{
  clrscr ();                // clear the screen and reset print position
  printf ("Hello world!");  // do you know what is this?
  ngetchx ();               // wait for a keypress
}
Note that the main entry point is _main, not main as defined in Kernighan & Ritchie. The reason for it is the compatibility with kernels like DoorsOS, Universal OS etc. which propose that the main program entry point is called _main. Also note that _main is a function with void return type (not int as usual), because you can not return a status code to the TIOS. _main will always be a void function, regardless of how you declare it, and you will be eventually warned if you try to return a value from it.

To compile this program (named hello.c), you can use TIGCC Integrated Environment, or you can type from the command line:

tigcc -O2 hello.c

Include switch '-O2' always: it will force the optimization (click here to see much more about compiler command line options). As you can see, defining global symbols named _ti89 or _ti92plus will force generating of the .89z (for TI-89) or .9xz (for TI-92 Plus) executable files. Directive SAVE_SCREEN forces saving content of the screen before the execution and restoring it after the execution of the program.

The users which are familiar with previous releases of TIGCCLIB may ask what had happened with nostub.h header file? Starting from release 2.2 usage of any header file from TIGCCLIB library will automatically include nostub.h header file, except if the global preprocessor symbol USE_KERNEL is defined, or if doors.h header file is included at the beginning (see section How to make a "Doors" program for more info). So, you need to include nostub.h manually only if you don't include any other header files from TIGCCLIB library, which is extremely unlikely. To retain compatibility with programs created with previous version of the library, forced including nostub.h will not cause any damage.

The example given above works, but it is better to use TIOS specific function than ANSI C console functions. First, they are more flexible, and second, they are built-in in the TIOS, so using them will usually produce much shorter code. For example, usage of printf function will increase the size of your program by about 200 bytes, because printf is an advanced high-level function (not present in TIOS) which may do much more than writing "Hello world" on the screen (like formatted output, screen scrolling, etc.). So, to write just "Hello world" on the screen, it is a better idea to use particular TIOS functions like DrawStr to do the same thing: your program will be much shorter and much efficient (although less "standard"). This idea is illustrated in the following (extended) "Hello world" program, which uses only TIOS functions, and which does the following:
#define SAVE_SCREEN

#include <graph.h>
#include <kbd.h>

int _ti89, _ti92plus;

void _main (void)
{
  static WIN_RECT rect = {0, 0, 100, 14};
  ClrScr ();
  FontSetSys (F_8x10);
  DrawStr (3, 3, "Hello world!", A_NORMAL);
  DrawClipRect (&rect, ScrRect, A_NORMAL);
  ngetchx ();
}
Note that SAVE_SCREEN is a new directive introduced in TIGCCLIB 2.0. In previous releases of TIGCCLIB you had to save and restore the screen manually, like in the following example:
#include <graph.h>
#include <kbd.h>

int _ti89, _ti92plus;

void _main (void)
{
  LCD_BUFFER buffer;
  static WIN_RECT rect = {0, 0, 100, 14};
  LCD_save (buffer);
  ClrScr ();
  FontSetSys (F_8x10);
  DrawStr (3, 3, "Hello world!", A_NORMAL);
  DrawClipRect (&rect, ScrRect, A_NORMAL);
  ngetchx ();
  LCD_restore (buffer);
}
See graph.h and kbd.h header files for detailed description of used functions and data types. Be aware of the slight difference between ClrScr defined in graph.h and clrscr defined in stdio.h.

The SAVE_SCREEN directive does exactly the same thing as in the previous example, but the task is automatized (i.e. you need not to explicitely declare the save buffer and to call functions for saving and restoring screen manually). If you are not happy with such allocation (the buffer is allocated on the stack, reducing its size by 3840 bytes), don't use SAVE_SCREEN directive and perform saving and restoring the screen using an other method (for example, using dynamic memory allocation). Note that the total stack size on TI is limited to 16384 bytes.

The disadvantage of "nostub" programs is in fact that they are somewhat longer than "DoorsOS" programs if the program contains many ROM calls (but, in the above example, the "nostub" version is shorter than "Doors" version), and they can not call routines from external files (often called "libraries") whithout special support code. Any other features supported with this library of header files work in both "Doors" and "nostub" mode, so if the difference in the program size is not enormous, and if no external libraries are needed, "nostub" mode is highly recommended. Note that routines defined in these header files contain most of routines which are seen in various external libraries, sometimes maybe with different name and syntax. I think that making a program which is independent of external library files is a big advantage!

Release 2.2 of TIGCCLIB introduces yet another interesting directive. If you put
#define OPTIMIZE_ROM_CALLS
at the beginning of the program, the compiler will reserve one processor register (a5) to keep the base address of TIOS jump table in it. This will make all calls to TIOS routines smaller and faster. The disadvantage of this method is in the fact that a5 register is fully reserved during the execution of the program, so the compiler would have one register less for internal manipulations. The consequence is that it sometimes can produce somewhat longer code when compiling particular expression or statement. Generally, usage of OPTIMIZE_ROM_CALLS usually leads to shorter and faster code, but this need not always to be true. It is best to try and see how it acts on a particular program.

NOTE: Avoid OPTIMIZE_ROM_CALLS in programs which may change its flow asynchronously on an unpredictable way (for example, in event-driven programs). Such programs are mainly all programs which uses some kind of callback functions (like programs which use OSVRegisterTimer, complex dialogs with callback functions, function vcbprintf etc.). There may also be some problems with floating point arithmetic.

If you make a "nostub" program, you also must to know the following facts:

Return to the main index