Ndless features and limitations: Difference between revisions

From Hackspire
Jump to navigation Jump to search
(→‎Syscalls: Remove useless parameter for SYSCALL_CUSTOM)
(→‎Syscalls: syscalls in assembly, OS variables)
Line 24: Line 24:
==Syscalls==
==Syscalls==
[[Syscalls]] are OS functions exposed by Ndless to C and assembly programs. Some syscalls are part of standard libraries and may be used to port programs to the TI-Nspire more easily.
[[Syscalls]] are OS functions exposed by Ndless to C and assembly programs. Some syscalls are part of standard libraries and may be used to port programs to the TI-Nspire more easily.
To call a syscall in assembly, use <tt>syscall(<symbol name>)</tt>.


If you have found an interesting syscall not defined in the latest version of Ndless, you can temporary define it locally to your program with <tt>SYSCALL_CUSTOM()</tt>. For example to call the syscall <tt>int internal_func(char *s)</tt> you have found, define in one of your program's header files:
If you have found an interesting syscall not defined in the latest version of Ndless, you can temporary define it locally to your program with <tt>SYSCALL_CUSTOM()</tt>. For example to call the syscall <tt>int internal_func(char *s)</tt> you have found, define in one of your program's header files:
Line 29: Line 31:
  #define internal_func SYSCALL_CUSTOM(internal_func_addrs, int, char *s)
  #define internal_func SYSCALL_CUSTOM(internal_func_addrs, int, char *s)
This is a temporary workaround which will force a re-build of the program each time a new OS version supported by Ndless comes out. You should suggest the syscall to the Ndless development team to make it standard, publicly available and maintained.
This is a temporary workaround which will force a re-build of the program each time a new OS version supported by Ndless comes out. You should suggest the syscall to the Ndless development team to make it standard, publicly available and maintained.
==OS variables==
Ndless also abstracts access to some OS variables.
To read from or write to these variables in assembly, use <tt>osvar(<symbol name>)</tt>. The address of the variable is returned in <tt>r0</tt>.


==Assembly source code==
==Assembly source code==

Revision as of 00:23, 23 December 2010

Ndless combines an executable loader and utilities to open the TI-Nspire to third-party C and assembly development.

This article covers advanced features of Ndless for developers. If you want to try C and assembly development on the TI-Nspire, start with the tutorial.

Some features described here require Ndless v1.7 or higher.

Entry point

You can optionally define the standard argc and argv parameters in your main function definition to get the current program path in argv[0]:

int main(int argc, char *argv[]) {
  printf("Run from '%s'\n", argv[0]);
}

Global variables

Global variables are generally defined in the BSS section of the executable format.

BSS sections are currently not allocated dynamically by the program loader of Ndless: global variables will make your programs bigger so use them with care, switch to malloc() when necessary.

Global variables with initialization data which requires relocation (for example an array of function pointers) must be relocated manually with the non standard nl_relocdata() because of the limited features of the lightweight program loader.

int global_int;
int* global_array[] = {&global_int};
nl_relocdata((unsigned*)nl_relocdata_data, sizeof(global_array)/sizeof(global_array[0]));
printf("global_int=%i\n", *global_array[0]);

Syscalls

Syscalls are OS functions exposed by Ndless to C and assembly programs. Some syscalls are part of standard libraries and may be used to port programs to the TI-Nspire more easily.

To call a syscall in assembly, use syscall(<symbol name>).

If you have found an interesting syscall not defined in the latest version of Ndless, you can temporary define it locally to your program with SYSCALL_CUSTOM(). For example to call the syscall int internal_func(char *s) you have found, define in one of your program's header files:

static const unsigned internal_func_addrs[] = {0x10123456, 0x10654321}; // non-CAS 1.7 and CAS 1.7 addresses
#define internal_func SYSCALL_CUSTOM(internal_func_addrs, int, char *s)

This is a temporary workaround which will force a re-build of the program each time a new OS version supported by Ndless comes out. You should suggest the syscall to the Ndless development team to make it standard, publicly available and maintained.

OS variables

Ndless also abstracts access to some OS variables.

To read from or write to these variables in assembly, use osvar(<symbol name>). The address of the variable is returned in r0.

Assembly source code

Pure-assembly programs must define the global symbol "main" as their entry point. See src/samples/hella/hella.S.

Always make sure that the assembly files extensions are in uppercase (.S) to let them be preprocessed by the C preprocessor on which Ndless include files depend.

Thumb state

The TI-Nspire ARM9 processor features a Thumb instruction set state which improves compiled code density with 16-bit instructions instead of 32-bit.

Only ARM state main() entry points is currently supported, but other source files may be built in Thumb state. Switching from one state to the other is transparent to C programs as long as the -mthumb-interwork GCC switch is used. To build a .c file in Thumb state, use a GCC command similar to:

test_thumb.o: test_thumb.c
 $(GCC) $(GCCFLAGS) --mthumb-interwork -mthumb -c $< -o $@

Calling syscalls in thumb state is supported by Ndless.

Assembly source files must declare the instruction set to use with the .arm and .thumb directives (ARM is the default). Switching from one mode to the other requires specific tricks.

Newlib

Newlib is an implementation of the C library intended for use on embedded systems, installed with the YAGARTO GNU ARM Toolchain.

Compatibility of Ndless with Newlib has not been tested. You may get definition conflicts and crashes due to Newlib running without the required relocation that Ndless doesn't provide. You should always build your programs with the nspire-ld flag -nostdlib, except if you need the single precision floating-point helper functions internally called by GCC when required (__aeabi_fadd, ...).