在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

探索ARM CPU架構的美妙以及C語言編譯器的奧秘

strongerHuang ? 來源:Mculover666 ? 作者:Mculover666 ? 2021-06-06 18:10 ? 次閱讀

筆者接觸嵌入式領域軟件開發以來,幾乎用的都是 ARM Cortex M 內核系列的微控制器。感謝C語言編譯器的存在,讓我不用接觸匯編即可進行開發,但是彷佛也錯過了一些風景,沒有領域到編譯器之美和CPU之美,所以決定周末無聊的休息時間通過尋找資料、動手實驗、得出結論的方法來探索 ARM CPU 架構的美妙,以及C語言編譯器的奧秘。(因為我個人實在是不贊同學校中微機原理類課程的教學方法)。

ARM探索之旅 01 | 帶你認識ARM Cortex-M陣營

ARM探索之旅 02 | ARM Cortex-M 用什么指令集?

一、浮點數的存儲

浮點數按照 IEEE 754 標準存儲在計算機中,ARM浮點環境是遵循「IEEE 754-1985」標準實現的。

IEEE 754 標準規定浮點數的存儲格式有三個域

sign:符號位,0表示正數、1表示負數;

exponent:二進制小數的指數值編碼;

fraction:二進制小數的有效值編碼;

具體的編碼規則過多,本文重點不在此,不再展開,感興趣可以閱讀我之前的文章:浮點數在計算機中的存儲 —— IEEE 754標準[1](可點擊閱讀原文查看)。

二、浮點支持軟件庫fplib

1. fplib介紹

ARM Cortex-M處理器中計算浮點數的方式有軟件和硬件兩種。

對于不帶 FPU 的處理器,ARM提供了一個「浮點支持軟件庫」用于計算浮點數:fplib。

fplib提供的 API 以__aeabi開頭,比如:

__aeabi_fadd:計算兩個float型浮點數(float占4個字節,32位)

__aeabi_dadd:計算兩個double型浮點數(double占8個字節,64位)

__aeabi_f2d:float型轉為double型

__aeabi_d2f:double型轉為float型

除此之外,fplib庫還提供取余、開方等非常多的浮點數操作函數,如有興趣可以查閱文末我列出的參考文檔[2]。

2. 測試代碼與優化等級

編寫如下測試代碼:

float a = 5.625; float b = 5.625; float res_add, res_sub, res_mul, res_div; res_add = a + b; res_sub = a - b; res_mul = a * b; res_div = a / b; printf(“res_add = %f ”, res_add); printf(“res_sub = %f ”, res_sub); printf(“res_mul = %f ”, res_mul); printf(“res_div = %f ”, res_div);

?

使用這段測試代碼,「編譯器優化等級推薦設置為-O0」,否則聰明的編譯器會直接將結果計算出來編譯到程序中,我們就沒法研究了。

?

3. armcc測試結果

這節我們驗證是否ARM使用 fplib 庫來計算浮點數,在設置中關閉FPU:

使用MDK編譯之后,進入調試模式查看反匯編結果。

在反匯編中可以看到,變量a是float類型,所以編譯器分配了一個寄存器用于存儲值:

查看0x080031C4處的值,小端存儲模式下(低位在低地址),變量a的值是0x40B40000,存儲方式符合IEEE 754標準。

再來看看浮點數運算操作的反匯編結果,果然調用fplib庫提供的函數完成浮點數的操作:這里還有一個有趣的小細節,在反匯編中可以看到「使用 %f 占位符打印浮點數時,printf是按照double型傳參的」:

4. arm-none-eabi-gcc測試結果

使用STM32CubeMX生成makeifle工程,修改makeifle中的等級為-O0,設置為軟件浮點計算:另外還需要注意,默認gcc編譯時不支持printf打印浮點數,需要在 makefile 中手動加入以下鏈接選項:

LDFLAGS += -u _printf_float

編譯完成之后進行反匯編(注意文件名):

arm-none-eabi-objdump -s -d build/usart1-fpu-test.elf 》 build/usart1-fpu-test.dis

同樣,在反匯編文件中即可找到浮點計算代碼:

三、使用 ARM FPU 加速浮點計算

1. ARM FPU的魅力

FPU(Floating Point Unit,浮點單元)是ARM內核中的硬件外設,用于硬件計算浮點數,要想使用FPU計算浮點數,需要程序和編譯器配合。

在程序中使能/開啟FPU硬件外設,「使 FPU 硬件可以正常工作」;

在編譯器中設置使用FPU,編譯器會將所有浮點計算的代碼都編譯為「使用FPU操作指令完成」。

目前Cortex-M4、Cortex-M7、Cortex-M33、Cortex-M35P、Cortex-M55處理器中都具備FPU硬件。

