Yahoo Groups archive

Lpc2000

Index last updated: 2026-04-28 23:31 UTC

Thread

How to declare RAM functions in GCC

How to declare RAM functions in GCC

2005-01-13 by sig5534

In the IAR compiler there was an attribute to declare a function to 
get it mapped into RAM.  How is this handled in GCC?  Is there some 
equiv attribute?

Thanks, Chris.

Re: How to declare RAM functions in GCC

2005-01-14 by ntfreak2000

--- In lpc2000@yahoogroups.com, "sig5534" <sig5534@h...> wrote:
> 
> In the IAR compiler there was an attribute to declare a function to 
> get it mapped into RAM.  How is this handled in GCC?  Is there some 
> equiv attribute?
> 
> Thanks, Chris.

Chris,

One method is to compile as normal in gcc then use objcopy to rename 
the .text segment to .data.
gcc ... file.c
objcopy --rename-section .text=.data file.o

Make sure your startup file inits the data section and away you go.

The other method is to add the file to the .data section in your 
linker script, eg.

.data : AT (_etext)
{
	__data_start = .;
        *file.o (.text*)
	*(.data .data.*)
	*(.gnu.linkonce.d.*)
	SORT(CONSTRUCTORS)
} >DATA
. = ALIGN(4);
This can sometimes fail if you have a *(.text*) in your text section.

You may sometimes need to use -mlong-calls gcc option or #pragma 
long_calls depending the device memory.

It could probably be done with __attribute__ ((section (".."))) - not 
tried this method.

Hope this helps
sjo

Re: How to declare RAM functions in GCC

2005-01-14 by sig5534

Thanks sjo.  Exactly what I was looking for.

I'm trying to get your last method to would, using the attribute.  
This is what I did for a test function:

void __attribute__((section(".data"))) IAP_Test( void ) {
  U32 N;
  N=IOPIN;
}  // IAP_Test

When I make I get:

main.o(.text+0x150): In function `main':
/cygdrive/d/GNUARM/Projects/Vader/main.c:96: relocation truncated to 
fit: R_ARM_PC24 IAP_Test
collect2: ld returned 1 exit status
D:\GNUARM\bin\make: *** [vader.elf] Error 1

The line #96 in main is where I put the call to IAP_Test().  GCC is 
taking the attribute, and seems to be doing something with it, but it 
is giving me this relocation error.  I don't know what R_ARM_PC24 is.

Do I need to allocate extra space for this in my startup.s file?

Can you give any help on this?  This would be great to get working 
with this method.  

Thanks,  Chris.

Re: How to declare RAM functions in GCC

2005-01-14 by Karl Olsen

--- In lpc2000@yahoogroups.com, "sig5534" <sig5534@h...> wrote:
> 
> Thanks sjo.  Exactly what I was looking for.
> 
> I'm trying to get your last method to would, using the attribute.  
> This is what I did for a test function:
> 
> void __attribute__((section(".data"))) IAP_Test( void ) {
>   U32 N;
>   N=IOPIN;
> }  // IAP_Test
> 
> When I make I get:
> 
> main.o(.text+0x150): In function `main':
> /cygdrive/d/GNUARM/Projects/Vader/main.c:96: relocation truncated 
to 
> fit: R_ARM_PC24 IAP_Test
> collect2: ld returned 1 exit status
> D:\GNUARM\bin\make: *** [vader.elf] Error 1
> 
> The line #96 in main is where I put the call to IAP_Test().  GCC is 
> taking the attribute, and seems to be doing something with it, but 
it 
> is giving me this relocation error.  I don't know what R_ARM_PC24 
is.
> 
> Do I need to allocate extra space for this in my startup.s file?

Nice trick of just locating the RAM function in .data.

With main() in flash and IAP_Test() in RAM, they are ~1GB apart, and 
a normal BL instruction can only handle distances of up to +/- 32 MB.
Try calling it indirectly:

static void (*pramfunc)(void) = IAP_Test;
(*pramfunc)();

Karl Olsen

Re: How to declare RAM functions in GCC

2005-01-15 by sig5534

> Try calling it indirectly:
> 
> static void (*pramfunc)(void) = IAP_Test;
> (*pramfunc)();
> 
> Karl Olsen

Karl, you're close but no cigar yet.  I tried it, and the compiler 
took it, but when the call gets made I get a PreFetch Abort Excep 
error.

