CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

byte alignment on struct (PCD)
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Pret



Joined: 18 Jul 2006
Posts: 92
Location: Iasi, Romania

View user's profile Send private message

byte alignment on struct (PCD)
PostPosted: Wed May 30, 2012 8:36 am     Reply with quote

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: 19337

View user's profile Send private message

PostPosted: Wed May 30, 2012 8:56 am     Reply with quote

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

View user's profile Send private message

PostPosted: Wed May 30, 2012 9:35 am     Reply with quote

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

View user's profile Send private message

PostPosted: Wed May 30, 2012 10:22 am     Reply with quote

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

View user's profile Send private message

PostPosted: Wed May 30, 2012 12:50 pm     Reply with quote

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: 1322

View user's profile Send private message

PostPosted: Wed May 30, 2012 1:18 pm     Reply with quote

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: 19337

View user's profile Send private message

PostPosted: Wed May 30, 2012 2:23 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Wed May 30, 2012 3:21 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Thu May 31, 2012 3:12 am     Reply with quote

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: 19337

View user's profile Send private message

PostPosted: Thu May 31, 2012 3:17 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu May 31, 2012 3:58 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu May 31, 2012 8:02 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu May 31, 2012 9:14 am     Reply with quote

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: 19337

View user's profile Send private message

PostPosted: Thu May 31, 2012 9:23 am     Reply with quote

Latest version is 4.132....

78 versions in the future?.

Best Wishes
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Thu May 31, 2012 3:23 pm     Reply with quote

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.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group