在上一節中我們使用fplib軟件庫來計算浮點數,但是fplib終歸還是軟件方式,每個計算函數的實現都是通過很多的指令去完成計算,并且最終的程序中還會把函數鏈接進可執行程序,導致程序體積變大。

「ARM FPU的魅力在于,浮點計算可以通過簡單的FPU操作指令去完成,相比之下,不僅計算快,也不會增大程序體積。」

2. 如何使能FPU硬件

ARM Cortex - M4內核中將 FPU 作為協處理器設計的,所以通過設置協處理器訪問控制(CPACR,Co-processor access control register)來控制是否使能FPU。

復位之后CP11=0、CP10=0,默認禁止訪問FPU,因為這是Cortex-M內核的外設,寄存器定義CMSIS-Core中,所以可以直接通過下面這行代碼設置CP11=1、CP10=1來允許訪問FPU:

SCB-》CPACR = 0x00F00000; // Enable the floating point unit for full access

無論是STM32 HAL庫還是標準庫,在SystemInit()函數中已經存在使能代碼,通過__FPU_PRESENT和__FPU_USED來控制:

/* FPU settings ------------------------------------------------------------*/ #if (__FPU_PRESENT == 1) && (__FPU_USED == 1) SCB-》CPACR |= ((3UL 《《 10*2)|(3UL 《《 11*2)); /* set CP10 and CP11 Full Access */ #endif

并且,在頭文件 stm32l431xx.h 中已經使能__FPU_PRESENT宏定義:__FPU_PRESENT宏定義是一直使能的,那么如何來控制FPU的使能呢?

別忘了還有一個宏定義__FPU_USED,這是留給編譯器來控制的!

3. ARMCC編譯器如何開啟FPU

MDK編譯器開啟FPU的方法非常簡單,如圖:在MDK中使能FPU,一方面編譯器會設置宏定義__FPU_USED == 1,不放心的話可以在任意位置添加下面的預處理代碼,分別在使用/不使用的情況編譯一下,查看編譯器輸出結果:

#if __FPU_USED == 1 #error “ok!” #endif

另一方面,編譯器在編譯的時候,會將所有的浮點運算都編譯為使用FPU操作指令去完成

4. gcc編譯器如何開啟FPU

在Makefile中加入以下gcc編譯設置項:

# fpu FPU = -mfpu=fpv4-sp-d16 # float-abi FLOAT-ABI = -mfloat-abi=hard

ABI是應用程序二進制接口(Application Binary Interface),-mfloat-abi用來指定使用哪種方式:

soft:使用CPU寄存器組+軟件庫(fplib)完成浮點操作;

softfp:使用CPU寄存組+FPU硬件+軟件庫完成浮點操作;

hard:使用FPU寄存器組+FPU硬件+軟件庫完成浮點操作;

mfpu選項用來指定FPU架構,具體值可以閱讀我在文末給出的參考文檔,本文所使用的值fpv4-sp-d16,意味著僅僅使能Armv7 FPv4-SP-D16 單精度浮點單元擴展。

同樣,對之前的測試代碼編譯,查看反匯編結果,可以看到使用了浮點操作全部使用了FPU相關指令。

四、使用Julia測試FPU加速性能

1. 測試準備

需要準備一份裸機工程,具有屏幕打點顯示功能和串口打印功能。

參考:STM32CubeMX_17 | 使用硬件SPI驅動TFT-LCD(ST7789)。

2. 移植Julia分形測試代碼

Julia測試是通過計算幾幀Julia分形的數據來測試單精度浮點運算的性能,測試代碼參考正點原子,如下:

/* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ #define ITERATION 128 //迭代次數 #define REAL_CONSTANT 0.285f //實部常量 #define IMG_CONSTANT 0.01f //虛部常量 //顏色表 uint16_t color_map[ITERATION]; //縮放因子列表 const uint16_t zoom_ratio[] = { 120, 110, 100, 150, 200, 275, 350, 450, 600, 800, 1000, 1200, 1500, 2000, 1500, 1200, 1000, 800, 600, 450, 350, 275, 200, 150, 100, 110, }; //初始化顏色表 //clut:顏色表指針 void InitCLUT(uint16_t * clut) { uint32_t i = 0x00; uint16_t red = 0, green = 0, blue = 0; for (i = 0;i 《 ITERATION; i++) { //產生 RGB 顏色值 red = (i*8*256/ITERATION) % 256;

green = (i*6*256/ITERATION) % 256; blue = (i*4*256 /ITERATION) % 256;

//將 RGB888,轉換為 RGB565 red = red 》》 3; red = red 《《 11; green = green 》》 2; green = green 《《 5; blue = blue 》》 3; clut[i] = red + green + blue; } } //產生 Julia 分形圖形 //size_x,size_y:屏幕 x,y 方向的尺寸 //offset_x,offset_y:屏幕 x,y 方向的偏移 //zoom:縮放因子 void GenerateJulia_fpu(uint16_t size_x,uint16_t size_y,uint16_t offset_x,uint16_t offset_y,uint16_t zoom) { uint8_t i; uint16_t x,y; float tmp1,tmp2; float num_real,num_img; float radius; for (y = 0; y 《 size_y; y++) { for (x = 0; x 《 size_x; x++) { num_real = y - offset_y; num_real = num_real / zoom; num_img = x-offset_x;

num_img = num_img / zoom; i = 0; radius = 0; while ((i 《 ITERATION-1) && (radius 《 4)) { tmp1 = num_real * num_real;

tmp2 = num_img * num_img; num_img = 2*num_real*num_img + IMG_CONSTANT; num_real = tmp1 - tmp2 + REAL_CONSTANT;

radius = tmp1 + tmp2; i++; } //繪制到屏幕 lcd_draw_color_point(x, y, color_map[i]); } } } /* USER CODE END 0 */

