EmbeddedRelated.com
Forums

Reading status register

Started by Mike Raines August 4, 2009
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.

Beginning Microcontrollers with the MSP430

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!
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.