The IAP_Test() func got put in RAM correctly.  It is right at 
0x40000000.  But the long call methodology is not quite right.  
The "sjo" person mentioned something about another long call method.  
But I'm not quite sure how he meant to set that up with the pragmas.

It's almost there.  Anymore ideas on making the long call?

Thanks,  Chris.

Re: How to declare RAM functions in GCC

2005-01-15 by ntfreak2000

--- In lpc2000@yahoogroups.com, "sig5534" <sig5534@h...> wrote:
> 
> > Try calling it indirectly:
> > 
> > static void (*pramfunc)(void) = IAP_Test;
> > (*pramfunc)();
> > 
> > Karl Olsen
> 
> Karl, you're close but no cigar yet.  I tried it, and the compiler 
> took it, but when the call gets made I get a PreFetch Abort Excep 
> error.
> 
> The IAP_Test() func got put in RAM correctly.  It is right at 
> 0x40000000.  But the long call methodology is not quite right.  
> The "sjo" person mentioned something about another long call 
method.  
> But I'm not quite sure how he meant to set that up with the pragmas.
> 
> It's almost there.  Anymore ideas on making the long call?
> 
> Thanks,  Chris.

Either use gcc option -mlong-calls on the src file or
#pragma long_calls
void myfunc(void);
#pragma no_long_calls
in the header file

The objcopy is the simplest and will cause the least problems, 
especially if you have a *(.text*) defind in your linker script.

Regards
sjo

Re: How to declare RAM functions in GCC

2005-01-16 by sig5534

Same result.  Still not working.  I get the Prefetch Abort Except.

When I trace it in the debugger I can see that it gets right to the 
call instruc:

   LDR    PC,[R5,#0]

And then it jumps to the Prefetch Abort Excep.

R5 is loaded with 0x40000000 which is the right RAM area, and the 
debugger says the IAP_Test() routine is at that location.  I can see 
the code is there as well in the debugger source.

Everything is right but the CPU is complaining about it's pipeline.  
Obviously executing code in flash ROM and then jumping to RAM is 
entirely different types of memory.  It's confusing the memory 
manager prefetch pipeline.

There must be something I am missing.  Something else is apparently 
necessary to tell the CPU the next instruc is in RAM. Otherwise the 
CPU instruc fetch fails.  Why?

Chris.

Re: [lpc2000] Re: How to declare RAM functions in GCC

2005-01-16 by Richard

Looks like you found the cause. You just need to tell the CPU to flush its 
pipeline. In the ARM ARM book, it mentions that

"The overall result is that code which writes one or more instructions to 
memory and then executes them (know as self modifying code) cannot be 
executed reliably on ARM processors without special precautions..." and then

"Each implementation therefore defines a sequence of operations that can be 
used in the middle of a self-modifying code sequence to make it execute 
reliably. This sequence is called an Instruction Memory Barrier...."

So "all" you have to do is look thru the LPC2K datasheet and hope they 
describe what the IMB sequences are!!

Good luck,

At 07:05 AM 1/16/2005, sig5534 wrote:



>Same result.  Still not working.  I get the Prefetch Abort Except.
>
>When I trace it in the debugger I can see that it gets right to the
>call instruc:
>
>    LDR    PC,[R5,#0]
>
>And then it jumps to the Prefetch Abort Excep.
>
>R5 is loaded with 0x40000000 which is the right RAM area, and the
>debugger says the IAP_Test() routine is at that location.  I can see
>the code is there as well in the debugger source.
>
>Everything is right but the CPU is complaining about it's pipeline.
>Obviously executing code in flash ROM and then jumping to RAM is
>entirely different types of memory.  It's confusing the memory
>manager prefetch pipeline.
>
>There must be something I am missing.  Something else is apparently
>necessary to tell the CPU the next instruc is in RAM. Otherwise the
>CPU instruc fetch fails.  Why?
>
>Chris.
>
>
>
>
>
>
>
>Yahoo! Groups Links
>
>
>
>

// richard (This email is for mailing lists. To reach me directly, please 
use richard at imagecraft.com)

Re: How to declare RAM functions in GCC

2005-01-16 by embeddedjanitor

From what I've seen, the self modifying code precautions in the ARMARM 
are mostly relevant to CPUs with caches. With caches, particularly 
with CPUs that have seperate caches for instructions and data. Clearly 
if you have an instruction cache that is different from the data cache 
you need to flush the caches to get the instructions to fetch 
properly.

The LPC21xx does not have caches, except for the MAM, so this is not 
an Ichache/Dcache issue.

I regularly use RAM-based code on ARM7s, but I achieve this by using 
the linker (GNU ld) to set up the addresses and my maincrt.s copies 
the RAM code from flash to RAM at start up. This is essentially what 
the .data thing will do too.
 
Some things that are worth considering:
1) Try turning off the MAM to eliminate this from the set of variable.

