This tutorial is geared towards those who want to write hand-optimized assembly code for the MSP430, but don't quite know how to get started. If you are interested in writing assembly on the PIC24 or dsPIC33 series, see our other tutorial on writing assembly for use in C using the XC16 compiler!
This tutorial assumes that you are using TI's Code Composer Studio, which is the 'default' IDE for the MSP430 series. It would help to be reasonably familiar with Eclipse, but not totally necessary.
This is similar to most other IDE's. I had an old launchpad around, so I used the MSP430G2231 that came with it to configure my project around. I created my project with an empty main.c file. This isn't necessary since the github page that I'm supplying to you already has a main.c, but if you are creating your own blank project, you will need to create main.c (or whatever you name your highest level file) at some point. Note the directory that your project is saved in, you will need it later!
Create a header file in which the assembly file and any associated C functions are declared. In the example project, we simply named this ‘mylib.h’. Note that this declaration is like any other function declaration – no underscores, return type, parameter, etc.
The basics are in the compiler documentation, but looking at the source will still help you out. You must create the file with a ‘.s’ extension. Additionally, DO NOT name the file the same as your C file. For instance, if you are writing a library called ‘mylib.c’, then do not name your assembly file ‘mylib.s’. Both of these potentially create a ‘mylib.o’ object file, which will confuse the linker. Stick with ‘mylib_msp430.s’, or something like that. Besides, if you port to the another processor achitecture, you can always write that assembly code into ‘mylib_xc16.s’ or similar.
The MSP430 compiler handles include files assembly in a strange way. You must type:
.cdecls C, list, “msp430.h“
This allows you to include a standard C header, 'msp430.h', into an assembly file. Normally, you would include a '.inc' file into assembly. This allows your C and assembly source to share the same file during compilation. If you don't understand this, you can read the compiler documentation or simply accept it. In truth, it doesn't have a lot of bearing once you are elbow-deep in assembly.
In your header, your function might be called ‘add’. You should also name your function within the assembler 'add'. When the compiler looks at your code, it is only looking for ‘global’ symbols to link with your C code. As a result, you need to add an additional declaration to the top of your file: ‘.global add’. This must be exactly the same as the assembly 'function' is named within your assembly file.
Write the assembly code into your function. Feel free to name sections of your code anything you like. As long as they are not declared ‘.global’, then the compiler won’t see them as C functions.
In this architecture, parameter passing is accomplished using the working registers w12-w15. Remember that these registers are 16-bit registers. If a function takes two 16-bit parameters, they will be located in w12 and w13. If a function takes a single 32-bit parameter, that parameter is located in [w13:w12] with w12 being the low word. There are lots of details to this, so it would really help to read the docs!
You can add other functions into this file as well, just be sure to perform the same steps so that the compiler knows the declared global symbols.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
.cdecls C, list, "msp430.h" ; this allows us to use C headers .text ; locates code in 'text' section .global add ; declares 'add' as global add: ; this is the function itself ; if bit 15 is set, then jump to add_neg bit.w #32768, r12 jc add_neg add_pos: bit.w #32768, r13 jc add_pos_neg add_pos_pos: ; this label isn't declared global, so it is only available locally add.w r13, r12 jn add_pos_pos_sat ret add_neg: bit.w #32768, r13 jc add_neg_neg add_pos_neg: add.w r13, r12 ret add_pos_pos_sat: mov #32767, r12 ret add_neg_neg: add.w r13, r12 ; result should be negative bit.w #32768, r12 jnc add_neg_neg_sat ret add_neg_neg_sat: mov #32768, r12 ret .end
If all of these files are within the project directory, then you should be ready to rock!
If the files are somewhere else in your directory tree, you may have to add the source files to your project and include directories to your gcc options.
As mentioned previously, there is a starter file set in github to help you get started. Just download and execute!