Reply by Bill Knight February 22, 20042004-02-22
The kernel of a preemptive RTOS might want to.

Bill
On Sun, 22 Feb 2004 14:32:55 -0500, Robert Adsett wrote:

At 02:22 PM 2/22/04 -0500, you wrote:
>At 10:13 AM 2/22/04 -0600, you wrote:
> >As a side note. The disabling and restoring of the global interrupt
> >flag in the cpsr can has a similar problem.

><snip>

> >For more info on this, Atmel has
> >an APP note discribing it on their web site in the AT91 ARM7 section.

>Thanks for the pointer.

I just had a chance to read the app note (I presume this is the one
http://www.atmel.com/dyn/resources/prod_documents/DOC1156.PDF) and it
appears to be warning about faults that can happen when using a style of
code I would consider very error prone to begin with. Unless I'm missing
something (I've only had a little while to consider it) the only time a
problem occurs if an interrupt routine actually modifies the cpu status of
the interrupted code. What would ever prompt anyone to do that in the
first place?

Robrt

" 'Freedom' has no meaning of itself. There are always restrictions,
be they legal, genetic, or physical. If you don't believe me, try to
chew a radio signal. "

Kelvin Throop, III Yahoo! Groups Links


An Engineer's Guide to the LPC2100 Series

Reply by Robert Adsett February 22, 20042004-02-22
At 03:55 PM 2/22/04 -0500, you wrote:
>You're right about the context of the processor status save. The only
>reason I can think of for modifying the PSW like that would be in a task
>switcher of some kind.

hmm, I don't yet see where that would be useful in a task switch but maybe
it can happen as a side effect. I've got a thread to worry at
anyway. Atmel went to a lot of trouble for a workaround so there must be
some reason to do it. Something to puzzle away at for a bit,

Robert

" 'Freedom' has no meaning of itself. There are always restrictions,
be they legal, genetic, or physical. If you don't believe me, try to
chew a radio signal. "

Kelvin Throop, III


Reply by David Willmore February 22, 20042004-02-22
> I was certainly used to fairly aggressive and neat opts with IAR, but I've
> never seen it change the sequence of things, that seems a bit rich.
> Mind you, that was on MSP430 and on AVR mainly.

I wouldn't expect the same kinds of optimizations on uCs that you may see
on larger systems. IBMs xcc for the POWER arch does a lot of bizarre
stuff to code. If the compiler can tell what the inputs of a function
are and all the things it touches, then if this does not conflict with
other things happening in the code, there is no programmer visible
problem with the compiler moving the execution of that chunk of code
around. There are even compilers that will throw it off in another
thread automatically--should you have multiple CPUs, this can be a win.

> Now that I know these things can happen (moving code around), I know what to
> look for and can stop bugging you guys :-)
> Without knowing this things look daunting.
>
> Is there a specific include file to use barrier() ???

It may not even be called barrier on your system. It's a compiler
specific option, so I don't even know where to point you. Sorry.

Cheers,
David



Reply by David Willmore February 22, 20042004-02-22
> > There is no guarantee that those statements will be performed in the order
> > you might guess. The compiler may even optimize some of them away
> > entirely. If write_to_reg is a macro, the compiler may chose to remove
> > the first invocation as the second will just overwrite it. It may even
> > remove the delay if it can figure out that it's not effecting any
> > variables.
> >
> > [snip]
>
> If write_to_reg is a function, GCC will in NO WAY change the
> ordering. If they are macros, then unless the person who wrote the
> headers is a complete hack, they will contain volatile (and anyone smart
> enough to write header files knows this), and GCC will not reorder them.

What a tangled web we weave when first we practice *edit* to write system
code. All I can say in my defence is take a look at the Linux kernel code
and see how many places bariers are used to keep GCC from getting overly
agressive. Yes, there are ways to make sure it doesn't do it by using
volatile. Yes, procedure calls will not be removed or moved *unless*
they are inline. In which they're fair game. And, yes, I've seen GCC
figure out that delay inlines were nulls and remove them. There are a
few tricks in the Linux kernel to defeat that behavior while still allowing
the use of inline delays.

> I've used GCC on several architectures, and I have never seen it
> arbitrarily reorder code execution. While it depends on the
> optimization level selected, I've only ever seen GCC reorder items in
> registers, and only then when there was no visible effect, i.e.
>
> int a;
>
> a++;
> do_some_func ();
> a++;

Yes, *from the point of view of the CPU*. From the point of hardware, no,
that is not true. I have seen writes to memory squashed when the same
location was written again shortly after. I've seen writes delayed
for a long time--throwing code off. Proper use of volitile fixes almost
all of this, but compilers have failed to do the right thing with volatile
in the past.

> I use GCC on x86, MSP430, AVR frequently, and occasionally on 68K
> and Sparc, written interrupt routines purely in C on all of those except
> 68K, and never run into re-ordering issues. If anything, I tend to get
> bit by forgetting to declare a global as volatile, and run into the
> issue of the value being cached in a register, so things like queue
> incrementers don't behave as expected. And I've come to be able to
> recognize those pretty quickly :(

Yep. Once you know the kinds of things the compiler is allowed to do--
unless you tell it not to--you're in a better position to debug such
failures. I'm just trying to point out things that the compiler can
do to help others learn what you and I have learned--the very hard way.

> I usually use -Os optimization on AVRs, and -O2 or -O3 on x86 and
> MSP430. On Sparcs I usually use -O1, but that's because there's a
> particular bug in the revision of compiler I'm running on it.

:) He he. :) -Oinfinity and damn the torpedoes!

