CSE477 C Compiler Support for the 68HC11


Contents:



1  Installation

In Sieg 327 lab
The Small C compiler is installed at c:\apps\smallc\. Copy the c:\apps\smallc\ directory to your own directory (z drive). Make a subdirectory in your copy of the smallc directory. Place all your work (asm and c files) in this subdirectory.

If not in Sieg 327 lab
Download the zipped file smallc.zip, then unzip it to where you want to place the compiler. There is no subdirectory when you finish unzipping the file, and no setup that needs to be done; all you need is to have all the .exe files and the sc.bat file in one directory for the compiler to work. After unzipping, the compiler is ready to use.



2  C programs and SmallC compiler

Some special functions to support the 68hc11 are described in the next section. This section provides some important notes about this free compiler.

2.1  Some features

The SmallC compiler does not support floating points yet; thus, all calculations must be done using either char (8 bit long) or int (16 bit long) in your program. Arrays are supported, but structures are not (neither are pointers to pointers). Operations such as multiplication, division, modulo are available, and so are bitwise and, bitwise or, left and right shift. This compiler also supports inline assembly code, allowing mixing C code and 6811 assembly code in your C program. This is done by preceding the assembly code segment by "#asm" and ending by "#endasm". Please look at the "clock.c" program for examples.

The SmallC compiler does not except declaring the type of formal parameters directly in parentheses, but rather after that, such as:

foo (val, input) char val; int input;{ code is here;}
Also, you don't need to specify the type of the return value of a function:
foo(in) int in;{
int temp;
temp = 100;
if (in < 10) return(temp);
else return (in);
}
Variables cannot be declared and initialized at the same time, either:
int temp = 10; /* compiler will complain */
2.2  What needs to be included in C programs

You MUST specify at the beginning of your C program where to put code and data on the EVB board. This is done by using the #code and #data directives. The code segment on the EVB board begins at 0xC000. We usually use 0xD000 for the starting address of the data segment, but this number can be changed to accommodate code that is bigger than 4KB. I was able to download to the EVB board and run programs slightly larger than 8KB (size of user RAM on the EVB board), using 0xC0F0 for code and 0xC000 for the starting address of data segment. You don't need to set up a stack pointer; this is taken care of by the BUFFALO program. (If you use the ROM version (to put your programs in ROM), you do need to set up the stack pointer. Please refer to the section "The Two Types of Generated Programs" in the read-me file for more information.)

There are two files that must be included in your program: the "stdio.h" (containing some basic definitions), and the "startup.c" (which does a jump to main()).

The "library" for this compiler ("68hc11_lib.c" file) only has some special functions (described below, section 3). You don't need to include this file in your C program in order to use those functions. To use other functions that came with this compiler, such as fprintf, itoa, etc., or the ones you write, you need to #include them.

2.3  The register header file, "68hc11.h"

The file "68hc11.h" contains the addresses of almost all the special registers of the 68hc11. Including this file in your program allows for specifying the address of a register in word (like TOC2) rather than in number (like 0x1018, the address of TOC 2). Since the addresses in this file are declared as an offset from 0x1000, you need to define a register base in your program. The address of a register will then be (base + offset):

#define REG_BASE 0x1000 
    /*=>It is a common error to not have this line in the program */
....
poke(REG_BASE + TOC2, 5000); 
    /* and to use TOC2 alone, not as an offset, as shown here */
TOC2 is already defined in "68hc11.h" to be 0x018. It is often a good idea to make sure the register names you use in your program match the names defined in this header file, or at least they are defined there.

2.4  A note on the fprintf function

To use the fprintf function, you have to #include several other functions. Please look at the "clock.c" program for details and how to use fprintf. The fprintf function will take up a lot of space in your s19 file (almost 4KB), so if memory is tight, use "fputs" (outputing a string) and "printdec" (printing a decimal number) instead. An example using fputs would be:

#include <fopen.c> /* all these files are needed to use fputs */
#include <fputs.c>
#include <fputc.c>
#include <EVB_out.c>
FILE stdout; stdout=fopen(EVB_out); fputs("Hello\n", stdout);
For the formatting purpose, printdec does not output an EOL, but you can always use "newline()" function, already defined in the lib.c.



3  Special functions and features that support the 68HC11

Some functions have been written to support the 6811 micro-controller, included in the file lib.c -- the runtime library. These functions can be called in the main program without having to #include the library file.

3.1  Special functions

Listed here are the special functions to support the 6811:

