Search code examples
c99msp430iar

IAR Embedded workbench 6 (MSP430 V5.6) Overriding program start


I am using IAR embedded workbench for MSP430 v5.60.7, which is IAR embedded workbench version 6.6. I am using C99.

I am trying to override __program_start() with my own symbol, a function called __unit_test_main(). I have gone to the linker config tab and checked the box "override default program entry", selected the "entry symbol" option and typed in __unit_test_main. This compiles and links however it does not run in the simulator. I get the message "User error: Illegal opcode found on address 0x0". When I try to run this on the target it just doesn't work - the controller goes into low power mode.

The PC and SP are both initialized to 0x00 at startup.

So what else do I need to do/define to get the PC and SP initialized properly?

My unit test main function is trivial right now, here's the whole file its in:

    #include <cstdio>
    void __unit_test_main(void);
    void __unit_test_main(void)
    {
        printf("Hello World");
        for(;;)
        {
        }
    }

Solution

  • __program_start: is defined in cstartup.s43. This file can be copied into your project directory and included in your project which overrides the library version.

    Immediately after __program_start: label the stack pointer is initialized, __low_level_init() is called, and then ?cstart_call_main is called.

    Around the ?cstart_call_main: label (line 339) is the following:

        XRSEGCSTART
        PUBLIC  ?cstart_call_main
    
        EXTERN  main
        EXTERN  exit
    
    ?cstart_call_main:
        XXCALL  main
        XXCALL  exit
    

    There you can add the symbol of the function you want to replace main with.

    You can do it conditionally with some #ifdef preprocessor logic.

    So I have

        XRSEGCSTART
        PUBLIC  ?cstart_call_main
    #ifdef UNIT_TEST
        EXTERN  test_runner_main
    #else
        EXTERN  main
    #endif
        EXTERN  exit
    
    ?cstart_call_main:
    #ifdef  UNIT_TEST
        XXCALL  test_runner_main
    #else
        XXCALL  main
    #endif
        XXCALL  exit
    
        PUBLIC  ?cstart_end
    

    I had to define my UNIT_TEST symbol in the assembler and the compiler options.

    Another option would have been implementing the function __low_level_init() somewhere in my project and conditionally making a call to test_runner instead of calling main()