Starting from reset

The standard library includes a start-up module that prepares the environment for running applications written in C. Several versions of the start-up script are available because each processor has different set-up requirements. The msp430-gcc compiler selects the appropriate module based on the processor specified in the command line options.

The start-up module is responsible for the following tasks

The start-up module contains a default interrupt vector table. The contents of the table are filled with predefined function names which can be overridden by the programmer. The last entry in the table, however, is the address of the reset vector. The "_reset_vector__" is defined as a weak symbol. This means that if the application doesn't define it, the linker will use the version in the library (or module). However, a user defined version will take precedence.

Look at the disassembled code produced by

$ msp430-objdump -DS a.out

a.out:     file format elf32-msp430

Disassembly of section .text:

0000fc00 <_reset_vector__>:
    fc00: b2 40 80 5a  mov #23168, &0x0120 ;  #0x5a80
    fc04: 20 01
    fc06: 3f 40 50 fc  mov #-944, r15 ;  #0xfc50
    fc0a: 3e 40 00 02  mov #512, r14 ;  #0x0200
    fc0e: 3d 40 00 02  mov #512, r13 ;  #0x0200
    fc12: 0d 9e        cmp r14, r13
    fc14: 06 24        jz $+14      ;  abs dst addr 0xfc22
    fc16: 1d 53        inc r13
    fc18: fe 4f 00 00  mov.b @r15+, 0(r14)
    fc1c: 1e 53        inc r14
    fc1e: 0f 9d        cmp r13, r15
    fc20: fb 2b        jnc $-8       ;  abs dst addr 0xfc18
    fc22: 3f 40 00 02  mov #512, r15 ;  #0x0200
    fc26: 3d 40 00 02  mov #512, r13 ;  #0x0200
    fc2a: 0d 9f        cmp r15, r13
    fc2c: 06 24        jz $+14      ;  abs dst addr 0xfc3a
    fc2e: 1d 53        inc r13
    fc30: cf 43 00 00  mov.b #0, 0(r15) ;  subst r3 with As==00
    fc34: 1f 53        inc r15
    fc36: 0f 9d        cmp r13, r15
    fc38: fb 2b        jnc $-8       ;  abs dst addr 0xfc30
    fc3a: 30 40 44 fc  br #0xfc44

0000fc3e <_unexpected_1_>:
    fc3e: 30 40 42 fc  br #0xfc42

0000fc42 <_unexpected_>:
    fc42: 00 13        reti

0000fc44 <main>:
    fc44: 31 40 80 02  mov #640, SP ;  #0x0280
    fc48: 30 40 4c fc  br #0xfc4c

0000fc4c <__stop_progExec__>:
    fc4c: 02 43        clr SR
    fc4e: fe 3f        jmp $-2       ;  abs dst addr 0xfc4c
Disassembly of section .data:
Disassembly of section .vectors:

0000ffe0 <InterruptVectors>:
    ffe0: 3e fc        interrupt service routine at 0xfc3e
    ffe2: 3e fc        interrupt service routine at 0xfc3e
    ffe4: 3e fc        interrupt service routine at 0xfc3e
    ffe6: 3e fc        interrupt service routine at 0xfc3e
    ffe8: 3e fc        interrupt service routine at 0xfc3e
    ffea: 3e fc        interrupt service routine at 0xfc3e
    ffec: 3e fc        interrupt service routine at 0xfc3e
    ffee: 3e fc        interrupt service routine at 0xfc3e
    fff0: 3e fc        interrupt service routine at 0xfc3e
    fff2: 3e fc        interrupt service routine at 0xfc3e
    fff4: 3e fc        interrupt service routine at 0xfc3e
    fff6: 3e fc        interrupt service routine at 0xfc3e
    fff8: 3e fc        interrupt service routine at 0xfc3e
    fffa: 3e fc        interrupt service routine at 0xfc3e
    fffc: 3e fc        interrupt service routine at 0xfc3e
    fffe: 00 fc        interrupt service routine at 0xfc00

OK. Lets start from the end. Every MSP430 device has interrupt vectors table located at 0xffe0. So, here we can see, that as execution begins, the PC is loaded with the address 0xfc00. "_reset_vector__" is located at this address.

The first thing that happens is the watchdog timer is initialized. Then the program copies the initialized global variables to RAM (0xfc0a - 0xfc20). After this, the uninitialized globals are cleared (0xfc22 - 0xfc3a). After this, we jump to 'main', which is located at 0xfc44.

In main, we copy the value 0x0280 to r1. This initializes the stack pointer, taking into account the space required for local variables.

Next, as long as main does nothing, it jumps to "__stop_progExec__". At this point the SR is zeroed. The next instruction is jump to "__stop_progExec__". This is the end of program execution.

In this module, the application uses:

All of these variables can be overridden with -Wl,--defsym=[symname]=(value) For example, to set the initial stack point to0x280, use -Wl,--defsym=__stack=0x280.

In most cases it is not necessary to redefine these values. They can be obtained from the user application as follows

...
extern int __stack;
int m;

(int *) m = &__stack;

/* now m contains the address of the stack */
...
Please note that these values do not change once they have been initialized.

The startup code adds a litter overhead to the application. The size of the startup code is 80 bytes without interrupt vector table. If you do not like this approach, you can define your own startup code.