Reply by non_...@diremo.mai●February 26, 20062006-02-26
> Here is my version of the macro above:
<snip>
> 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.
I'm now reading about ARM processor structure, as I'm a long-time
assembly programmer, but I've never used ARM before :-(
> 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).
I think so too.
> 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.
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.
> Been there myself, know how it feels.
:-)
Thank you and best regards,
Oraz
Reply by non_...@diremo.mai●February 26, 20062006-02-26
Richard ha scritto:
> <code snipped>
>
> Little point, please do not post copyright code without a link to the
> copyright/license notice.
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@diremo.mai wrote:
> 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 :-) ).
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.
------
> 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; \
> }
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.
> Can you point me to a good tutorial about gas syntax (things like "m"
> (pxCurrentTCB) and so on)?
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.
> Thank you in advance, you are very kind.
Been there myself, know how it feels.
---
Best regards from Helsinki, the home city of Linux,
Tauno Voipio
tauno voipio (at) iki fi
Reply by Richard●February 24, 20062006-02-24
> 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:
<code snipped>
Little point, please do not post copyright code without a link to the
copyright/license notice.
Regards,
Richard.
http://www.FreeRTOS.org
Reply by non_...@diremo.mai●February 24, 20062006-02-24
Tauno Voipio wrote:
> 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.
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.
> 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'.
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 by non_...@diremo.mai●February 24, 20062006-02-24
Tauno Voipio wrote:
> 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.
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.
> 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'.
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 by Tauno Voipio●February 24, 20062006-02-24
non_ve_lo@diremo.mai wrote:
> 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?
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
Reply by non_...@diremo.mai●February 24, 20062006-02-24
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