FPCA bit in CONTROL register stays high...

cancel
Showing results for 
Search instead for 
Did you mean: 

FPCA bit in CONTROL register stays high...

Jump to solution
171 Views
Senior Contributor II

I'm trying to understand more of the guts of the 106x.  The Cortex-M7 User's Guide states that the FPCA bit in the CONTROL register is used to determine whether to preserve floating-point state when processing an exception.  That implies to me that this bit is automatically set whenever the core is in the middle of some floating point operation so that if interrupted, the floating point context will also be saved.  That makes sense; but what I see is this bit goes high and stays high after any floating point operation is performed.  That doesn't make sense... shouldn't it only be active during the FP operation?

Labels (1)
0 Kudos
1 Solution
88 Views
Senior Contributor II

Ok, I did a bit more reading (see this page among others), and I think I get it now...

Regarding the CONTROL.FPCA bit, it seems pretty important for folks doing any real-time bare metal firmware to be aware that once they do any FP operation this bit is set permanently.  This causes all future interrupts to push/pop all FP registers regardless of the actual need to do so.  This occurs because the default state of FPCCR.ASPEN is 1.  So if you're really squeezing real-time, and you don't have any interrupt handlers doing floating point, but you may do some floating point in your application code, you're best off to clear the FPCCR.ASPEN bit at startup.

Please inform if this is incorrect!  I'm basing it on empirical data (code I executed) and snippets of documentation on the web..

HTH

View solution in original post

8 Replies
161 Views
NXP TechSupport
NXP TechSupport

Hi,

Thank you for your interest in NXP Semiconductor products and for the opportunity to serve you.
To be honest, I'm not very clear with your question, whether you mean that the FPCA bit always stays high in the CONTROL register when i.MX RT106x runs code.

Have a great day,
TIC

-------------------------------------------------------------------------------
Note:
- If this post answers your question, please click the "Mark Correct" button. Thank you!

- We are following threads for 7 weeks after the last post, later replies are ignored
Please open a new thread and refer to the closed one, if you have a related question at a later point in time.
-------------------------------------------------------------------------------

0 Kudos
150 Views
Senior Contributor II

I'm trying to better understand exception handling.  According to the M7 User's Guide, the FPCA bit in the Core Control register is used to determine whether to preserve floating-point state when processing an exception (see section 2.1.3 "Core Registers").  That implies to me that this bit is used by the CPU to determine whether or not to push/pop floating point context just in case a floating point operation is interrupted.  That makes sense to me; but I noticed that the FPCA bit is set in my program even when I set a breakpoint in code that is not doing anything with floating point.  So I dug a bit deeper...

The following JLINK trace shows the CPU at a breakpoint just before the first floating point operation after bootup...

J-Link>regs
PC = 8000CA9C, CycleCnt = D5829099
R0 = 00000000, R1 = 00000000, R2 = 8010C129, R3 = 44787CAC
R4 = 60002000, R5 = 20203A70, R6 = C4F44721, R7 = 8010C0C4
R8 = 00200300, R9 = 00000000, R10= 00000000, R11= 400F8000
R12= 00000000
SP(R13)= 8010C0C4, MSP= 8010C0C4, PSP= 8010C2FC, R14(LR) = 8000CA91
XPSR = 61000000: APSR = nZCvq, EPSR = 01000000, IPSR = 000 (NoException)
CFBP = 00000000, CONTROL = 00, FAULTMASK = 00, BASEPRI = 00, PRIMASK = 00

