1

我正在尝试在我的 STM32L476 探索板、ARM Cortex-M4 CPU 上实现浮点运算。我所有的代码都只能用 ARM 汇编编写。

首先,我通过激活 CoProcesser 10 和 11 来启用 FPU,

.thumb
.thumb_func
.globl fpu_init
fpu_init:
    ldr r0,=0xE000ED88
    ldr r1,[r0]
    ldr r2,=0xF00000
    orr r1,r2, #(0xF << 20)
    str r1,[r0]
    dsb
    isb
    bx lr

这是程序的其余部分,我在其中实现浮点运算。

.syntax unified
.global main
.fpu vfpv4

.type main, %function
main:
  bl fpu_init
  LDR R0, =val1           @ load variable address
  VLDR S0, [R0]           @ load the value into the VFP register

  LDR R0, =val2           @ load variable address
  VLDR S1, [R0]           @ load the value into the VFP register

  VMUL.F32 S2, S0, S1     @ compute S2 = S0 * S1

  VCVT.F64.F32 D4, S2     @ covert the result to double precision for printing
  VMOV R1, R2, D4         @ split the double VFP register into two ARM registers
  BL  _printf_result      @ print the result

  B   _exit               @ branch to exit procedure with no return
  .size main, .-main

_exit:  
  MOV R7, #4              @ write syscall, 4
  MOV R0, #1              @ output stream to monitor, 1
  MOV R2, #21             @ print string length
  LDR R1, =exit_str       @ string at label exit_str:
  SWI 0                   @ execute syscall
  MOV R7, #1              @ terminate syscall, 1
  SWI 0                   @ execute syscall

_printf_result:
  PUSH {LR}               @ push LR to stack
  LDR R0, =result_str     @ R0 contains formatted string address
  BL printf               @ call printf
  POP {PC}                @ pop LR from stack and return

.data
result_str:     .asciz      "Multiplication result = %f \n"
exit_str:       .ascii      "Terminating program.\n"
val1:           .float      3.14159
val2:           .float      0.100

以上代码都在我的 main.s 中。

当我的程序到达第一个 VLDR 函数并跳转到startup_stm32l476xx.s文件中的默认处理程序时,就会出现问题(我的猜测是浮点运算函数未定义)。

在我startup_stm32l476xx.sFPU_IRQHandler映射到Default_Handler.

    .weak   FPU_IRQHandler
    .thumb_set FPU_IRQHandler,Default_Handler

VLDR 被跳转到Default_Handler,是因为它未定义,还是因为我没有FPU_IRQHandler在我的程序中编写 a。

如何FPU_IRQHandler在没有任何额外 C 代码的情况下仅在 ARM 汇编中编写。

附加说明:该文件startup_stm32l476xx.s.fpu设置为softvfp. 这会导致问题吗,即使我已经设置.fpu vpfv4main.s

  .syntax unified
    .cpu cortex-m4
    .fpu softvfp
    .thumb

我对组装很陌生,任何帮助将不胜感激。谢谢

编辑:我添加了我的启动代码。我正在使用 PlatfromIO 来构建这个项目。

启动代码如下:

/**
  ******************************************************************************
  * @file      startup_stm32l476xx.s
  * @author    MCD Application Team
  * @brief     STM32L476xx devices vector table GCC toolchain.
  *            This module performs:
  *                - Set the initial SP
  *                - Set the initial PC == Reset_Handler,
  *                - Set the vector table entries with the exceptions ISR address,
  *                - Configure the clock system  
  *                - Branches to main in the C library (which eventually
  *                  calls main()).
  *            After Reset the Cortex-M4 processor is in Thread mode,
  *            priority is Privileged, and the Stack is set to Main.
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; COPYRIGHT(c) 2017 STMicroelectronics</center></h2>
  *
  * Redistribution and use in source and binary forms, with or without modification,
  * are permitted provided that the following conditions are met:
  *   1. Redistributions of source code must retain the above copyright notice,
  *      this list of conditions and the following disclaimer.
  *   2. Redistributions in binary form must reproduce the above copyright notice,
  *      this list of conditions and the following disclaimer in the documentation
  *      and/or other materials provided with the distribution.
  *   3. Neither the name of STMicroelectronics nor the names of its contributors
  *      may be used to endorse or promote products derived from this software
  *      without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  ******************************************************************************
  */

  .syntax unified
    .cpu cortex-m4
    .fpu softvfp
    .thumb

