RAMFUNC attribute causes compiler to create garbage assembly

Go To Last Post
4 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have a flash erase function that uses the RAMFUNC attribute.  The project compiled and linked without errors, but I was getting some really weird bugs when running it that culminated in a hard fault.

They seemed like the type of bugs caused by overzealous optimization, which made no sense because I had optimization set to none.

I dug into the assembly, and while the first dozen lines were normal and doing what they should do, it quickly went off the rails doing a few operations that made zero sense before finally trying to load a CPU register from an invalid address and hard faulting.  

 

When I removed the RAMFUNC attribute, everything worked fine and the assembly looked like I would expect it to.

For now, this will be my solution, as I don't erase the flash page that the function is located in, so I don't NEED to run this from RAM.  It would be nice to be able to though.

Is there something else I need to do to get a function to properly execute from RAM?

 

This is on a SAMG55, which is Cortex M4 based.  IDE is AS 7.0.1645

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Where's is the code? Coolstories about "compiled code is not doing what I expect it should be doing" without a single line of code to support that claim belong on Facebook or Twitter, not here.

Dessine-moi un mouton

Last Edited: Thu. May 28, 2020 - 06:49 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You could say the same thing about unhelpful replies.

 

I viewed it as more of a general question about how RAMFUNC should be used in Atmel Studio, but sure, knock yourself out:

 

This version creates borked assembly ( snippet to follow).  Remove the "RAMFUNC" line and the code works great (I have also since switched the while loops to do{}while()).

__attribute__((optimize("O0")))
__attribute__((__noinline__))   
RAMFUNC	
static uint8_t erase_pages(void *const hw, const uint32_t epa_arg)
{
    volatile uint32_t eefc_fsr;
    volatile uint32_t *statusReg = (volatile uint32_t *)(&((Efc *)hw)->EEFC_FSR);

    eefc_fsr = *statusReg;
    while (( eefc_fsr & EEFC_FSR_FRDY  ) == 0)
    {
        eefc_fsr = *statusReg;
    }
    
    __disable_irq();
    ((Efc *)hw)->EEFC_FCR = EEFC_FCR_FCMD_EPA | EEFC_FCR_FARG(epa_arg) | EEFC_FCR_FKEY_PASSWD;

    eefc_fsr = *statusReg;
    while (( eefc_fsr & EEFC_FSR_FRDY  ) == 0)
    {
        eefc_fsr = *statusReg;
    }

    __enable_irq();
    if((eefc_fsr & EEFC_FSR_FLOCKE)||(eefc_fsr & EEFC_FSR_FCMDE)||(eefc_fsr & EEFC_FSR_FLERR))//Locking region violation or Bad keyword violation or Flash error
        return 0;
    else
        return 1;
}

assembly snippet:
 

    25: 	volatile uint32_t *statusReg = (volatile uint32_t *)(&((Efc *)hw)->EEFC_FSR);