FPS0 = 00000000, FPS1 = 00000000, FPS2 = 00000000, FPS3 = 00000000
FPS4 = 00000000, FPS5 = 00000000, FPS6 = 00000000, FPS7 = 00000000
FPS8 = 00000000, FPS9 = 00000000, FPS10= 00000000, FPS11= 00000000
FPS12= 00000000, FPS13= 00000000, FPS14= 00000000, FPS15= FFFFFFFF
FPS16= 00000000, FPS17= 00000000, FPS18= 00000000, FPS19= 00000000
FPS20= 00000000, FPS21= 00000000, FPS22= 00000000, FPS23= 00000000
FPS24= 00000000, FPS25= 00000000, FPS26= 00000000, FPS27= 00000000
FPS28= 00000000, FPS29= 00000000, FPS30= 00000000, FPS31= FFFFFFFF
FPSCR= 00000000
J-Link>s
8000CA9C:  FB 60              STR       R3, [R7, #+0x0C]
J-Link>regs
PC = 8000CA9E, CycleCnt = D58291C8
R0 = 00000000, R1 = 00000000, R2 = 8010C129, R3 = 44787CAC
R4 = 60002000, R5 = 20203A70, R6 = C4F44721, R7 = 8010C0C4
R8 = 00200300, R9 = 00000000, R10= 00000000, R11= 400F8000
R12= 00000000
SP(R13)= 8010C0C4, MSP= 8010C0C4, PSP= 8010C2FC, R14(LR) = 8000CA91
XPSR = 61000000: APSR = nZCvq, EPSR = 01000000, IPSR = 000 (NoException)
CFBP = 00000000, CONTROL = 00, FAULTMASK = 00, BASEPRI = 00, PRIMASK = 00

FPS0 = 00000000, FPS1 = 00000000, FPS2 = 00000000, FPS3 = 00000000
FPS4 = 00000000, FPS5 = 00000000, FPS6 = 00000000, FPS7 = 00000000
FPS8 = 00000000, FPS9 = 00000000, FPS10= 00000000, FPS11= 00000000
FPS12= 00000000, FPS13= 00000000, FPS14= 00000000, FPS15= FFFFFFFF
FPS16= 00000000, FPS17= 00000000, FPS18= 00000000, FPS19= 00000000
FPS20= 00000000, FPS21= 00000000, FPS22= 00000000, FPS23= 00000000
FPS24= 00000000, FPS25= 00000000, FPS26= 00000000, FPS27= 00000000
FPS28= 00000000, FPS29= 00000000, FPS30= 00000000, FPS31= FFFFFFFF
FPSCR= 00000000
J-Link>s
8000CA9E:  97 ED 04 7A        VLDR.32 S14, [R7, #+16]
J-Link>regs
PC = 8000CAA2, CycleCnt = D5829367
R0 = 00000000, R1 = 00000000, R2 = 8010C129, R3 = 44787CAC
R4 = 60002000, R5 = 20203A70, R6 = C4F44721, R7 = 8010C0C4
R8 = 00200300, R9 = 00000000, R10= 00000000, R11= 400F8000
R12= 00000000
SP(R13)= 8010C0C4, MSP= 8010C0C4, PSP= 8010C2FC, R14(LR) = 8000CA91
XPSR = 61000000: APSR = nZCvq, EPSR = 01000000, IPSR = 000 (NoException)
CFBP = 04000000, CONTROL = 04, FAULTMASK = 00, BASEPRI = 00, PRIMASK = 00

FPS0 = 00000000, FPS1 = 00000000, FPS2 = 00000000, FPS3 = 00000000
FPS4 = 00000000, FPS5 = 00000000, FPS6 = 00000000, FPS7 = 00000000
FPS8 = 00000000, FPS9 = 00000000, FPS10= 00000000, FPS11= 00000000
FPS12= 00000000, FPS13= 00000000, FPS14= 407CAC08, FPS15= FFFFFFFF
FPS16= 00000000, FPS17= 00000000, FPS18= 00000000, FPS19= 00000000
FPS20= 00000000, FPS21= 00000000, FPS22= 00000000, FPS23= 00000000
FPS24= 00000000, FPS25= 00000000, FPS26= 00000000, FPS27= 00000000
FPS28= 00000000, FPS29= 00000000, FPS30= 00000000, FPS31= FFFFFFFF
FPSCR= 00000000

Notice that initially the CONTROL register is 00, but as soon as I step into the VLDR instruction the FPCA bit of the CONTROL register goes active (04).  So far so good.  The problem is that bit never clears.  It is then set forever (as far as I can tell); so that seems to imply to me that all exceptions are pushing and popping FP registers when they don't need to.

Can someone explain that?  I'm sure I'm just misunderstanding something, but I don't get it...

Thanks,

0 Kudos
136 Views
NXP TechSupport
NXP TechSupport

Hi Ed,

Thanks for your reply.
1) Can someone explain that?
-- Whether you can share the source code and introduce the test procedure, as I've not replicated the phenomenon you described, then I'd like to replicate the phenomenon on my site.
Looking forward to your reply.

Have a great day,
TIC

-------------------------------------------------------------------------------
Note:
- If this post answers your question, please click the "Mark Correct" button. Thank you!

- We are following threads for 7 weeks after the last post, later replies are ignored
Please open a new thread and refer to the closed one, if you have a related question at a later point in time.
-------------------------------------------------------------------------------

0 Kudos
122 Views
Senior Contributor II

Here's an easy way to reproduce it...

Build the demo_apps/hello_world application, but with the following changes...

Turn on FP printf/sscanf as follows (CFLAGS):

-DPRINTF_FLOAT_ENABLE=1 -DSCANF_FLOAT_ENABLE=1 -DPRINTF_ADVANCED_ENABLE=1 -DSCANF_ADVANCED_ENABLE=1

and append -lm to the linker line.

Then modify the main function as follows

float
dofp(float a, float b)
{
    return(a * b);
}

/*!
 * @brief Main function
 */
int main(void)
{
    char ch;

    /* Init board hardware. */
    BOARD_ConfigMPU();
    BOARD_InitPins();
    BOARD_InitBootClocks();
    BOARD_InitDebugConsole();

    PRINTF ("PRE_ FP CONTROL: %08x\r\n",__get_CONTROL());
    float fpval = dofp(3.4,5.123);
    PRINTF ("POST FP CONTROL: %08x %f\r\n",__get_CONTROL(), fpval);

    PRINTF("hello world.\r\n");

    while (1)
    {
        ch = GETCHAR();
        PUTCHAR(ch);
    }
}

build it and run it (I used EVK1060/armgcc).  Notice that the PRE-FP CONTROL is 0, but the POST-FP CONTROL is 4 (FPCA bit is still set)...

PRE_ FP CONTROL: 00000000
POST FP CONTROL: 00000004 17.418201

The FP transaction is complete at that point, so shouldn't the FPCA bit be cleared?

0 Kudos
115 Views
NXP TechSupport
NXP TechSupport

Hi Ed,

Thanks for your reply.
After checking, I find that the FPCCR.ASPEN bit is 1 after entering the main function, and it enables automatic FP state preservation, then the processor sets this bit to 1 on successful completion of any FP instruction.
Hope it helps.

jeremyzhou_0-1602557152275.png

Have a great day,
TIC

-------------------------------------------------------------------------------
Note:
- If this post answers your question, please click the "Mark Correct" button. Thank you!

- We are following threads for 7 weeks after the last post, later replies are ignored
Please open a new thread and refer to the closed one, if you have a related question at a later point in time.
-------------------------------------------------------------------------------

109 Views
Senior Contributor II

Ok, I see that, but I still don't get it...

The CONTROL.FPCA bit, as far as I understand it, determines whether or not an exception will include save/restore of floating point context.  That is a lot of additional push/pop overhead; but it makes sense if a floating point operation is interrupted.

The problem I have is that the CONTROL.FPCA bit never goes low after the FP operation is completed; so this still implies to me that all subsequent exceptions (regardless of whether or not they interrupt a FP operation) will push/pop floating point context.

Is this correct?

What happens if the FPCCR.ASPEN bit is not set, then a floating point operation is interrupted by an exception?  Is the context potentially corrupted (if the exception handler uses FP)?

Ed

0 Kudos
97 Views
NXP TechSupport
NXP TechSupport

Hi Ed,

Thanks for your reply.
1) Is this correct?
-- Yes, I think so. And you can try to create some code for testing and confirmation.
2) What happens if the FPCCR.ASPEN bit is not set, then a floating-point operation is interrupted by an exception?
-- Actually, the question beyond my ability, I'd like to suggest you contact the ARM for help.
Have a great day,
TIC

-------------------------------------------------------------------------------
Note:
- If this post answers your question, please click the "Mark Correct" button. Thank you!

- We are following threads for 7 weeks after the last post, later replies are ignored
Please open a new thread and refer to the closed one, if you have a related question at a later point in time.
-------------------------------------------------------------------------------

0 Kudos
89 Views
Senior Contributor II

Ok, I did a bit more reading (see this page among others), and I think I get it now...

Regarding the CONTROL.FPCA bit, it seems pretty important for folks doing any real-time bare metal firmware to be aware that once they do any FP operation this bit is set permanently.  This causes all future interrupts to push/pop all FP registers regardless of the actual need to do so.  This occurs because the default state of FPCCR.ASPEN is 1.  So if you're really squeezing real-time, and you don't have any interrupt handlers doing floating point, but you may do some floating point in your application code, you're best off to clear the FPCCR.ASPEN bit at startup.

Please inform if this is incorrect!  I'm basing it on empirical data (code I executed) and snippets of documentation on the web..

HTH

View solution in original post