May 3, 2004
This is a quick description of how to use gputils to generate relocatable objects and how to link those objects to generate an executable. This document is very brief. It is no substitute for the Microchip document.
This information will be incorporated into the gputils manual at some point in the future.
They are files which contain machine code, symbols, and relocation information. The relocation information allows the file to be placed "anywhere" in memory. gputils uses Common Object File Format (COFF). A good book describing COFF is "Understanding and Using COFF" by Gircys. It is out of print, but you can still buy used copies. gputils users shouldn't need the book, but the developers might.
The code is assembled into a COFF. After all the code is compiled, the coff are input into the linker. Symbols are resolved, addresses are assigned, and the machine code is patched with the new addresses. The output from the linker is an absolute executable object.
Most development tools create then link relocatable objects to generate an executable. The exception is some tools for microcontrollers. The applications are relatively small so creating one big file isn't impractical.
Using relocatable objects does have advantages:
For PICs, it has one big disadvantage. The bank and page control is a challenge.
You are interested in data memory and program memory. In absolute code, you have orgs to assign the start address of program memory and cblock to generate a block of data memory. In relocatable code, program memory is created using the code directive and uninitialized data memory using udata.
Take a look at the following code segment:
processor 16f877 include "p16f877.inc" udata mem1 res 1 mem2 res 2 mem3 res 1 ; symbols from other modules extern _main code _init banksel mem1 movlw 0 movwf mem1 movwf mem2 movwf mem2 + 1 movwf mem3 pagesel _main goto _main ; global symbols in this module global mem1 global mem2 global _init end
4 bytes of uninitialized data are reserved. A code segment to initialize the data starts at symbol _init. Once complete the code branches to _main. Mem1 and mem2 are global file registers. mem3 is static, which is a waste considering it is only initialized and never used.
This file would be assembled by gpasm:
gpasm -c init.asmgpasm would output a COFF, init.o.
You can assign the section address in the assembler by adding an address to the section directive (udata or code). This is not recomended. You don't want to assign the address at assembly time, that would defeat the purpose.
code 0x100 _init banksel mem1 movlw 0 movwf mem1 movwf mem2 movwf mem2 + 1 movwf mem3 pagesel _main goto _main
Multiple sections can exist in the same file, but they must have different names. The section name proceeds the section directive. If no name is provided a default name is used.
code _init banksel mem1 movlw 0 movwf mem1 movwf mem2 movwf mem2 + 1 movwf mem3 pagesel _main goto _main mycode code banksel mem1 incf mem1, f
Other types of sections exist, it is beyond the scope of this document to describe them all. See the document in the intro for a more detailed description.
gpvo is a tool for viewing objects. If you are interested in seeing how things work, use it.
gpvo init.o | less
So you have assembled several objects and now you need to make a COD file for simulation and a hex file for programming. gplink takes care of this.
gplink only requires the objects and a linker script to build the required output files. A set of scripts are included in /usr/share/gputils/lkr. These scripts were generated by Microchip. They were intended to cutomized by the user, but for many applications they can work as is.
Commanding:
gplink -m -c -s /usr/share/gputils/lkr/16f877.lkr main.o init.o isr.o
Will result in a map file (-m) to be output. This file contains the final addresses assigned to the data and program memory. An executable coff (-c) that is good for reference and simulation in MPLAB. Also a set of output files a.hex and a.cod. The default base filename is "a". It is best to specify your own output name using "-o".
In the future the path to the scripts will be added, just like the path to the headers for gpasm. For now, use the full path or copy the file to your working directory.
Gplink outputs a COD file that is compatible with gpsim. Gpsim will generate a few new warnings. One will be about not finding a list file. Others may be generated about not using gpasm. These warnings can be ignored. They will be fixed in a future release of gpsim.
If you have a collection of objects they can be combined into one archive. The archive is a convient way to link an application against a common library. The tool is gplib. It is very easy to use.
gplib -c math.a mult.o add.o sub.o exp.o
Creates a new archive math.a. The name is arbitary. It could be called "math.lib" or "math". gputils doesn't use file extensions to determine file types.
Then when you link the application add math.a to the list of objects
gplink -m -c -s /usr/share/gputils/lkr/16f877.lkr main.o init.o isr.o math.a
gplink will only extract those archive members that are required to resolve external references. So the application won't necessarily contain the code of all the archive members.
Here is one of the Makefiles I have been working with. It can be a template for you:
SCRIPT = 16f877.lkr OBJECTS = main.o startup.o isr.o i2c.o OUTPUT = example.hex all: $(OUTPUT) $(OUTPUT): $(OBJECTS) $(SCRIPT) gplink --map -c -s $(SCRIPT) -o $(OUTPUT) $(OBJECTS) %.o: %.asm gpasm -c $< clean: rm -f *.o *.lst *.map *.hex i2c.o: i2c.asm common.inc isr.o: isr.asm common.inc main.o: main.asm common.inc startup.o: startup.asm common.inc
There are many features that are planned. Linker optimizations, assembler extensions for high level languages. ...
I will try to keep this document updated. Please send me your comments and questions.