There is a new 8051 C compiler in beta test that beats Keil's compiler by 35% code size, and 14% speed, on the Dhrystone benchmark. And, there is no need to select a memory model or use special keywords to control data placement.
More details here: www.htsoft.com/.../silabs8051beta
Mr. Sprat, those logic/implementation errors are found in the "C" construct in most of the occurrences... not necessarily most of the 'time.'
You can find ten of those errors in ten minutes but the one that which takes two hours is the type I'm talking about. Hence, most of your 'time' is spent debugging something that is not glaringly obvious that the faulty "C" implementation of faulty logic is in error. Usually the problems that take the most time are those that are a result of 'undocumented features' in the data-sheets, somebody else's code, or self generated. And for those long duration bugs, you'll need to delve into the assembly.
Your request for a logic/implementation flaw that is more easily found at the assembly level was fulfilled by Mr. Westermark's #define type errors. Yes it is possible to deduce it from within the "C" platform, but a quicker approach is to validate the post-processor result of the #define at the assembly level. It was a valid example of your request.
But an example of a 'bug' that is more easily found in the hand tracing level of assembly code is this one (yes, it is an 'undocumented feature' of Keil' optimization settings, but it could be argued that I created it myself too)...
extern u16 Get_ADC_Level( void ); #define MIN_VOLTAGE (2458) // 2457.6 = ((FULL_SCALE)/2)+(FULL_SCALE*0.10)) void Intruder_isr( void ) interrupt 0 using 2 { u16 val; do { Charge_Pump( ); // should take 10mS/kV val = Get_ADC_Vector( ); // lsb = 0.043 kV } while( val < MIN_VOLTAGE ); // removed time-out and hi-rel code // for 'example' clarity }
The "Get_ADC_Vector( )" function is external and in another module--as you would expect. The compiler (Keil) compiles and links with zero errors/warnings.
By having "Global Register Coloring" enabled in Keil's "Code Optimization" options, the Keil compiler did/does not account for the register bank switch from the "using 2" directive, so the parameter passed back from the function is in error: the compiler generates code that accessed the registers absolutely and tries to place them into the function-return registers.
Keil should have either identified that you must use "Don't use absolute register access" when you use "Global Register Coloring" and you are using the "using" directive in your code, -OR- Keil's optimizer should have properly handled it.
This example of an assembly traced bug didn't take too long because I realized that the 'using' directive does modify the reg-bank and I knew it was a risk point.
But initially I, like any typical user, was relying on Keil to handle that deviation properly: especially since the pre-optimization proved valid. (An OCG would 'see' this cross module error and avoid it)
FYI: My cure was to eliminate the "using" directive since it was clearly not a need. This is because I take the time/overhead to call two functions, from within the ISR, I could obviously afford the time delays of not switching banks. I also un-checked the "Global Register Coloring" since Keil proved that you cannot trust it. Keil's own documentation does not clarify the conflict.
Sprat, the real point I was making is that most of a "competent" embedded engineer's TIME is spent in dealing with "bugs" at the assembly level. The bugs that are cured at the "C" level are the easy "Doh! what a stupid mistake" type while the gotcha's are not as easily found and do require assembly level tracing.
Hopefully the underlying assembly code is not so mangled as to make it hard to trace. (such as register optimization where some needed data-store is held in R3 since the optimizer knows that it can stay there until it is needed, and doesn't have to write it out to the data space just to keep the data-element current. So then you can find the [traced] code comparing against a 'mysterous' R3 that was loaded a long time ago instead of comparing against 'Critical_Threshold' which is what you expected to see).
"find patterns where no patterns exists" == "code hallucinations"
--Cpt. Vince Foster 2nd Cannon Place Fort Marcy Park, VA
You can find ten of those errors in ten minutes but the one that which takes two hours is the type I'm talking about. Hence, most of your 'time' is spent debugging something that is not glaringly obvious that the faulty "C" implementation of faulty logic is in error. Usually the problems that take the most time are those that are a result of 'undocumented features' in the data-sheets, somebody else's code, or self generated. And for those long duration bugs, you'll need to delve into the assembly
The issue here is that debugging is not pantyhose (one size does NOT fit all). There are individual methods to the sequence ( look at source, check it in the ICE, do a, most likely hopeless, try with a simulator, insert some printf ...) but to find all bugs in a timely manner the most dangerous attitude is "THIS is THE way".
Yes, I do, occasionally resort to looking at the assembler, that is, indeed, a tool in my toolchest and it has, at times helped immensely. Does that make it "the right debugging method", of course not, but neither does it make it "the wrong debugging method".
Erik