So I have been playing with writing assembly again within the context of C and I have run into the usual issues. I have decided to create a quick little 'getting started' tutorial.
If you are interested in the same type of writeup regarding TI's MSP430 series, head over to the tutorial!
For those who just want to see the results, skip on over to the github repository, download the MPLAB X project and source files and get started. For those who would like a gentler introduction, read on!
This tutorial assumes that you are already pretty familiar with MPLAB X and writing programs in C or assembly and are just looking for the next steps. I am using version 3.20 of the MPLAB X IDE, and version 1.25 of XC16, but my experience is that the tips here will port across a wide range of versions.
Create your MPLAB X project (File -> New Project...). You will be presented with a series of choices which I can't really guide you through. You should have an idea of the processor that you are using and the location that you want to store your project, so just follow the steps with what you know. If you are just exploring, then use the PIC24FJ32GA102. It is a good basic processor that doesn't have all of the bells and whistles, but shares a core with all PIC24 and dsPIC33 series.
Create your main.c file where your application code will reside. For you guys already creating C projects, this is no different from any other C project.
Your implementation may have one or morel C files that are part of the same library. Create these functions in the usual way.
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.
This is the part that will trick most of us up. The basics are in the compiler documentation, but there is some real information missing. 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 create a 'mylib.o' object file, which will confuse the linker. Stick with 'mylib_xc16.s', or something like that. Besides, if you port to the another processor achitecture, you can always write that assembly code into 'mylib_msp430.s' or similar.
In your header, your function might be called 'add'. When this is compiled, it gets an underscore added to it. As a result, when you are writing your assembly function, you need to append an underscore at the beginning of the name. For instance '_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 function is named within your header file, but with an underscore.
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 w0-w7. Remember that these registers are 16-bit registers. If a function takes two 16-bit parameters, they will be located in w0 and w1. If a function takes a single 32-bit parameter, that parameter is located in [w1:w0] with w0 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
.include "xc.inc" .text ; variables and functions that are to be used in the C ; domain must be declared 'global'. Additionally, an ; underscore must be placed in front of it since the ; compiler places an underscore in front of code to be ; assembled. .global _add _add: add w0, w1, w2 btsc SR, #2 ; check the overflow bit goto _add_sat mov w2, w0 return ; if the code gets here, then an overflow occured, need to saturate ; mask = 0x8000 _add_sat: ; if w0 is negative, then saturate negative, otherwise positive btsc w0, #15 goto _add_neg_sat _add_pos_sat: mov #32767, w0 return _add_neg_sat: mov #32768, w0 return .end
If all of these files are within the project.X directory, then you should be able to add the *.c and *.s files to the 'source' directory and the *.h files to the 'header' directory.
If the files are somewhere else in your directory tree, you may have to add the include directories to your gcc options.
As mentioned previously, there is a starter project in github to help you out. Just download and execute!