.global g_pfnVectors
.global Default_Handler

/* start address for the initialization values of the .data section.
defined in linker script */
.word   _sidata
/* start address for the .data section. defined in linker script */
.word   _sdata
/* end address for the .data section. defined in linker script */
.word   _edata
/* start address for the .bss section. defined in linker script */
.word   _sbss
/* end address for the .bss section. defined in linker script */
.word   _ebss

.equ  BootRAM,        0xF1E0F85F
/**
 * @brief  This is the code that gets called when the processor first
 *          starts execution following a reset event. Only the absolutely
 *          necessary set is performed, after which the application
 *          supplied main() routine is called.
 * @param  None
 * @retval : None
*/

    .section    .text.Reset_Handler
    .weak   Reset_Handler
    .type   Reset_Handler, %function
Reset_Handler:
  ldr   sp, =_estack    /* Atollic update: set stack pointer */

/* Copy the data segment initializers from flash to SRAM */
  movs  r1, #0
  b LoopCopyDataInit

CopyDataInit:
    ldr r3, =_sidata
    ldr r3, [r3, r1]
    str r3, [r0, r1]
    adds    r1, r1, #4

LoopCopyDataInit:
    ldr r0, =_sdata
    ldr r3, =_edata
    adds    r2, r0, r1
    cmp r2, r3
    bcc CopyDataInit
    ldr r2, =_sbss
    b   LoopFillZerobss
/* Zero fill the bss segment. */
FillZerobss:
    movs    r3, #0
    str r3, [r2], #4

LoopFillZerobss:
    ldr r3, = _ebss
    cmp r2, r3
    bcc FillZerobss

/* Call the clock system intitialization function.*/
    bl  SystemInit
/* Call static constructors */
    bl __libc_init_array
/* Call the application's entry point.*/
    bl  main

LoopForever:
    b LoopForever

.size   Reset_Handler, .-Reset_Handler

/**
 * @brief  This is the code that gets called when the processor receives an
 *         unexpected interrupt.  This simply enters an infinite loop, preserving
 *         the system state for examination by a debugger.
 *
 * @param  None
 * @retval : None
*/
    .section    .text.Default_Handler,"ax",%progbits
Default_Handler:
Infinite_Loop:
    b   Infinite_Loop
    .size   Default_Handler, .-Default_Handler
/******************************************************************************
*
* The minimal vector table for a Cortex-M4.  Note that the proper constructs
* must be placed on this to ensure that it ends up at physical address
* 0x0000.0000.
*
******************************************************************************/
    .section    .isr_vector,"a",%progbits
    .type   g_pfnVectors, %object
    .size   g_pfnVectors, .-g_pfnVectors