2) Are you using Thumb code? If so, perhaps the .data assignment is 
throwing away the thumb attributes.

3) A Prefetch Abort means that there is no memory available at the 
address you specify (like a data abort, but for instructions).

The code 

    LDR  PC,[R5,#0]

should be loading the pointer from this address (ie. R5 + #0 should be 
a 32-bit value that is the pointer to the code).

Check that the address actually contains the **pointer** to the code 
you want to execute and not the actual code itself.

Perhaps try

static const (*fnptr)(void) = IAP_Test;
 ...
 *fnptr();
 ...

which should put the pointer in the literal pool and generate 
different code.






 In lpc2000@yahoogroups.com, Richard <richard-lists@i...> wrote:
> Looks like you found the cause. You just need to tell the CPU to 
flush its 
> pipeline. In the ARM ARM book, it mentions that
> 
> "The overall result is that code which writes one or more 
instructions to 
> memory and then executes them (know as self modifying code) cannot 
be 
> executed reliably on ARM processors without special precautions..." 
and then
> 
> "Each implementation therefore defines a sequence of operations that 
can be 
> used in the middle of a self-modifying code sequence to make it 
execute 
> reliably. This sequence is called an Instruction Memory Barrier...."
> 
> So "all" you have to do is look thru the LPC2K datasheet and hope 
they 
> describe what the IMB sequences are!!
> 
> Good luck,
> 
> At 07:05 AM 1/16/2005, sig5534 wrote:
> 
> 
> 
> >Same result.  Still not working.  I get the Prefetch Abort Except.
> >
> >When I trace it in the debugger I can see that it gets right to the
> >call instruc:
> >
> >    LDR    PC,[R5,#0]
> >
> >And then it jumps to the Prefetch Abort Excep.
> >
> >R5 is loaded with 0x40000000 which is the right RAM area, and the
> >debugger says the IAP_Test() routine is at that location.  I can 
see
> >the code is there as well in the debugger source.
> >
> >Everything is right but the CPU is complaining about it's pipeline.
> >Obviously executing code in flash ROM and then jumping to RAM is
> >entirely different types of memory.  It's confusing the memory
> >manager prefetch pipeline.
> >
> >There must be something I am missing.  Something else is apparently
> >necessary to tell the CPU the next instruc is in RAM. Otherwise the
> >CPU instruc fetch fails.  Why?
> >
> >Chris.
> >
> >
> >
> >
> >
> >
> >
> >Yahoo! Groups Links
> >
> >
> >
> >
> 
> // richard (This email is for mailing lists. To reach me directly, 
please 
> use richard at imagecraft.com)

Re: How to declare RAM functions in GCC

2005-01-17 by sig5534

> 1) Try turning off the MAM to eliminate 
> this from the set of variable. 

Already using MAM_OFF.

> 2) Are you using Thumb code? If so, perhaps the .data assignment is 
> throwing away the thumb attributes.

Nope, 32b code.
 
