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!
why not '#if' instad of 'if'
Erik
So, I updated my code to look 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 */ } #endif }
It appears that it's working as it's supposed to (my code dropped by 50 bytes, so that's good) but I did get the following warnings:
warning C322: unknown identifier warning C322: unknown identifier
It might still work but I'd feel a lot more comfortable making those warnings go away, in case I'm doing something wrong.
If I was to guesstimate the problem, I'm guessing it's referring to DiagMode twice. Is this because I need to do some sort of #declare statement or something to that effect (#declare DiagMode = 0, possibly?)? Or set it as a constant? Or do I need to include some sort of library I'm missing?
Also, I wasn't able to get a #elseif statement working. I got the following error when I tried
#elseif (DiagMode == 1)
:
warning C315: unknown #directive 'elseif'
Did I screw something else up or is there a Keil specific way to do this?
Ok, now I'm confused. What is it you guys are proposing me to do at this point?
Originally, I had:
VARS.H
#ifndef _D4_VARS_H #define _D4_VARS_H extern unsigned char idata DiagMode;
vars.c
#include "VARS.H" unsigned char idata DiagMode = 0;
main.c
#include "VARS.H" 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 */ } }
I have now changed it to:
#ifndef _D4_VARS_H #define _D4_VARS_H //extern unsigned char idata DiagMode; #define DiagMode 0
#include "VARS.H" //unsigned char idata DiagMode = 0;
This appears to work as I can change the Diagmode = 0 to 1 and it gives me a different code size, which I assume means it's working (maybe I'm wrong). Am I doing this right or are you suggesting I need to do it a bit differently?
I understand that you guys generally want to give guidance without giving sample code but at this point, I think you're losing me with what it is you're suggesting. Can you give me a quick code example for what you think I should be doing because, if I'm doing something incorrectly right now, I really don't understand what it is you are suggesting.
Look at my example.
I have a question for you. So, if you look at my last post, you can see what I did and it seemed to work without updating any of my if statements to #if statements. Is this because Keil fixed the issue for me with the compiler (which probably means I am still doing it incorrectly, regardless of how Keil fixes it for me) or is what I did actually correct?
I found an area that had an if/else diagmode statement and changed them to #if and #else and noticed no change in code size (ie the code I had was executing correctly with my fixes) so it appears to be doing what I wanted it to do correctly.
I just want to know if my procedure is incorrect and, for best practices or when using other compilers (or even changing optimization levels, possibly), I need to implement it differently or if my coding is correct.
Let me know if my wording is confusing and I can try and explain it again. Thanks!
you are mixing precompiler and compiler directive
THIS IS AN EXAMPLE VARIABLE NAMES ARE FICTIONAL
common.h
//#define OMIT1 //uncomment if certain code is to be omitted //#define OMIT2 //uncomment if certain other code is to be omitted
whatever.c
#include common.h code #ifndef OMIT1 code that is to be excluded if omit 1 #endif code #ifndef OMIT2 code that is to be excluded if omit 2 #endif code #ifndef OMIT1 more code that is to be excluded if omit 1 #endif code
Ok, I understand.
Out of curiosity, is it really easier to create your own examples from scratch rather than to simply demonstrate by correcting code that is incorrect (such as my examples)? Could save a few posts.
Oh, and for the record, I don't want to come off as ungrateful because I do appreciate the help I'm getting.
And so you know, I used "BUILD1" for reference purpose, not because I thought BUILD1 was the required variable (I understand you weren't being literal with that name). So that part wasn't lost on me, in case I gave you the impression I didn't know how variables worked . . . :p
The compiler is smart. If it see C code that is unreachable, it can remove it.
So:
int charlie=1 if (charlie == 1) { ... } else { ... }
the compiler can throw away the code inside the else statement.
If the code instead looks like:
void my_function(int charlie) { if (charlie == 1) { ... } else { ... } }
Then the compiler can't throw away any code.
But when using #ifdef x or #if defined(x) or #if x == y then the preprocessor will filter away non-matching code and the compiler don't need to worry about what can be resolved at compile time and what needs to be resolved at runtime.
Out of curiosity, is it really easier to create your own examples from scratch rather than to simply demonstrate by correcting code that is incorrect (such as my examples)? I consider it more important that you get to understand how this works than giving you code. Giving you code will not help you next time
I don't do it because i worry about "giving code". I do it because I want to show a skeleton showing the concept without any extra noise around.
Remember that threads on this forum are read by people who find the threads using search engines at a much later time. They don't care about your specific source code. But they may care about the concept that is covered in the thread.
So it's likely that Keil is overcompensating for errors in my code. I should still use the #if statements rather than if statements, even if it seems to be working correctly, just to play it safe. Thanks for the help.
No - Keil is not overcompensating.
But compilers do optimize code. So if the compiler knows that specific code lines can never be reached, then the compiler still need to process the lines to verify that they are grammatically correct. But the compiler can decide to not generate any code. You may potentially get a warning "unreachable code".
The #if version is the only one where all information is known at compile time.
The if (expr) version depends on the contents of the expression, if the compiler will be able to deduce that the expression has a fixed value or not.
Well, I did define DiagMode using the following code:
#define DiagMode 0
So, if I understand correctly, it knows the value of DiagMode at compile time. If the code is generated based on that, does this mean I don't need to convert all my if/else statements to #if/#else statements?
It makes sense in my head that this should work but I want to do it the right way, so if this leaves it open for future errors, I'd rather make the correction now than wait until it fails down the road.
if (xxx) { code }
the code will always be included in memory and only execute if the if is valid. . .
#if (xxx) code #endif
the code will only be included in memory if xxx is valid . .
so, if xxx is not valid the second build will be smaller than the first.
Maybe not but it sounds like you and Per are saying two conflicting things. What the heck am I supposed to think?
If I understand Per, he seems to imply that if a variable is declared at compile time, it won't compile statements that don't meet that criteria. That seems to be what my code is doing, even without your #if statements.
I am now asking HIM based on what he is telling me if I need to do what YOU are suggesting. I completely understand what you are saying. Don't get me wrong. But I'm trying to understand why it appears to be working correctly with what I have, even if it contradicts what YOU are saying. I WANT to do it the correct way so I'm trying to get more information.
If you disagree with Per on something, just SAY it. But don't get annoyed with me when I try to piece bits of information together from two different people that seem to be saying different things.
Right now, my code is acting the same with my if statements as it SHOULD be acting with #if statements, which is what is leaving me conflicted. Me changing to #if statements should change the way it acts if what you are saying is correct but when I changed a few of them, the code space did not change at all, implying that either my current code is correct (without changing the #if statements BECAUSE I added the #define statement) or Keil is correcting for me and I SHOULD have the #if statements just to play it safe (which is what you seem to suggest).
The problem here is I'm having a conversation with Per about trying to understand what is going on with Keil and you're spitting out the same data over and over with no real explanation as to what Keil is doing or why I should correct my code to do it your way if it works just fine without it. I UNDERSTAND WHAT IT IS YOU'RE TRYING TO GET ME TO DO! I want to understand HOW Keil works and what it's doing and that's what Per is trying to help me understand.
If you want to help out and give me more information, that's fine. But don't judge me ("you just don't get it do you") because I'm not immediately jumping on your suggestion without fully understanding WHY it's necessary. That's the point of why you post here, correct?
If I understand Per, he seems to imply that if a variable is declared at compile time, it won't compile statements that don't meet that criteria. That seems to be what my code is doing, even without your #if statements. true IF the 'variable' (which, in this case, it is not) is used in a # statement find a 'C' book, it will have a chapter "the preprocessor"
If you disagree with Per on something, just SAY it. But don't get annoyed with me when I try to piece bits of information together from two different people that seem to be saying different things. I do not disagree with Per, however I do disagree with your interpretation of what he says. Do we have a language problem? is English your first language?
Right now, my code is acting the same with my if statements as it SHOULD be acting with #if statements, which is what is leaving me conflicted. Me changing to #if statements should change the way it acts if what you are saying is correct but when I changed a few of them, the code space did not change at all show a simple example
I want to understand HOW Keil works in this respect, just like any C compiler and what it's doing find a 'C' book, it will have a chapter "the preprocessor"
without fully understanding WHY it's necessary. find a 'C' book, it will have a chapter "the preprocessor"
read this msdn.microsoft.com/.../ew2hz0yd(v=vs.80).aspx
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
I have posted with the understanding that you want to build a code two ways a) for the processor excludng some code b) for the simulator including all code
I hope this is correct, if not please clarify
if this is correct, you NEED to use preprocessor conditionals
true IF the 'variable' (which, in this case, it is not) is used in a # statement
Maybe this is where we're not seeing eye to eye. Is #define not a preprocessor statement? If not, then that's my confusion and yes, you are correct, I need to change all my statements to #if statements.
However, my code appears to be acting as if that #define statement is a preprocessor statement. At your request, here's my example.
I have code that says
if(DiagMode==1) { //Execute Code 1 } else { //Execute Code 2 }
When I use the line:
my code size is set to code size x and it executes Code 1. When I change it to:
#define DiagMode 1
my code size now changes to code size y and executes Code 2. So for all intents and purposes, my code is acting the way I want it, changing what is compiled based on the value of DiagMode.
I then went back to my code and altered it in this way:
#if(DiagMode==1) { //Execute Code 1 } #else { //Execute Code 2 } #endif
When I use:
I now have it executing Code 1 and the size is the previously mentioned code size x (just as it was prior to me adding the # signs). When I change my DiagMode to:
It executes Code 2 and the code size changes to size y (once again, the same way it was WITHOUT the # signs).
Now from this, I conclude that the #define is acting as a preprocessor statement and that the # signs that you insist I need are absolutely necessary but I have no proof that that is the case, hence my confusion and my questions.
Now, about this . . .
Do we have a language problem? is English your first language? You can easily read my statements here and have a pretty good idea of whether or not my first language is English. Me having a different interpretation of something than you doesn't mean I don't understand the english language. Honestly, you do give a lot of helpful information but sometimes, you're just a complete ass.
Now, you say that my interpretation of what Per is saying is incorrect. Then correct me! If you understand it differently, explain what it is YOU understand from it and where my thinking is wrong. Simply saying "You're wrong because I understand it differently" is not helpful at all. And it just proves your blind arrogance.
Or rather APPEARS like blind arrogance (I'm not trying to cast judgement on you, I don't know you outside this forum. That's just how it comes off).
the 1000 pound elephant is the optimizer
Is #define not a preprocessor statement? If not, then that's my confusion and yes, you are correct, I need to change all my statements to #if statements. # define is a preprocessor statement #if is a preprocessor statement if is not a preprocessor statement regardless if whether the x in if(x) is #defined
However, my code appears to be acting as if that #define statement is a preprocessor statement. At your request, here's my example. not because #define is a preprocessor statement, see below
if(DiagMode==1) { //Execute Code 1 } else { //Execute Code 2 } When I use the line:
#define DiagMode 0 my code size is set to code size x and it executes Code 1. When I change it to:
#define DiagMode 1 my code size now changes to code size y and executes Code 2. So for all intents and purposes, my code is acting the way I want it, changing what is compiled based on the value of DiagMode
#if(DiagMode==1) { //Execute Code 1 } #else { //Execute Code 2 } #endif When I use:
#define DiagMode 0 I now have it executing Code 1 and the size is the previously mentioned code size x (just as it was prior to me adding the # signs). When I change my DiagMode to:
#define DiagMode 1 It executes Code 2 and the code size changes to size y (once again, the same way it was WITHOUT the # signs). as it should be
AAAH, got it, you have heavy optimization which will do this
if(0) { lines will be excluded }
THUS, if you reduce optimization level (heavy optimization while debugging is a ***) you need the # for the if's, if you optimize heavy, you do not
so with heavy optimization Per and I are both right, with low optimization Per is wrong and I'm right.
by the NASA philosophy "we fly what we test" I do not use heavy optimizations.
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 . . .
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'
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;
View all questions in Keil forum