g_pfnVectors:
    .word   _estack
    .word   Reset_Handler
    .word   NMI_Handler
    .word   HardFault_Handler
    .word   MemManage_Handler
    .word   BusFault_Handler
    .word   UsageFault_Handler
    .word   0
    .word   0
    .word   0
    .word   0
    .word   SVC_Handler
    .word   DebugMon_Handler
    .word   0
    .word   PendSV_Handler
    .word   SysTick_Handler
    .word   WWDG_IRQHandler
    .word   PVD_PVM_IRQHandler
    .word   TAMP_STAMP_IRQHandler
    .word   RTC_WKUP_IRQHandler
    .word   FLASH_IRQHandler
    .word   RCC_IRQHandler
    .word   EXTI0_IRQHandler
    .word   EXTI1_IRQHandler
    .word   EXTI2_IRQHandler
    .word   EXTI3_IRQHandler
    .word   EXTI4_IRQHandler
    .word   DMA1_Channel1_IRQHandler
    .word   DMA1_Channel2_IRQHandler
    .word   DMA1_Channel3_IRQHandler
    .word   DMA1_Channel4_IRQHandler
    .word   DMA1_Channel5_IRQHandler
    .word   DMA1_Channel6_IRQHandler
    .word   DMA1_Channel7_IRQHandler
    .word   ADC1_2_IRQHandler
    .word   CAN1_TX_IRQHandler
    .word   CAN1_RX0_IRQHandler
    .word   CAN1_RX1_IRQHandler
    .word   CAN1_SCE_IRQHandler
    .word   EXTI9_5_IRQHandler
    .word   TIM1_BRK_TIM15_IRQHandler
    .word   TIM1_UP_TIM16_IRQHandler
    .word   TIM1_TRG_COM_TIM17_IRQHandler
    .word   TIM1_CC_IRQHandler
    .word   TIM2_IRQHandler
    .word   TIM3_IRQHandler
    .word   TIM4_IRQHandler
    .word   I2C1_EV_IRQHandler
    .word   I2C1_ER_IRQHandler
    .word   I2C2_EV_IRQHandler
    .word   I2C2_ER_IRQHandler
    .word   SPI1_IRQHandler
    .word   SPI2_IRQHandler
    .word   USART1_IRQHandler
    .word   USART2_IRQHandler
    .word   USART3_IRQHandler
    .word   EXTI15_10_IRQHandler
    .word   RTC_Alarm_IRQHandler
    .word   DFSDM1_FLT3_IRQHandler
    .word   TIM8_BRK_IRQHandler
    .word   TIM8_UP_IRQHandler
    .word   TIM8_TRG_COM_IRQHandler
    .word   TIM8_CC_IRQHandler
    .word   ADC3_IRQHandler
    .word   FMC_IRQHandler
    .word   SDMMC1_IRQHandler
    .word   TIM5_IRQHandler
    .word   SPI3_IRQHandler
    .word   UART4_IRQHandler
    .word   UART5_IRQHandler
    .word   TIM6_DAC_IRQHandler
    .word   TIM7_IRQHandler
    .word   DMA2_Channel1_IRQHandler
    .word   DMA2_Channel2_IRQHandler
    .word   DMA2_Channel3_IRQHandler
    .word   DMA2_Channel4_IRQHandler
    .word   DMA2_Channel5_IRQHandler
    .word   DFSDM1_FLT0_IRQHandler
    .word   DFSDM1_FLT1_IRQHandler
    .word   DFSDM1_FLT2_IRQHandler
    .word   COMP_IRQHandler
    .word   LPTIM1_IRQHandler
    .word   LPTIM2_IRQHandler
    .word   OTG_FS_IRQHandler
    .word   DMA2_Channel6_IRQHandler
    .word   DMA2_Channel7_IRQHandler
    .word   LPUART1_IRQHandler
    .word   QUADSPI_IRQHandler
    .word   I2C3_EV_IRQHandler
    .word   I2C3_ER_IRQHandler
    .word   SAI1_IRQHandler
    .word   SAI2_IRQHandler
    .word   SWPMI1_IRQHandler
    .word   TSC_IRQHandler
    .word   LCD_IRQHandler
    .word 0
    .word   RNG_IRQHandler
    .word   FPU_IRQHandler


