7.Introducing NEON
NEON技术在ARM处理器中提供单指令多数据(SIMD)操作,实施高级SIMD架构扩展,可以加速运行在ARM Cortex-A系列处理器上的多媒体应用程序的性能。这些操作可以显著加速对大型数据集的重复操作。这在媒体编码器等应用中非常有用。
NEON作为一个独立的硬件单元在Cortex-A系列处理器中可选实现。将NEON硬件设为可选使得ARM SoC能够针对特定市场进行优化。在大多数通用应用处理器SoC中,NEON可能会被包含。然而,对于网络路由器等嵌入式应用,NEON可以被省略,从而节省硅片面积,降低成本。
7.1 SIMD
SIMD 是一种计算技术,用于处理多个数据值(通常是2的幂次方),使用一条指令,将操作数的数据打包到专门的宽寄存器中。因此,一条指令可以完成许多单独指令的工作。这种并行处理指令通常被称为 SIMD(单指令多数据),这是由 Michael J. Flynn 在1966年根据架构中可用的指令流和数据流的数量定义的四种计算机架构之一。
单指令多数据(SIMD)
一种使用单条指令处理多个数据值的技术,操作数的数据被打包到宽寄存器中。因此,一条指令可以完成许多任务。SIMD 指令在处理媒体数据时非常强大。
单指令单数据(SISD)
单核执行单一指令流,操作存储在单一内存中的数据,一次操作一条指令。通常有一个中央控制器将指令流广播到所有处理元素。几乎所有 ARM 处理器在 ARMv6 架构之前都使用 SISD 处理。
多指令单数据(MISD)
一种并行计算架构,其中多个功能单元在相同数据上执行不同操作。容错计算机执行相同指令以检测和掩盖错误可能属于此类型。这种架构的一个例子是航天飞机的飞行控制计算机。
多指令多数据(MIMD)
多个计算机指令,可能相同,也可能同步执行不同或相同的操作,处理两块或更多数据。多核超标量处理器就是 MIMD 处理器。
对于可以并行化的代码,性能可以获得大幅提升。SIMD 扩展存在于许多32位架构上——PowerPC 有 AltiVec,x86 有多个 MMX/SSE 变体。
许多软件程序处理大量数据集。这些数据项的大小可以小于 32 位。8 位像素数据常见于视频、图像处理和图形处理中,16 位样本常见于音频编码器中。在这种情况下,所执行的操作是简单、重复且不需要大量控制代码的。SIMD 可以为这种数据处理提供显著的性能改进。它特别有利于处理数字信号处理或多媒体算法,例如:
基于块的数据处理
音频、视频和图像处理编解码器
基于矩形像素块的 2D 图形
3D 图形
颜色空间转换
物理模拟
在像 Cortex-A 系列处理器这样的 32 位内核上,逐个执行大量 8 位或 16 位的单个操作相对低效。处理器的算术逻辑单元 (ALU)、寄存器和数据路径是为 32 位计算设计的。SIMD 允许单条指令将寄存器值视为多个数据元素(例如,将 32 位寄存器中的值视为四个 8 位值),并对这些元素执行多个相同的操作。
如果不使用 SIMD 来实现四次独立的加法操作,你需要使用四条 ADD 指令,如下图所示,并且还需要额外的指令来防止一个结果溢出到相邻的字节。而使用 SIMD 只需要一条指令即可完成这些操作。
上图显示了 SIMD 指令 UADD8 R0, R1, R2 的操作。该操作对存储在通用寄存器 R1 和 R2 中的向量中的四对 8 位元素(称为通道)进行并行加法运算,并将结果放入寄存器 R0 中的一个向量中。
需要注意的是,这些加法运算是完全独立的。来自通道 0 的位 [7] 的任何溢出或进位都不会影响通道 1 的位 [0](整个寄存器的位 [8]),因为这是一次独立的计算。
ARM NEON 技术是基于 SIMD 概念设计的。NEON 是一个结合了 64 位和 128 位 SIMD 指令集的技术,提供了 128 位宽的向量操作,相比 ARMv6 架构中的 32 位 SIMD 更强大。NEON 技术在 ARMv7 架构中引入,目前仅适用于 ARM Cortex-A 和 Cortex-R 系列处理器。它是一项面向高级多媒体和信号处理应用以及嵌入式处理器的 SIMD 技术,能够加速多媒体和信号处理算法,例如视频编码/解码、2D/3D 图形、游戏、音频和语音处理、图像处理、电话通信和声音合成,并将 ARMv6 SIMD 的性能提高至少两倍。
在 Cortex-A7、Cortex-A12 和 Cortex-A15 处理器中,NEON 默认包含,但在其他 ARMv7 Cortex-A 系列处理器中是可选的。NEON 能够在运行频率为 10 MHz 的处理器上执行 MP3 音频解码。它具有全面的指令集、独立的寄存器文件和独立的执行硬件。NEON 支持 8、16、32 和 64 位整数以及单精度(32 位)浮点数据,并通过 SIMD 操作处理音频、视频、图形和游戏处理。NEON 支持同时执行多达 16 次操作。NEON 硬件与 VFP 共享相同的寄存器。它作为 ARM 处理器的一部分实现,但拥有独立的执行流水线和不同于 ARM 内核寄存器库的寄存器库。NEON 数据组织为非常长的寄存器(64 或 128 位宽)。这些寄存器可以存储长度为 8、16、32 或 64 位的数据项。
7.2 NEON architecture overview
NEON被设计为一种附加的加载/存储架构,以提供良好的向量化编译器支持,支持诸如C/C++等语言。NEON指令集包含丰富的指令,能够在宽64位和128位向量寄存器上操作,从而实现高水平的并行性。NEON指令简单易懂,这也使得对于要求极高性能的应用程序手动编码变得更加容易。
NEON技术的一个主要优势是,这些指令是ARM或Thumb代码的一部分,使得编程比使用外部硬件加速器更为简单。NEON指令可以用于读写外部内存、在NEON寄存器与其他ARM寄存器之间移动数据,以及执行SIMD操作。
NEON架构使用32 × 64位的寄存器文件。这实际上与浮点单元(VFPv3)使用的寄存器相同。浮点寄存器作为NEON寄存器的重用并不重要。所有编译的代码和子程序将遵循EABI,它规定了哪些寄存器可以被破坏,哪些寄存器必须被保留。编译器可以在代码的任何位置自由使用NEON或VFPv3寄存器来处理浮点值或NEON数据。
NEON架构支持64位或128位的并行性。这个选择是为了保持NEON单元的大小可控(一个向量算术逻辑单元很容易变得相当庞大),同时仍然提供良好的向量化性能优势。NEON架构也没有规定指令的时间,而是在不同的处理器上执行同一指令可能需要不同的周期数。
7.2.1 Commonality with VFP
ARM架构可以支持多种不同的NEON和VFP选项,但实际上只会看到以下组合:
不支持NEON或VFP。
仅支持VFP。
同时支持NEON和VFP。
这些是架构的供应商实现选项,因此对于特定的ARM设计实现是固定的。
NEON和VFP之间的主要区别在于,NEON仅针对向量操作,不支持双精度浮点数(双精度由VFP支持),并且不支持某些复杂操作,如平方根和除法。NEON有一个包含三十二个64位寄存器的寄存器组。如果同时实现了NEON和VFPv3,这个寄存器组在硬件上是共享的。这意味着VFPv3必须以其VFPv3-D32形式存在,该形式具有32个双精度浮点寄存器。这使得上下文切换的支持变得更简单。保存和恢复VFP上下文的代码也会保存和恢复NEON上下文。
7.2.2 Data types
NEON指令操作以下类型的元素:
注意:F16不支持数据处理操作,仅支持作为转换格式。
多项式算术在实现某些加密或数据完整性算法时非常有用。对{0,1}上的两个多项式相加等同于按位异或。多项式加法的结果与传统加法的结果不同。
对{0,1}上的两个多项式相乘首先需要确定部分积,如同传统的乘法,然后对部分积进行异或,而不是传统的加法。多项式乘法的结果与传统乘法不同,因为它需要对部分积进行多项式加法。
NEON技术符合IEEE 754-1985标准,但仅支持四舍五入到最接近的舍入模式。这是大多数高级语言(如C和Java)使用的舍入模式。此外,NEON指令始终将非规范数视为零。
7.2.3 NEON registers
寄存器组可以视为十六个128位寄存器(Q0-Q15)或三十二个64位寄存器(D0-D31)。每个Q0-Q15寄存器对应一对D寄存器,如下图所示。
下图中寄存器的视图由使用的指令形式决定,因此软件不必显式地改变状态。
单个元素也可以作为标量进行访问。这种双重视图的优势在于,它适应了扩展或缩小结果的数学操作。例如,两个D寄存器相乘会产生一个Q寄存器的结果。双重视图使寄存器组的使用更加高效。
NEON数据处理指令通常有正常、长、宽、窄和饱和几种变体。
正常指令可以在任何向量类型上操作,产生与操作数向量相同大小且通常相同类型的结果向量。
长指令在双字向量操作数上操作,并产生四字向量结果。结果元素的宽度通常是操作数的两倍,且类型相同。长指令通过在指令后附加L来指定。下图展示了这一点,输入操作数在操作之前被提升。
宽指令在双字向量操作数和四字向量操作数上操作,产生四字向量结果。结果元素和第一个操作数的宽度是第二个操作数元素的两倍。宽指令在指令后附加W。下图展示了这一点,输入的双字操作数在操作之前被提升。
窄指令在四字向量操作数上操作,并产生双字向量结果。结果元素的宽度通常是操作数元素的一半。窄指令在指令后附加N来指定。下图展示了这一点,输入操作数在操作之前被降级。
一些NEON指令同时作用于标量和向量。标量可以是8位、16位、32位或64位。使用标量的指令可以访问寄存器组中的任何元素,但乘法指令有一些区别。该指令使用一个索引进入双字向量来指定标量值。乘法指令仅支持16位或32位标量,并且只能访问寄存器组中的前32个标量(即,对于16位标量是D0-D7,对于32位标量是D0-D15)。
7.2.4 NEON instruction set
所有NEON指令的助记符(与VFP相同)均以字母“V”开头。指令通常能够在不同的数据类型上操作,这在指令编码中得以指定。大小通过指令的后缀表示,元素的数量由指定的寄存器大小决定。
例如,查看指令时:
因此,该指令执行了八次并行加法。
还有一些操作使用不同大小的输入和输出寄存器。
例如: VMULL.S16 Q2, D8, D9 这条指令对打包在 D8 和 D9 中的数据执行四个 16 位乘法,并在 Q2 中产生四个 32 位结果。
VCVT 指令在单精度浮点数与 32 位整数、定点数以及(如果实现了)半精度浮点数之间转换。
NEON 包含加载和存储指令,这些指令可以加载或存储单个或多个值到寄存器。此外,还有一些指令可以在多个寄存器和内存之间传输数据块。还可以在这些传输过程中交错或取消交错数据。
以下修饰符可以与某些高级 SIMD 指令一起使用(某些修饰符只能用于少数可用指令):
Q:指令使用饱和算术,因此结果在指定数据类型范围内饱和。FPSCR 中的粘性 QC 位会在任何线路中发生饱和时设置。VQADD 是此类指令的一个示例。
H:指令会将结果减半。它通过右移一位来实现(实际上是通过截断除以二)。VHADD 是此类指令的一个示例,它可以用于计算两个输入的平均值。
D:指令将结果加倍并饱和。这通常在 Q15 格式下乘法时需要,其中需要额外的加倍操作以使结果处于正确的形式。
R:指令将在结果上执行舍入,相当于在截断前向结果添加 0.5。VRHADD 是此类指令的一个示例。
指令的一般格式如下:
V{<mod>}{<shape>}{<op>}{<cond>}{.<dt>}{<dest>}, src1, src2
其中:
是前面描述的修饰符之一(Q、H、D、R)
是操作(例如,ADD、SUB、MUL)
是形状(L、W 或 N)
是条件,使用 IT 指令
是目标
源操作数 1
源操作数 2
NEON 指令集包含一系列向量加法和减法操作,包括成对加法,它将相邻的向量元素相加。还有许多乘法操作,包括乘加、乘减、加倍和饱和选项。没有 SIMD 除法操作,但可以使用 VRECPE(向量倒数估计)和 VCREPS(向量倒数步长)指令来执行牛顿-拉弗森迭代来完成除法操作。
同样,没有向量平方根指令,但可以使用 VRSQRTE、VRSQRTS 和乘法来计算平方根。还提供了左移、右移和插入操作,以及选择最小值或最大值的指令。可以执行常见的逻辑操作(AND、OR、EOR、AND NOT 和 OR NOT)。指令集还包括计数元素中设置的位数、计数前导零或符号位的功能。
还有多种不同的指令用于在寄存器之间或元素之间移动数据。指令也可以交换或复制寄存器,执行反转、矩阵转置以及提取单个向量元素。
7.3 NEON C Compiler and assembler
针对 NEON 硬件的代码可以用 C 语言或汇编语言编写,并且有一系列工具和库支持。
在许多情况下,最好在较大的 C/C++ 函数中使用 NEON 代码,而不是在单独的文件中通过汇编器处理。可以通过使用 NEON 内嵌函数来实现这一点。
7.3.1 Vectorization
向量化编译器可以将你的 C 或 C++ 源代码并行化,从而有效利用 NEON 硬件。这意味着你可以编写可移植的 C 代码,同时仍然获得 NEON 所提供的性能水平。由于 C 语言并未指定并行化行为,因此有时需要向编译器提供提示。例如,定义指针时可能需要使用 __restrict 关键字,这可以保证指针不会指向重叠的内存区域。此外,确保循环迭代次数是四或八的倍数也很有帮助。
自动向量化可以通过 GCC 选项 -ftree-vectorize(以及 –mfpu=neon)来指定。使用 ARM 编译器时,你必须指定优化级别 –O2(或 –O3)、-Otime 和 –-vectorize。
7.3.2 Detecting NEON
由于 NEON 硬件在处理器实现中可能被省略,因此有时需要检测其是否存在。
编译时 NEON 选择
这是选择 NEON 最简单的方法。在 armcc(RVCT 4.0 及更高版本)或 GCC 中,当向编译器提供合适的处理器和 FPU 选项时,会定义预定义的宏 ARM_NEON。armasm 中的对应预定义宏是 TARGET_FEATURE_NEON。这可以用于在 C 源文件中包含 NEON 和非 NEON 优化版本。
运行时 NEON 检测
在运行时检测 NEON 需要操作系统的帮助,因为 ARM 架构故意不向用户模式应用程序暴露处理器能力。
在 Linux 下,/proc/cpuinfo 以可读形式包含此信息。在 Tegra2(一个带有 FPU 的双核 Cortex-A9 处理器)上,运行 cat /proc/cpuinfo
会显示以下内容:
...
Features : swp half thumb fastmult vfp edsp thumbee vfpv3 vfpv3d16
...
而带有 NEON 的 ARM 四核 Cortex-A9 处理器会显示略有不同的结果:
...
Features : swp half thumb fastmult vfp edsp thumbee neon vfpv3
...
由于 /proc/cpuinfo 的输出是基于文本的,通常更倾向于查看辅助向量 /proc/self/auxv。它以二进制格式包含内核的硬件能力标志。可以轻松搜索 /proc/self/auxv 文件中的 AT_HWCAP 记录,以检查 HWCAP_NEON 位(4096)。
某些Linux发行版(例如Ubuntu 09.10或更高版本)会透明地利用NEON技术。ld.so链接器脚本被修改为通过glibc读取hwcap,并为启用了NEON的共享库添加了一个额外的搜索路径。在Ubuntu的情况下,新的搜索路径**/lib/neon/vfp** 包含来自 /lib 的NEON优化版本的库。
相关链接cortex-A:
【ARM中文手册】第一章 Introduction
【ARM中文手册】第二章 ARM Architecture and Processors
【ARM中文手册】第三章 ARM Processor Modes and Registers
【ARM中文手册】第四章 Introduction to Assembly Language
......
相关链接cortex-R:
《ARM Cortex-R 学习指南》-【第二章】-ARM 架构与处理器
《ARM Cortex-R 学习指南》-【第三章 】-ARM 处理器模式与寄存器
《ARM Cortex-R 学习指南》-【第四章】-汇编语言简介
《ARM Cortex-R 学习指南》-【第五章】-统一汇编语言指令
《ARM Cortex-R 学习指南》-【第六章】-浮点数
......
(广告时间)
Arm架构类课程:
安全热销大课程:
安全类经典课程:
其它课程:
铂金VIP课程介绍
之最介绍
招牌课程:Truszone标准版、Trustzone高配版
销量前三课程:ARM三期、Secureboot、Android15安全架构
持续更新的课程:ARM三期、铂金VIP
非常好非常好但又被忽视的课程:CA/TA开发
近期更新/力推的课程/重点课程:optee系统架构从入门到精通
说点心里话:
1、不要再说课贵了,你看看咱这是啥课?别家的能比不?请不要拿通用的linux、android、python、C语言和咱这专业课比。
2、咱们的VIP是数十门课程的集合。不要拿别人一门课程的价格对标咱这20门课程价格。
3、这些知识很多人都会,但能拿出来讲的有多少人? 愿意拿出来讲的有多少人?会讲的又有多少人?
4、价格都是认真计算的,并非随意定价。都是根据内容质量、核心知识点、时长和节数计算而来。从来不无缘无故涨价(涨价是需要理由的,如课程内容增加了....)。咱靠的是内容质量和长期服务,而不是运营和营销(无脑涨价)。
5、如果你刷到此处,可能是老粉/铁粉,记得点赞、评论哦。感谢您的支持。