Cheers,
David



Reply by Robert Adsett February 22, 20042004-02-22
At 08:07 AM 2/23/04 +1100, you wrote:
>I must assume that Bill Knight's original speculation that direct writes to
>eg. UxIER still
>*can* cause "spurious interrupts" is correct.
>There must be a mechanism where the write instruction is still be in
>execution unit while a
>vectored INT request decodes in the VIC.

That triggers a thought. There is a writeback cache on the LPC. It's only
a single entry and I thought it was only for the SRAM but maybe it's more
universal than I remember. There was a note in the User manual saying that
if a write to ram (?) absolutely had to be there a second write was
required. It also appeared to be the case that a write followed by a read
to the same location would work though since it would read out of the
cache. In fact I thought reading through it that the only place this could
be an issue is if you wanted the written value to get through a
reset. It's a bit of a stretch but it might be worth checking the user manual. >In any case, I presume that the best prottection is to have it in a separate
>function....?
>I found that calling a function that explicitly Disables IRQ Global,
>sets/clears THRE,
>then re-Enables IRQ Global, then returns makes all the permuations of
>previous code now
>behave as I expected it to, regardless of the method of doing the TX buffer
>write and update
>of the pointer, and regardless of how I set the optimisation.
>
>This to me implies that the instruction sequences indeed are being changed.
>I've been stepping around in ASM, but it is _very_ time consuming, it
>started to annoy me :-)

gcc -S -Os is very enlightening. Definitely not a simple mapping.

>I do intend to fully get to the bottom of this, as I want to know what on
>earth was causing these
>bizarre behaviours, it seems that it's compiler reordering, I will revisit
>this later.
>I'm writing 2 functions set_int() and clr_int() that take a register and a
>bit number, and then
>Enable/Disable individual INTs.
>
>Does that seem like a plausible scenario ????

Sounds good. I'd expand those functions a bit and have them return the
previous interrupt state so you could do something like;

pre_int = DisableINT( INT_BLAH);

blah blah;

RestoreINT( pre_int); That allows things like nested disable/enables to work. >Best regards,
>Kris >
>
>Yahoo! Groups Links >
>

" 'Freedom' has no meaning of itself. There are always restrictions,
be they legal, genetic, or physical. If you don't believe me, try to
chew a radio signal. "

Kelvin Throop, III


Reply by microbit February 22, 20042004-02-22
Hi John,
 
> Kris,
>
>     Instead of stepping around, why not use objdump on the elf file to
> produce an assembly listing, and take a look at the ordering?
>
>     objdump -dSt foo >foo.lst
>   
>     Be sure to compile your sources with the -g option.
Because of the confusion reigning, I'm trying it alternating between HI-TECH C
and also on CrossWorks for ARM.
I'm not proficient with the actual GCC toolchain itself, but I can easily check the tool to
produce an ASM listing (absolute I hope).
I will investigate this at ASM level when I return to it, and certainly post my findings here.
 
On one hand it's like I've already spent way too much time on it ("Don't muck with it" :-)
but on the other hand it's given me further insight into the instruction set, the VIC and
other obvious intrinsic issues.
 
I need to now start re-thinking my tasking, as this project set out to easily port around between
different MCUs. (before ARM came into ti)
I need to rework my HW abstraction. so other changes can still efficiently run just as well on MSP430
as on ARM or AVR etc. , it's quite a bit of a challenge.....
 
 
-- Kris
 


Reply by J.C. Wren February 22, 20042004-02-22
Kris,

Instead of stepping around, why not use objdump on the elf file to
produce an assembly listing, and take a look at the ordering?

objdump -dSt foo >foo.lst

Be sure to compile your sources with the -g option.

--jc

microbit wrote:

> Hi all,
>
> Well, here'e some feedback to this bizarre issue.
> Everything was already volatile, except for the local "temp" variable.
> Refer the earlier example below :
>
> > > > UINT temp;
> > > >
> > > > /* Handle TX buffer wrap */
> > >temp = (tx_head+1)%RS232_SIZE;
> > > >
> > > > /* Disable TX interrupts */
> > > > U0IER = 0x01;
> > > >
> > > > /* Circ buffer not empty ? */
> > > > if (comm_tx_running)
> > > > {
> > > > comm_tx[tx_head] = (UCHAR)ch;
> > > > tx_head = temp;
> > > > }
> > > > else
> > > > {
> > > > comm_tx_running = 1;
> > > > U0THR = ch;
> > > > }
> > > >
> > > > /* Reenable TX interrupts */
> > > > U0IER = 0x03;
> > > > return (ch);
>
> Declaring "temp" volatile didn't help a bit, on the contrary, some tests
> started
> exhibiting default_IRQs, whereas before they didn't.
>
> It MUST be that the compiler is changing the sequence of things (when I
> single step
> at C level, it's certainly all over the place) - despite the volatiles.
> In any case, even so, I don't get why that should have a bearing on
> reading
> the head_pointer
> and increment/wrapping it, and then inside the protected part using the
> current pointer, and then
> updating it
> - VERSUS -
> Post incrementing on tx_head while doing the write to comm_tx[] TX buffer.
>
> I must assume that Bill Knight's original speculation that direct
> writes to
> eg. UxIER still
> *can* cause "spurious interrupts" is correct.
> There must be a mechanism where the write instruction is still be in
> execution unit while a
> vectored INT request decodes in the VIC.
>
> In any case, I presume that the best prottection is to have it in a
> separate
> function....?
> I found that calling a function that explicitly Disables IRQ Global,
> sets/clears THRE,
> then re-Enables IRQ Global, then returns makes all the permuations of
> previous code now
> behave as I expected it to, regardless of the method of doing the TX
> buffer
> write and update
> of the pointer, and regardless of how I set the optimisation.
>
> This to me implies that the instruction sequences indeed are being
> changed.
> I've been stepping around in ASM, but it is _very_ time consuming, it
> started to annoy me :-)
> I do intend to fully get to the bottom of this, as I want to know what on
> earth was causing these
> bizarre behaviours, it seems that it's compiler reordering, I will revisit
> this later.
> I'm writing 2 functions set_int() and clr_int() that take a register and a
> bit number, and then
> Enable/Disable individual INTs.
>
> Does that seem like a plausible scenario ????
>
> Best regards,
> Kris


Reply by microbit February 22, 20042004-02-22
Hi all,

Well, here'e some feedback to this bizarre issue.
Everything was already volatile, except for the local "temp" variable.
Refer the earlier example below :

> > > UINT temp;
> > >
> > > /* Handle TX buffer wrap */
> >temp = (tx_head+1)%RS232_SIZE;
> > >
> > > /* Disable TX interrupts */
> > > U0IER = 0x01;
> > >
> > > /* Circ buffer not empty ? */
> > > if (comm_tx_running)
> > > {
> > > comm_tx[tx_head] = (UCHAR)ch;
> > > tx_head = temp;
> > > }
> > > else
> > > {
> > > comm_tx_running = 1;
> > > U0THR = ch;
> > > }
> > >
> > > /* Reenable TX interrupts */
> > > U0IER = 0x03;
> > > return (ch);

Declaring "temp" volatile didn't help a bit, on the contrary, some tests
started
exhibiting default_IRQs, whereas before they didn't.