/*******************************************************************************
*
* Provide weak aliases for each Exception handler to the Default_Handler.
* As they are weak aliases, any function with the same name will override
* this definition.
*
*******************************************************************************/

  .weak NMI_Handler
    .thumb_set NMI_Handler,Default_Handler

  .weak HardFault_Handler
    .thumb_set HardFault_Handler,Default_Handler

  .weak MemManage_Handler
    .thumb_set MemManage_Handler,Default_Handler

  .weak BusFault_Handler
    .thumb_set BusFault_Handler,Default_Handler

    .weak   UsageFault_Handler
    .thumb_set UsageFault_Handler,Default_Handler

    .weak   SVC_Handler
    .thumb_set SVC_Handler,Default_Handler

    .weak   DebugMon_Handler
    .thumb_set DebugMon_Handler,Default_Handler

    .weak   PendSV_Handler
    .thumb_set PendSV_Handler,Default_Handler

    .weak   SysTick_Handler
    .thumb_set SysTick_Handler,Default_Handler

    .weak   WWDG_IRQHandler
    .thumb_set WWDG_IRQHandler,Default_Handler

    .weak   PVD_PVM_IRQHandler
    .thumb_set PVD_PVM_IRQHandler,Default_Handler

    .weak   TAMP_STAMP_IRQHandler
    .thumb_set TAMP_STAMP_IRQHandler,Default_Handler

    .weak   RTC_WKUP_IRQHandler
    .thumb_set RTC_WKUP_IRQHandler,Default_Handler

    .weak   FLASH_IRQHandler
    .thumb_set FLASH_IRQHandler,Default_Handler

    .weak   RCC_IRQHandler
    .thumb_set RCC_IRQHandler,Default_Handler

    .weak   EXTI0_IRQHandler
    .thumb_set EXTI0_IRQHandler,Default_Handler

    .weak   EXTI1_IRQHandler
    .thumb_set EXTI1_IRQHandler,Default_Handler

    .weak   EXTI2_IRQHandler
    .thumb_set EXTI2_IRQHandler,Default_Handler

    .weak   EXTI3_IRQHandler
    .thumb_set EXTI3_IRQHandler,Default_Handler

    .weak   EXTI4_IRQHandler
    .thumb_set EXTI4_IRQHandler,Default_Handler

    .weak   DMA1_Channel1_IRQHandler
    .thumb_set DMA1_Channel1_IRQHandler,Default_Handler

    .weak   DMA1_Channel2_IRQHandler
    .thumb_set DMA1_Channel2_IRQHandler,Default_Handler

    .weak   DMA1_Channel3_IRQHandler
    .thumb_set DMA1_Channel3_IRQHandler,Default_Handler

    .weak   DMA1_Channel4_IRQHandler
    .thumb_set DMA1_Channel4_IRQHandler,Default_Handler

    .weak   DMA1_Channel5_IRQHandler
    .thumb_set DMA1_Channel5_IRQHandler,Default_Handler

    .weak   DMA1_Channel6_IRQHandler
    .thumb_set DMA1_Channel6_IRQHandler,Default_Handler

    .weak   DMA1_Channel7_IRQHandler
    .thumb_set DMA1_Channel7_IRQHandler,Default_Handler

    .weak   ADC1_2_IRQHandler
    .thumb_set ADC1_2_IRQHandler,Default_Handler

    .weak   CAN1_TX_IRQHandler
    .thumb_set CAN1_TX_IRQHandler,Default_Handler

    .weak   CAN1_RX0_IRQHandler
    .thumb_set CAN1_RX0_IRQHandler,Default_Handler

    .weak   CAN1_RX1_IRQHandler
    .thumb_set CAN1_RX1_IRQHandler,Default_Handler

    .weak   CAN1_SCE_IRQHandler
    .thumb_set CAN1_SCE_IRQHandler,Default_Handler

    .weak   EXTI9_5_IRQHandler
    .thumb_set EXTI9_5_IRQHandler,Default_Handler

    .weak   TIM1_BRK_TIM15_IRQHandler
    .thumb_set TIM1_BRK_TIM15_IRQHandler,Default_Handler

    .weak   TIM1_UP_TIM16_IRQHandler
    .thumb_set TIM1_UP_TIM16_IRQHandler,Default_Handler

    .weak   TIM1_TRG_COM_TIM17_IRQHandler
    .thumb_set TIM1_TRG_COM_TIM17_IRQHandler,Default_Handler

    .weak   TIM1_CC_IRQHandler
    .thumb_set TIM1_CC_IRQHandler,Default_Handler

    .weak   TIM2_IRQHandler
    .thumb_set TIM2_IRQHandler,Default_Handler

    .weak   TIM3_IRQHandler
    .thumb_set TIM3_IRQHandler,Default_Handler

    .weak   TIM4_IRQHandler
    .thumb_set TIM4_IRQHandler,Default_Handler

    .weak   I2C1_EV_IRQHandler
    .thumb_set I2C1_EV_IRQHandler,Default_Handler

    .weak   I2C1_ER_IRQHandler
    .thumb_set I2C1_ER_IRQHandler,Default_Handler

    .weak   I2C2_EV_IRQHandler
    .thumb_set I2C2_EV_IRQHandler,Default_Handler

    .weak   I2C2_ER_IRQHandler
    .thumb_set I2C2_ER_IRQHandler,Default_Handler

    .weak   SPI1_IRQHandler
    .thumb_set SPI1_IRQHandler,Default_Handler

    .weak   SPI2_IRQHandler
    .thumb_set SPI2_IRQHandler,Default_Handler

    .weak   USART1_IRQHandler
    .thumb_set USART1_IRQHandler,Default_Handler

    .weak   USART2_IRQHandler
    .thumb_set USART2_IRQHandler,Default_Handler

    .weak   USART3_IRQHandler
    .thumb_set USART3_IRQHandler,Default_Handler

    .weak   EXTI15_10_IRQHandler
    .thumb_set EXTI15_10_IRQHandler,Default_Handler

    .weak   RTC_Alarm_IRQHandler
    .thumb_set RTC_Alarm_IRQHandler,Default_Handler

    .weak   DFSDM1_FLT3_IRQHandler
    .thumb_set DFSDM1_FLT3_IRQHandler,Default_Handler

    .weak   TIM8_BRK_IRQHandler
    .thumb_set TIM8_BRK_IRQHandler,Default_Handler

    .weak   TIM8_UP_IRQHandler
    .thumb_set TIM8_UP_IRQHandler,Default_Handler

    .weak   TIM8_TRG_COM_IRQHandler
    .thumb_set TIM8_TRG_COM_IRQHandler,Default_Handler

    .weak   TIM8_CC_IRQHandler
    .thumb_set TIM8_CC_IRQHandler,Default_Handler

    .weak   ADC3_IRQHandler
    .thumb_set ADC3_IRQHandler,Default_Handler

    .weak   FMC_IRQHandler
    .thumb_set FMC_IRQHandler,Default_Handler

    .weak   SDMMC1_IRQHandler
    .thumb_set SDMMC1_IRQHandler,Default_Handler

    .weak   TIM5_IRQHandler
    .thumb_set TIM5_IRQHandler,Default_Handler

    .weak   SPI3_IRQHandler
    .thumb_set SPI3_IRQHandler,Default_Handler

    .weak   UART4_IRQHandler
    .thumb_set UART4_IRQHandler,Default_Handler

    .weak   UART5_IRQHandler
    .thumb_set UART5_IRQHandler,Default_Handler

    .weak   TIM6_DAC_IRQHandler
    .thumb_set TIM6_DAC_IRQHandler,Default_Handler

    .weak   TIM7_IRQHandler
    .thumb_set TIM7_IRQHandler,Default_Handler

    .weak   DMA2_Channel1_IRQHandler
    .thumb_set DMA2_Channel1_IRQHandler,Default_Handler

    .weak   DMA2_Channel2_IRQHandler
    .thumb_set DMA2_Channel2_IRQHandler,Default_Handler

    .weak   DMA2_Channel3_IRQHandler
    .thumb_set DMA2_Channel3_IRQHandler,Default_Handler

    .weak   DMA2_Channel4_IRQHandler
    .thumb_set DMA2_Channel4_IRQHandler,Default_Handler

    .weak   DMA2_Channel5_IRQHandler
    .thumb_set DMA2_Channel5_IRQHandler,Default_Handler

    .weak   DFSDM1_FLT0_IRQHandler
    .thumb_set DFSDM1_FLT0_IRQHandler,Default_Handler   

    .weak   DFSDM1_FLT1_IRQHandler
    .thumb_set DFSDM1_FLT1_IRQHandler,Default_Handler   

    .weak   DFSDM1_FLT2_IRQHandler
    .thumb_set DFSDM1_FLT2_IRQHandler,Default_Handler   

    .weak   COMP_IRQHandler
    .thumb_set COMP_IRQHandler,Default_Handler

    .weak   LPTIM1_IRQHandler
    .thumb_set LPTIM1_IRQHandler,Default_Handler

    .weak   LPTIM2_IRQHandler
    .thumb_set LPTIM2_IRQHandler,Default_Handler    

    .weak   OTG_FS_IRQHandler
    .thumb_set OTG_FS_IRQHandler,Default_Handler    

    .weak   DMA2_Channel6_IRQHandler
    .thumb_set DMA2_Channel6_IRQHandler,Default_Handler 

    .weak   DMA2_Channel7_IRQHandler
    .thumb_set DMA2_Channel7_IRQHandler,Default_Handler 

    .weak   LPUART1_IRQHandler
    .thumb_set LPUART1_IRQHandler,Default_Handler   

    .weak   QUADSPI_IRQHandler
    .thumb_set QUADSPI_IRQHandler,Default_Handler   

    .weak   I2C3_EV_IRQHandler
    .thumb_set I2C3_EV_IRQHandler,Default_Handler   

    .weak   I2C3_ER_IRQHandler
    .thumb_set I2C3_ER_IRQHandler,Default_Handler   

    .weak   SAI1_IRQHandler
    .thumb_set SAI1_IRQHandler,Default_Handler

    .weak   SAI2_IRQHandler
    .thumb_set SAI2_IRQHandler,Default_Handler

    .weak   SWPMI1_IRQHandler
    .thumb_set SWPMI1_IRQHandler,Default_Handler

    .weak   TSC_IRQHandler
    .thumb_set TSC_IRQHandler,Default_Handler

    .weak   LCD_IRQHandler
    .thumb_set LCD_IRQHandler,Default_Handler

    .weak   RNG_IRQHandler
    .thumb_set RNG_IRQHandler,Default_Handler

    .weak   FPU_IRQHandler
    .thumb_set FPU_IRQHandler,Default_Handler
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

