Basics

 

Starting the system

When the processor first starts, it has to pick up its first instruction from somewhere, this is determined by the people that made the processor, sometimes the first instruction is at location 0, sometimes it is at the last memory location, it depends. In our case, our initial stack pointer and the address of the first instruction is stored at location 0, and 4 respectively.

The stack pointer normally points at the last address of RAM. It is the LAST location since the stack grows towards address 0.

The first instruction will be stored in ROM somewhere, since we don't have such things as disk drives and the application has not been loaded into RAM.

So, when the processor starts, it picks up the stack pointer from location 0 and puts it into the SP (stack pointer) register. It picks up the address of the first instruction and places it into the PC (program counter) register. Next, it starts executing instructions at the position pointed to by the PC, our first instruction.

So far we have seen what the first two longwords of memory contains. Following these two longwords is the interrupt vector table for another 254 longwords for a total of 256 longwords or 1024 bytes (a longword being 4 bytes). It ends up looking like:

Address     Contents      What it contains

0x000000    0x13FFFF      Initial stack pointer (0x13FFFF)

0x000004    0x000400      Initial program counter (0x400 in this case)

0x000008                  Address of the bus error handling routine

0x00000C                  Address of the address error handling routine

0x000010                  Address of the illegal instruction handling routine

0x000014                  Address of the zero division handling routine

...                                                        ...

0x0003F8                  Address of the user defined vector handling routine

0x0003FC                  Address of the user defined vector handling routine

0x000400                  Typical first executable instruction

...

0x03FFFC                  Last longword of ROM

0x040000    ????????      Unassigned space location

...

0x0FFFFF                  Last location of unassigned space

0x100000                  First byte of RAM, first location of the heap

...

0x13FFFF                  Last byte of RAM, first location of the stack

0x140000    ???????       Unassigned space

...

????????

The code and other values in ROM are put in there before the system is turned on. It is either done by a programming tool like a EPROM programmer or using some sort of in circuit programmer like a BDM pod.

The values in RAM are lost when the system looses power. Don't expect anything to be stored there between runs.

crts0

Many years ago, a structure was put in place to start C programs on an operating system. A C program starts executing at the beginning. Well duh! But wait, you have to do stuff before the beginning. The system provides a piece of startup code called the C runtime startup or crts. In most systems based vaguely on UNIX, this was a file called crts0 which was placed before any of your executable code. crts0 sets up the execution environment for the C program like initializing all of your variables, setting up all command line parameters and environment variables, then calls the routine called “main”. This is why C programs always have their starting point as the routine called “main”.

One of the things that crts0 is responsible for is initializing your variables. C specifies that all variables will be initialized to 0 by default, crts0 takes care of doing that for you. When your system is compiled, all of your variables have their initial values stored in ROM along with your program. When crts0 runs, it copies some the initial values from ROM into the proper places in RAM. When main starts it looks like RAM is ready to go, the initial values are there and ready to be changed.

When your program is compiled, you can tell the compiler hints about how the variables will be used. The keyword const on a variable -

const FP32 Pi = 3.14159;

tells the compiler that the variable is actually a constant. It does not need to be copied from ROM into RAM. This saves RAM space (which in embedded systems is typically really small), and the value cannot be stomped on by over-indexing an array.

The keyword static on a variable -

static BOOLEAN isInitialized = FALSE;

tells the compiler to place this variable on the “heap” instead of on the “stack”. The stack is reused as functions are called and the space is released when a function ends. The heap is allocated at compile time, is not reused, and values persist between function calls.

Your compiler will allocate your code and variables to one of three named areas of memory; .text – which contains the instructions of your program, .data – which contains your initialized data items, and .bss – which contains your uninitialized data items. The stuff in .text does not get copied to RAM typically, .data does get copied, and .bss is initialized to 0.

Your program, stored in .text, should not be able to be altered at run time, if it was alterable you would have the problem that we see with Micro$oft Windows where overindexing an array allows you to deposit data into the code areas. On a real operating system, this would be trapped as a write to read-only memory and the problem would be found early. Some systems will copy code ROM to RAM for speed of execution, on these little systems there is no performance gain and RAM is very small.

Initialized variables, stored in .data, must be copied into RAM. If they are kept in ROM, they cannot be altered without causing a write to read-only memory fault. If it is not copied into RAM ,the values would not have their initial values. So, by using some tricks in the loader and adding a small amount of code to crts0 we copy the values from their storage place in ROM into their destination addresses in RAM.

In an embedded environment, crts0 has another purpose (as well as the stuff described above), to set up the chips to a point where the main routine can even start. This typically involves doing the very rudimentary register setting to enable processor modules, bringing all of the memory chips on line, setting up the stack pointer, running initial memory tests, and other things that you don't have to worry about on a desktop system. crts0 is normally written in assembly language since your system is not running enough to support C yet. Lastly it branches to your program starting the main routine.

There are two methods of referring to the main routine. In UNIX like systems, all of the C symbols like main and your subroutine names had "__" (underscore underscore) prepended to the names so that they would not clash with the system symbols. Internally, your mainline routine would be called __main. This is dependent on the C compiler that you are using though, in more recent C compilers it is assumed that assembly will never be used so there is no prefix. In your crts0 routine, your last instruction will be something like jsr __main, jump to subroutine __main.

Main takes over

Now that the system has been started and main takes over, the next job is to complete the setup of the device registers, set up the variables for the application, and start the application.

You could do the setting of the device registers in assembly, but it turns out that you can write about 50 lines of code a day whether you are writing in in assembly or C. You can do a whole bunch more in 50 lines of C than you can in assembly, so restrict the use of assembly to starting the system and places where timing is critical or where instructions are not supported in C.

Embedded systems are typically architected so that main never returns. A return from main would put you back into crts0 just after the jsr __main call. There are a few ways to handle this, you can either loop back to the call to main, go into an infinite loop to lock up the system, or use one of the features of the processor to reset the processor.

Introducing the Real Time Operating System

This project uses the RTEMS (Real-Time Executive for Multiprocessor Systems) operating system. Real-time operating systems (RTOS) are basically different from desktop computer operating systems like Windows, in that they are designed to reliably execute code according to a schedule. Windows, on the other hand, will do things like reindex the file system while you are watching your movies. The buffering on the movie must keep up with the play out or the movie will stall. With an RTOS, the buffering would be guaranteed to run and would never starve the playing of the movie.

A system using RTEMS has three pieces, the RTOS itself, the board support package (BSP), and your application. RTEMS supplies various facilities like networking, a file system, memory allocation, processor time allocation, task creation, scheduling, and deletion, and inter-task communications. The BSP implements what crts0 does, prepares the system to run RTEMS, and provides support routines for networking, timer ticks, and communicating with serial ports.

Your application implements your algorithms and uses the facilities of RTEMS and the BSP.