3 Gordon Drive, P.O.Box 1347 Rockland, Maine 04841 U.S.A.
Find Tools for Your Chip


Subscribe to our Newsletter

© 2004 Avocet Systems, Inc.
Call Us Today at 207-596-0080
Avocet Systems, Inc. : The Complete Solution for Embedded Systems Development Tools
Tech Tips
David Bardon


I have your 68HC05 compiler and I wrote some code using character arrays. The code wasn't working right so I rewrote some of it using character pointers. There must be something wrong with the compiler because the assembly generated was different from the code generated using arrays.

The code should be different by reason of the difference between a character array and a pointer to a character.

Q But they're the same! I've been using them interchangeably for years!

A It is true that they are often handled the same way in writing code, but internally they are handled differently by most compilers. You can prove to yourself that they are different by attempting to compile the following code with any decent compiler:

char ch_array[20];
char *pc;
main()
{
      ch_array = pc;
      pc = ch_array;
}

You will always get an error message on the first assignment and no message on the second.

Q Why is that?

A An array name represents the address at which the array starts, or to look at it another way, the address of the first element. This address is fixed for the lifetime of the array. The pointer, on the other hand, is a variable which holds an address, and that can be changed. You can, of course, assign values to array elements but the address range of the array itself remains the same.

How is it that I can pass an array name to a function prototyped to take a character pointer as an argument, with no complaint from the compiler?

A What really happens is that the address of the array is assigned to the character pointer argument. You are really making an implicit typecast of an array name to a character pointer. With some compilers, if the warning sensitivity is cranked up, you might get a message that you are effecting a type conversion. If we continue our example code by adding a function call where we pass the array name to a function:

void fn(char*);

charch_array[20];

char*pc;

main()

{

.

fn(ch_array);

.

then the code generated is:

lda #high _ch_array

sta ?_fn

lda #low _ch_array

sta ?_fn+1

bsr _fn

The symbol _ch_array is the assembly code label marking the address where the array starts; i.e. its address. Byte by byte, you can see that this value is loaded via the accumulator into that part of the compiled stack used by the function (the start address of such a space is marked by ?_ followed by the function name).

If on the other hand, we write the function call:

fn(pc);

then we get:

lda _pc

sta ?_fn

lda _pc+1

sta ?_fn+1

bsr _fn

Here you can see that the data residing at the address, rather than the address itself is loaded; i.e. the memory contents at _pc; in other words, what it points to.

Using your compiler for the 68HC05, tell me, how do you program the options register?

It depends on the type of 6805 you have. Certainly with many of the earlier processors, the register was implemented entirely in ROM, and was often referred to ask the Mask Option Register. I don't know if any current 6805 processors are implemented that way. I certainly haven't noticed any in any recent list I've seen.

Well, we haven't decided exactly which 6805 type to use yet, so, just to make sure we have all bases covered, how would you do it for a ROM implemented device.

To do this we have to make the compiler produce a hex file which contains a byte with data we need at the address of the Mask Options Register. Let us take the MC68705P3 by way of an example, no matter whether this particular one is still current or not! The Mask Option register for this processor resides at $784. We could use the #asm and #endasm directives to insert a piece of assembly code into any function in the following way:

#asm

psect optreg,abs

org $784

fcb $42

psect text

#endasm

You will typically find a hex record generated with the load address specified in our org statement, with the single data byte defined. On burning into the processor's (E)PROM, the appropriate data is then set in the Mask Option Register.

Fine, and for more recent devices?

A For a modern device most of the control bits are implemented as RAM. As an example, let's take the MC68HC05C8. The Options Register in this processor is located at $1FDF. Bits 7, 6 and 1 are RAM implemented, although bit 1, designated IRQ, can only be written to once following each reset. Suppose we wish to set bit 7 to 1. When this bit, designated RAM0, is set, we have 32 bytes of RAM in the address range $30 to $4F.

We start by defining a bit-field type for the options

register and then defining a name to use in accessing its hardware address:

typedef struct

{

unsigned RAM0:1; /* bit 7 */

unsigned RAM1:1;

unsigned unused1:2;

unsigned SEC:1;

unsigned unused2:1;

unsigned IRQ:1;

unsigned unused3:1; /* bit 0 */

} OPTREGTYPE;

OPTREGTYPE optreg @ 0x1FDF;

We can then set or clear control bits typically as follows:

optreg.RAM0=1;

optreg.IRQ=0;