Making Kernel-Less (NoStub) Programs

Making TIGCC Programs Next

NoStub programs are programs which don't need any kernel like DoorsOS, Universal OS, TeOS, PlusShell etc. for execution. This does not imply that they do not work with a kernel installed. Starting from release 2.2 of TIGCCLIB, TIGCC produces NoStub programs by default (there is no need to include nostub.h before including any other header files from this library as in releases of TIGCCLIB prior 2.2; this will be explained 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 (called "Hello World 1", slightly modified to include clearing the screen and waiting for the keypress):

#define SAVE_SCREEN         // this directive forces saving/restoring the screen

#define USE_TI89            // produce all types of files
#define USE_TI92PLUS
#define USE_V200

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

void _main(void)            // main entry point is function _main
{
  clrscr ();                // clear the screen and reset print position
  printf ("Hello world!");  // do you know what this is?
  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, which propose that the main program entry point is called _main. Also note that _main should be a function with return type void (not int as usual), because you can not return a status code to the operating system.

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

tigcc -O2 hello.c

Always include the switch '-O2'. It will turn on optimization (click here to see much more about compiler command line options).

As you can see, defining macros named USE_TI89, USE_TI92PLUS (or USE_TI92P), and USE_V200 will generate .89z (for the TI-89) or .9xz (for the TI-92 Plus and V200) executable files. Only the calculators which you define this way are supported; if you only define USE_TI89, then only the TI-89 will be supported. Defining only one calculator model may generate shorter and faster code. See compat.h for more info.

The old way of defining global variables called _ti89 and _ti92plus is still supported, but it is not recommended to use it any more, since no optimization of the above kind can be performed. In the IDE, you will find replacements for these macros in the project options.

The directive SAVE_SCREEN forces saving the screen contents before execution and restoring them after execution of the program.

Users which are familiar with previous releases of TIGCCLIB may ask what has happened to the nostub.h header file. Starting from release 2.2 the use of any header file from TIGCCLIB will automatically include the nostub.h header file, except if the global preprocessor symbol USE_KERNEL is defined, or if the doors.h is included at the beginning (see section How to make a kernel-based program for more info). This way you need to include nostub.h manually only if you don't include any other header file from TIGCCLIB, which is extremely unlikely. To retain compatibility with programs created with previous versions of the library, including nostub.h explicitly will not cause any damage.

The example given above works, but it is better to use TIOS-specific functions than ANSI C console functions. First, they are more flexible, and second, they are built-in in the OS, so using them will usually produce much shorter code. For example, the use of the printf function will increase the size of your program by about 200 bytes, because printf is an advanced high-level function (not present in the 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 more efficient (although less "standard"). This idea is illustrated in the following program ("Hello World 2"), which uses only TIOS functions, and which does the following:
#define SAVE_SCREEN

#define USE_TI89
#define USE_TI92PLUS
#define USE_V200

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

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 ("Hello World 3"):
#define USE_TI89
#define USE_TI92PLUS
#define USE_V200

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

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 for detailed descriptions of the 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 that they are somewhat longer than kernel programs if the program contains many ROM calls (but in the above example, the NoStub version is shorter than the kernel 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 kernel 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 a different name and syntax. I think that making a program which is independent of external library files is a big advantage!

If you make a NoStub program, you must also know that the exit point defined by the function _exit has no meaning in NoStub programs.


See also: nostub.h