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 CCS Technical Support

looking for tips for reducing ROM footprint

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
kender



Joined: 09 Aug 2004
Posts: 768
Location: Silicon Valley

View user's profile Send private message Send e-mail Visit poster's website Yahoo Messenger

looking for tips for reducing ROM footprint
PostPosted: Wed Aug 25, 2010 5:32 pm     Reply with quote

Colleagues,

My project was evolving for years, and now I’m out of program memory. I’m using 18F4620, which has the most Flash in its line. Are there any CCS-specific tricks that can free-up some code memory?

I’m sure, this subject was discussed previously on the forum. But I couldn’t find those threads.

Any suggestion, insight, reference is appreciated!

- Nick
_________________
Read the label, before opening a can of worms.
collink



Joined: 08 Jan 2010
Posts: 137
Location: Michigan

View user's profile Send private message Visit poster's website

Re: looking for tips for reducing ROM footprint
PostPosted: Wed Aug 25, 2010 5:49 pm     Reply with quote

kender wrote:
Colleagues,

My project was evolving for years, and now I’m out of program memory. I’m using 18F4620, which has the most Flash in its line. Are there any CCS-specific tricks that can free-up some code memory?

I’m sure, this subject was discussed previously on the forum. But I couldn’t find those threads.

Any suggestion, insight, reference is appreciated!

- Nick


Sure, what sort of things does your program do?

Something I do a lot of is factoring code so that as much code as possible is shared by as many routines as possible. That is, if two routines both do almost the same thing then factor the common stuff to another function and call it from both. This can save a lot of space in the long run. For instance, if you have a lot of menus in your code then make a function which draws and operates menus given a const string and use that instead of hand coding each and every menu. This way you have only one place that has to have code for menu drawing, selection, movement, etc. However, it also eats up your stack levels so you might have to watch how deeply you nest functions.

Also, try to make sure that #separate is in front of any functions that you suspect the compiler might otherwise inline in the code. This is especially important if the function is reasonably small and called in many different places. It adds up. I think that the compiler does a pretty good job of optimizing for space at opt level 9 though so this might not do a whole lot.

Try optimizing at the unsupported optimization levels 10 and 11. It's scary but sometimes it will actually produce code that is amazingly small and still works. You can try enabling the optimization at the function level and pick and choose functions to super optimize. Both optimization levels have a tendency to ruin your program so be careful. When I've tried opt level 11 I've seen code usage on a big project go from 98% down to like 85%. Granted the program puked after that and wouldn't run... I have actually had a program work at opt level 10.

If you have a lot of strings it might become advantageous to compress them in some way. Maybe huffman coding, maybe packing them to 6 bit chars (thus saving 25%) This is only worth it if you have a lot of strings. Say, if you have 30k worth of strings then saving 25% is a 7.5k savings. Keep in mind, though, that you'll have to code up a decompressing routine while will eat up some of the savings.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed Aug 25, 2010 5:55 pm     Reply with quote

Look at the ASM code in the .LST file. Look for routines that use a lot of
ROM compared to what they do. The functions may have features that
you don't use and yet it's in the source code, so it gets compiled and it
wastes ROM. Example: Several different radixes may be supported
for a string to integer conversion routine (such as hex, decimal, octal, etc)
but you only need decimal. You could make your own version of the
routine and cut out all the unnecessary source code.

You may be using built-in functions that are replicated with inline code for
each call, such as write_eeprom(). This is very wasteful, but you can
fix this compiler behavior by adding a "wrapper" function to write to
an eeprom location, and then call the wrapper instead. Look for ASM
routines that are replicated over and over again in the .LST file.

You may be doing ROM tables inefficiently. For example, #rom has the
option of using an 'int8' qualifier. This allows you to pack 2-bytes per
ROM word, instead of just one.

Floating point math eats ROM. Try to avoid using functions in math.h.
Find some clever way to do use integer math instead. Quite often there
is one.

I think the most important thing is to review the .LST file and see where
the problems are. If you're using math.h routines, it will be obvious that
it uses 100's and 100's of ROM words, and something must be done about it.
andrewg



Joined: 17 Aug 2005
Posts: 316
Location: Perth, Western Australia

View user's profile Send private message Visit poster's website

PostPosted: Wed Aug 25, 2010 9:28 pm     Reply with quote

I've recently been tinkering with the CCS MMC/SD/FAT library code, and found that I could shave 1K off the code. What they are doing is passing structure pointers into functions, then dereferencing using the -> operator. That takes a relatively large amount of code. The fix is to copy the structure to a local copy at the start of the function, use the . operator instead, and copy the local copy back at the end of the function. One memorable function started out at 422 words and ended up 192 words. Watch out for the extra RAM the local copies take up, though.
_________________
Andrew
kender



Joined: 09 Aug 2004
Posts: 768
Location: Silicon Valley

