|
|
View previous topic :: View next topic |
Author |
Message |
ELCouz
Joined: 18 Jul 2007 Posts: 427 Location: Montreal,Quebec
|
16-bit MCUs |
Posted: Sun Jan 03, 2016 12:14 pm |
|
|
Hi,
I'm still learning the PCD related world regarding optimization.
I was wondering when reading the PIC24 platform datasheet:
I comes with a ALU dealing with multiplying 16 bit ints and dividing too.
It makes me wonder if they are any performance restriction using ONLY 16-bit ints in place where normally I only need a 8-bit one?
I know 16-bit MCUs work/store natively on 16-bit wide data.
Bad idea (beside taking more space)?
Thanks! _________________ Regards,
Laurent
-----------
Here's my first visual theme for the CCS C Compiler. Enjoy! |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19496
|
|
Posted: Sun Jan 03, 2016 1:03 pm |
|
|
Worry more about the data access...
DIV is the big gain MUL has byte wide versions.
However, to access a byte on an odd address, is slower, and more complex than accessing a byte/word on an even address.
The compiler knows and will correctly handle switching to use byte access if you access a byte size object, but if you use a word size object and then try to access this on an odd boundary, you will cause an address error.
So (for instance):
Code: |
char array[6] = { 0, 1, 2, 3, 4, 5 };
int16 val;
val=*(int16 *) array+1; //will cause an address error....
|
This can cause problems when building data arrays for accessing things being passed to/from the outside world. It'll work fine if you use a char pointer (since then byte access will be used), but to access a 16bit value on an odd address, it needs to be read as two byte accesses and then re-constructed.
The same applies with most 'bigger' chips (Intel etc.).
You can use the 'packed' attribute to create data structures for such outside world accesses, but you then have to remember to make sure you do not bypass the compiler's 'knowledge' of the sizes involved (as shown above).
If you use a packed structure for instance, and place an int16 on an odd boundary, the compiler will automatically access this using byte accesses.
The default integer size on PCD, is the int16. CCS here follow the original C manual exactly, by using the basic processor integer size on each chip. |
|
|
ELCouz
Joined: 18 Jul 2007 Posts: 427 Location: Montreal,Quebec
|
|
Posted: Sun Jan 03, 2016 5:15 pm |
|
|
Ttelmah wrote: | Worry more about the data access...
DIV is the big gain MUL has byte wide versions.
However, to access a byte on an odd address, is slower, and more complex than accessing a byte/word on an even address.
The compiler knows and will correctly handle switching to use byte access if you access a byte size object, but if you use a word size object and then try to access this on an odd boundary, you will cause an address error.
So (for instance):
Code: |
char array[6] = { 0, 1, 2, 3, 4, 5 };
int16 val;
val=*(int16 *) array+1; //will cause an address error....
|
This can cause problems when building data arrays for accessing things being passed to/from the outside world. It'll work fine if you use a char pointer (since then byte access will be used), but to access a 16bit value on an odd address, it needs to be read as two byte accesses and then re-constructed.
The same applies with most 'bigger' chips (Intel etc.).
You can use the 'packed' attribute to create data structures for such outside world accesses, but you then have to remember to make sure you do not bypass the compiler's 'knowledge' of the sizes involved (as shown above).
If you use a packed structure for instance, and place an int16 on an odd boundary, the compiler will automatically access this using byte accesses.
The default integer size on PCD, is the int16. CCS here follow the original C manual exactly, by using the basic processor integer size on each chip. |
Thanks Ttelmah for the explanation!
I've stumbled upon this today when reading the CCS Book (embedded c programming).
Quote: | Structure Layout in Memory
[...]
In a structure with an int8 followed by an int16, the compiler may insert an unused int8 between the two.
[...]
Using packed will prevent any gaps; however, there could also be some implementation problems so care should be used.
** quote is from a copyrighted book but however is very relevant and use fair use.
|
From your post, packing a struct is not safe because if you access a int which the address is odd (because there is no padding), it will fail??
From what I've understood that normally PCD will manage the "struct alignment" (take more space in RAM/ROM) unless forced to packed attribute but I should be careful with that.
I'm getting confused by the book and your post
Thanks! _________________ Regards,
Laurent
-----------
Here's my first visual theme for the CCS C Compiler. Enjoy! |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19496
|
|
Posted: Mon Jan 04, 2016 1:58 am |
|
|
If you access an int16 in a packed structure, then it'll work OK. The compiler will 'know' that it is an int16 on an odd boundary and automatically add the extra code to access it using two byte accesses, and re-construct the data.
However quite significant code/time overhead.
I use these for things like USB, where the data placement is forced upon you.
Where the problem comes is if instead you try to access an item, and override the compiler's 'knowledge' (as I did by changing the pointer to be to an int16, when it was designed to access an int8). So if (for instance) you built a data buffer, and retrieved data from serial, and then tried to retrieve larger objects from this using a pointer as I show.
On the maths, the compiler is smart enough to know that (for instance) performing int8/int8, is done with less code and faster, by actually using the int16 DIV.
Other thing to beware of is that the default integer is signed in PCD. This has varied with some older compiler versions, and is a very good reason to always be explicit on your integer types.
As another comment, it is worth deliberately arranging things to be more efficient, if the locations are not forced by other things. So:
Code: |
struct {
int8 value;
int16 value1;
int8 value2;
} demo;
//will be inefficient in it's memory use, actually using 6 bytes, where:
struct {
int16 value1;
int8 value;
int8 value2;
} demo;
//will only use four bytes
|
So when designing structures etc., always put the elements that are multiples of the alignment size first. |
|
|
ELCouz
Joined: 18 Jul 2007 Posts: 427 Location: Montreal,Quebec
|
|
Posted: Mon Jan 04, 2016 3:16 pm |
|
|
Thanks Ttelmah, it's very clear in my head now
After so many years of following this forum, PCM Programmer and you should write a book.
You've got deeper knowledge of PICs that what's found in books! _________________ Regards,
Laurent
-----------
Here's my first visual theme for the CCS C Compiler. Enjoy! |
|
|
|
|
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
|