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:
- saves the content of the screen;
- clears the screen;
- displays the "Hello world!" message using big font;
- draws a border around the message;
- waits for a keypress;
- restores the original content of the screen before returning.
#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: