Helium指令集
這里介紹的是Helium的匯編語言指令集,雖然大部分程序員不會(huì)直接使用這些指令,而是通過C語言或者高級語言編程實(shí)現(xiàn),但是了解匯編語言指令集,可以有如下收獲:
在優(yōu)化C代碼時(shí),為了確定其是否被充分地矢量化,能夠?qū)徱暰幾g器的輸出以及熟悉指令集是非常有幫助的。
當(dāng)調(diào)試不能正常工作的代碼時(shí),通過閱讀反匯編代碼去理解每一行發(fā)生了什么,對于尋找代碼的問題是非常有用的。
了解指令集可能有助于編寫高效的代碼,甚至節(jié)省功耗,尤其是在使用原語函數(shù)的情況下。
Helium指令結(jié)構(gòu)和其他Cortex-M處理器中的VFP(浮點(diǎn))指令結(jié)構(gòu)是相似的。
Helium指令格式如下:

Helium指令都是以字母V開始的,然后跟著如下符號,符合中的{}是可選的,<>是必須出現(xiàn)的:
mod:指令修飾符,可能沒有,也可能是Q(saturating)飽和,H(halving)減半,D(doubling)加倍,R(rounding)四舍五入中的一個(gè)。
op:具體操作,例如ADD(相加),SUB(相減),CMP(比較)等。
shape:有些指令中,可以選擇性的指定L(long)或N(narrow),這是 “形態(tài)” 相關(guān)的修飾符。
- L:Long表示輸入元素在操作前會(huì)被擴(kuò)寬。1個(gè)8位的元素可能會(huì)被擴(kuò)寬為16位或32位,或者1個(gè)16位元素被擴(kuò)寬為32位。
- N:Narrow表示輸入元素在操作前會(huì)被壓縮。
extra:有些指令中的特定修飾符,可能是T(top),B(bottom),A(accumulate),X(exchange)或者V(across)中的一個(gè)。
cond:此處指定的條件僅適用于VPT(Predication)模塊??赡苁荰(Then)或者E(Else)。
.dt:數(shù)據(jù)類型,可能是F(float)浮點(diǎn),I(integer)整數(shù),S(signed)有符號,U(unsigned)無符號。
dst:目標(biāo)寄存器,可以是通用寄存器(R)或者矢量寄存器(Q)。
src:源寄存器,可以是通用寄存器(R)或者矢量寄存器(Q)。
rot:旋轉(zhuǎn),用于一些操作復(fù)數(shù)的指令。
下面給出一條指令示例展示:
VLDRW.U32 Q0, [R0]

該指令中的首字母是V,表示這是一條Helium(或是Neon,或者浮點(diǎn))指令,LDR表示寄存器從內(nèi)存加載內(nèi)容,W表示按字大小操作,
Helium指令分類如下:

Helium編程方式
Helium編程方式目前來說,一共4種。
矢量庫
自動(dòng)矢量化
原語函數(shù)(intrinsics)編程
匯編指令編程
矢量庫
目前,ARM CMSIS DSP和NN是已經(jīng)對Helium優(yōu)化好的Helium矢量庫。使用矢量庫來進(jìn)行Helium編程,是最簡單的方法。
CMSIS DSP是數(shù)字信號處理函數(shù)庫,具有針對8位整數(shù),16位整數(shù),32位整數(shù)和32位浮點(diǎn)數(shù)的不同函數(shù),提供了豐富的函數(shù),包括基本數(shù)學(xué)函數(shù),復(fù)數(shù)數(shù)學(xué)函數(shù),濾波器函數(shù),變換函數(shù),矩陣操作函數(shù),電機(jī)控制函數(shù),插值函數(shù),統(tǒng)計(jì)函數(shù)等。該庫包含了這些函數(shù)的Helium優(yōu)化版本,并不斷更新迭代中。
CMSIS NN是神經(jīng)網(wǎng)絡(luò)函數(shù)庫,以最小的內(nèi)存開銷針對Cortex-M處理器優(yōu)化的軟件內(nèi)核,同樣地,這些函數(shù)也可以利用Helium得到最優(yōu)性能。
CMSIS矢量庫中的函數(shù)代碼有3個(gè)C預(yù)處理器定義來選擇Helium版本。
#define ARM_MATH_HELIUM #define ARM_MATH_MVEI //支持整型Helium #define ARM_MATH_MVEF //支持浮點(diǎn)型Helium
比如CMSIS DSP中的 arm_clip_f32函數(shù),可以看到該函數(shù)已經(jīng)使用了Helium原語函數(shù)。

比如CMSIS NN中的arm_nn_lstm_update_cell_state_s16函數(shù),可以看到該函數(shù)使用了Helium原語函數(shù)。

當(dāng)使用矢量庫的時(shí)候,不同編譯器中的MVE設(shè)置
Keil MDK 5(5.38以上版本)
在圖標(biāo)
“Options for target”中選擇“Target”頁面中的“Vector Extensions”,通過下拉列表選擇
“Not Used”(不使用helium,即宏ARM_MATH_HELIUM沒有被定義,使用標(biāo)量相關(guān)函數(shù))。
“Integer”(宏ARM_MATH_HELIUM和ARM_MATH_MVEI被定義,使用整型Helium)。
“Integer + Floating Point” (宏ARM_MATH_HELIUM,ARM_MATH_MVEI和ARM_MATH_MVEF被定義,使用整型和浮點(diǎn)型Helium)。

IAR EWARM(v9.40.1以上版本)
通過右鍵選擇項(xiàng)目名稱后,在 “Options”中的“General Options”頁面下的“32-bit”中的“Advanced SIMD(NEON/HELIUM)”。
勾選(即選中,ARM_MATH_HELIUM,ARM_MATH_MVEI和ARM_MATH_MVEF被定義,使用整型和浮點(diǎn)型Helium)。
不勾選(即不選中),編譯的時(shí)候會(huì)報(bào)“MVE support not enable”錯(cuò)誤。
e2 studio
e2 studio中可以使用LLVM或者GCC工具鏈,在使用矢量庫的時(shí)候,不需要設(shè)置,默認(rèn)是啟用的。如果通過設(shè)置編譯參數(shù)來禁用,編譯的時(shí)候會(huì)報(bào)“MVE support not enable”錯(cuò)誤。
自動(dòng)矢量化
自動(dòng)矢量化就是編譯器在C/C++代碼中自動(dòng)檢測到可以使用Helium指令并執(zhí)行優(yōu)化的過程。優(yōu)化后的代碼在速度和尺寸方面可能與手工優(yōu)化的匯編代碼或包含原語函數(shù)的C代碼一樣高效,這只需要很少的時(shí)間去編寫和調(diào)試代碼,而且無須對目標(biāo)微架構(gòu)有詳細(xì)了解。C代碼也更有可移植性。
如下面的代碼,這是一種很常見的普通寫法,一個(gè)for循環(huán)里面做一些邏輯判斷處理。

點(diǎn)擊可查看大圖
通過使用自動(dòng)矢量化后的反匯編代碼如下,紅色框部分的代碼里面已經(jīng)出現(xiàn)了Helium的匯編指令。

自動(dòng)矢量化和編譯器的優(yōu)化等級設(shè)置有關(guān),當(dāng)Arm Complier 6和LLVM編譯器的優(yōu)化等級為-O2或者更高時(shí),自動(dòng)矢量化默認(rèn)使能,在MDK ArmComplier 6中可以使用“-fno-vectorize”選項(xiàng)可以禁止自動(dòng)矢量化。當(dāng)優(yōu)化等級為-O1時(shí),自動(dòng)矢量化默認(rèn)禁止,使用“-fvectorize”選項(xiàng)可以使能自動(dòng)矢量化,當(dāng)優(yōu)化等級為-O0時(shí),自動(dòng)矢量化總是被禁止。其他編譯器的行為可能不同,具體可以查閱對應(yīng)的文檔。
原語函數(shù)(intrinsics)編程
原語函數(shù)是允許利用Helium而不必直接編寫匯編代碼的一組C/C++函數(shù)。ACLE文檔中包括Helium原語規(guī)范。目前最新的文檔為mve-2021Q4。原語函數(shù)的實(shí)現(xiàn)包含在arm_mve.h文件中。函數(shù)包含簡短的匯編語言部分,它們被內(nèi)聯(lián)到調(diào)用的代碼中。
使用原語函數(shù)有如下優(yōu)點(diǎn):
程序員能夠直接訪問Helium指令集,這允許編寫充分優(yōu)化的代碼,利用所有Helium特性。
C/C++可用于大多數(shù)代碼,只有當(dāng)需要優(yōu)化而矢量化C編譯器無法執(zhí)行優(yōu)化時(shí),才會(huì)使用Helium原語。這就意味著只有在必要時(shí)才使用底層代碼。
相比于采用匯編語言編寫的代碼,含有Helium原語的C和C++代碼可以移植到一個(gè)新的平臺(tái),僅需要少量修改,甚至無須修改。
使用原語避免了很多與直接使用匯編語言編碼相關(guān)的難點(diǎn)。
原語函數(shù)中,Helium矢量數(shù)據(jù)類型名字模式如下所示,這在“arm_mve.h”中有詳細(xì)定義和描述。
type:元素類型,可能是int整形,uint無符號整形,float浮點(diǎn)。
size:元素大小,可能是8位,16位,32位。
number_of_lanes:通道總數(shù)。可以是16通道,8通道,或者4通道。
如:
uint8x16_t是一個(gè)描述16個(gè)無符號8位的矢量。
int16x8_t是一個(gè)描述8個(gè)16位的矢量。
float16x8_t是一個(gè)描述4個(gè)16位浮點(diǎn)數(shù)(半精度)的矢量。
float32x4_t是一個(gè)描述4個(gè)32位浮點(diǎn)數(shù)(單精度)的矢量。
注:Helium是128位寄存器,它的元素大小和通道總數(shù)相乘的結(jié)果只能是128,不能是64,也就是說,不支持int8x8_t/uint8x8_t/int16x4_t/uint16x4_t/float16x4_t/float32x2_t數(shù)據(jù)類型。這點(diǎn)和Neon是不同的。Neno可以支持64和128。
Helium矢量數(shù)組結(jié)構(gòu)體類型如下:
可以發(fā)現(xiàn),矢量數(shù)組結(jié)構(gòu)體名字只比單個(gè)矢量數(shù)據(jù)類型多了一個(gè)length_of_array。它表示一共有幾個(gè)helium寄存器組成,即helium寄存器的數(shù)量。在該結(jié)構(gòu)體中,包含一個(gè)名為val的元素,此結(jié)構(gòu)體類型映射Helium加載和存儲(chǔ)操作訪問的寄存器,Helium可以用一條指令加載/存儲(chǔ)多達(dá)4個(gè)寄存器。結(jié)構(gòu)定義示例如下:
struct int16x8x2_t
{
int16x8_t val[2];
};
此結(jié)構(gòu)類型僅由加載、存儲(chǔ)、轉(zhuǎn)置、交織和去交織指令使用;要對實(shí)際數(shù)據(jù)執(zhí)行操作,請從各個(gè)寄存器中選擇元素。如:
下圖代碼片段是使用原語函數(shù)進(jìn)行矢量相乘的例子。

原語編程里面還涉及原語預(yù)測,原語尾部處理等知識(shí),本處不在展開說明,詳細(xì)信息可以訪問arm官網(wǎng)查閱相關(guān)文檔了解和學(xué)習(xí)。
匯編語言編程
在匯編代碼中直接編寫Helium指令是很沒有必要的,通常只會(huì)在特殊的場景下才會(huì)這樣做。即當(dāng)編程人員可以比編譯器更好地分配寄存器時(shí),比如有太多重寫變量和輸入輸出變量。
下圖所示為復(fù)數(shù)矢量點(diǎn)積的匯編語言代碼。

-
處理器
+關(guān)注
關(guān)注
68文章
20339瀏覽量
255303 -
電機(jī)控制
+關(guān)注
關(guān)注
3601文章
2180瀏覽量
279263 -
C語言
+關(guān)注
關(guān)注
183文章
7646瀏覽量
146193 -
LDR
+關(guān)注
關(guān)注
0文章
101瀏覽量
8311 -
Cortex-M85
+關(guān)注
關(guān)注
0文章
15瀏覽量
822
發(fā)布評論請先 登錄
RA8 Cortex-M85 Helium技術(shù)入門指南(1)
瑞薩RA8快速上手指南:Cortex-M85內(nèi)核瑞薩RA8開發(fā)環(huán)境搭建 并點(diǎn)亮一個(gè)LED
瑞薩電子RA8M2 MCU的架構(gòu)解析與應(yīng)用場景
瑞薩推出全新RA8入門級MCU產(chǎn)品群, 提供極具性價(jià)比的高性能Arm Cortex-M85處理器
Arm Cortex-M處理器—Cortex-M85介紹
IAR為瑞薩RA8系列MCU開發(fā)提供支持
業(yè)界首款基于Arm Cortex-M85的超高性能MCU
瑞薩電子推出全新RA MCU家族產(chǎn)品RA8
瑞薩電子發(fā)布業(yè)界首款基于Cortex-M85處理器的全新超高性能MCU
Cortex-M85內(nèi)核單片機(jī)如何快速上手
業(yè)界首款基于Arm Cortex-M85處理器的MCU
RA8 Cortex-M85 Helium入門指南(3)
瑞薩電子全新RA8系列MCU產(chǎn)品介紹
瑞薩電子RA8E1和RA8E2 MCU新品解讀
瑞薩RA8系列教程 | 瑞薩 RA8 開發(fā)環(huán)境搭建,并點(diǎn)亮一個(gè)LED
RA8 Cortex-M85 Helium入門指南(2)
評論