Effect of additionnal save/restore instructions

Gedare Bloom gedare at rtems.org
Wed Apr 24 14:53:15 UTC 2013


The details can be found in SPARC Architecture Manuals, but the high level
is that local registers are safe to use if the register window has changed.
For a leaf function (that does not call any other function), the compiler
can "leaf-optimize" the function by not changing the register window. In
such case, only the output (o0-o7) and global registers can safely be
accessed. My guess is that your contractor tried to get around this
somewhat with the (poorly designed, incorrectly implemented) save/restore
pair. The better solution would have been to let gcc assign the register,
as you are now doing, or to use a register that is "safe" such as %o0 and
put it in the clobber list.

-Gedare


On Wed, Apr 24, 2013 at 9:31 AM, Leonard Bise <leonard.bise at syderal.ch>wrote:

> Thank you Gedare for the input.
> There is also something not very clear for me.
> Claudio earlier told me that using %l7 register was not safe but how come?
> Since it is a local register I'd expect I can do whatever I want with it?
>
>
> 2013/4/24 Gedare Bloom <gedare at rtems.org>
>
>> This is a lot better. As Joel said, there is still a problem if an
>> interrupt can come. For that you should use a general timer if available.
>> Also, I made one comment below.
>>
>>
>> On Wed, Apr 24, 2013 at 5:54 AM, Leonard Bise <leonard.bise at syderal.ch>wrote:
>>
>>> Thanks a lot for your inputs guys. I realise now that I actually didn't
>>> know exactly how to write inline assembly code properly.
>>>
>>> Joel: Yes the goal of this function is to have a known number of cycles.
>>> Thank you for your precious input.
>>>
>>> Here is the final code version we settled on.
>>>
>>> void SCET_wait_2us(void) {****
>>>
>>>     {****
>>>
>>>         /*#[ operation SCET_wait_2us() */****
>>>
>>>     uint32 count;****
>>>
>>>         /* Performs a 60us delay using an __asm__ __volatile__ loop,
>>> this piece of code has been****
>>>
>>>          * measured on HW to validate the duration is correct */****
>>>
>>>     __asm__ __volatile__("set " XSTR(NB_ITER_60US) ", %0" : "=r"(count));
>>> ****
>>>
>>>     __asm__ __volatile__("StartLoop1us:");****
>>>
>>>     __asm__ __volatile__("dec 1, %0" : "=r" (count));****
>>>
>>>     __asm__ __volatile__("cmp %0, 0" : "=r" (count));
>>>
>> While this should work, the count variable is actually an input here, so
>> you really just need
>> __asm__ __volatile__("cmp %0, 0" : :  "r" (count));
>>
>> As always, check the output of the assembler pass to make sure your
>> function looks like how you expect. The compiler could (in theory) move
>> data between memory and register within this code block.
>>
>>> ****
>>>
>>>     __asm__ __volatile__("bne StartLoop1us");****
>>>
>>>     __asm__ __volatile__("nop");****
>>>
>>>         /*#]*/****
>>>
>>>     }****
>>>
>>> }
>>>
>>>
>>> 2013/4/23 Joel Sherrill <joel.sherrill at oarcorp.com>
>>>
>>>>  Hi
>>>>
>>>> SPARC register usage combined with the the register windowing
>>>> makes things difficult to figure out.  Using save/restore in the middle
>>>> of inline assembly like that is too scary for my personal taste. It is
>>>> certainly not normal SPARC programming.
>>>>
>>>> I don't like the fact they used a "trivial" save instruction which adds
>>>> 0 bytes to the stack as best I can tell. It is equivalent to
>>>> "save %g0,%g0,%g0". Normal usage includes three real arguments
>>>> and looks more like this:
>>>>
>>>>         PUBLIC(_CPU_Context_save_fp)
>>>> SYM(_CPU_Context_save_fp):
>>>>         save    %sp, -CPU_MINIMUM_STACK_FRAME_SIZE, %sp
>>>>
>>>> That saves space on the stack to save the window. I THINK the trivial
>>>> save rotates the CWP but doesn't make space. I expect this would
>>>> lead to a crash eventually as (my guess) is that you end up with
>>>> two register windows associated with the same spot on the stack.
>>>> You have rotated twice but only saved one hole on the stack. As
>>>> you start returning and restoring, I expect this would result in
>>>> some odd type of stack reuse.
>>>>
>>>> My first question is always ... Why is this in inline assembly anyway?
>>>>
>>>> If it is to do a tight loop with a known number of cycles, then the
>>>> second round of questions are:
>>>>
>>>> + Why didn't they use the proper asm statement constraints?
>>>> + Why isn't this asm volatile?
>>>> + What happens if an interrupt occurs in the middle of this?
>>>>
>>>> If you are using a general purpose register gcc may use, then you need
>>>> to
>>>> specify that. Generally speaking, you can declare local variables and
>>>> "pass"
>>>> them to inline asm via constraint specifications. This lets gcc pick
>>>> the register(s)
>>>> and avoids one type of trouble.
>>>>
>>>> There are some asm with constraint examples in cpukit/score/cpu/sparc.
>>>>
>>>> --joel
>>>>
>>>>
>>>> On 4/23/2013 4:02 AM, Leonard Bise wrote:
>>>>
>>>> Hello all,
>>>>
>>>>  I'm having a problem regarding the processor window registers that I
>>>> cannot explain easily mostly because I'm not super familiar with this
>>>> subject.
>>>>
>>>>  First, I'm using a LEON2 Sparc v8 processor and RTEMS 4.8 version
>>>> which is required by our project.
>>>>
>>>>  We have a function using inline assembly to perform a flat delay,
>>>> here is the code it use.
>>>>
>>>>   void SCET_wait_2us(void) {
>>>>
>>>>     {
>>>>
>>>>         /*#[ operation SCET_wait_2us() */
>>>>
>>>>         /* Performs a 60us delay using an ASM loop, this piece of code
>>>> has been
>>>>
>>>>          * measured on HW to validate the duration is correct */
>>>>
>>>>         __asm__("                                \
>>>>
>>>>                 save;                            \
>>>>
>>>>                 set " XSTR(NB_ITER_60US) ", %l7; \
>>>>
>>>>                 StartLoop1us:                    \
>>>>
>>>>                 dec 1, %l7;                      \
>>>>
>>>>                 cmp %l7, 0;                      \
>>>>
>>>>                 bne StartLoop1us;                \
>>>>
>>>>                 nop;                             \
>>>>
>>>>                 restore;                         \
>>>>
>>>>                 ");
>>>>
>>>>         /*#]*/
>>>>
>>>>     }
>>>>
>>>> }
>>>>
>>>>  Originally this code didn't have the save and restore instruction but
>>>> our sub contractor added them because they had problems compiling. I find
>>>> it an odd solution but whatever.
>>>>
>>>>  Once this code was implemented we started seeing random processor
>>>> reset occurring in various contexts.
>>>>
>>>>  I tested this code while being in the Eclipse debugger and once the
>>>> crash happened I noticed I had a segmentation fault in Eclipse. I used
>>>> GRMON to check the processor register and noticed that the last trap that
>>>> occurred was a window underflow trap 0x06.
>>>>
>>>>  I found in the RTEMS sources the code for this handler, and while I
>>>> haven't understood everything I took out that the code was trying to
>>>> recover from this error, is this correct?
>>>>  I copied the trap handler code below.
>>>>
>>>>  RTEMS 4.8 branch
>>>> file : rtems / c / src / lib / libcpu / sparc / reg_win / window.S
>>>> *
>>>> *
>>>> SYM(window_underflow_trap_handler):
>>>>
>>>>         /*
>>>>          * Calculate new WIM by "rotating" the valid bits in the WIM
>>>> left
>>>>          * by one position. The following shows how the bits move for a
>>>> SPARC
>>>>          * cpu implementation where SPARC_NUMBER_OF_REGISTER_WINDOWS is
>>>> 8.
>>>>          *
>>>>          * OLD WIM = 76543210
>>>>          * NEW WIM = 07654321
>>>>          *
>>>>          * NOTE: New WIM must be stored in a global register since the
>>>>          * "save" instruction just prior to the load of the wim
>>>>          * register will result in the local register set changing.
>>>>          */
>>>>
>>>>         mov %wim, %l3 ! Calculate new WIM
>>>>         sll %l3, 1, %l4 ! l4 = WIM << 1
>>>>         srl %l3, SPARC_NUMBER_OF_REGISTER_WINDOWS-1, %l5
>>>>                                         ! l5 = WIM >> (Number Windows-1)
>>>>         or %l5, %l4, %l5 ! l5 = (WIM << 1) |
>>>>                                         ! (WIM >> (Number Windows-1))
>>>>         mov %l5, %wim ! load the new WIM
>>>>         nop; nop; nop
>>>>         restore ! Two restores to get into the
>>>>         restore ! window to restore
>>>>         ldd [%sp + 0x00], %l0 ! First the local register set
>>>>         ldd [%sp + 0x08], %l2
>>>>         ldd [%sp + 0x10], %l4
>>>>         ldd [%sp + 0x18], %l6
>>>>         ldd [%sp + 0x20], %i0 ! Then the input registers
>>>>         ldd [%sp + 0x28], %i2
>>>>         ldd [%sp + 0x30], %i4
>>>>         ldd [%sp + 0x38], %i6
>>>>         save ! Get back to the trap window.
>>>>         save
>>>>         jmp %l1 ! Re-execute restore.
>>>>         rett %l2
>>>>
>>>>  From my understanding this code should not ever fail, is that correct?
>>>> What I'm not sure is that if this type of trap can be a
>>>> common occurrence or if that means something went bad in the software.
>>>>
>>>>  Basically now I removed the save/restore and it seems to be working
>>>> fine but I'll have to explain exactly what was happening before.
>>>> Is the compiler not expecting the user to add save/restore and could
>>>> that lead to the behavior we see sometimes (processor reset). What are the
>>>> usual way to handle this type of inline assembly? Never use save/restore?
>>>>
>>>>  Also our customer gave us a sequence of command to send to the
>>>> software that would produce this reset systematically however when we got
>>>> the equipment over here, I tried with the same code the sequence and it is
>>>> not happening as often as they say. There seem to be a lot of randomness to
>>>> this problem.
>>>>
>>>>  I really hope someone can provide some knowledge on this type of
>>>> issue.
>>>> --
>>>>  *
>>>> *
>>>>  *Léonard Bise*
>>>> Software Design Engineer
>>>> Direct Line +41 (0)32 338 9902
>>>>
>>>>  *SYDERAL SA*
>>>> Neuenburgstrasse 7
>>>> CH-3238 Gals (Switzerland)
>>>> Desk Line +41 (0)32 338 9800
>>>> Web Site http://www.syderal.ch
>>>>
>>>>
>>>>
>>>> --
>>>> Joel Sherrill, Ph.D.             Director of Research & Development joel.sherrill at OARcorp.com        On-Line Applications Research
>>>> Ask me about RTEMS: a free RTOS  Huntsville AL 35805
>>>> Support Available                (256) 722-9985
>>>>
>>>>
>>>
>>>
>>> --
>>> *
>>> *
>>> *Léonard Bise*
>>> Software Design Engineer
>>> Direct Line +41 (0)32 338 9902
>>>
>>> *SYDERAL SA*
>>> Neuenburgstrasse 7
>>> CH-3238 Gals (Switzerland)
>>> Desk Line +41 (0)32 338 9800
>>> Web Site http://www.syderal.ch
>>>
>>> _______________________________________________
>>> rtems-users mailing list
>>> rtems-users at rtems.org
>>> http://www.rtems.org/mailman/listinfo/rtems-users
>>>
>>>
>>
>
>
> --
> *
> *
> *Léonard Bise*
> Software Design Engineer
> Direct Line +41 (0)32 338 9902
>
> *SYDERAL SA*
> Neuenburgstrasse 7
> CH-3238 Gals (Switzerland)
> Desk Line +41 (0)32 338 9800
> Web Site http://www.syderal.ch
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.rtems.org/pipermail/users/attachments/20130424/6c225f77/attachment-0001.html>


More information about the users mailing list