Inline Assembly

Corrin Meyer Corrin.Meyer at dornerworks.com
Tue Aug 5 13:58:46 UTC 2008


I am having issues generating inline assembly for the ColdFire with GCC.
Below is the function with inline assembly in question.

 

static inline uint32_t hal_set_ipl(uint32_t new_ipl)

{

    uint32_t old_ipl;

    register uint32_t _ipl;

 

    _ipl = (new_ipl & 0x00000007) << 8;

 

    // Get the old IPL setting and set it to the new one.

    __asm__ __volatile__ (

        "move.w     %%sr, %%d7      \n\t"

        "move.l     %%d7, %0        \n\t"

        "andi.l     #0xf8ff, %%d7   \n\t"

        "or.l       %1, %%d7        \n\t"

        "move.w     %%d7, %%sr      \n\t"

 

        : "=d" (old_ipl) : "d" (_ipl) : "%%d7" );

 

    // Mask out non-IPL bits (placed in lower 7 bits).

    old_ipl = (old_ipl & 0x0700) >> 8;

 

    return old_ipl;

}

 

The assembly generated is below (I disabled function inlining for
debugging purposes though I get a similar result even when inlining).

 

static inline uint32_t hal_set_ipl(uint32_t new_ipl)

{

200006e4:       4e56 0000       linkw %fp,#0

200006e8:       2f07            movel %d7,%sp at -

    register uint32_t _ipl;

 

    _ipl = (new_ipl & 0x00000007) << 8;

 

    // Get the old IPL setting and set it to the new one.

    __asm__ __volatile__ (

200006ea:       7007            moveq #7,%d0

200006ec:       c0ae 0008       andl %fp@(8),%d0

200006f0:       e188            lsll #8,%d0

200006f2:       40c7            movew %sr,%d7

200006f4:       2007            movel %d7,%d0

200006f6:       0287 0000 f8ff  andil #63743,%d7

200006fc:       8e80            orl %d0,%d7

200006fe:       46c7            movew %d7,%sr

20000700:       0280 0000 0700  andil #1792,%d0

 

    // Mask out non-IPL bits (placed in lower 7 bits).

    old_ipl = (old_ipl & 0x0700) >> 8;

 

    return old_ipl;

}

20000706:       e088            lsrl #8,%d0

20000708:       2e1f            movel %sp at +,%d7

2000070a:       4e5e            unlk %fp

2000070c:       4e75            rts

 

The problem is that register %d0 is being used for both 'old_ipl' and
'_ipl' (as can be seed at 200006f4 and 200006fc) and the result is that
%d7 and hence %sr are not updated appropriately.  The purpose of this
function is to set the Interrupt Priority level (IPL) bits in the Status
Register and to return the original value of the IPL bits.  I have tried
using both 'r' and 'd' constraints on the output/input to the inline
assembly but both result in this problem.  Using a constraint of 'i'
does not work unless optimization level of at least "-O"  is used (which
makes since I think since it would actually require the or.l instruction
changing to ori.l and figuring out the actual value of new_ipl at
compile time).

 

Any insights on why GCC is not allocating the registers correctly (or
maybe I am missing something...)?  I can get to straight assembly if
needed but I would prefer, for the simplicity of this series of
instructions, to use inline assembly.

 

Corrin J. Meyer 
DornerWorks, Ltd. 
Embedded Systems Engineering 
  
T: 616.389.8336 
F: 616.245.8372 
E: corrin.meyer at dornerworks.com <mailto:corrin.meyer at dornerworks.com>  
  
3445 Lake Eastbrook Blvd. SE 
Grand Rapids, MI 49546 

 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://sourcerytools.com/pipermail/coldfire-gnu-discuss/attachments/20080805/3dd3fe45/attachment.html>


More information about the coldfire-gnu-discuss mailing list