View user's profile Send private message Send e-mail Visit poster's website Yahoo Messenger

PostPosted: Thu Aug 26, 2010 2:03 pm     Reply with quote

Gentlemen, thank you for the suggestions. I will try your approaches, and I will keep you posted.

I've noticed that seemingly simple* writing to structures takes a lot of instructions. I wonder if there's a way to improve that. For example:
Code:
....................       g_sChannels[iCh].sPID.iMax = 4095; // global struct
1D52:  MOVF   x86,W
1D54:  MULLW  42
1D56:  MOVF   FF3,W
1D58:  CLRF   x88
1D5A:  MOVWF  x87
1D5C:  MOVLW  0C
1D5E:  ADDWF  x87,W
1D60:  MOVWF  x89
1D62:  MOVLW  00
1D64:  ADDWFC x88,W
1D66:  MOVWF  x8A
1D68:  MOVLW  14
1D6A:  ADDWF  x89,W
1D6C:  MOVWF  01
1D6E:  MOVLW  00
1D70:  ADDWFC x8A,W
1D72:  MOVWF  03
1D74:  MOVF   01,W
1D76:  ADDLW  D3
1D78:  MOVWF  FE9
1D7A:  MOVLW  02
1D7C:  ADDWFC 03,W
1D7E:  MOVWF  FEA
1D80:  MOVF   FEE,F
1D82:  MOVF   FEE,F
1D84:  CLRF   FEC
1D86:  MOVF   FED,F
1D88:  CLRF   FEF
1D8A:  MOVF   FED,F
1D8C:  MOVLW  0F
1D8E:  MOVWF  FEF
1D90:  MOVF   FED,F
1D92:  MOVLW  FF
1D94:  MOVWF  FEF

* It's a global structure. In theory, address of each of it's member can be determined at compile time.
_________________
Read the label, before opening a can of worms.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Aug 26, 2010 2:52 pm     Reply with quote

Quote:

In theory, address of each of it's member can be determined at compile time.

g_sChannels[iCh].sPID.iMax = 4095;

It would if you got rid of the variable index and replaced it with a
number. The code would reduce down to almost nothing.
EdWaugh



Joined: 07 Dec 2004
Posts: 127
Location: Southampton, UK

View user's profile Send private message

PostPosted: Mon Sep 20, 2010 5:46 am     Reply with quote

Hi all,

Interesting discussion here and some good suggestions. I am having a similar problem and by using PCM Programmer's encapsulating floating point math as functions I have managed to save some space. Does anyone have any tips for identifying functions that are appearing very often in the hex so these can also be encapsulated?
I also had another idea relating to kender's structure problem. I typically do this kind of access to lots of items in the same structure so be calculating the ptr first you save space by doing it only once (perhaps this is what PCM Programmer meant). You start with this:
Code:

global_structure.structure_array[i].value = 1;
global_structure.structure_array[i].value2 = 2;

Then change to:
Code:

structure_array_t *ptr = &(global_structure.structure_array[i]);
ptr->value = 1;
ptr->value2 = 2;

This cuts out a lot of address recalculation.

Also, what actually happens on #opt 10 and 11? Moving to 10 offers further savings but I am nervous about it, could it have broken my code in a way I can't easily notice? 11 just gives an 'internal error' during compile.

Cheers

Ed
collink



Joined: 08 Jan 2010
Posts: 137
Location: Michigan

View user's profile Send private message Visit poster's website

PostPosted: Mon Sep 20, 2010 6:13 am     Reply with quote

EdWaugh wrote:

Also, what actually happens on #opt 10 and 11? Moving to 10 offers further savings but I am nervous about it, could it have broken my code in a way I can't easily notice? 11 just gives an 'internal error' during compile.


I can't answer with any certainty but from what I've seen in the list file when trying to compare code from optimization level 9 and 11 it seems like what it's doing is code sharing. It seems like it tries to find areas that are in common between multiple areas (or even functions) and factor them out so that there is only one instance. This saves code space but it seems like sometimes it gets a little confused and factors out areas of code that aren't compatible. Or maybe it's just that sometimes it factors out a code section that ends up calling itself or something and crashing.

At any rate, opt level 10 is scary to use and opt level 11 seems like suicide. They both stand a good chance of totally destroying your code. However, I have gotten programs to work at opt level 11 so it IS possible. If you can get your program to work at opt level 11 you can see space savings of upwards of 20%. I'm not kidding! The program space savings can be really large. This does you no good if your program crashes though.

Come to think of it, I think that the program I got to work at opt level 11 had no interrupt calls. It's possible that the optimization factors code in common between interrupt called functions and non interrupt functions and thus clobbers on interrupts. I should try a different program with interrupts and try setting opt level 9 around every function called from an interrupt and see what happens...
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
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