+1  A: 

most efficient is first one, since it is done in single instruction.

NO! I lied to you sorry. I forgot that 8051 instruction set has only 1-bit shift instructions. Second should be faster, but compiler may generate stupid code, so beware and check assembly code.

Andrey
But is there any other way to divide the address?
Grissiom
How can the second one generate several instructions? My guess is that they are equally efficient
Anders Westrup
Depends on compiler. The easiest way is to compile and check assembly
Andrey
@Anders: the main way I can think that a simple compiler might mess up 2, is that it might write `ptr` out of a register on to the stack in order to take the address of it, then read a char back from the stack. So a write and two reads for the two lines of code (hopefully to fast memory, like cache, I don't know the 8051 at all). Conversely, the first version of the code may or may not just perform some integer ops. I note that most of the 8051's registers are 8-bit, so either option might be a no-op: registers could just be reassigned so the register that was the low part of ptr is now ADDH.
Steve Jessop
first is slow. see my revised answer. there is no cache at 8051, but there is fast on chip memory, not transparent to developer
Andrey
@Andrey: I have now given myself the bluffer's introduction to 8051, and I can confidently guess that my mention of "cache" should be replaced with "internal RAM". Hopefully the compiler uses that for stack, the point being that although it might be worse than some other clever way of doing it, a spill to stack isn't as bad as a spill to external RAM would be, in terms of insn or cycle count. I'm still rooting for register reassignment, though, when we see the asm code. All depends how the variables are used afterwards, of course: if `ptr` isn't "zapped" it may not be possible.
Steve Jessop
@Steve: (regarding your first comment) why does it need to "write ptr out of a register on to the stack in order to take the address of it"?
Lazer
It doesn't need to (that's why it's a "mess up"), but as I said a primitive compiler *might* reasonably do so. All it takes is for the compiler to be smart enough to keep variables in registers, but not smart enough to do so once the address of the variable has been taken (and turn access through the pointer into register manipulations). I now see that on 8051, registers are directly addressable RAM if you know what bank you're on, so there may be no need at all. I'm curious to see what the questioner's compiler does, since I have no instinct for writing 8051 code myself.
Steve Jessop
... so I'm not saying the second one will be bad, but Anders specifically asked "how *could* the second one generate several instructions", so I'm trying to oblige with a hopefully-plausible scenario. Perplexing register spills do happen from time to time, or at least perplexing to me :-)
Steve Jessop
I've uploaded the assembly code. Have a look at them if you are interested. ;)
Grissiom
+1  A: 

Another not so bright way to split the address:

 ADDH = ptr / 256;
 ADDL = ptr % 256;
Anders Westrup
At least this version takes less chars in source code ;)
Grissiom
Man, do you know cost of div instructions on processors like 8051?
Andrey
@Andrey: I don't know what compilers for 8051 are like, but at least for an unsigned type I'd be astonished if a C compiler (on any architecture) which claimed to optimize at all, emitted different code for `ptr / 256` as against `ptr >> 8`. I can't say what insns it uses, but it's not that hard for the compiler to spot the equivalence and pick the best. Negative values aren't necessarily so simple.
Steve Jessop
+3  A: 

The most efficient way is completely dependent on the compiler. You definitely have to figure out how to get an assembly listing from your compiler for an 8051 project.

One method you might try that is similar to those already mentioned is a union:

typedef union
   {
   unsigned short u16;
   unsigned char u8[2];
   } U16_U8;

U16_U8 ptr;

// Do something to set the variable ptr
ptr.u16 = ?;

ADDH = ptr.u8[0];
ADDL = ptr.u8[1];
semaj
I use this method to when dealing with endian issues on AVR with GCC where the other methods don't always generate decent code -- especially for constants.
nategoose
A: 

I just create two defines. It seems more straight forward, and less error prone.

define HI(x) ((x) >> 8)

define LO(x) ((x) & 0xFF)

Jim T
Thanks! It is more clear then typing all the expressions all the time. But does the bitwise operation more effective than other ways?
Grissiom