View previous topic :: View next topic |
Author |
Message |
Pret
Joined: 18 Jul 2006 Posts: 92 Location: Iasi, Romania
|
byte alignment on struct (PCD) |
Posted: Wed May 30, 2012 8:36 am |
|
|
Hi guys.
On PCD compiler the default alignment for fields in a struct is 2 (meaning each 16 bit). I need somehow to force the compiler to align them to 1. Similar to "#pragma pack(1)" for msvc users.
For instance:
Code: | typedef struct
{
uint8 a;
uint16 b;
uint8 c;
} dummy; |
In this case sizeof(dummy) is 6. What I want is, of course, 4.
Does the CCS PCD support different data alignment? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19499
|
|
Posted: Wed May 30, 2012 8:56 am |
|
|
Not directly.
It is a lot more work to 'do', since the chip itself can directly do a 16bit fetch, only when starting on an even byte boundary. However the default only applies to objects larger than 8bits. So:
Code: |
typedef struct
{
uint8 a;
uint8 blow;
uint8 bhigh;
uint8 c;
} dummy;
|
Will give the 4byte size, and you can then just use make16 to access the 16bit value (doing exactly the same extra work the compiler would have to do...). A couple of judiciously defined macros, would allow this to be simplified for coding, both for declaration, and extraction.
Best Wishes |
|
|
Pret
Joined: 18 Jul 2006 Posts: 92 Location: Iasi, Romania
|
|
Posted: Wed May 30, 2012 9:35 am |
|
|
That's far from being elegant. And it escapes me why the compiler cannot do such a basic thing.
Though, playing a little bit with struct, I think I've found the workaround.
Code: | typedef union
{
struct
{
uint8 high;
uint8 low;
};
uint16 val;
} st_uint16;
typedef struct
{
uint8 a;
st_uint16 b;
uint8 c;
} dummy;
|
This way the sizeof(dummy) is 4, and more than that, I can even do something like: Code: | dummy var;
var.a = 1;
var.b = 2;
var.c = 3; | So basically, I can assign a value to b directly.
Thanks Ttelmah. |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Wed May 30, 2012 10:22 am |
|
|
PCD does pack byte variables in a struct without specifying a pragma as far as possible.
But the structure from your initial post can't be implemented by PCD without a fill byte, because uint16 must be allocated at an even address, as well as the structure itself.
Code: | typedef struct
{
uint8 a;
uint16 b;
uint8 c;
} dummy; |
Exchanging the positions will however work:
Code: | typedef struct
{
uint8 a;
uint8 c;
uint16 b;
} dummy; |
|
|
|
Pret
Joined: 18 Jul 2006 Posts: 92 Location: Iasi, Romania
|
|
Posted: Wed May 30, 2012 12:50 pm |
|
|
This is only a PCD limitation. Not even on our 386+ desktop processor can access data that is not align to 32 bit. But it doesn't mean that the compiler shouldn't handle this situation. And, as I mentioned in previous post, it's actually capable. It just needs some tricks.
Another example:
Code: | uint8 vector[10];
uint16 myvalue = 10;
*(uint16 *)&vector[1] = myvalue; |
This works just fine, even if i'm writing myvalue on a odd address. |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1345
|
|
Posted: Wed May 30, 2012 1:18 pm |
|
|
It does compile, but you run the risk of generating address traps if the output code issues a word instruction on a misaligned word. See the PIC24F data sheets' data space sections:
Quote: |
All word accesses must be aligned to an even address.
Misaligned word data fetches are not supported, so
care must be taken when mixing byte and word operations,
or translating from 8-bit MCU code. If a
misaligned read or write is attempted, an address error
trap will be generated. If the error occurred on a read,
the instruction underway is completed; if it occurred on
a write, the instruction will be executed but the write will
not occur. In either case, a trap is then executed, allowing
the system and/or user to examine the machine
state prior to execution of the address Fault.
|
That's from the data space section of the data sheet. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19499
|
|
Posted: Wed May 30, 2012 2:23 pm |
|
|
Realistically, though using bytes, is 'not elegant', it is easily implemented as a macro. Just create a write macro to create two data bytes, using the value passed, with a _L, and _H attached for the bytes, and a read macro to undo this reading the two bytes, and reassembling them for you. As Jeremiah has pointed out the need to switch to byte addressing, is a _hardware_ limitation of the PIC in this regard.
Best Wishes |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Wed May 30, 2012 3:21 pm |
|
|
Quote: | This is only a PCD limitation. |
No, as said, it's basically a hardware limitation.
The x86 comparison is misleading, because x86 has been designed to allow access to word and dword at arbitrary addresses. The compiler tries to avoid unaligned accesses, because they are slow.
PIC24 and many other micros are unable to perform unaligned accesses. In situations where word and dword objects have to be copied from a byte aligned data stream, memcpy() or other means of bytewise copy have to be used. |
|
|
Pret
Joined: 18 Jul 2006 Posts: 92 Location: Iasi, Romania
|
|
Posted: Thu May 31, 2012 3:12 am |
|
|
Thanks guys, I think I understand now. So PIC24 can access 16bit variables on 2byte aligned data, and 8bit var on any alignment.
In this case, how a structure is being copied from one instance to another? For instance: Code: | typedef union{
struct
{
uint8 high;
uint8 low;
};
} uint16st;
uint16st a;
uint16st b;
[...]
a = b; |
This copy is being made most likely using a memcpy-alike routine, right? It's kinda overkill for a simply 16bit variable, but, in essence should work.
I'm surprised that the compiler allow something like: Code: | uint16st a;
a = 512; | I'm curios on what will happen... |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19499
|
|
Posted: Thu May 31, 2012 3:17 am |
|
|
Yes, bytewise copy.
Since it doesn't 'know' at heart how big each piece of the structure is, and the structure could even be an odd number of bytes in length, the compiler has to 'assume the worst', and use the slower method.
If you want to get a real 'touch' on it, try declaring two normal int16 variables, and copying them, in MPLAB, with the stopwatch selected, then do the structure movement. You may be surprised at how much slower it is.
Best Wishes |
|
|
Pret
Joined: 18 Jul 2006 Posts: 92 Location: Iasi, Romania
|
|
Posted: Thu May 31, 2012 3:58 am |
|
|
Looking in ASM, i've found some strange things. For this code:
Code: | typedef union{
struct
{
uint8 high;
uint8 low;
};
} uint16st;
typedef struct
{
uint8 a;
uint16st b;
} mytype;
// sizeof mytype is 3.
mytype x, y;
x = y;
x.a = y.a;
x.b = y.b;
x.b.high = y.b.high;
x.b.low = y.b.low;
x.b = 513; |
The assignments are looking like: Code: | .................... x = y;
00290: PUSH 806
00292: POP 802
00294: MOV.B 808,W0L
00296: MOV.B W0L,804
....................
.................... x.a = y.a; // fine !
00298: MOV.B 806,W0L
0029A: MOV.B W0L,802
....................
.................... x.b = y.b; // wtf !
0029C: PUSH 806
0029E: POP 802
....................
.................... x.b.high = y.b.high;
002A0: MOV.B 807,W0L
002A2: MOV.B W0L,803
.................... x.b.low = y.b.low;
002A4: MOV.B 808,W0L
002A6: MOV.B W0L,804
....................
.................... x.b = 513;
002A8: MOV #201,W0
002AA: MOV.B W0L,803
002AC: SWAP W0
| I find this very surprisingly. Apparently field a and field b are overlapped on second assignment. And an attribution with a const value looks fine... I understand the limitation of hw alignment, but I did nothing wrong in terms of C language. The compiler should force padding or prone errors, but not overlap my fields. Or there is something that escapes me? |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Thu May 31, 2012 8:02 am |
|
|
What's your PCD version? I don't see the union placed at an odd address. |
|
|
Pret
Joined: 18 Jul 2006 Posts: 92 Location: Iasi, Romania
|
|
Posted: Thu May 31, 2012 9:14 am |
|
|
PCD version is 4.200. And it's not being aligned because I was able to fool the compiler with a struct into an union. If I would let the struct directly it would have been aligned. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19499
|
|
Posted: Thu May 31, 2012 9:23 am |
|
|
Latest version is 4.132....
78 versions in the future?.
Best Wishes |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Thu May 31, 2012 3:23 pm |
|
|
Quote: | And it's not being aligned because I was able to fool the compiler with a struct into an union. If I would let the struct directly it would have been aligned. |
I copied your latest example code and tried in different PCD versions, 4.099 and 4.132. |
|
|
|