 |
Making Kernel-Less (NoStub) Programs |
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:
- saves the contents of the screen;
- clears the screen;
- displays the "Hello world!" message using the large font;
- draws a border around the message;
- waits for a keypress;
- restores the original contents of the screen before returning.
#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