This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TM4C1294KCPDT: FPU float directive

Guru 55913 points
Part Number: TM4C1294KCPDT

Datasheet states the FPU is disabled by default and requires code below to enable FPU instructions. How and why does CCS compiler not throw an exception when (float) directive is seemingly calling parts of eabi.lib in order to carry out the float directive syntax? How is the runtime application not faulting the MCU when the compiled float directive is encountered and CCS debug shows a floating point decimal in float variables?

3.1.5.7 Enabling the FPU
The FPU is disabled from reset. You must enable it before you can use any floating-point instructions. The processor must be in privileged mode to read from and write to the Coprocessor Access Control (CPAC) register. The below example code sequence enables the FPU in both privileged and user modes.

; CPACR is located at address 0xE000ED88
LDR.W R0, =0xE000ED88
; Read CPACR
LDR R1, [R0]
; Set bits 20-23 to enable CP10 and CP11 coprocessors
ORR R1, R1, #(0xF << 20)
; Write back the modified value to the CPACR
STR R1, [R0]; wait for store to complete
DSB
;reset pipeline now the FPU is enabled
ISB

  • Hi BP101,

     The compiler doesn't know if you had enabled the FPU or the processor has the built-in FPU or not. In the compiler setting you probably have specified the FPv4SPD16 for FPU support and hence the compiler will generate code utilizing the FPU. In the boot.asm code the hardware FPU is enabled before the application is run. See below snippet of the boot.asm.

    ;

    .if __TI_ARM_V7M__ | __TI_ARM_V6M0__
    .thumbfunc _c_int00
    .else
    .armfunc _c_int00
    .endif

    ;****************************************************************************
    ; Accomodate different lowerd names in different ABIs
    ;****************************************************************************
    .if __TI_EABI_ASSEMBLER
    .asg _system_pre_init, PRE_INIT_RTN
    .asg __TI_auto_init, AUTO_INIT_RTN
    .asg _args_main, ARGS_MAIN_RTN
    .asg exit, EXIT_RTN
    .asg main_func_sp, MAIN_FUNC_SP
    .else ; COFF TI ARM9 ABI
    .asg __system_pre_init, PRE_INIT_RTN
    .asg __TI_auto_init, AUTO_INIT_RTN ; NOTE does not use COFF prefix
    .asg __args_main, ARGS_MAIN_RTN
    .asg _exit, EXIT_RTN
    .asg _main_func_sp, MAIN_FUNC_SP
    .endif

    .if .TMS470_16BIS

    ;****************************************************************************
    ;* 16 BIT STATE BOOT ROUTINE *
    ;****************************************************************************

    .if __TI_ARM_V7M__ | __TI_ARM_V6M0__
    .thumb
    .else
    .arm
    .endif

    .global __stack
    ;***************************************************************
    ;* DEFINE THE USER MODE STACK (DEFAULT SIZE IS 512)
    ;***************************************************************
    __stack:.usect ".stack", 0, 4

    .global _c_int00

    ;***************************************************************
    ;* FUNCTION DEF: _c_int00
    ;***************************************************************
    _c_int00: .asmfunc stack_usage(0)

    .if !__TI_ARM_V7M__ & !__TI_ARM_V6M0__
    .if __TI_NEON_SUPPORT__ | __TI_VFP_SUPPORT__
    ;*------------------------------------------------------
    ;* SETUP PRIVILEGED AND USER MODE ACCESS TO COPROCESSORS
    ;* 10 AND 11, REQUIRED TO ENABLE NEON/VFP
    ;* COPROCESSOR ACCESS CONTROL REG
    ;* BITS [23:22] - CP11, [21:20] - CP10
    ;* SET TO 0b11 TO ENABLE USER AND PRIV MODE ACCESS
    ;*------------------------------------------------------
    MRC p15,#0x0,r0,c1,c0,#2
    MOV r3,#0xf00000
    ORR r0,r0,r3
    MCR p15,#0x0,r0,c1,c0,#2

    ;*------------------------------------------------------
    ; SET THE EN BIT, FPEXC[30] TO ENABLE NEON AND VFP
    ;*------------------------------------------------------
    MOV r0,#0x40000000
    FMXR FPEXC,r0
    .endif ; __TI_NEON_SUPPORT__ | __TI_VFP_SUPPORT__

    ;------------------------------------------------------
    ;* SET TO USER MODE
    ;*------------------------------------------------------
    MRS r0, cpsr
    BIC r0, r0, #0x1F ; CLEAR MODES
    ORR r0, r0, #0x10 ; SET USER MODE
    MSR cpsr_cf, r0

    ;*------------------------------------------------------
    ;* CHANGE TO 16 BIT STATE
    ;*------------------------------------------------------
    ADD r0, pc, #1
    BX r0

    .thumb
    .else ; !__TI_ARM_V7M & !__TI_ARM_V6M0
    .if __TI_TMS470_V7M4__ & __TI_VFP_SUPPORT__
    .thumb
    ;*------------------------------------------------------
    ;* SETUP FULL ACCESS TO COPROCESSORS 10 AND 11,
    ;* REQUIRED FOR FP. COPROCESSOR ACCESS CONTROL REG
    ;* BITS [23:22] - CP11, [21:20] - CP10
    ;* SET TO 0b11 TO ENABLE FULL ACCESS
    ;*------------------------------------------------------
    cpacr .set 0xE000ED88 ; CAPCR address
    MOVW r1, #cpacr & 0xFFFF
    MOVT r1, #cpacr >> 16
    LDR r0, [ r1 ]
    MOV r3, #0xf0
    ORR r0,r0,r3, LSL #16
    STR r0, [ r1 ]
    .thumb
    .endif ; __TI_TMS470_V7M4__ & __TI_VFP_SUPPORT__
    .endif ; !__TI_ARM_V7M & !__TI_ARM_V6M0__

    ;*------------------------------------------------------
    ;* INITIALIZE THE USER MODE STACK
    ;*------------------------------------------------------
    .if __TI_AVOID_EMBEDDED_CONSTANTS
    .thumb
    MOVW r0, __stack
    MOVT r0, __stack
    MOV sp, r0
    MOVW r0, __STACK_SIZE
    MOVT r0, __STACK_SIZE
    .thumb
    .else ; __TI_AVOID_EMBEDDED_CONSTANTS
    LDR r0, c_stack
    MOV sp, r0
    LDR r0, c_STACK_SIZE
    .endif ; __TI_AVOID_EMBEDDED_CONSTANTS
    ADD sp, r0

    ;*-----------------------------------------------------
    ;* ALIGN THE STACK TO 64-BITS IF EABI.
    ;*-----------------------------------------------------
    .if __TI_EABI_ASSEMBLER
    MOV r7, sp
    MOVS r0, #0x07
    BICS r7, r0 ; Clear upper 3 bits for 64-bit alignment.
    MOV sp, r7
    .endif

    ;*-----------------------------------------------------
    ;* SAVE CURRENT STACK POINTER FOR SDP ANALYSIS
    ;*-----------------------------------------------------
    .if __TI_AVOID_EMBEDDED_CONSTANTS
    .thumb
    MOVW r0, MAIN_FUNC_SP
    MOVT r0, MAIN_FUNC_SP
    .thumb
    .else
    LDR r0, c_mf_sp
    .endif
    MOV r7, sp
    STR r7, [r0]

    ;*------------------------------------------------------
    ;* Call the __mpu_init hook function.
    ;*------------------------------------------------------
    BL __mpu_init

    ;*------------------------------------------------------
    ;* Perform all the required initializations when
    ;* _system_pre_init() returns non-zero:
    ;* - Process BINIT Table
    ;* - Perform C auto initialization
    ;* - Call global constructors
    ;*------------------------------------------------------
    BL PRE_INIT_RTN
    CMP R0, #0
    BEQ bypass_auto_init
    BL AUTO_INIT_RTN
    bypass_auto_init:

    ;*------------------------------------------------------
    ;* CALL APPLICATION
    ;*------------------------------------------------------
    BL ARGS_MAIN_RTN

    ;*------------------------------------------------------
    ;* IF APPLICATION DIDN'T CALL EXIT, CALL EXIT(1)
    ;*------------------------------------------------------
    MOVS r0, #1
    BL EXIT_RTN

    ;*------------------------------------------------------
    ;* DONE, LOOP FOREVER
    ;*------------------------------------------------------
    L1: B L1
    .endasmfunc

    .else ; !.TMS470_16BIS

    ;****************************************************************************
    ;* 32 BIT STATE BOOT ROUTINE *
    ;****************************************************************************

    .global __stack
    ;***************************************************************
    ;* DEFINE THE USER MODE STACK (DEFAULT SIZE IS 512)
    ;***************************************************************
    __stack:.usect ".stack", 0, 4

    .global _c_int00
    ;***************************************************************
    ;* FUNCTION DEF: _c_int00
    ;***************************************************************
    _c_int00: .asmfunc stack_usage(0)

    .if __TI_NEON_SUPPORT__ | __TI_VFP_SUPPORT__
    ;*------------------------------------------------------
    ;* SETUP PRIVILEGED AND USER MODE ACCESS TO COPROCESSORS
    ;* 10 AND 11, REQUIRED TO ENABLE NEON/VFP
    ;* COPROCESSOR ACCESS CONTROL REG
    ;* BITS [23:22] - CP11, [21:20] - CP10
    ;* SET TO 0b11 TO ENABLE USER AND PRIV MODE ACCESS
    ;*------------------------------------------------------
    MRC p15,#0x0,r0,c1,c0,#2
    MOV r3,#0xf00000
    ORR r0,r0,r3
    MCR p15,#0x0,r0,c1,c0,#2

    ;*------------------------------------------------------
    ; SET THE EN BIT, FPEXC[30] TO ENABLE NEON AND VFP
    ;*------------------------------------------------------
    MOV r0,#0x40000000
    FMXR FPEXC,r0
    .endif

    ;*------------------------------------------------------
    ;* SET TO USER MODE
    ;*------------------------------------------------------
    MRS r0, cpsr
    BIC r0, r0, #0x1F ; CLEAR MODES
    ORR r0, r0, #0x10 ; SET USER MODE
    MSR cpsr_cf, r0

    ;*------------------------------------------------------
    ;* INITIALIZE THE USER MODE STACK
    ;*------------------------------------------------------
    .if __TI_AVOID_EMBEDDED_CONSTANTS
    MOVW sp, __stack
    MOVT sp, __stack
    MOVW r0, __STACK_SIZE
    MOVT r0, __STACK_SIZE
    .else
    LDR sp, c_stack
    LDR r0, c_STACK_SIZE
    .endif
    ADD sp, sp, r0

    ;*-----------------------------------------------------
    ;* ALIGN THE STACK TO 64-BITS IF EABI.
    ;*-----------------------------------------------------
    .if __TI_EABI_ASSEMBLER
    BIC sp, sp, #0x07 ; Clear upper 3 bits for 64-bit alignment.
    .endif

    ;*-----------------------------------------------------
    ;* SAVE CURRENT STACK POINTER FOR SDP ANALYSIS
    ;*-----------------------------------------------------
    .if __TI_AVOID_EMBEDDED_CONSTANTS
    MOVW r0, MAIN_FUNC_SP
    MOVT r0, MAIN_FUNC_SP
    .else
    LDR r0, c_mf_sp
    .endif
    STR sp, [r0]

    ;*------------------------------------------------------
    ;* Call the __mpu_init hook function.
    ;*------------------------------------------------------
    BL __mpu_init

    ;*------------------------------------------------------
    ;* Perform all the required initializations when
    ;* _system_pre_init() returns non-zero:
    ;* - Process BINIT Table
    ;* - Perform C auto initialization
    ;* - Call global constructors
    ;*------------------------------------------------------
    BL PRE_INIT_RTN
    CMP R0, #0
    BEQ bypass_auto_init
    BL AUTO_INIT_RTN
    bypass_auto_init:

    ;*------------------------------------------------------
    ;* CALL APPLICATION
    ;*------------------------------------------------------
    BL ARGS_MAIN_RTN

    ;*------------------------------------------------------
    ;* IF APPLICATION DIDN'T CALL EXIT, CALL EXIT(1)
    ;*------------------------------------------------------
    MOV R0, #1
    BL EXIT_RTN

    ;*------------------------------------------------------
    ;* DONE, LOOP FOREVER
    ;*------------------------------------------------------
    L1: B L1
    .endasmfunc

    .endif ; !.TMS470_16BIS

    ;***************************************************************
    ;* CONSTANTS USED BY THIS MODULE
    ;***************************************************************
    .if !__TI_AVOID_EMBEDDED_CONSTANTS
    c_stack .long __stack
    c_STACK_SIZE .long __STACK_SIZE
    c_mf_sp .long MAIN_FUNC_SP
    .endif

    .if __TI_EABI_ASSEMBLER
    .data
    .align 4
    _stkchk_called:
    .field 0,32
    .else
    .sect ".cinit"
    .align 4
    .field 4,32
    .field _stkchk_called+0,32
    .field 0,32

    .bss _stkchk_called,4,4
    .symdepend ".cinit", ".bss"
    .symdepend ".cinit", ".text"
    .symdepend ".bss", ".text"
    .endif

    ;******************************************************
    ;* UNDEFINED REFERENCES *
    ;******************************************************
    .global _stkchk_called
    .global __STACK_SIZE
    .global PRE_INIT_RTN
    .global AUTO_INIT_RTN
    .global ARGS_MAIN_RTN
    .global MAIN_FUNC_SP
    .global EXIT_RTN
    .global __mpu_init

    .end

  • Create (startup_ccs.s) for the script above [LDR.W] generates illegal operand error.

    ;;*****************************************************************************
    ;;
    ;; Put the assembler into the correct configuration.
    ;;
    ;;*****************************************************************************
        .thumb
    
    ;;/********************************************************************************************
    ;;* The FPU is disabled from reset. Enable it before use of any floating-point instructions.
    ;;* The processor must be in privileged mode to read from and write to the Coprocessor Access
    ;;* Control (CPAC) register.                                                           
    ;;*********************************************************************************************/
    
      .thumbfunc EnableFPU
    EnableFPU: .asmfunc
        ;CPACR is located at address 0xE000ED88
         LDR.W R0, 0xE000ED88
        ;Read CPACR
         LDR R1, [R0]
        ;Set bits 20-23 to enable CP10 and CP11 coprocessors
         ORR R1, R1, #(0xF << 20)
        ;Write back the modified value to the CPACR
         STR R1, [R0]
        ;wait for store to complete
         DSB
        ;reset pipeline now the FPU is enabled
         ISB
    .endasmfunc

  • Why don't you use just LDR instead of LDR.W?

  • Hi Charles,

    Yes FPv4SPD16 support was enabled for the project. Will check compile logs to see if (boot.asm) is being invoked. It does invoke during debug sessions get loaded into the project files view pane. Wonder why the script in datasheet assembler refuse to accept LDR.W during compile?
  • Hi BP101,
    The LDR.W is supposed to force it to be a 32-bit Thumb-2 instruction. However, I will suggest you post your question to the TI Compiler forum why the LDR.W is not taken as this is more a tool issue rather than MCU hardware. In the meantime, please use LDR instead.
  • Compiler still shows illegal operand error (LDR) for R0 = unexpected operand or illegal operand without =

    Have to wonder if the datasheet page 146 has a typo in the code?

  • To my knowledge, the = is no longer supported for literal pool in TI assembler.
  • Hi Charles,

    Great detective work!

    There was no such Thumb instruction listed M4v7 reference. However if you enable ASM listing output under compiler advanced options  the float directives math (V~~~) are compiled. There was no boot.asm generated in the compile log. Seemingly boot.asm FP section is for Debug emulator to show the decimal point in the variables view pane.

    ;* --------------------------------------------------------------------------*
    	.dwpsn	file "../adc_ctrl.c",line 638,column 13,is_stmt,isa 1
            MOVS      A1, #0                ; [DPU_3_PIPE] |638| 
            VMOV      S0, V3                ; [DPU_LIN_PIPE] |638| 
            MOVT      A1, #17792            ; [DPU_3_PIPE] |638| 
            VMOV      S1, A1                ; [DPU_LIN_PIPE] |638| 
            MOVS      V4, #0                ; [DPU_3_PIPE] |638| 
            VCVT.F32.U32 S0, S0             ; [DPU_LIN_PIPE] |638| 
            MOVW      A1, #5770             ; [DPU_3_PIPE] |638| 
            MOVT      A1, #15182            ; [DPU_3_PIPE] |638| 
            VMOV      S2, A1                ; [DPU_LIN_PIPE] |638| 
            MOVT      V4, #17327            ; [DPU_3_PIPE] |638| 
            VMUL.F32  S0, S1, S0            ; [DPU_LIN_PIPE] |638| 
            VMOV      S1, V4                ; [DPU_LIN_PIPE] |638| 
            VMUL.F32  S0, S2, S0            ; [DPU_LIN_PIPE] |638| 
            VCVT.U32.F32 S0, S0             ; [DPU_LIN_PIPE] |638| 
            VMOV      A1, S0                ; [DPU_LIN_PIPE] |638| 
    	.dwpsn	file "../adc_ctrl.c",line 641,column 13,is_stmt,isa 1
            MOV       LR, #0                ; [DPU_3_PIPE] |641| 
    	.dwpsn	file "../adc_ctrl.c",line 638,column 13,is_stmt,isa 1
            VMOV      S0, A1                ; [DPU_LIN_PIPE] |638| 
    	.dwpsn	file "../adc_ctrl.c",line 641,column 13,is_stmt,isa 1
            STRH      LR, [A4, #0]          ; [DPU_3_PIPE] |641| 
    	.dwpsn	file "../adc_ctrl.c",line 638,column 13,is_stmt,isa 1
            VCVT.F32.U32 S0, S0             ; [DPU_LIN_PIPE] |638| 
    	.dwpsn	file "../adc_ctrl.c",line 635,column 13,is_stmt,isa 1
            STRH      V3, [A2, #0]          ; [DPU_3_PIPE] |635| 
    	.dwpsn	file "../adc_ctrl.c",line 638,column 13,is_stmt,isa 1
            VSUB.F32  S1, S0, S1            ; [DPU_LIN_PIPE] |638| 
    	.dwpsn	file "../adc_ctrl.c",line 641,column 13,is_stmt,isa 1
            B         ||$C$L13||            ; [DPU_3_PIPE] |641| 
            ; BRANCH OCCURS {||$C$L13||}     ; [] |641| 
    ;* -------------------------------------------------------------------

  • HI Charles,

    There was an easier way to enable FPU via Tivaware calls. Even though CCS compiled for and output FPU assembler results, it seems we still need to enable the FPU in the MCU. Perhaps the float directive in application is ignored by the CPU when FPU has not been enabled?

     /* Enable NVIC Floating Point Unit, FPU */
     MAP_FPUEnable();
    
     /* Floating-point state is not saved on interrupt entry */
     MAP_FPULazyStackingEnable();