> 3) A Prefetch Abort means that there is no memory available at the 
> address you specify (like a data abort, but for instructions).
> 
> The code 
> 
>     LDR  PC,[R5,#0]
> 
> should be loading the pointer from this address
> (ie. R5 + #0 should be a 32-bit value that is the pointer
> to the code).
> 
> Check that the address actually contains the **pointer**
> to the code you want to execute and not the actual code itself.
 
Now we're getting somewhere.  I think this is the problem.  I want it 
to jump to and execute at the 0x4000000 adr.  There is no pointer 
there.

> Perhaps try
> 
> static const (*fnptr)(void) = IAP_Test;
>  ...
>  *fnptr();

That gives a compiler error:

main.c:107: error: invalid type argument of `unary *'
D:\GNUARM\bin\make: *** [main.o] Error 1
 
> which should put the pointer in the literal pool and generate 
> different code.

Yeh I think this is on the right track.  I need to get my C syntax 
correct here to generate a long jump directly rather than loading a 
pointer.  The function is at 0x40000000 not a pointer to it.

If you have any other ideas for this, please pass them on.  Meanwhile 
I check my C books to try to figure out the needed syntax.

Chris.

Re: [lpc2000] Re: How to declare RAM functions in GCC

2005-01-17 by Richard

C syntax portion is easy:

void (*func)(void) = (void (*)())0x40000000;

(*func)();

At 04:17 PM 1/16/2005, sig5534 wrote:



> > 1) Try turning off the MAM to eliminate
> > this from the set of variable.
>
>Already using MAM_OFF.
>
> > 2) Are you using Thumb code? If so, perhaps the .data assignment is
> > throwing away the thumb attributes.
>
>Nope, 32b code.
>
> > 3) A Prefetch Abort means that there is no memory available at the
> > address you specify (like a data abort, but for instructions).
> >
> > The code
> >
> >     LDR  PC,[R5,#0]
> >
> > should be loading the pointer from this address
> > (ie. R5 + #0 should be a 32-bit value that is the pointer
> > to the code).
> >
> > Check that the address actually contains the **pointer**
> > to the code you want to execute and not the actual code itself.
>
>Now we're getting somewhere.  I think this is the problem.  I want it
>to jump to and execute at the 0x4000000 adr.  There is no pointer
>there.
>
> > Perhaps try
> >
> > static const (*fnptr)(void) = IAP_Test;
> >  ...
> >  *fnptr();
>
>That gives a compiler error:
>
>main.c:107: error: invalid type argument of `unary *'
>D:\GNUARM\bin\make: *** [main.o] Error 1
>
> > which should put the pointer in the literal pool and generate
> > different code.
>
>Yeh I think this is on the right track.  I need to get my C syntax
>correct here to generate a long jump directly rather than loading a
>pointer.  The function is at 0x40000000 not a pointer to it.
>
>If you have any other ideas for this, please pass them on.  Meanwhile
>I check my C books to try to figure out the needed syntax.
>
>Chris.
>
>
>
>
>
>
>Yahoo! Groups Links
>
>
>
>

// richard (This email is for mailing lists. To reach me directly, please 
use richard at imagecraft.com)

Re: How to declare RAM functions in GCC

2005-01-17 by sig5534

Hold the phone, something funny is going on here.  The debugger says 
that IAP_Test() is at adr 0x40000000.  However when I look at the 
dissassembly I see this:

pramfunc:
0x40000000 E321F0D1    DD 0xE321F0D1 ; DATA SECTION
  14:         return IOPIN|n;
