HC12: Difficulty casting data in byte array to (word *__far)

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

HC12: Difficulty casting data in byte array to (word *__far)

5,366 Views
dp
Contributor III
Simplified example. Banked model for s12x...
extern byte RamByteArray[3];

#pragma CODE_SEG __PIC_SEG __NEAR_SEG NON_BANKED
void foo() {
  byte *BytePtr;
  word *__far FarWordPtr;

  BytePtr = RamByteArray;
  BytePtr[0] = 0x7F;
  BytePtr[1] = 0x80;
  BytePtr[2] = 0xC0;

  FarWordPtr = (word *__far)BytePtr[0];
}
#pragma DEFAULT_SEG


FarWordPtr is 0x00007F instead of 0x7F80C0. The cast converts only the byte at BytePtr[0] instead of all 3 bytes starting at BytePtr[0]. What am I missing? Thanks.

Message Edited by CrasyCat on 2007-04-13 11:44 AM

Labels (1)
Tags (1)
0 Kudos
Reply
7 Replies

2,170 Views
CompilerGuru
NXP Employee
NXP Employee
The expression "BytePtr[0]" refers to the first byte, which happens to be 0x7F, so the outcome is correct.

The problem is that you cannot cast things like array or structs in C. But you can cast pointers to those, so for example:
FarWordPtr = *(word **__far)&BytePtr
(also without trying it out)

It's probably a bit simpler and more understandable tough to directly write into FarWordPtr.
For example:
memcpy(&FarWordPtr, BytePtr, sizeof(FarWordPtr));

or

*((byte*)&FarWordPtr) + 0) = BytePtr[0]; // =0x7F
*((byte*)&FarWordPtr) + 1) = BytePtr[1]; // =0x80
*((byte*)&FarWordPtr) + 2) = BytePtr[2]; // =0xC0

or

use a union which contains a far pointer and the 3 byte array.

Also, what the reason not to use something like this:
FarWordPtr= (word *__far)0x7F80C0;

Do you really have to have an array representation for a far pointer?

Daniel
0 Kudos
Reply

2,170 Views
dp
Contributor III

CompilerGuru wrote:

The problem is that you cannot cast things like array or structs in C.
snip...




Thank you for the explaination. My simplified example simulates a section of a serial receive buffer so the value cannot be hard-coded.

Interestingly, FarWordPtr = *(word **__far)&BytePtr yields 0x7f7f80 instead of 0x7f80c0. (Why?)

The byte-by-btye copy techniques work fine so I'll stay with that.
0 Kudos
Reply

2,170 Views
CompilerGuru
NXP Employee
NXP Employee
>Interestingly, FarWordPtr = *(word **__far)&BytePtr yields 0x7f7f80 instead of 0x7f80c0.
>(Why?)
Because I made a mistake.
Smiley Sad

Well, I said I did not try it out. Here's the fixed version (this time I compiled it):
#include <string.h>
unsigned char ptrData[3]= {0x7F, 0x80, 0xC0};
unsigned char *__far farPtr;

static void confUnion(void) {
  union {
    unsigned char* __far ptr;
    unsigned char asBytes[3];
  } u;
  (void)memcpy(u.asBytes, ptrData, sizeof(u.asBytes));
  farPtr= u.ptr;
}
static void confCast(void) {
  farPtr= *(unsigned char *__far*)ptrData;
}
void main(void) {
  confCast();
  if (farPtr != (unsigned char *__far)0x7F80C0) {
    for(;;) {/* bug */}
  }
  farPtr= 0;
  confUnion();
  if (farPtr != (unsigned char *__far)0x7F80C0) {
    for(;;) {/* bug */}
  }
  for(;;) {}
}


As you can see, the __far was at the wrong indirection in my initial try, so the dereferenciation did only read 2 bytes.
Anyway, the byte per byte copy is simpler, so I prefer it. It's always good if one can easily see what is going on and this was the version which we both did get right in the first try. Keep it simple (so even I get it right Smiley Happy.
Using the union would also be a possible thing to do. Well not portable, but this problem is per definition not portable. So probably the union is even a bit cleaner as it clearly shows the reinterpretation of the values and it does not need any address casts at all.

Daniel


PS: It does not matter if you take the address of the array as I initially did. Probably its more clean to use the implicit conversion of the array to a pointer of its first field (its C...) One & less.
0 Kudos
Reply

2,170 Views
dp
Contributor III
FarWordPtr = *(word *__far*)BytePtr;
                          ^

Thank you so much Daniel. This is the cast I was trying for. I did not occur to me that the cast must take the form (word *__far*). Why doesn't (word *__far) work? I thought it would be sufficient to re-cast the pointer type.

Dave
0 Kudos
Reply

2,170 Views
dp
Contributor III
Duh, I see it. *(word *__far) says the object at the address is a word, whereas *(word *__far*) says the object at the address is a far pointer to a word. Thank you again to Sten and Daniel.
0 Kudos
Reply

2,170 Views
Sten
Contributor IV
Without testing it, I would say that you have to write
 
 FarWordPtr = *(word *__far)&BytePtr[0];
 
saying that the address of BytePtr[0] is the address of a far word pointer which you want to assign to FarWordPtr.

 
0 Kudos
Reply

2,170 Views
dp
Contributor III
*(word *__far)&BytePtr[0]

yields a word since it is saying that &BytePtr[0] is a far pointer to a word. To properly make the assignment in the example, it would need to be further cast to
FarWordPtr = (word *__far)*(word *__far)&BytePtr[0]

and would yield FarWordPtr = 0x7F80, still one byte shy. I have some alternative code to get the needed result by copying bytes individually but I have yet to come up with a cast that will use all 3 bytes in the array to make a (word *__far).
0 Kudos
Reply