Reply by Dan Bloomquist August 5, 20092009-08-05
Paul Curtis wrote:
> Hi,
>
>
>>>> I could not find a __get_SR_register_on_exit but it would look like:
>>>>
>>>> #define GET_SR_ON_EXIT \
>>>> ({ \
>>>> uint16_t __x; \
>>>> __asm__ __volatile__( \
>>>> "mov .L__FrameOffset_" __FUNCTION__ "(r1), r15" \
>>>> : "=r" ((uint16_t) __x) \
>>>> :); \
>>>> __x; \
>>>> })
>>>>
>>>>
>>> I don't believe this definition is correct; for a start, the =r
>>>
>> constraint
>>
>>> assigns x to *some* register, might be r15, might not. It might work
>>>
> out
>
>>> for some functions, but won't for others. (Why use the =r constraint if
>>> there is no constraint in the assembly template text?)
>>>
>>>
>> I'm not up on the details of gcc but I I think that the compiler does a
>> one to one with the asm and the colon designations.
>>
>
> Having written some of these things for ARM, I can assure you that "think"
> is necessary but not sufficient to get this right.
>

Well yes, and why I wrote 'think' instead of 'is'.

>
>> But why it is not:
>>
>> : \
>> : "=r" ((uint16_t) __x)); \
>> I don't know, (I will eventually find out.). I just made it from code in
>> iomacros.h
>>
>
> You need some percents (%) in the assembly template. So, go read up on this
> stuff is my suggestion.
>

I have many times looked for information on gcc asm in lining, this time
I did find more info. But the real implication of the parameter list
have been left mostly as understood. But now I understand the colon set.
They separate input, output, and clobbered memory. The equal sign sets
'r' an output operand. I'll have to read it again, (and again :) but
here is the most complete paper I've found so far.

http://www.cs.virginia.edu/~clc5q/gcc-inline-asm.pdf
"The total number of operands is limited to ten or to the maximum number
of operands in any instruction pattern in the machine description,
whichever is greater."

Yet my example seems to trump that and it was derived from an example
that shipped with mspgcc.
>
>> Here is where I have the question. You wrote:
>>
>> "This only works if the stack pointer is not adjusted after the stack
>>
> frame
>
>> is created during execution of the function"
>>
>> From what I see it does not matter where the stack is.
>>
>
> Stack adjustment matters a great deal.
>

Well, now that I know 'what' stack adjustment you are talking about, sure...

>
>> The stack reference
>> in the call is relative to the current stack pointer. I don't see how the
>> stack can change while you are in the function call unless it is done
>> explicitly.
>>
>
> It is done explicitly. For instance
>
> void foobar(long, long, long, long);
>
> void fn(void)
> {
> foobar(1, 2, 3, 4);
> }
>
> Take a look at the assembly output. Now try to understand...

This is old stuff for me, I've been there before. I had a case where I
wanted to leave low power from a call made in an interrupt and knew the
stack pointer would be in the wrong place. But this is a case where you
are 'not' in the function call. The stack will be correct in the
interrupt call. I had it on the todo shelf to see if there was a way in
gcc to deal with this elegantly. I take it the Crossworks compiler, or
macro, is written to deal with this.

Best, Dan.

Beginning Microcontrollers with the MSP430

Reply by Paul Curtis August 5, 20092009-08-05
Hi,

> >> I could not find a __get_SR_register_on_exit but it would look like:
> >>
> >> #define GET_SR_ON_EXIT \
> >> ({ \
> >> uint16_t __x; \
> >> __asm__ __volatile__( \
> >> "mov .L__FrameOffset_" __FUNCTION__ "(r1), r15" \
> >> : "=r" ((uint16_t) __x) \
> >> :); \
> >> __x; \
> >> })
> >>
> >
> > I don't believe this definition is correct; for a start, the =r
> constraint
> > assigns x to *some* register, might be r15, might not. It might work
out
> > for some functions, but won't for others. (Why use the =r constraint if
> > there is no constraint in the assembly template text?)
> >
>
> I'm not up on the details of gcc but I I think that the compiler does a
> one to one with the asm and the colon designations.