我上面的启动代码中的 Reset_Handler :

   .section .text.Reset_Handler
    .weak   Reset_Handler
    .type   Reset_Handler, %function
Reset_Handler:
  ldr   sp, =_estack    /* Atollic update: set stack pointer */

/* Copy the data segment initializers from flash to SRAM */
  movs  r1, #0
  b LoopCopyDataInit

CopyDataInit:
    ldr r3, =_sidata
    ldr r3, [r3, r1]
    str r3, [r0, r1]
    adds    r1, r1, #4

LoopCopyDataInit:
    ldr r0, =_sdata
    ldr r3, =_edata
    adds    r2, r0, r1
    cmp r2, r3
    bcc CopyDataInit
    ldr r2, =_sbss
    b   LoopFillZerobss
/* Zero fill the bss segment. */
FillZerobss:
    movs    r3, #0
    str r3, [r2], #4

LoopFillZerobss:
    ldr r3, = _ebss
    cmp r2, r3
    bcc FillZerobss

/* Call the clock system intitialization function.*/
    bl  SystemInit
/* Call static constructors */
    bl __libc_init_array
/* Call the application's entry point.*/
    bl  main

LoopForever:
    b LoopForever

.size   Reset_Handler, .-Reset_Handler

我的 PlatformIO 构建配置如下:

[env:disco_l476vg]
platform = ststm32@4.5.0
board = disco_l476vg
framework = stm32cube
build_flags = -g -O0 -mfloat-abi=softfp -mfpu=fpv5-d16
upload_protocol = stlink
extra_scripts = update_link_flags.py
4

0 回答 0