在main函數中創建一些需要的變量:

/* USER CODE BEGIN 1 */ uint8_t zoom_index = 0; uint32_t start_time = 0, end_time = 0; /* USER CODE END 1 */

調用初始化函數:

/* USER CODE BEGIN 2 */ printf(“Julia test by Mculover666 ”); lcd_init(); //初始化顏色表 InitCLUT(color_map); /* USER CODE END 2 */

調用測試函數:

/* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ start_time = HAL_GetTick(); GenerateJulia_fpu(240, 240, 120, 120, zoom_ratio[zoom_index]); end_time = HAL_GetTick(); printf(“diff time is %d ms ”, end_time - start_time); zoom_index++; if (zoom_index 》 sizeof(zoom_ratio)) { zoom_index = 0; } } /* USER CODE END 3 */

3. 測試結果

使用-O2優化等級,在不開 FPU 的情況下,「顯示一幀平均需要11s左右」:程序大小情況:

d4847f56-c55a-11eb-9e57-12bb97331649.png

使用-O2優化等級,在開啟 FPU 的情況下,「顯示一幀平均需要4s左右」:程序大小情況:

d4ebf7da-c55a-11eb-9e57-12bb97331649.png

最后放上好看的Julia分形圖:

原文標題:揭秘ARM FPU 加速浮點計算

文章出處:【微信公眾號:strongerHuang】歡迎添加關注!文章轉載請注明出處。

責任編輯:haq

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • ARM
    ARM
    +關注

    關注

    134

    文章

    9107

    瀏覽量

    367985
  • 嵌入式
    +關注

    關注

    5087

    文章

    19145

    瀏覽量

    306111
  • C語言
    +關注

    關注

    180

    文章

    7608

    瀏覽量

    137119

原文標題:揭秘ARM FPU 加速浮點計算

