We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
Hello everyone,
So, I am working with an 8051W core processor (with OTP, once again, that's a whole other discussion) and I'm pretty maxed out on code space and looking to trim it down a bit. I need to check the functionality of some of my interrupts so I've had to create code that looks like this:
void main (void) { DiagMode = 0; /* Loop for standard/hardware diagnostics mode */ if ((DiagMode == 0) || (DiagMode == 2)) { while (1) { // Insert code here }; /* Loop forever */ } /* Loop for simulation/software diagnostic mode */ else if (DiagMode == 1) { while(1) { decimator2_ISR(); // Insert code here }; /* Loop forever */ } }
So if I wanted to use the code in simulation mode, I set DiagMode = 1. When I go to burn the chip, I set it equal to 0 (or 2 if I'm doing some hardware diagnostics, I have various case statements throughout the code that run only if DiagMode = 1 or 2).
Currently, if I want to cut down the code I have, I can comment out any unnecessary code portions (anything with DiagMode = 1, etc). I was wondering if there was a way to set my code to build the code differently if it is being used in simulation mode and when I compile it to hex (or set DiagMode to 0), the portions in code with DiagMode set to 1 are not built into the hex code, saving space.
I apologize if what I'm asking for is confusing. Realistically, it probably isn't possible but I figure if anyone would know how to do something along these lines (or has a better alternative), this would be the place to go.
Let me know when you get the chance. Thanks!
I actually wondered if that was the case and should have mentioned I had it on optimization 8 (which is very high).
Unfortunately, it's a custom ASIC with only 8k of code space and we're at 7.4k already WITH the optimizer already set to 8. Ideally, I'd like to drop it down but we don't have the space for it (and we haven't even added the I2C or SPI code to it yet).
Thanks for your help, that makes a lot more sense. In future projects when we have more available code space, I'll be sure to set the #if statements correctly. At least now I understand why it's acting in the way it is.
Oh, and please use the appropriate tags when posting code! Heh . . .
Ok - sorry for the confusion here.
If the code uses #if defined(symbol) or #if symbol == xx or #ifdef(symbol) then there is a contract between you and the compiler vendor (based on the C language standard) that the compiler/preprocessor/linker combination will completely ignore lines that are within a block that where the condition isn't fulfilled.
So you can write:
#define SKIP_DEBUG #if !defined(SKIP_DEBUG) here I can have whatever random text I want (that doesn't look like some important preprocessor directive like #else, #endif, ... and the compiler will totally ignore if this is valid C or not. It will be stripped away before the C compiler starts to figure out what code you have. #endif
But you will get errors if you write:
int skip_debug = 1; if (!skip_debug) { I want the compiler to ignore this. But the compiler will scream blue murder because this is random text within the C source code. }
Ok. So what about "correct" code, but you want to save space.
int charlie(int a,int b) { int skip_debug = 1; if (!skip_debug) { printf("I'm in debug mode now. So lots of nice extra printouts.\n"); printf("I'm in function charlie() and time of day is '%s'.\n",my_time_of_day(tmpbuf)); } return a+b; }
The compiler will process every single line as C code. Any syntax error will be caught. The compiler can see that skip_debug is always non-zero. The compiler can know that the print() statements can never be activated. The compiler _may_ decide to not generate any code for that block and compile your source as if you had:
int charlie(int a,int b) { return a+b; }
I say _may_. There is no "must". The language standard allows the compiler to figure out that the if block can never be activated, and that the expression "skip_debug" don't have any side effect.
But there are no contract between you and the language standard that guarantees the optimization. There _may_ be a contract between you and the language standard that the compiler should optimize away the code.
So try same thing agan, but we move the variable include_debug outside the function.
int skip_debug = 1; int charlie(int a,int b) { if (!skip_debug) { printf("I'm in debug mode now. So lots of nice extra printouts.\n"); printf("I'm in function charlie() and time of day is '%s'.\n",my_time_of_day(tmpbuf)); } return a+b; }
Now, the life is way harder for the compiler. include_debug is a global variable, and the above code isn't enough to prove if any other code within the full program may modify the value of skip_debug to zero.
So unless the compiler/linker have very advanced code for performing full (cross)module optimization, it must include the code even if _you_ know the the variable is always zero and the code should never be run.
So then we have the mixed case.
#define skip_debug 1; int charlie(int a,int b) { if (!skip_debug) { printf("I'm in debug mode now. So lots of nice extra printouts.\n"); printf("I'm in function charlie() and time of day is '%s'.\n",my_time_of_day(tmpbuf)); } return a+b; }
This gets processed as:
int charlie(int a,int b) { if (!1) { printf("I'm in debug mode now. So lots of nice extra printouts.\n"); printf("I'm in function charlie() and time of day is '%s'.\n",my_time_of_day(tmpbuf)); } return a+b; }
Now, it is easier again for the compiler to notice the impossible-to-reach code block. So the compiler is free to (i.e. _may_) not generate any processor instructions for the unproductive source code statements. But the compiler isn't required to save code space by throwing away the block.
So you really should use the preprocessor fully (setting the symbol that selects include/skip, and that checks this symbol) to reduce the code size. Only then will you have a valid contract guaranteeing removal of the unwanted code.
If you do not use the preprocessor, but still see the code size shrink, that will be caused by the _may_ rule. The compiler _may_ be smart enough, and the code _may_ be simple enough, that the compiler can deduce that it can throw away code. Some compilers are marvels at analyzing code. Some are rather stupid. But the marvel and the stupid compiler will honor the intentions of the #if constructs.
Unfortunately, it's a custom ASIC with only 8k of code space and we're at 7.4k already WITH the optimizer already set to 8. Ideally, I'd like to drop it down but we don't have the space for it (and we haven't even added the I2C or SPI code to it yet). OH, what fun fitting I²C and SPI (and the code that uses it) into 600 bytes. I hope your costom chip has it in hardware, NOW, beware - if you need delay routine(a) you need to do it) in assembly, that high optimization will simply drop routines that "do nothing'
Erik
That makes sense. Sounds like, whether my code needs it or not using the optimization I'm using, it's in my best interest to add the #if statements to ensure I'm not relying on "MAY" conditions to occur.
At least now I understand what's happening and why. Thanks, guys!
Yeah, to be honest with you, I might have to look at compiling separate code for digital output code because I doubt it's going to fit (then maybe we can reduce the optimization).
Thanks for the heads up regarding delay routines, that will probably save me a lot of headaches.
I wish OUR company had the NASA attitude . . . "Well, it may be expensive, but we need it." Oh well, not much I can do about it except make the most of the situation. Brings up new challenges and I develop new skills, I guess.
some things I have a problem with with, when doing huge projects, is inactive code showing up as active on global scans and, sometimes, getting lost studying inactive code when the problem is elsewhere.
in such cases I, sometimes do the following (which seems silly in an example this small)
#ifdef TEST #define TESTCODE #endif then the following var47 = ADCinput; #ifdef TEST TESTCODE if var47 > 222 TESTCODE { TESTCODE var47 = 222; TESTCODE } #endif vr47 =/ 10;