[FreeRTOS for ARM7]: asm macro reference problem

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

Reply to
non_ve_lo
Loading thread data ...

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
tauno voipio (at) iki fi
 Click to see the full signature
Reply to
Tauno Voipio

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

Reply to
non_ve_lo

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

Reply to
non_ve_lo

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

Regards, Richard.

formatting link

Reply to
Richard

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

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
 Click to see the full signature
Reply to
Tauno Voipio

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 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 @

formatting link
distributed under a slightly-modified GPL license you can read there. Regards, Oraz

Reply to
non_ve_lo

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

Reply to
non_ve_lo

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.