C and assembly development introduction: Difference between revisions

From Hackspire
Jump to navigation Jump to search
m (→‎A C program: Great job, friends!)
(Add a WSL section back)
 
(27 intermediate revisions by 6 users not shown)
Line 1: Line 1:
This tutorial describes how to set up an environment and use the Ndless SDK to write native Ndless-compatible programs for the TI-Nspire '''on Linux'''.
This tutorial describes how to set up an environment and use the Ndless SDK to write native Ndless-compatible programs for the TI-Nspire.


If you are looking for a Windows tutorial, get one in the development resources of [http://ndlessly.wordpress.com ndlessly].
==Install dependencies==
===On Linux distros===
* '''Make sure your system has the following dependencies''': git, GCC (with c++ support), binutils, GMP (libgmp-dev), MPFR (libmpfr-dev), MPC (libmpc-dev), zlib, boost-program-options, wget. Install them with your system's package manager if not.


==Setting up a development environment==
===On Mac OS X===
*Get the [http://www.unsads.com/projects/nsptools/downloader/download/release/5 Ndless SDK] which resources for C and assembly development on TI-Nspire. This article is written for the Ndless SDK v3.1 beta r695 and higher.
* TODO
*Add the <tt>ndless/bin/</tt> directory of the SDK to your <tt>PATH</tt> environment variable (see [http://www.troubleshooters.com/linux/prepostpath.htm this tutorial]). If you don't like messing with PATH stuff, it's easy to just link the files inside. As root in the sdk/bin directory, run "link ./nspire-* /bin/nspire-*" where * is replaced with gcc, as and ld.
* '''Make sure your system has the following dependencies''': git, GCC (with c++ support), binutils, GMP, MPFR, MPC, boost-program-options, zlib, wget. Install them with your system's package manager if not, for example brew.
*Choose an [[Emulators|emulator]] that will ease the development of programs
*Install a GNU ARM toolchain. You can use the following script:
**No need to be root
**Add $HOME/bin to $PATH
**You need the GMP, MPFR, MPC and CURSES development libraries.


#!/bin/sh
===On Windows===
# Written by Uwe Hermann <uwe@hermann-uwe.de>, released as public domain.
MinGW and MSYS do not work correctly, so use WSL or install Cygwin (32bit, x86). WSL is closer to a real Linux environment and likely easier to set up.  
# Edited by Travis Wiens ( http://blog.nutaksas.com/2009/05/installing-gnuarm-arm-toolchain-on.html )
# Edited by Lionel Debroux for newer gcc/binutils/newlib/gdb versions and nspire-gcc.
 
TARGET=arm-none-eabi
PREFIX=/usr/local
PARALLEL="-j2" # or "-j<number of build jobs>"
 
BINUTILS=binutils-2.23.2 # http://www.gnu.org/software/binutils/
GCC=gcc-4.8.1 # http://gcc.gnu.org/
NEWLIB=newlib-2.0.0 # http://sourceware.org/newlib/
GDB=gdb-7.6 # http://www.gnu.org/software/gdb/
 
mkdir build-binutils
mkdir build
 
# IMPORTANT NOTE: in order to compile GCC 4.8, you need the GMP, MPFR and MPC development libraries.
# For example, if you have installed them yourself in $PREFIX, you'll have to add --with-gmp=$PREFIX --with-mpfr=$PREFIX --with-mpc=$PREFIX.
 
# NOTE: the second rm -rf is commented, because it's not strictly necessary.
 
# Section 1: GNU Binutils.
(wget -c http://ftp.gnu.org/gnu/binutils/$BINUTILS.tar.bz2 && tar xvjf $BINUTILS.tar.bz2 && cd build-binutils && ../$BINUTILS/configure --target=$TARGET --prefix=$PREFIX --enable-interwork --enable-multilib --with-system-zlib --with-gnu-as --with-gnu-ld --disable-nls --with-float=soft --disable-werror && make $PARALLEL all && make install && cd ..) || exit 1;
##rm -rf $BINUTILS $BINUTILS.tar.bz2
 
# Section 2: GCC, step 1.
(wget -c ftp://ftp.gnu.org/gnu/gcc/$GCC/$GCC.tar.bz2 && tar xvjf $GCC.tar.bz2 && cd build && ../$GCC/configure --target=$TARGET --prefix=$PREFIX --enable-interwork --enable-multilib --enable-languages="c,c++" --with-system-zlib --with-newlib --without-headers --disable-shared --with-gnu-as --with-gnu-ld --with-float=soft --disable-werror && make $PARALLEL all-gcc && make install-gcc && cd .. && rm -rf build/*) || exit 1;
##rm -rf $GCC.tar.bz2
 
# Section 3: Newlib.
(wget -c ftp://sourceware.org/pub/newlib/$NEWLIB.tar.gz && tar xvzf $NEWLIB.tar.gz && cd build && ../$NEWLIB/configure --target=$TARGET --prefix=$PREFIX --enable-interwork --enable-multilib --with-gnu-as --with-gnu-ld --disable-nls --with-float=soft --disable-werror && make $PARALLEL && make install && cd .. && rm -rf build/*) || exit 1;
##rm -rf $NEWLIB $NEWLIB.tar.gz
 
# Section 4: GCC, step 2. Yes, this is necessary.
(cd build && ../$GCC/configure --target=$TARGET --prefix=$PREFIX --enable-interwork --enable-multilib --enable-languages="c,c++" --with-system-zlib --with-newlib --disable-shared --with-gnu-as --with-gnu-ld --with-float=soft --disable-werror && make $PARALLEL && make install && cd .. && rm -rf build/*) || exit 1
##rm -rf $GCC
 
# Section 5: GDB.
(wget -c ftp://ftp.gnu.org/gnu/gdb/$GDB.tar.bz2 && tar xvjf $GDB.tar.bz2 && cd build && ../$GDB/configure --target=$TARGET --prefix=$PREFIX --enable-interwork --enable-multilib --disable-werror && make $PARALLEL && make install && cd .. && rm -rf build/*) || exit 1;
##rm -rf $GDB $GDB.tar.bz2
 
# Section 6: elf2flt.
cat > Ndless-elf2flt.patch << EOF
91a92,97
> #define R_ARM_CALL    28
> #define R_ARM_JUMP24  29
> #define R_ARM_TARGET1 38
> #define R_ARM_V4BX    40
> #define R_ARM_TARGET2 41
> #define R_ARM_PREL31  42
647a654,660
>                              case R_ARM_NONE:
>                              case R_ARM_PREL31:
>                              case R_ARM_TARGET1:
>                              case R_ARM_TARGET2:
>                              case R_ARM_CALL:
>                              case R_ARM_V4BX:
>                              case R_ARM_JUMP24:
EOF
 
(cvs -z3 -d:pserver:anonymous@cvs.uclinux.org:/var/cvs checkout -P elf2flt && patch elf2flt/elf2flt.c Ndless-elf2flt.patch && cd build && ../elf2flt/configure --target=$TARGET --prefix=$PREFIX -with-libbfd=../build-binutils/bfd/libbfd.a --with-libiberty=../build-binutils/libiberty/libiberty.a --with-bfd-include-dir=../build-binutils/bfd --with-binutils-include-dir=../$BINUTILS/include && make $PARALLEL && make install && cd .. && rm -rf build/*) || exit 1;


*Create symbolic links to <tt>arm-linux-gnueabi-*</tt> for the different GCC tools (ld, gcc, objcopy, ...) if your installation use custom file names.
====Cygwin====
Install the following dependencies: php (5.6+), libboost-devel, libboost_program_options*, binutils, gcc-core, gcc-g++, git, mpfr, mpfr-devel, gmp, libgmp-devel, libmpc3, libmpc-devel, make, zlib-devel, wget
 
====Windows Subsystem for Linux (WSL)====
Install a distro (which one should not matter much) and continue in the Linux section.
 
==Build and install toolchain and SDK==
*'''Get the latest code from [https://github.com/ndless-nspire/Ndless GitHub]'''
git clone --recursive https://github.com/ndless-nspire/Ndless.git
 
* On Windows, fix the few symlinks, for instance zehn.h in the ndless-sdk/tools/genzehn folder, which has to be deleted then copied there from ndless-sdk/include (and if you intend to rebuild Ndless, utils.c from the resources folder into the different installers folders)
 
* '''Run the SDK's ''build_toolchain.sh'' '''script that will download and build a complete ARM toolchain compatible with Ndless, and install it (edit the <tt>PREFIX</tt> variable at the beginning of the script to change the install location). You don't need to be root for this.
cd ndless-sdk/toolchain/
./build_toolchain.sh
 
Running the script again will continue from the last successful step (not redownloading everything for instance). At the end of a successful build you should see <tt>Done!</tt>. Alternatively you can verify the build using <tt>echo $?</tt>. <tt>0</tt> indicates success.
* Now '''add the following folders to your PATH environment variable'''. On linux, <tt>~/.bash_profile</tt> should be a good place for this, just add something like this to it:
export PATH="[path_to_ndless]/ndless-sdk/toolchain/install/bin:[path_to_ndless]/ndless-sdk/bin:${PATH}"
* '''Build Ndless and the SDK''', in the top level of the repository, run:
make


===Verifying the installation===
===Verifying the installation===
*Open a console, and run:
*Open a console, and run:
  $ nspire-gcc
  $ nspire-gcc
If everything has been correctly set up you should see something similar to:
If everything has been set up correctly you should see something similar to:
  arm-none-eabi-gcc: no input files
  arm-none-eabi-gcc: fatal error: no input files
compilation terminated.


As a convention for the next chapters, lines starting with <tt>$</tt> are commands you should type in a console. Other lines are commands output. You may [http://info.ee.surrey.ac.uk/Teaching/Unix/ pick up a tutorial] to learn the basic Unix commands before we continue.
==2-minute tutorial==
 
As a convention for the next chapters, lines starting with <tt>$</tt> are commands you should type in a console. Other lines are the command's output.
==5-minute tutorial==
===Your first build===
===Your first build===
Ndless comes with sample programs in the ''_samples/'' directory of the Ndless SDK. We will try to build the C Hello World.
Ndless comes with sample programs in the ''samples/'' directory of the Ndless SDK. We will try to build the C Hello World.
Change the current directory of the console:
Change the current directory of the console:
  $ cd "<my_ndless_sdk_copy>/_samples/helloworld"
  $ cd "<my_ndless_sdk_copy>/ndless-sdk/samples/helloworld-sdl"
Check the content of the directory:
Ndless programs are built with ''GNU Make'', which is run with the command <tt>make</tt>. So let's ''make'' the program:
$ ls
Makefile  hello.c
A ''Makefile'' is a script which describes how to build the program. It is interpreted by ''GNU Make'', which is run with the command <tt>make</tt>. So let's ''make'' the program:
  $ make
  $ make
  nspire-gcc -Os -Wall -W -c hello.c
  nspire-gcc -Wall -W -marm -Os -c hello-sdl.c
  nspire-ld -nostdlib hello.o -o hello.elf
mkdir -p .
  mkdir -p ../../calcbin/samples
  nspire-ld hello-sdl.o -o ./helloworld-sdl.elf  
''make'' tells us the different commands used during the building process.
  genzehn --input ./helloworld-sdl.elf --output ./helloworld-sdl.tns --name "helloworld-sdl"
 
make-prg ./helloworld-sdl.tns ./helloworld-sdl.prg.tns
arm-none-eabi-objcopy -O binary hello.elf ../../calcbin/samples/hello.tns
<tt>nspire-gcc</tt> is Ndless's wrapper for the GNU C Compiler ''GCC'', which compiles C and assembly source files to object files (here ''hello.o'').
<tt>nspire-gcc</tt> is Ndless's wrapper for the GNU C Compiler ''GCC'', which compiles C and assembly source files to object files (here ''hello.o'').


<tt>nspire-ld</tt> is the wrapper for the GNU linker ''ld'', which combines object files to produce an executable in the [http://en.wikipedia.org/wiki/Executable_and_Linkable_Format ELF] format (here ''hello.elf'').
<tt>nspire-ld</tt> is the wrapper for ''GCC'', which redirects gcc with the option "-fuse-ld=gold" to use another wrapper "arm-none-eabi-ld.gold" as linker. "arm-none-eabi-ld.gold" adds some necessary libraries to the final program.


<tt>arm-none-eabi-objcopy</tt> is a GNU utility used to convert the ELF file to an Ndless-compatible executable directly runnable on a TI-Nspire. The file ''hello.tns'' can be found in ''src/calcbin/samples''.
<tt>genzehn</tt> converts the executable created by "nspire-ld" to a format, which ndless supports.


===A C program===
<tt>make-prg</tt> adds a simple loader on top so the executable works on older versions of ndless.
Let's have a look at the Hello World source code ''hello.c''. It follows the C conventions.
 
It has an entry point:
int main(void) {
and a return code (required but currently ignored by Ndless and the OS):
  return 0;
}
All Ndless programs requires the standard include file, ''os.h'':
#include <os.h>
 
This allows programs to call ''syscalls'' provided by the TI-Nspire Operating System. Some syscalls are functions from the [http://en.wikipedia.org/wiki/C_standard_library C standard library], others are part of the [http://en.wikipedia.org/wiki/C_POSIX_library C POSIX library]. There are also functions of [http://en.wikipedia.org/wiki/Nucleus_RTOS Nucleus RTOS] on which is based the TI-Nspire OS.
 
We are also using the ''nspireio2'' library provided with the SDK:
#include <nspireio2.h>
 
Let's now say hello with nspireio2:
nio_console csl;
lcd_ingray(); // because nspireio2 doesn't support colors
clrscr(); // clear the screen
// 53 columns, 29 rows. 0px offset for x/y.
// Background color 0 (black), foreground color 15 (white)
nio_InitConsole(&csl, 53, 29, 0, 0, 0, 15);
nio_DrawConsole(&csl);
nio_printf(&csl, "hello world!");
wait_key_pressed();
nio_CleanUp(&csl);


===Your first program===
===Your first program===
You can copy the ''helloworld'' directory and start to adapt the source code.
If you want to create a program from scratch:
If you want to create a program from scratch:
*Create a new directory for the program
*Create a new directory for the program
*Type in a console:
*Type in a console:
  cd "<your directory path>"
  cd "<your directory path>"
  nspire-tools new <program>
  nspire-tools new <name>
:where <program> is your program name. This will create a Makefile to build ''<program>.tns''
:where <name> is your program name. This will create a Makefile to build ''<program>.tns''
*Create a new .c file and edit your program
*Create a new .c file and edit your program
*Run the <tt>make</tt> command to build it
*Run <tt>make</tt> to build it
 
===Going further===
*Pick up a good C tutorial before writing your own programs
*Learn the syntax of [http://www.gnu.org/software/make/manual/make.html GNU Make's Makefiles] to adapt them to your own build requirements
*Learn to use [http://gcc.gnu.org/onlinedocs/gcc/ GNU GCC] features and extensions

Latest revision as of 18:51, 16 May 2022

This tutorial describes how to set up an environment and use the Ndless SDK to write native Ndless-compatible programs for the TI-Nspire.

Install dependencies

On Linux distros

  • Make sure your system has the following dependencies: git, GCC (with c++ support), binutils, GMP (libgmp-dev), MPFR (libmpfr-dev), MPC (libmpc-dev), zlib, boost-program-options, wget. Install them with your system's package manager if not.

On Mac OS X

  • TODO
  • Make sure your system has the following dependencies: git, GCC (with c++ support), binutils, GMP, MPFR, MPC, boost-program-options, zlib, wget. Install them with your system's package manager if not, for example brew.

On Windows

MinGW and MSYS do not work correctly, so use WSL or install Cygwin (32bit, x86). WSL is closer to a real Linux environment and likely easier to set up.

Cygwin

Install the following dependencies: php (5.6+), libboost-devel, libboost_program_options*, binutils, gcc-core, gcc-g++, git, mpfr, mpfr-devel, gmp, libgmp-devel, libmpc3, libmpc-devel, make, zlib-devel, wget

Windows Subsystem for Linux (WSL)

Install a distro (which one should not matter much) and continue in the Linux section.

Build and install toolchain and SDK

  • Get the latest code from GitHub
git clone --recursive https://github.com/ndless-nspire/Ndless.git
  • On Windows, fix the few symlinks, for instance zehn.h in the ndless-sdk/tools/genzehn folder, which has to be deleted then copied there from ndless-sdk/include (and if you intend to rebuild Ndless, utils.c from the resources folder into the different installers folders)
  • Run the SDK's build_toolchain.sh script that will download and build a complete ARM toolchain compatible with Ndless, and install it (edit the PREFIX variable at the beginning of the script to change the install location). You don't need to be root for this.
cd ndless-sdk/toolchain/
./build_toolchain.sh

Running the script again will continue from the last successful step (not redownloading everything for instance). At the end of a successful build you should see Done!. Alternatively you can verify the build using echo $?. 0 indicates success.

  • Now add the following folders to your PATH environment variable. On linux, ~/.bash_profile should be a good place for this, just add something like this to it:
export PATH="[path_to_ndless]/ndless-sdk/toolchain/install/bin:[path_to_ndless]/ndless-sdk/bin:${PATH}"
  • Build Ndless and the SDK, in the top level of the repository, run:
make

Verifying the installation

  • Open a console, and run:
$ nspire-gcc

If everything has been set up correctly you should see something similar to:

arm-none-eabi-gcc: fatal error: no input files
compilation terminated.

2-minute tutorial

As a convention for the next chapters, lines starting with $ are commands you should type in a console. Other lines are the command's output.

Your first build

Ndless comes with sample programs in the samples/ directory of the Ndless SDK. We will try to build the C Hello World. Change the current directory of the console:

$ cd "<my_ndless_sdk_copy>/ndless-sdk/samples/helloworld-sdl"

Ndless programs are built with GNU Make, which is run with the command make. So let's make the program:

$ make
nspire-gcc -Wall -W -marm -Os -c hello-sdl.c
mkdir -p .
nspire-ld hello-sdl.o -o ./helloworld-sdl.elf 
genzehn --input ./helloworld-sdl.elf --output ./helloworld-sdl.tns --name "helloworld-sdl"
make-prg ./helloworld-sdl.tns ./helloworld-sdl.prg.tns

nspire-gcc is Ndless's wrapper for the GNU C Compiler GCC, which compiles C and assembly source files to object files (here hello.o).

nspire-ld is the wrapper for GCC, which redirects gcc with the option "-fuse-ld=gold" to use another wrapper "arm-none-eabi-ld.gold" as linker. "arm-none-eabi-ld.gold" adds some necessary libraries to the final program.

genzehn converts the executable created by "nspire-ld" to a format, which ndless supports.

make-prg adds a simple loader on top so the executable works on older versions of ndless.

Your first program

If you want to create a program from scratch:

  • Create a new directory for the program
  • Type in a console:
cd "<your directory path>"
nspire-tools new <name>
where <name> is your program name. This will create a Makefile to build <program>.tns
  • Create a new .c file and edit your program
  • Run make to build it