文章出處:【微信號:strongerHuang,微信公眾號:strongerHuang】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    Triton編譯器與GPU編程的結合應用

    Triton編譯器簡介 Triton編譯器是一種針對并行計算優化的編譯器,它能夠自動將高級語言代碼轉換為針對特定硬件優化的低級代碼。Triton編譯
    的頭像 發表于 12-25 09:13 ?249次閱讀

    Triton編譯器如何提升編程效率

    在現代軟件開發中,編譯器扮演著至關重要的角色。它們不僅將高級語言代碼轉換為機器可執行的代碼,還通過各種優化技術提升程序的性能。Triton 編譯器作為一種先進的編譯器,通過多種方式提升
    的頭像 發表于 12-25 09:12 ?244次閱讀

    Triton編譯器在高性能計算中的應用

    先進的編譯技術,為高性能計算提供了強大的支持。 Triton編譯器簡介 Triton編譯器是一種開源的編譯器框架,旨在為異構計算環境提供高效的編譯
    的頭像 發表于 12-25 09:11 ?261次閱讀

    Triton編譯器的優化技巧

    在現代計算環境中,編譯器的性能對于軟件的運行效率至關重要。Triton 編譯器作為一個先進的編譯器框架,提供了一系列的優化技術,以確保生成的代碼既高效又適應不同的硬件架構。 1. 指令
    的頭像 發表于 12-25 09:09 ?243次閱讀

    Triton編譯器支持的編程語言

    Triton編譯器支持的編程語言主要包括以下幾種: 一、主要編程語言 Python :Triton編譯器通過Python接口提供了對Triton語言
    的頭像 發表于 12-24 17:33 ?376次閱讀

    Triton編譯器與其他編譯器的比較

    的GPU編程框架,使開發者能夠編寫出接近手工優化的高性能GPU內核。 其他編譯器 (如GCC、Clang、MSVC等): 定位:通用編譯器,支持多種編程語言,廣泛應用于各種軟件開發場景。 目標:提供穩定、高效的
    的頭像 發表于 12-24 17:25 ?388次閱讀

    Triton編譯器功能介紹 Triton編譯器使用教程

    Triton 是一個開源的編譯器前端,它支持多種編程語言,包括 CC++、Fortran 和 Ada。Triton 旨在提供一個可擴展和可定制的
    的頭像 發表于 12-24 17:23 ?452次閱讀

    ARM優化C/C++編譯器 v20.2.0.LTS

    電子發燒友網站提供《ARM優化C/C++編譯器 v20.2.0.LTS.pdf》資料免費下載
    發表于 11-07 10:46 ?0次下載
    <b class='flag-5'>ARM</b>優化<b class='flag-5'>C</b>/<b class='flag-5'>C</b>++<b class='flag-5'>編譯器</b> v20.2.0.LTS

    TMS320C6000優化C/C++編譯器v8.3.x

    電子發燒友網站提供《TMS320C6000優化C/C++編譯器v8.3.x.pdf》資料免費下載
    發表于 11-01 09:35 ?0次下載
    TMS320<b class='flag-5'>C</b>6000優化<b class='flag-5'>C</b>/<b class='flag-5'>C</b>++<b class='flag-5'>編譯器</b>v8.3.x

    C7000優化C/C++編譯器

    電子發燒友網站提供《C7000優化C/C++編譯器.pdf》資料免費下載
    發表于 10-30 09:45 ?0次下載
    <b class='flag-5'>C</b>7000優化<b class='flag-5'>C</b>/<b class='flag-5'>C</b>++<b class='flag-5'>編譯器</b>

    AI編譯器技術剖析

    隨著人工智能技術的飛速發展,AI編譯器作為一種新興的編譯技術逐漸進入人們的視野。AI編譯器不僅具備傳統編譯器的功能,如將高級語言編寫的源代碼
    的頭像 發表于 07-17 18:28 ?1667次閱讀

    人工智能編譯器與傳統編譯器的區別

    人工智能編譯器(AI編譯器)與傳統編譯器在多個方面存在顯著的差異。這些差異主要體現在設計目標、功能特性、優化策略、適用范圍以及技術復雜性等方面。以下是對兩者區別的詳細探討,旨在全面解析
    的頭像 發表于 07-17 18:19 ?1963次閱讀

    SEGGER編譯器優化和安全技術介紹 支持最新CC++語言

    SEGGER編譯器是專門為ARM和RISC-V微控制設計的優化C/C++編譯器。它建立在強大的
    的頭像 發表于 06-04 15:31 ?1490次閱讀
    SEGGER<b class='flag-5'>編譯器</b>優化和安全技術介紹 支持最新<b class='flag-5'>C</b>和<b class='flag-5'>C</b>++<b class='flag-5'>語言</b>

    C語言:嵌入式開發中的關鍵編譯器角色

    嵌入式程序開發跟硬件密切相關,需要使用C語言來讀寫底層寄存、存取數據、控制硬件等,C語言和硬件之間由
    發表于 04-26 14:53 ?653次閱讀
    <b class='flag-5'>C</b><b class='flag-5'>語言</b>:嵌入式開發中的關鍵<b class='flag-5'>編譯器</b>角色

    C語言#define的應用

    C/C++ 編程語言中,當程序被編譯時,被發送到編譯器編譯器將程序轉換為機器
    發表于 03-06 11:29 ?393次閱讀
    <b class='flag-5'>C</b><b class='flag-5'>語言</b>#define的應用
    主站蜘蛛池模板: 亚洲人成影院在线高清| 日本三级成人中文字幕乱码| 女人69xxx| 国产黄色大全| 亚洲一区二区三区免费在线观看| 天堂在线资源最新版| 五月天婷婷网址| 人人艹人人干| 97久久天天综合色天天综合色 | 757福利影院合集3000| 国产在线视频网站| 性xxxxhd高清| 视频在线观看一区二区| 777色淫网站女女免费| 色爱区综合五月激情| 在线观看中文字幕第一页| 性夜影院午夜看片| 欧美一级日韩一级亚洲一级| 久久久久久久网站| 在线看3344免费视频| 久久久久久人精品免费费看| 男人日女人视频在线观看| 免费在线公开视频| 欧美卡一卡二卡新区网站| 午夜在线观看完整高清免费| aaaaa国产毛片| 四虎影院黄色片| 久久久久久久久综合影视网| 真实的国产乱xxxx在线| 美女操网站| 手机看片午夜| 放荡女同老师和女同学生| 性网站免费| 四虎影视永久在线观看| 黄色污网站在线观看| 天天色天| 91大神在线观看精品一区| 一区二区免费视频| 亚洲美国avcom| 久久夜色精品国产噜噜| 午夜影院一区二区三区|