Well, we have a program, now let's compile it.
Let me describe my setup first. I use Windows 98 SE on an old P90 machine. I believe the instructions here will work on any Windows environment and if something does not work for you please send me a message so I can correct the page. I believe that if you are brave enough to be using Linux, you do not need my help at all and I will not discuss any specifics. Many of the commands should be easily transferable to Linux or any other Unix for that mater.
Before you start you will need a few things. Most of all you will need the compiler - download and install the GCC for 68HC11 from the links section - if you have not already. Download and unpack the GEL library in your work folder. I also recommend installing the cygwin environment.
Cross your fingers, open a command line prompt, go to your work folder and create a cc.bat file with the following content (copy and paste into notepad should be fine):
m6811-elf-gcc -nostdlib -nostartfiles -Wl,-defsym,_io_ports=0x1000 -Wl,-defsym,_.tmp=0x0 -Wl,-defsym,_.z=0x2 -Wl,-m,m68hc11elfb -mshort -Os -fomit-frame-pointer -msoft-reg-count=0 -I gel-hc1x-1.4\include %1 %2 %3 %4 %5 %6 %7 %8 %9
You will also need the following a file called memory.x in your work directory containing the following:
MEMORY
{
page0 (rwx) : ORIGIN = 0x0, LENGTH = 256
}
Now hopefully you can do:
cc blink.c -o blink.elf
This will compile the blink.c program and create a binary file blink.elf.
Let's step back and explain what just happened.
As you have guessed the cc.bat file is to save you the trouble of typing this hideous command line every time. The bat file assumes that the GEL library is unpacked in the current directory and that you are using version 1.4 of the GEL library. If that is not the case replace the -I gel-hc1x-1.4\include with the appropriate path. Note that you have to use DOS path format even if you are using cygwin environment.
Here are the bat file options explained in detail:
| m6811-elf-gcc | this is the name of the compiler program. All programs in the GCC cross compiler package for 68HC11 begin with m6811-elf |
| -nostdlib | instructs the compiler not to use the standard C library - we do not need it for this simple program |
| -nostartfiles | instruct the compiler not to use the default C startup code - we have our own _start function |
| -Wl,defsym, _io_ports=0x1000 |
assigns address 0x1000 to the symbol _io_ports - this tells the linker that our _io_ports array starts at address 0x1000 - this is the default location for the IO port registers of 68HC11 |
| -Wl,defsym,_.tmp=0x0 | assigns address 0 to the symbol _.tmp - the compiler needs a temp variable, so we instruct the linker to place the variable at address 0 |
| -Wl,defsym,_.z=0x2 | assign address 0x2 to the symbol _.z - second temp variable needed by the compiler |
| -Wl,-m,m68hc11elfb | tells the linker to use this machine definition script - the script files are located in usr\m6811-elf\lib\ldscripts subdirectory of your GCC install directory - you may take a peak |
| -mshort | instructs the compiler to threat int as 16 bit not 32 bit (define int as short). Since 68HC11 has 8 bit CPU having 32-bit integer type does not make much sense. |
| -Os | optimize for space - most common in embedded applications is optimization for space, not speed |
| -fomit-frame-pointer | generates yet smaller code |
| -msoft-reg-count=0 | do not use soft registers - GCC is designed for CPUs which use numerous general purpose registers, 68HC11 have only 3 registers and they are limited in function, for that purpose the compiler uses so called "soft registers" - variables in memory to emulate general purpose registers. Since our program is simple enough the compiler works just fine even without the use of "soft registers" |
| -I gel-hc1x-1.4\include | Add this directory to the include path. Note that this is relative to the current directory - which is generally not a good practice - replace it with an absolute path in DOS format. |
|
|
| -o blink.elf | tells the compiler what output file to generate - the default is a.out |
The mystery of the memory.x file.
When compiling programs for embedded systems you usually have pretty good idea what region of the memory you program will occupy. In our case we are targeting the build-in 256 bytes of RAM which start at address 0. When placed in "Boot mode" the MPU has a build in loader which allows us to load a program in this 256 byte memory region. Another requirement is that the code of our program actually starts from address 0, since this is the address to which the boot loader transfers the control after the program is loaded. So how do we achieve all this?
First let me explain that all this is possible thanks to the power of the GNU linker. The memory.x file is a "linker script", which defines a region or memory called page0, starting from address 0 and with size 256 bytes. We also instruct the linker, that this region of memory can read write data and execute instructions. So having this information the linker knows that it has to place all out program code and data into this region of memory. If you try to trite a program which is long enough and can not fit in the first 256 bytes, the linker will give an error message.
We achieve the second requirement - that our program start is at address 0 - by some sheer damn luck. Actually since we use only one .c file the compiler places the first function or data at address 0 - so we make sure our _start function is the first thing in the .c file for which code or data will be generated. Actually there are some sophisticated linker scripts which make sure the right code is in the right place, but since out program has to be as small as possible we ignore all the standard code and have to take care of the start address requirement ourselves.
Checkout part 2: So we have a compiled binary what do we do with it?