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.
All,
I am trying to track down a problem of some code that was written by an 'overseas' 3rd party (I will be nice and not state the country of origin).
This code uses a single timer set at a 1mS interrupt rate in order to determine if the SPI is still communicating externally with it's master. If no communications are detected the timer resets the SPI port, clears the interrupt, and jumps to the reset vector. The problem is: the SPI port remains dead until a power cycle is accomplished.
The obvious fix is to use the watchdog (which is what I will eventually do), but I would like to understand the why of why this does not work (yes, bad coding practice is the real reason)...
Since the code jumps to the reset vector this is what I have been able to analyze:
(1) Since this is not a true reset (ie: via watchdog) all hardware registers are not reset - problem potential here. (2) The jump to the reset vector was accomplished while in supervisor mode, so the privleged registers (ie: SP,etc) can be written. (3) The timer interrupt was cleared prior to making the jump to the reset vector, so all interrupts are still enabled. (4) Since this is not a true reset, all resident code can still execute (ie: interrupt handlers). (5) The startup code will reset all initialized data, registers, etc prior to jumping to program main(), effectively returning data to a power up state.
One reason I can currently come up with as to why the SPI is never functional after this occurs is that maybe an interrupt occurs while in the startup code (clearing a tracking variable or resetting the processor registers). But the interrupt would also inhibit the startup code until it was serviced. This potential cause is (probably) not the only reason for this issue, and why I am asking for your input(s).
Unfortunately, this board has no JTAG to connect so stepping through the code is not an option. I could write to the serial port - if it was connected, but it isnt. Right now I am trying to analyze my way through this code before using a 'hammer' approach to solving this problem.
What else am I missing in this analysis? Thanks.
because the specification provides no real clarity regarding implied use.
No specification in the world can provide clarity. People will fail, or outright refuse, to understand what they read for various reasons, ranging from lack of understanding of technical/legalese English, to prejudice getting in the way.
As a programmer, how are we to know the implications of these statements? Should we?
By investing the time and effort to understand them. Yes, getting one's head around the more intricate aspects of C, of which "volatile" certainly is one, is hard work for most people. Hard work we're all presumably being paid for, that is.
To me, it is clear that the compiler would never move the variable buffer_ready above the for loop in optimizations.
What you (and the author of said paper) overlook is that the compiler doesn't have to do that to cause this code to violate the programmer's expectations. You're assuming that there's any guarantee whatsoever about when during execution of this function the non-volatile variable, buffer, will take on its value. Well, there isn't. The compiler is fully allowed to move any and all writes to buffer below the write to buffer_ready.
Ok, so your position is that the onus to understanding a weakly written document is solely on the readers of that document - not the writer(s)?
Wow. All I can say in response to that is - I agree we disagree.
The compiler is fully allowed to move any and all writes to buffer below the write to buffer_ready.
That kind of interpretation makes it diffult to ascribe meaning to the word 'previous':
"At certain specified points in the execution sequence called sequence points, all side effects of previous evaluations shall be complete"
That kind of interpretation makes it diffult to ascribe meaning to the word 'previous': [...]
Well yes, that's the kind of difficulty that will result from ripping a single sentence out of a text written in densely worded Legalese, and trying to take the result strictly at face value.
onus to understanding a weakly written document is solely on the readers of that document - not the writer(s)?
No. The onus on the readers is to actually prove that the document is weakly written before complaining about it. The onus on the writers is to amend it if it was proven to be defective. ISO has the Defect Report mechanism for that.
The onus on the readers is to actually prove that the document is weakly written before complaining about it.
Um. THAT was the whole point of the link Per included in his response. Did you read it? They documented a 96% failure rate using different programs and multiple compilers. They (the readers - specifically Utah CS) have done that part.
If your referring to this line posted by Jack - it is part of the Utah CS paper - not the spec
The onus on the readers is to actually prove that the document is weakly written before complaining about it...ISO has the Defect Report mechanism for that.
Um. THAT was the whole point of the link Per included in his response. Did you read it? They documented a 96% failure rate using different programs and multiple compilers.
You did not understand. As far as I understand it, Hens-Bernhard is referring to the razor-sharp language of the standard. You are referring to some article that tested implementations of it.
Tamir,
Please clarify what you mean by razor-sharp language. I read the specification as a typical technical standards document.
I personally do not see the 'legalese' that was mentioned within the specification to any great degree, but I do see the attempt to be a generic as possible. This in itself creates is the issue I believe leads to potential implementation problems.
For example, if you read lets say the description on how the 'for' loop should be handled/processed - it is quite clear to the reader (at least me) as to how it should function. However I don't see the same clarity with the volatile keyword implementation.
Well, ok, here's the complete paragraph from the standard:
Accessing a volatile object, modifying an object, modifying a file, or calling a function that does any of those operations are all side effects, which are changes in the state of the execution environment. Evaluation of an expression may produce side effects. At certain specified points in the execution sequence called sequence points, all side effects of previous evaluations shall be complete and no side effects of subsequent evaluations shall have taken place.
Now, consider this:
buffer_ready=1;
The code above modifies an object and therefore generates a side effect. The for loop contains several sequence points. If the position of 'buffer_ready=1' is moved relative to the for loop the condition that previous evaluation side effects must be complete and subsequent evaluation side effects must not have happened is breached.
Ridiculous. But makes the point nonetheless:
volatile int launch_missle; char default_coordinates[BUF_SIZE]; void LoadNLaunch() { int i; for (i=0; i<BUF_SIZE; i++) default_coordinates[i] = 0; launch_missle = 1; }