Arguments are passed among functions using the stack and are pushed onto the stack from right to left. For example, if a function in the main program calls poke(addr,val), with 0x1021 as the address and 5000 as the value to write to that address, 5000 will be pushed onto the stack before 0x1021. In the calling function, the compiler will generate code that pushes arguments onto the stack, then performs a jump to the "poke" function, which in turn takes the arguments off the stack and does what it needs to do with those arguments passed to it. Upon return from the function call, the stack pointer is adjusted to where it was before the call.

Peek and poke are functions to read from and write to a register, or an address in general. Please note that reading or writing a byte uses different functions from reading or writing a word: peekb vs. peek, and pokeb vs. poke. In both cases, the "b" at the end stands for "byte". Be sure to use the right function for different registers.

The bit_set and bit_clr functions are called with a 1 in the position to be set or cleared. All other bits at addr are unchanged. Writing "bit_set(0x1020,0x01)" sets bit zero at address 0x1021 (the TCTL1 register). Bit_set and bit_clr are different from peek and poke in that only one bit is changed as supposed to changing the whole word.

In order for the delay function to work, you must have interrupt enabled first (using e_int()) because this function uses OC5 to do the delay. This function was written to run correctly with the default prescaler of 4 on the EVB board. You can modify this function to delay smaller time unit if you wish. This can be done by changing the number written into the TOC5 (please look at the code for this function in lib.c).

The file lib.c is the "runtime library" and is compiled every time the compiler is invoked. If you wish, you can modified it, or add more functions to it to fit your needs. The declarations in assembly syntax at the end of the file are used by the functions written in this file.

3.2  Interrupt service routines in C

The SmallC compiler supports writing interrupt service routines in C. To do that, precede the function with the "interrupt" keyword. You cannot have local variables in interrupt service routines, but you can manipulate global variables. Again, "clock.c" gives concrete example of how to use this feature.

Note that in the main program, you need to write the address of the service routine into pseudo-vector+1:

poke(0xE0, tme_oc1); where tme_oc1 is the name of the service routine.

A very important note here is that the address of toc1 is written into pseudo-vector+1. The byte starting at pseudo vector address is for the jump opcode ($7E), and this is taken care of by the compiler. In the example above, the pseudo vector address of TOC1 is $DF, but we are writing to $DF+1, which is $E0.

Although the readme file states that "In order to be recognized by the compiler, all interrupts must have a specific name," and the names are listed in that file, I tried different names for the interrupt service routines and they still worked.



4  Compiling and running a C program on the EVB board

Open a DOS window, change directory to where you have the compiler installed. The command to compile a C program is "sc" followed by the name of the file. (Refer to the readme file in the installed directory for more information on ROM version, that is , the "sc -r" command. To put programs in RAM, you don't need to use that version). An example to compile a C program would be:

sc lab3
(lab3.c is in the same directory with the installation of the compiler, no file extension included.)

(As an aside, when you invoke the sc command, you are invoking a batch file (sc.bat) that does compiling, linking and assembling. So don't lose or delete that file, by chance.)

If the source program to be compiled is in a subdirectory, you need to provide the path to that file when you invoke the sc command, such as:

sc cse477/lab3
(no file extension included  /  cse477 is your subdirectory made in step 1)

There are three files generated after the sc command is issued (and everything is OK): the .asm file, the .lst file, and the .s19 file. All these three files will be in the same directory with the source program. The .asm file contains the assembly code that the compiler generates, without the address of each instruction. The .lst file has the address of each instruction. The .s19 is the S-record file. It is a good idea to check if the list file contains any error before downloading the S19 file to the EVB board. Download the .s19 file onto the EVB board using the "load t" command as usual. If you have problem downloading the .s19 file to your board (the downloading takes too long, even doesn't finish -- be sure to wait a while for a big s19 file), check if the list file contains any error that the compiler didn't catch, but the assembler did. Fix it, and you can run the program on the EVB board by invoking the "g" command, followed by the starting address of your program, defined by the #code in the C program.

To save you some troubles, note that you only need to name your file, NOT including the extension (.c) The compiler won't generate correct s19 files if you include the extension or type in the name of a file that does not exist (the size of the s19 file generated will be very small, in the order of dozens of bytes). During the process of compiling, the compiler compiles the runtime library file, your program and put them into one temporary file, called "CODEOUT", and all the data in "DATAOUT". Those two files will then be merged into the final list file for the assembler to assemble (to S-record file). Thus, even if you type in at the DOS prompt a file name that does not exist, there still be a list file generated, but it's useless. Make sure that the generated list file has the same name with the source file that you want to compile.


Originally created by Quang Pham, see his original project (Spring 97).
Comments to: cse477-webmaster@cs.washington.edu (Last Update: )