IAP_Test:
0x40000004 E59FD05C    LDR       SP,[PC,#+0x5c]
0x40000008 E321F0D2    MSR       CPSR_c,#0xd2
0x4000000C E59FD054    LDR       SP,[PC,#+0x54]
  15: }
0x40000010 E321F0D7    MSR       CPSR_c,#0xd7
0x40000014 E59FD04C    LDR       SP,[PC,#+0x4c]

This looks like there is some kind of data or segment marker right at 
0x40000000.  However, the actual code is at 0x40000004.

So it appears the adr being loaded into the PC is 0x40000000 and that 
does not appear to be code.

What's going on here?  Why did the compiler/linker do this?  

It is placing this RAM function before the variables.  The RAM 
variables have been moved to 0x40000020.

I'd rather have it the other way around.  The RAM functions after the 
variables.  That might solve this problem too.

Any thoughts on how to get the RAM functions after the RAM 
variables?  Do I need to define some more segments and the the linker 
how to order them?

Chris.

Re: [lpc2000] Re: How to declare RAM functions in GCC

2005-01-17 by Charles Manning

More below...

On Monday 17 January 2005 13:34, sig5534 wrote:
> Hold the phone, something funny is going on here.  The debugger says
> that IAP_Test() is at adr 0x40000000.  However when I look at the
> dissassembly I see this:
>
> pramfunc:
> 0x40000000 E321F0D1    DD 0xE321F0D1 ; DATA SECTION
>   14:         return IOPIN|n;

pramfunc is supposed to be a pointer, so it should be holding 0x40000004 or 
something (ie. a pointer to the actual function).

Try consting the pointer... this should shift it into the literal pool. This 
will alter the code slightly and maybe make it work.




> IAP_Test:
> 0x40000004 E59FD05C    LDR       SP,[PC,#+0x5c]
> 0x40000008 E321F0D2    MSR       CPSR_c,#0xd2
> 0x4000000C E59FD054    LDR       SP,[PC,#+0x54]
>   15: }
> 0x40000010 E321F0D7    MSR       CPSR_c,#0xd7
> 0x40000014 E59FD04C    LDR       SP,[PC,#+0x4c]
>
> This looks like there is some kind of data or segment marker right at
> 0x40000000.  However, the actual code is at 0x40000004.
>
> So it appears the adr being loaded into the PC is 0x40000000 and that
> does not appear to be code.
>
> What's going on here?  Why did the compiler/linker do this?

What seems strange to me is that the code you showed was

       LDR PC,[R5,#0]

This is not what I'd expect unless the previous instruction was 

       MOV LR,PC 

This would syntesize a branch and link.

I'd expect more to see something like:

       MOV or LDR to get address into a register Rx

       BL Rx


What version compiler/linker are you using? Could be an older broken one.


>
> It is placing this RAM function before the variables.  The RAM
> variables have been moved to 0x40000020.
>
> I'd rather have it the other way around.  The RAM functions after the
> variables.  That might solve this problem too.
>
> Any thoughts on how to get the RAM functions after the RAM
> variables?  Do I need to define some more segments and the the linker
> how to order them?

To control the placement you really need to use an ldscript and if you're 
doing that you might as well then use the ldscript to do the placement for 
you.

I do this with a section that looks like:

        /* Code goes into internal RAM */
	__textram_VMA__ = .;    /* Where code is to be located */
	.ram_text __textram_VMA__ : AT ( __textram_bLMA__ )
	{
	                    
	       ramfunc.o(.text)
               }


This makes a whole seperate section that I copy in maincrt.s, just like the 
.data section is copied.

You could also place this at the end of the .data section and see if that 
works.
Show quoted textHide quoted text
>
> Chris.
>
>
>
>
>
>
> Yahoo! Groups Links
>
>
>

Re: How to declare RAM functions in GCC

2005-01-17 by sig5534

YEH! I think I got it working.

The problem was in my startup.s file.  I had turned off a flag before 
that left my .data section init routine bypassed.  So the data 
section was not being init'd and therefore the pointer at 0x40000000 
and the code itself at 0x40000004 were actually zeros/junk.

When I turned the .data init back on, the call is working!  The 
function is in RAM, the ptr is good, and it is running.

So to summarize, to get and use a function in RAM you only need to do 
three things:

(1) Have an init in the startup code for the .data section.
(2) Use the __attribute__((section(".data"))) on the functions.
(3) Define function pointer variables for the functions and make 
indirect calls using those. 

That seems to do it.  I'm sure there are other ways too.

Thanks guys.  Now off to get my IAP code done.

Chris.

Re: [lpc2000] Re: How to declare RAM functions in GCC

2005-01-17 by Anton Erasmus

On 14 Jan 2005 at 19:15, sig5534 wrote:

> 
> 
> Thanks sjo.  Exactly what I was looking for.
> 
> I'm trying to get your last method to would, using the attribute. 
> This is what I did for a test function:
> 
> void __attribute__((section(".data"))) IAP_Test( void ) {
>   U32 N;
>   N=IOPIN;
> }  // IAP_Test
> 
> When I make I get:
> 
> main.o(.text+0x150): In function `main':
> /cygdrive/d/GNUARM/Projects/Vader/main.c:96: relocation truncated to
> fit: R_ARM_PC24 IAP_Test collect2: ld returned 1 exit status
> D:\GNUARM\bin\make: *** [vader.elf] Error 1
> 
> The line #96 in main is where I put the call to IAP_Test().  GCC is
> taking the attribute, and seems to be doing something with it, but it
> is giving me this relocation error.  I don't know what R_ARM_PC24 is.
> 
> Do I need to allocate extra space for this in my startup.s file?
> 
> Can you give any help on this?  This would be great to get working
> with this method.  
> 
> Thanks,  Chris.
> 
> 

The following seems to work:

void foo(void) __attribute__ ((section ("data")));
void bar(void);



void foo(void)
{

}

int global1;

void bar(void)
{
   foo();
}             

Both function foo and global int global1 is put into the data section.

Regards
   Anton Erasmus
-- 
A J Erasmus

Move to quarantaine

This moves the raw source file on disk only. The archive index is not changed automatically, so you still need to run a manual refresh afterward.