Having written some of these things for ARM, I can assure you that "think"
is necessary but not sufficient to get this right.

> But why it is not:
>
> : \
> : "=r" ((uint16_t) __x)); \
>
>
> I don't know, (I will eventually find out.). I just made it from code in
> iomacros.h

You need some percents (%) in the assembly template. So, go read up on this
stuff is my suggestion.

> Here is where I have the question. You wrote:
>
> "This only works if the stack pointer is not adjusted after the stack
frame
> is created during execution of the function"
>
> From what I see it does not matter where the stack is.

Stack adjustment matters a great deal.

> The stack reference
> in the call is relative to the current stack pointer. I don't see how the
> stack can change while you are in the function call unless it is done
> explicitly.

It is done explicitly. For instance

void foobar(long, long, long, long);

void fn(void)
{
foobar(1, 2, 3, 4);
}

Take a look at the assembly output. Now try to understand how, and why, a
constant offset from the stack pointer will get you different values out of
the frame during the setup to the call of foobar().

This is why engineers that write compilers usually assume code written by
customers to be highly suspect in bug reports.

--
Paul Curtis, Rowley Associates Ltd http://www.rowley.co.uk
CrossWorks V2 is out for LPC1700, LPC3100, LPC3200, SAM9, and more!
Reply by Dan Bloomquist August 5, 20092009-08-05
Paul Curtis wrote:
> On Tue, 04 Aug 2009 20:13:46 +0100, Dan Bloomquist
> wrote:
>
>
>> So I did a test, the lights came on. .L__FrameOffset_ is an assembler
>> directive to offset the SP according to what is pushed on the stack in a
>> call. In one interrupt, no pushes I get:
>> LPM3_EXIT;
>> 279a: b1 c0 d0 00 bic #208, 0(r1) ;#0x00d0
>>
>> And with an r15 push I get:
>> LPM3_EXIT;
>> 2758: b1 c0 d0 00 bic #208, 2(r1) ;#0x00d0
>> 275c: 02 00
>>
>
> This only works if the stack pointer is not adjusted after the stack frame
> is created during execution of the function--a big ask.
>

See below.
>
>> I could not find a __get_SR_register_on_exit but it would look like:
>>
>> #define GET_SR_ON_EXIT \
>> ({ \
>> uint16_t __x; \
>> __asm__ __volatile__( \
>> "mov .L__FrameOffset_" __FUNCTION__ "(r1), r15" \
>> : "=r" ((uint16_t) __x) \
>> :); \
>> __x; \
>> })
>>
>
> I don't believe this definition is correct; for a start, the =r constraint
> assigns x to *some* register, might be r15, might not. It might work out
> for some functions, but won't for others. (Why use the =r constraint if
> there is no constraint in the assembly template text?)
>

I'm not up on the details of gcc but I I think that the compiler does a
one to one with the asm and the colon designations. But why it is not:

: \
: "=r" ((uint16_t) __x)); \
I don't know, (I will eventually find out.). I just made it from code in
iomacros.h

>
>> It compiles:
>> GET_SR_ON_EXIT;
>> 2790: 1f 41 02 00 mov 2(r1), r15 ;
>>
>
> Like I said, lucky. This time.
>
> You are not alone in getting this wrong--even Luminary (now owned by TI)
> got this stuff wrong with GCC and shipped it. I'm not sure anybody
> bothered to test their broken code on GCC because Michael has spent a few
> days correcting the "canned examples that just work!" that don't.
>

Here is where I have the question. You wrote:

"This only works if the stack pointer is not adjusted after the stack frame
is created during execution of the function"

>From what I see it does not matter where the stack is. The stack reference in the call is relative to the current stack pointer. I don't see how the stack can change while you are in the function call unless it is done explicitly.

I hate mysteries that could come back to bit me so I really want to understand what you see here.

Thanks, Dan.
Reply by Paul Curtis August 4, 20092009-08-04
On Tue, 04 Aug 2009 20:13:46 +0100, Dan Bloomquist
wrote:

> Paul Curtis wrote:
>> On Tue, 04 Aug 2009 18:31:20 +0100, Dan Bloomquist
>> wrote:
>>> (I have not used a device past 64k yet).
>>>
>>> But for a <64k device shouldn't 'if( *(int*)READ_SP & CPUOFF )' work
>>> fine?
>>> No. Consider a function with a local that is addressed--SP will
>> (usually)
>> be decremented by two on entry to the function to make a stack frame,
>> hence *SP or 2(SP) does not get you the saved SR and return address, it
>> would now be 2(SP) and 4(SP). Even worse, if in your C code you needed
>> to
>> call a function which requires arguments on the stack *and* you want to
>> read what's in the stack frame, then those 2(SP) and 4(SP) refrences
>> have
>> to change (depending on how much is currently pushed on to the stack,
>> aka
>> the stack adjustment).
>> So I did a test, the lights came on. .L__FrameOffset_ is an assembler
> directive to offset the SP according to what is pushed on the stack in a
> call. In one interrupt, no pushes I get:
> LPM3_EXIT;
> 279a: b1 c0 d0 00 bic #208, 0(r1) ;#0x00d0
>
> And with an r15 push I get:
> LPM3_EXIT;
> 2758: b1 c0 d0 00 bic #208, 2(r1) ;#0x00d0
> 275c: 02 00

This only works if the stack pointer is not adjusted after the stack frame
is created during execution of the function--a big ask.

> I could not find a __get_SR_register_on_exit but it would look like:
>
> #define GET_SR_ON_EXIT \
> ({ \
> uint16_t __x; \
> __asm__ __volatile__( \
> "mov .L__FrameOffset_" __FUNCTION__ "(r1), r15" \
> : "=r" ((uint16_t) __x) \
> :); \
> __x; \
> })

I don't believe this definition is correct; for a start, the =r constraint
assigns x to *some* register, might be r15, might not. It might work out
for some functions, but won't for others. (Why use the =r constraint if
there is no constraint in the assembly template text?)

> It compiles:
> GET_SR_ON_EXIT;
> 2790: 1f 41 02 00 mov 2(r1), r15 ;

Like I said, lucky. This time.

You are not alone in getting this wrong--even Luminary (now owned by TI)
got this stuff wrong with GCC and shipped it. I'm not sure anybody
bothered to test their broken code on GCC because Michael has spent a few
days correcting the "canned examples that just work!" that don't.

-- Paul.
Reply by Dan Bloomquist August 4, 20092009-08-04
Paul Curtis wrote:
> On Tue, 04 Aug 2009 18:31:20 +0100, Dan Bloomquist
> wrote:
>
>
>> (I have not used a device past 64k yet).
>>
>> But for a <64k device shouldn't 'if( *(int*)READ_SP & CPUOFF )' work
>> fine?
>>
>
> No. Consider a function with a local that is addressed--SP will (usually)
> be decremented by two on entry to the function to make a stack frame,
> hence *SP or 2(SP) does not get you the saved SR and return address, it
> would now be 2(SP) and 4(SP). Even worse, if in your C code you needed to
> call a function which requires arguments on the stack *and* you want to
> read what's in the stack frame, then those 2(SP) and 4(SP) refrences have
> to change (depending on how much is currently pushed on to the stack, aka
> the stack adjustment).
>

So I did a test, the lights came on. .L__FrameOffset_ is an assembler
directive to offset the SP according to what is pushed on the stack in a
call. In one interrupt, no pushes I get:
LPM3_EXIT;
279a: b1 c0 d0 00 bic #208, 0(r1) ;#0x00d0

And with an r15 push I get:
LPM3_EXIT;
2758: b1 c0 d0 00 bic #208, 2(r1) ;#0x00d0
275c: 02 00

I could not find a __get_SR_register_on_exit but it would look like:

#define GET_SR_ON_EXIT \
({ \
uint16_t __x; \
__asm__ __volatile__( \
"mov .L__FrameOffset_" __FUNCTION__ "(r1), r15" \
: "=r" ((uint16_t) __x) \
:); \
__x; \
})
It compiles:
GET_SR_ON_EXIT;
2790: 1f 41 02 00 mov 2(r1), r15 ;

Thanks, Dan.

Reply by Mike Raines August 4, 20092009-08-04
Thanks to all who replied and either pointed out the faults in my algorithm or pointed to a better way.
I checked the intrinsic functions for IAR (full) and am using "if (__get_SR_register_on_exit() & CPUOFF) "
to determine if I will be asleep when exiting the ISR.

Thanks again. Great bunch of Guys,
Mike Raines

________________________________
From: m... [mailto:m...] On Behalf Of Dan Bloomquist
Sent: Tuesday, August 04, 2009 1:31 PM
To: m...
Subject: Re: [msp430] Reading status register

Paul Curtis wrote:
> Hi,
>> Mike Raines wrote:
>>
>>> Folks,
>>>
>>> I'm trying to read the status register to see if the cpu is off while
>>>
>> inside the SYSNMI ISR. I have tried if (SR & CPUOFF) and if (R2 & CPUOFF)
>> and the compiler doesn't recognize SR or R2. I'm sure this is simple.
>> What am I missing? MSP430F5438 chip...
>>
>> As pointed out, the cpu is running in the interrupt. The condition of
>> LPM is on the stack and gets popped back at the interrupt exit. I don't
>> know about your compiler but for mspgcc there is READ_SP. It assembles to:
>> mov r1, r15;
>>
>> So you can:
>> if( READ_SP & CPUOFF)
>> I think you're just testing a bit in the stack pointer. That's not what you
> want to do. You need to read a value offset from the stack pointer--doing
> so is inherently non-portable. There are intrinsic functions to do this for
> you which will account for the current stack pointer and the stack pointer
> on entry to the ISR.
>

Hi Paul,
Thanks. And it occurred to me after posting. I don't know what that
function is in mspgcc so I would end up hacking one. But I'm not sure
about the rest. I take it the offset is about using an extended memory
device like the MSP430F543x? Is that what the .L__FrameOffset_ is for?
(I have not used a device past 64k yet).

But for a <64k device shouldn't 'if( *(int*)READ_SP & CPUOFF )' work fine?

And yes! by declaring my int pointer unsigned I get clrc, rrc!

It just doesn't feel right that whatever was sitting in the carry flag
gets shifted in for a signed int.

Best, Dan.



Reply by Paul Curtis August 4, 20092009-08-04
On Tue, 04 Aug 2009 18:31:20 +0100, Dan Bloomquist
wrote:

>>> So you can:
>>> if( READ_SP & CPUOFF)
>>
>> I think you're just testing a bit in the stack pointer. That's not
>> what you
>> want to do. You need to read a value offset from the stack
>> pointer--doing
>> so is inherently non-portable. There are intrinsic functions to do
>> this for you which will account for the current stack pointer and the
>> stack pointer on entry to the ISR.
>> Hi Paul,
> Thanks. And it occurred to me after posting. I don't know what that
> function is in mspgcc so I would end up hacking one. But I'm not sure
> about the rest. I take it the offset is about using an extended memory
> device like the MSP430F543x? Is that what the .L__FrameOffset_ is for?

Who knows? I've no interest in MSPGCC. ;-)

> (I have not used a device past 64k yet).
>
> But for a <64k device shouldn't 'if( *(int*)READ_SP & CPUOFF )' work
> fine?

No. Consider a function with a local that is addressed--SP will (usually)
be decremented by two on entry to the function to make a stack frame,
hence *SP or 2(SP) does not get you the saved SR and return address, it
would now be 2(SP) and 4(SP). Even worse, if in your C code you needed to
call a function which requires arguments on the stack *and* you want to
read what's in the stack frame, then those 2(SP) and 4(SP) refrences have
to change (depending on how much is currently pushed on to the stack, aka
the stack adjustment).

> And yes! by declaring my int pointer unsigned I get clrc, rrc!