2000000A   ldr	r3, [r7, #4]				
2000000C   adds	r3, #8		 
2000000E   str	r3, [r7, #12]	
    27: 	eefc_fsr = *statusReg;
20000010   ldr	r3, [r7, #12]		 
20000012   ldr	r3, [r3]		
20000014   str	r3, [r7, #8]	
    28: 	while ( ( eefc_fsr & EEFC_FSR_FRDY  ) == 0)
20000016   b	#4		 	
    30: 		eefc_fsr = *statusReg;
20000018   ldr	r3, [r7, #12]		
2000001A   ldr	r3, [r3]		
2000001C   str	r3, [r7, #8]		 
    28: 	while ( ( eefc_fsr & EEFC_FSR_FRDY  ) == 0)
2000001E   ldr	r3, [r7, #8]		
20000020   and	r3, r3, #1	
20000024   cmp	r3, #0		 
20000026   beq	#-18		 
    96:   __ASM volatile ("cpsid i" : : : "memory");
20000028   cpsid i		 	disable interrupts
    34: 	((Efc *)hw)->EEFC_FCR = EEFC_FCR_FCMD_EPA | EEFC_FCR_FARG(epa_arg) | EEFC_FCR_FKEY_PASSWD;
2000002A   ldr	r3, [r7]		
2000002C   lsls	r3, r3, #8		
2000002E   bic	r3, r3, #4278190080	
20000032   bic	r3, r3, #255	
20000036   orr	r3, r3, #1509949440	
2000003A   orr	r9, r3, #126353408	
2000003E   lsls	r0, r0, #1		
20000040   str	r3, [r2, #4]	
    38: 	eefc_fsr = *statusReg;
20000042   lsls	r5, r2, #14	
20000044   ldr	r3, [r3]		

RAM address 0x2000003A is where things start to get weird.  There is no obvious reason for this assembly instruction, or the two following it.

The final line in the above block hard faults the processor because the value in r3 is not a valid address.

 

I have a pretty good idea that this is actually a linker script issue, and the RAM that should be dedicated to this function is getting shared with something else, and thus stepped on.  I haven't investigated this yet though.

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You could say the same thing about unhelpful replies.

Unless there is someone who has had exactly the same problem, and recognizes it,  and can say "you, you need to xxx", you'd otherwise be looking at NO replies...

 

assembly snippet:

One of the possibilities is that something is going wrong with copying the RAMFUNC code from Flash into RAM.

Is the snippet from the .elf file, or actually reading the memory off of your failing system?

If the latter, does it agree with the .lss file (which is produced from the .elf file, AFAIK)?   What about the code that the C compiler thinks it's spitting out? (I'm not quite sure how to get that out of AS7.  You can cut&paste to an "AS Command Prompt" window....)

 

I added your function to the IOPORT_EXAMPLE11 SAMG55 example, and it produces relatively different code (in a different place.  Apparently the standard ASF startup code adds some RAMFUNCs as well?)

I have arm-none-eabi-gcc.exe (Atmel build: 508) 6.3.1 20170620 (release) [ARM/embedded-6-branch revision 249437]

(I do NOT have a SAMG55 board to try it out on...)

 

20000094 <erase_pages>:
  :
  __ASM volatile ("cpsid i" : : : "memory");
200000bc:	b672      	cpsid	i
	((Efc *)hw)->EEFC_FCR = EEFC_FCR_FCMD_EPA | EEFC_FCR_FARG(epa_arg) | EEFC_FCR_FKEY_PASSWD;
200000be:	683b      	ldr	r3, [r7, #0]
200000c0:	021b      	lsls	r3, r3, #8
200000c2:	f023 437f 	bic.w	r3, r3, #4278190080	; 0xff000000
200000c6:	f023 03ff 	bic.w	r3, r3, #255	; 0xff
200000ca:	f043 43b4 	orr.w	r3, r3, #1509949440	; 0x5a000000
200000ce:	f043 0307 	orr.w	r3, r3, #7
200000d2:	687a      	ldr	r2, [r7, #4]
200000d4:	6053      	str	r3, [r2, #4]
	eefc_fsr = *statusReg;
200000d6:	68fb      	ldr	r3, [r7, #12]
200000d8:	681b      	ldr	r3, [r3, #0]
200000da:	60bb      	str	r3, [r7, #8]
	while (( eefc_fsr & EEFC_FSR_FRDY  ) == 0)
200000dc:	e002      	b.n	200000e4 <erase_pages+0x50>
		eefc_fsr = *statusReg;
200000de:	68fb      	ldr	r3, [r7, #12]
200000e0:	681b      	ldr	r3, [r3, #0]
200000e2:	60bb      	str	r3, [r7, #8]
	while (( eefc_fsr & EEFC_FSR_FRDY  ) == 0)
200000e4:	68bb      	ldr	r3, [r7, #8]
200000e6:	f003 0301 	and.w	r3, r3, #1
200000ea:	2b00      	cmp	r3, #0
200000ec:	d0f7      	beq.n	200000de <erase_pages+0x4a>
  __ASM volatile ("cpsie i" : : : "memory");
200000ee:	b662      	cpsie	i
	if((eefc_fsr & EEFC_FSR_FLOCKE)||(eefc_fsr & EEFC_FSR_FCMDE)||(eefc_fsr & EEFC_FSR_FLERR))//Locking region violation or Bad keyword violation or Flash error
200000f0:	68bb      	ldr	r3, [r7, #8]
200000f2:	f003 0304 	and.w	r3, r3, #4
200000f6:	2b00      	cmp	r3, #0
200000f8:	d109      	bne.n	2000010e <erase_pages+0x7a>
200000fa:	68bb      	ldr	r3, [r7, #8]
200000fc:	f003 0302 	and.w	r3, r3, #2
20000100:	2b00      	cmp	r3, #0
20000102:	d104      	bne.n	2000010e <erase_pages+0x7a>
20000104:	68bb      	ldr	r3, [r7, #8]
20000106:	f003 0308 	and.w	r3, r3, #8
2000010a:	2b00      	cmp	r3, #0
2000010c:	d001      	beq.n	20000112 <erase_pages+0x7e>
	return 0;
2000010e:	2300      	movs	r3, #0
20000110:	e000      	b.n	20000114 <erase_pages+0x80>
	return 1;
20000112:	2301      	movs	r3, #1
}
20000114:	4618      	mov	r0, r3
20000116:	3714      	adds	r7, #20
20000118:	46bd      	mov	sp, r7
2000011a:	f85d 7b04 	ldr.w	r7,  , #4
2000011e:	4770      	bx	lr