It MUST be that the compiler is changing the sequence of things (when I
single step
at C level, it's certainly all over the place) - despite the volatiles.
In any case, even so, I don't get why that should have a bearing on reading
the head_pointer
and increment/wrapping it, and then inside the protected part using the
current pointer, and then
updating it
- VERSUS -
Post incrementing on tx_head while doing the write to comm_tx[] TX buffer.

I must assume that Bill Knight's original speculation that direct writes to
eg. UxIER still
*can* cause "spurious interrupts" is correct.
There must be a mechanism where the write instruction is still be in
execution unit while a
vectored INT request decodes in the VIC.

In any case, I presume that the best prottection is to have it in a separate
function....?
I found that calling a function that explicitly Disables IRQ Global,
sets/clears THRE,
then re-Enables IRQ Global, then returns makes all the permuations of
previous code now
behave as I expected it to, regardless of the method of doing the TX buffer
write and update
of the pointer, and regardless of how I set the optimisation.

This to me implies that the instruction sequences indeed are being changed.
I've been stepping around in ASM, but it is _very_ time consuming, it
started to annoy me :-)
I do intend to fully get to the bottom of this, as I want to know what on
earth was causing these
bizarre behaviours, it seems that it's compiler reordering, I will revisit
this later.
I'm writing 2 functions set_int() and clr_int() that take a register and a
bit number, and then
Enable/Disable individual INTs.

Does that seem like a plausible scenario ????

Best regards,
Kris




Reply by J.C. Wren February 22, 20042004-02-22
Robert Adsett wrote:

> [snip]
>
> That I can understand (I've done it myself), but even in that case you
> don't modify the status register of the process you are interrupting but
> only your own copy. The usual interrupt entry in either SW or HW goes
> something like
>
> save processor status
> save interrupt return address
>
> and then on exit
>
> return to saved return address
> restore processor status
>
> The issue in the appnote involves modifying the saved processor
> status. (ie that of the interrupted code) I don't understand why you
> would want to do that. In the best case it will do nothing and in the
> worst....
>
[snip]

You're right about the context of the processor status save. The only
reason I can think of for modifying the PSW like that would be in a task
switcher of some kind.

--jc



Reply by Robert Adsett February 22, 20042004-02-22
At 02:50 PM 2/22/04 -0500, you wrote:
>Robert Adsett wrote:
>
> > At 02:22 PM 2/22/04 -0500, you wrote:
> > >At 10:13 AM 2/22/04 -0600, you wrote:
> > > >As a side note. The disabling and restoring of the global interrupt
> > > >flag in the cpsr can has a similar problem.
> > >
> > ><snip>
> > >
> > > >For more info on this, Atmel has
> > > >an APP note discribing it on their web site in the AT91 ARM7 section.
> > >
> > >Thanks for the pointer.
> >
> > I just had a chance to read the app note (I presume this is the one
> > http://www.atmel.com/dyn/resources/prod_documents/DOC1156.PDF)
> > <http://www.atmel.com/dyn/resources/prod_documents/DOC1156.PDF%29> and it
> > appears to be warning about faults that can happen when using a style of
> > code I would consider very error prone to begin with. Unless I'm missing
> > something (I've only had a little while to consider it) the only time a
> > problem occurs if an interrupt routine actually modifies the cpu
> > status of
> > the interrupted code. What would ever prompt anyone to do that in the
> > first place?
> >
> > [snip]
>
> It's a common method of creating interrupt prioritization. If you
>have a "slow" interrupt routine, or something more critical, it's common
>to re-enable interrupts inside the interrupt routines.

That I can understand (I've done it myself), but even in that case you
don't modify the status register of the process you are interrupting but
only your own copy. The usual interrupt entry in either SW or HW goes
something like

save processor status
save interrupt return address

and then on exit

return to saved return address
restore processor status

The issue in the appnote involves modifying the saved processor
status. (ie that of the interrupted code) I don't understand why you
would want to do that. In the best case it will do nothing and in the
worst.... > I kinda miss the days of the 8051 and such when an arbitrary
>peripherial that generates interrupts could be specified to be high or
>low priority.

Or the ST10/C166 where they are almost infinitely variable :)

The VIC would seem to provide at least some of that but I haven't played
with it yet.

Robert

" 'Freedom' has no meaning of itself. There are always restrictions,
be they legal, genetic, or physical. If you don't believe me, try to
chew a radio signal. "

Kelvin Throop, III