That's fine. And shifting an int is (in fact) inherently non-portable.

> It just doesn't feel right that whatever was sitting in the carry flag
> gets shifted in for a signed int.

If you read the C standard you will find that shifting a signed integer
can result in an aritmetic shift (shift sign bit in) *or* a logical shift
(shift a zero bit in).

How portable is that? Is it any wonder that there are brittle programs in
this world when users assume a specific type of shift?

-- Paul.
Reply by Dan Bloomquist August 4, 20092009-08-04
Paul Curtis wrote:
> Hi,
>
>
>> Mike Raines wrote:
>>
>>> Folks,
>>>
>>> I'm trying to read the status register to see if the cpu is off while
>>>
>> inside the SYSNMI ISR. I have tried if (SR & CPUOFF) and if (R2 & CPUOFF)
>> and the compiler doesn't recognize SR or R2. I'm sure this is simple.
>> What am I missing? MSP430F5438 chip...
>>
>> As pointed out, the cpu is running in the interrupt. The condition of
>> LPM is on the stack and gets popped back at the interrupt exit. I don't
>> know about your compiler but for mspgcc there is READ_SP. It assembles to:
>> mov r1, r15;
>>
>> So you can:
>> if( READ_SP & CPUOFF)
>>
>
> I think you're just testing a bit in the stack pointer. That's not what you
> want to do. You need to read a value offset from the stack pointer--doing
> so is inherently non-portable. There are intrinsic functions to do this for
> you which will account for the current stack pointer and the stack pointer
> on entry to the ISR.
>

Hi Paul,
Thanks. And it occurred to me after posting. I don't know what that
function is in mspgcc so I would end up hacking one. But I'm not sure
about the rest. I take it the offset is about using an extended memory
device like the MSP430F543x? Is that what the .L__FrameOffset_ is for?
(I have not used a device past 64k yet).

But for a <64k device shouldn't 'if( *(int*)READ_SP & CPUOFF )' work fine?

And yes! by declaring my int pointer unsigned I get clrc, rrc!

It just doesn't feel right that whatever was sitting in the carry flag
gets shifted in for a signed int.

Best, Dan.

Reply by Paul Curtis August 4, 20092009-08-04
Hi,

> Mike Raines wrote:
> > Folks,
> >
> > I'm trying to read the status register to see if the cpu is off while
> inside the SYSNMI ISR. I have tried if (SR & CPUOFF) and if (R2 & CPUOFF)
> and the compiler doesn't recognize SR or R2. I'm sure this is simple.
> What am I missing? MSP430F5438 chip...
> >
>
> As pointed out, the cpu is running in the interrupt. The condition of
> LPM is on the stack and gets popped back at the interrupt exit. I don't
> know about your compiler but for mspgcc there is READ_SP. It assembles to:
> mov r1, r15;
>
> So you can:
> if( READ_SP & CPUOFF)

I think you're just testing a bit in the stack pointer. That's not what you
want to do. You need to read a value offset from the stack pointer--doing
so is inherently non-portable. There are intrinsic functions to do this for
you which will account for the current stack pointer and the stack pointer
on entry to the ISR.

--
Paul Curtis, Rowley Associates Ltd http://www.rowley.co.uk
CrossWorks V2 is out for LPC1700, LPC3100, LPC3200, SAM9, and more!
Reply by Dan Bloomquist August 4, 20092009-08-04
Mike Raines wrote:
> Folks,
>
> I'm trying to read the status register to see if the cpu is off while inside the SYSNMI ISR. I have tried if (SR & CPUOFF) and if (R2 & CPUOFF) and the compiler doesn't recognize SR or R2. I'm sure this is simple. What am I missing? MSP430F5438 chip...
>

As pointed out, the cpu is running in the interrupt. The condition of
LPM is on the stack and gets popped back at the interrupt exit. I don't
know about your compiler but for mspgcc there is READ_SP. It assembles to:
mov r1, r15;

So you can:
if( READ_SP & CPUOFF)

to see if you will be in LPM.

Best, Dan.