1. This forum section is a read-only archive which contains old newsgroup posts. If you wish to post a query, please do so in one of our main forum sections (here). This way you will get a faster, better response from the members on Motherboard Point.

[FreeRTOS for ARM7]: asm macro reference problem

Discussion in 'Embedded' started by non_ve_lo, Feb 24, 2006.

  1. non_ve_lo

    non_ve_lo Guest

    Hi,
    I'm experimenting an odd problem with a FreeRTOS asm/C mixed macro as my
    code grows bigger:

    I'm using an ATMEL EB40A ev. board and GCC 4.02 WinARM dev. environment,
    and my application runs fairly good. The problem is that now my code is
    large (.text is about 0x12000 bytes long) and some macros (like
    portSAVE_CONTEXT() and restore()) macros stopped working: the compiler
    stops reporting:
    "Error: invalid literal constant: pool needs to be closer"
    several times (one per far data reference).
    The same macros work fine elsewhere in the code, nearer to the required
    variable: they address global C variables like:

    asm volatile ( "LDR R0, =ulCriticalNesting " );

    that are now too far to be directly referred (the C compiler instead
    addresses them by storing their address in local constants, eg:

    ldr r1, .LC3
    ....
    ..LC3:
    ..word __data_beg__

    ).
    I think that the problem can be fixed using the same technique (a local
    constant), but I'd like to place this declaration INSIDE the macros
    themselves, by using something like the old "local" or "private"
    assembly directive to avoid generating duplicate symbols... I don't know
    how is this kind of construct managed by gnu asm.
    Using a location OUTSIDE of the macro implies that I have to change the
    location name inside the macro at any usage, so I cannot use the plain
    macro...
    Does anybody know the ARM gas syntax well enough to fix this problem?
    Thank you,
    Oraz
     
    non_ve_lo, Feb 24, 2006
    #1
    1. Advertisements

  2. non_ve_lo

    Tauno Voipio Guest

    OK.

    Gosh - your macros need to go on a diet. The reach in ARM mode
    is 4 kbytes. IMHO, any subroutine of more than 4 kilobytes is
    attempting too much in one place - refactor it.

    This may cure the immediate problem, but it's Aspirin for a
    hangover instead of drinking less.

    Put the literal pool at the place of your choice inside the macro.
    The trick is the .lpool directive (on a line of its own). Put a
    jump around it to prevent the program flow hitting the constants.

    ---- @ some code
    b 1f @ jump around the literal pool
    .lpool @ a place for the literals
    1: ---- @ more code or end of macro

    Please note that the label is a number. For details, see the GNU
    assembler manual for 'local labels'.

    HTH
     
    Tauno Voipio, Feb 24, 2006
    #2
    1. Advertisements

  3. non_ve_lo

    non_ve_lo Guest

    Thank you for your reply. Well... the macros (it's not mine, it's
    FreeRTOS') are not so huge (some lines long), but they are used in many
    routines, eg. to save the context in interrupt handlers and in context
    switches. They refer to a couple of variables and fail when they are
    placed too far from them.
    Yes, I think that the solution is using an indirect reference as in the
    compiler example and like you are saying.
    Yes, I'm trying to modify the macro in this way, but I'm fighting with
    the asm syntax (the local numeric label for branch actually works). To
    give you a more precise info, this is one of the original macros:

    #define portRESTORE_CONTEXT() \
    { \
    extern volatile void * volatile pxCurrentTCB; \
    extern volatile unsigned portLONG ulCriticalNesting; \
    /* Set the LR to the task stack. */ \
    asm volatile ( "LDR R0, %0" : : "m" (pxCurrentTCB) );\
    asm volatile ( "LDR LR, [R0]" ); \
    /* The critical nesting depth is the first item on the stack. */ \
    /* Load it into the ulCriticalNesting variable. */\
    asm volatile ( "LDR R0, =ulCriticalNesting" );\
    asm volatile ( "LDMFD LR!, {R1}" ); \
    asm volatile ( "STR R1, [R0]" ); \
    /* Get the SPSR from the stack. */ \
    asm volatile ( "LDMFD LR!, {R0}" ); \
    asm volatile ( "MSR SPSR, R0" ); \
    /* Restore all system mode registers for the task. */\
    asm volatile ( "LDMFD LR, {R0-R14}^" ); \
    asm volatile ( "NOP" ); \
    /* Restore the return address. */ \
    asm volatile ( "LDR LR, [LR, #+60]" ); \
    /* And return - correcting the offset in the LR to obtain the */ \
    /* correct address. */ \
    asm volatile ( "SUBS PC, LR, #4" ); \
    ( void ) ulCriticalNesting; \
    }

    Can you point me to a good tutorial about gas syntax (things like "m"
    (pxCurrentTCB) and so on)?
    Thank you in advance, you are very kind.
    Oraz
     
    non_ve_lo, Feb 24, 2006
    #3
  4. non_ve_lo

    non_ve_lo Guest

    Hi Tauno,
    Thank you for your reply. Well... the macros (it's not mine, it's
    FreeRTOS') are not so huge (some lines long), but they are used in many
    routines, eg. to save the context in interrupt handlers and in context
    switches. They refer to a couple of variables and fail when they are
    placed too far from them.
    Yes, I think that the solution is using an indirect reference as in the
    compiler example and like you are saying.
    Yes, I'm trying to modify the macro in this way, but I'm fighting
    against the asm syntax (the local numeric label for branch is actually
    working :) ). To give you a more precise idea, this is one of the
    original macros:

    #define portRESTORE_CONTEXT() \
    { \
    extern volatile void * volatile pxCurrentTCB; \
    extern volatile unsigned portLONG ulCriticalNesting; \
    /* Set the LR to the task stack. */ \
    asm volatile ( "LDR R0, %0" : : "m" (pxCurrentTCB) );\
    asm volatile ( "LDR LR, [R0]" ); \
    /* The critical nesting depth is the first item on the stack. */ \
    /* Load it into the ulCriticalNesting variable. */\
    asm volatile ( "LDR R0, =ulCriticalNesting" );\
    asm volatile ( "LDMFD LR!, {R1}" ); \
    asm volatile ( "STR R1, [R0]" ); \
    /* Get the SPSR from the stack. */ \
    asm volatile ( "LDMFD LR!, {R0}" ); \
    asm volatile ( "MSR SPSR, R0" ); \
    /* Restore all system mode registers for the task. */\
    asm volatile ( "LDMFD LR, {R0-R14}^" ); \
    asm volatile ( "NOP" ); \
    /* Restore the return address. */ \
    asm volatile ( "LDR LR, [LR, #+60]" ); \
    /* And return - correcting the offset in the LR to obtain the */ \
    /* correct address. */ \
    asm volatile ( "SUBS PC, LR, #4" ); \
    ( void ) ulCriticalNesting; \
    }

    Can you point me to a good tutorial about gas syntax (things like "m"
    (pxCurrentTCB) and so on)?
    Thank you in advance, you are very kind.
    Oraz
     
    non_ve_lo, Feb 24, 2006
    #4
  5. non_ve_lo

    Richard Guest

    Yes, I'm trying to modify the macro in this way, but I'm fighting
    <code snipped>

    Little point, please do not post copyright code without a link to the
    copyright/license notice.

    Regards,
    Richard.

    http://www.FreeRTOS.org
     
    Richard, Feb 24, 2006
    #5
  6. non_ve_lo

    Tauno Voipio Guest

    IMHO, it would be better to keep the assembly code in
    a single asm() statement. Here's a working example:


    /* Change PSR - return old value */

    unsigned long change_psr(unsigned long mask, unsigned long data)
    {
    unsigned long result;

    asm (
    "adr r3,chg32\n\t" /* -> 32 bit code */
    "bx r3\n\t" /* enter 32 bit mode */

    ".code 32\n"

    "chg32:\t"
    "mrs %0,cpsr\n\t" /* get current PSR */
    "bic r3,%0,%1\n\t" /* clean up old PSR */
    "orr r3,r3,%2\n\t" /* insert new bits */
    "msr cpsr,r3\n\t" /* update current PSR */

    "adr r3,chg16+1\n\t" /* -> 16 bit code */
    "bx r3\n\t" /* return to 16 bit mode */

    ".code 16\n"
    "chg16:"

    : "=&r" (result)
    : "r" (mask),
    "r" (mask & data)
    : "r3");

    return result;
    }

    The code above is for accessing the processor status register from
    Thumb mode C code.

    ------

    Here is my version of the macro above:

    #define portRESTORE_CONTEXT() \
    { \
    extern volatile void * volatile pxCurrentTCB; \
    extern volatile unsigned portLONG ulCriticalNesting; \
    \
    asm ( \
    "ldr r0,%0\n" \
    "ldr lr,[r0]\n" \
    \
    "ldr r0,=ulCriticalNesting\n" \
    "ldmfd lr!,{r1}\n" \
    "str r1,[r0]\n" \
    \
    "ldmfd lr!,{r0}\n" \
    "msr spsr,r0\n" \
    \
    "ldmfd lr,{r0-r14}^\n" \
    \
    "ldr lr,[lr,#60]\n" \
    "subs pc,lr,#4" \
    \
    : : "m" (pxCurrentTCB) \
    ); \
    \
    (void)ulCriticalNesting; /* this does not create any code */ \
    }

    -----

    The code is not optimised. For example, the two first ldmfd
    instructions can be combined into one, using some more registers
    with no ill effect, as the last ldmfd clobbers them anyway.

    It seems to me that the empty statement at the end is there to
    keep the compiler from complaining of unused variable (although
    it's used in assembly code, indeed).

    In this case, you can insert the .lpool directive directly after
    the subs pc,lr,#4 instruction, as it breaks the program flow anyway.

    I'd insert another input parameter (%1) with the value of
    (&ulCriticalNesting) and change the literal address in the
    assembly code to a reference to the parameter. This would put
    the literal management responsibility to the compiler.

    The asm() statement and its constraints (that's what the thing
    above is called) are documented in the GCC manual
    <http://gcc.gnu.org/onlinedocs/gcc-4.0.2/gcc/>

    in

    5.34 Assembler Instructions with C Expression Operands

    Pick the manual version matching most closely the compiler
    at your disposal.
    Been there myself, know how it feels.

    ---

    Best regards from Helsinki, the home city of Linux,

    Tauno Voipio
    tauno voipio (at) iki fi
     
    Tauno Voipio, Feb 24, 2006
    #6
  7. non_ve_lo

    non_ve_lo Guest

    Richard ha scritto:
    Dear Mr. Richard,
    You're right, I'm sorry: posting on an embedded ng does not imply that
    every reader knows about your RTOS. I apologize for the mistake and I
    want to thank you for your great efforts in writing FreeRTOS and
    delivering it to the embedded community.
    BTW, hope this discussion about these macros can meet your interest too.

    For sake of correctness: the <snipped> code I reported is taken from the
    portmacro.h header file included in the "AT91FR40008 GCC" port of the
    current Mr. Barry's FreeRTOS release (v3.2.4).
    FreeRTOS is a lightweight and small-footprint opensource RealTime kernel
    you can find @ http://www.freertos.org, distributed under a
    slightly-modified GPL license you can read there.
    Regards,
    Oraz
     
    non_ve_lo, Feb 26, 2006
    #7
  8. non_ve_lo

    non_ve_lo Guest

    Here is my version of the macro above:

    I'm now reading about ARM processor structure, as I'm a long-time
    assembly programmer, but I've never used ARM before :-(
    I think so too.
    If it can be done, this could be an elegant way to solve the problem.
    I'll read the gcc-asm manual reference you suggested me.
    :)

    Thank you and best regards,
    Oraz
     
    non_ve_lo, Feb 26, 2006
    #8
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.