您的位置:首页 > 编程语言 > Go语言

Hexagon处理器的特殊功能

2015-08-21 15:52 190 查看
本文将涵盖如下六个内容:l  二级缓存 / 紧耦合存储器l  指令延时l  数据访问l  指令访问l  多线程l  低功耗的代码优化

二级缓存/紧耦合存储器

V5版本的Hexagon处理器包含了内置的二级缓存,同时我们也可以将其用于紧耦合的存储器(TCM)。二级缓存的大小取决于处理器的版本,各版本对应的大小如下:256 KB (V5a)768 KB (V5h)128 KB (V5l)二级内存被分区为缓存或紧耦合存储器。从软件角度,紧耦合存储器是一种物理内存,它的功能与一般内存没有什么差异。但是从硬件角度来说,紧耦合存储器能够从芯片中获得低延时的访问。下图描述了紧耦合存储器与二级缓存的图示:

将二级内存作为缓存来使用

二级缓存有如下的特性八路级联PLRU替换32位线路支持写回与写入页可配置的写开辟当二级内存被配置作为缓存来使用,配置为二级可缓存的线路会被复制到二级和一级中。因此,正确的标定内存为二级可缓存还是不可缓存是非常重要的。那些已经被使用但是不太可能被再次使用的数据应该被配置为二级可访问。暂存的数据将增加二级内存的被污染可能并减少效率。同样的,对性能与功耗没什么影响的内存应该从二级缓存中替换出去。二级缓存应该是为那些本可以从中获取最大效益的内存准备的。l2fetch指令可以用来提前将数据在使用之前放入二级内存中

访问紧耦合存储器的数据

Hexgon处理器的二级紧耦合存储器位于物理内存地址映射的可编程地址区域中。该区域是芯片专用的,不同的芯片各有不同。紧耦合存储器内存既可以通过Hexagon处理器来访问,也可以从外界的从口进行访问。从端口的读/写来源于外在的硬件区,例如DMA。

对TCM的未缓存访问

Hexagon处理器拥有一个全功能的MMU,用于将虚拟地址翻译为物理地址。每个页包含一系列的缓存属性位。为了使用未缓存的方法去访问紧耦合存储器,下面的要求必须满足:虚拟页必须被设置为未缓存类型。操作系统负责配置MMU。物理页在可编程地址的范围。内存范围是芯片指定的,不同的芯片各有不同如果load指令碰到了这样的情况,那么数据将直接从TCM中取到目标寄存器。这样的访问完全绕开了一级内存系统。启动了无缓存访问的程序将停止四个周期,在这四个周期中,程序不会相应任何指令。如果store指令碰到了这样的情况,那么数据会被送到TCM中。bus单元中有一个缓存区域用于将这些保存数据发送。如果缓存可用,那么调用未缓存store指令的程序不会停止,它会继续在下一个指令包上执行。如果缓存是不可用的,那么程序会一直等到资源可用为止。

对TCM的缓存访问

为了性能考虑,在一级数据或指令缓存中缓存TCM数据是非常可取的。这样的操作允许双访问load以及store指令。为了使用缓存方式来访问TCM, 下面的条件一定要满足:虚拟页必须被设置为可缓存写入或写回状态,操作系统负责为MMU配置可缓存类型物理页将为可编程区间。内存范围是芯片制定的,不同芯片各有不同load指令首先会寻找一级数据的缓存。如果遇到了缓存命中,那么load指令会继续运行而不会停止。如果发生了缓存缺失,那么丢失的那一行将会从TCM中放入到一级数据缓存中。load指令将会为此为等待四个周期。数据的替代使用一般数据缓存替代原则,这也意味着TCM数据可以被放置在任何一个一级数据缓存内。如果store指令碰到了这种情况,那么store指令首先会寻找一级数据的缓存,如果发生了缓存命中,那么数据被写入到缓存中。如果页被设置为写入,那么数据被直接送到TCM中。当TCM使用缓存方式访问时,硬件可以在一级数据缓存以及TCM中保持一致性。数据应该被配置为写入。但外界设备写入到TCM中,处理器将保障旧数据不会再一级缓存中出现。二级TCM可以被用来保存代码。例如,它可以被用来保存TCM中的关键代码如中断句柄。如果指令缓存发生了丢失而丢失的代码存在于TCM中,那么指令缓存可以从TCM中装填。通常的指令缓存原则被用于选择一个替换的内存。这意味着TCM代码可以在一级指令缓存的任何地方出现。

从端口对TCM的访问

外界硬件可以写/读Hexagon处理器的TCM,通过AXI从端口。这个端口可以被任何访问AXI的硬件使用:例如ARM芯片,移动数据,视频硬件等二级TCM在Hexagon处理器一级外界硬件中是完全可共享的,而对于从端口附有权限。因为二级TCM是可共享的,因此软件需要管理一致性操作。例如,如果Hexagon处理器以及从端口需要自发的写到TCM中的同一个地址,那么硬件将不能保证写操作是以什么顺序进行的。

指令延时

Hexagon处理器不会有任何程序员能察觉到的指令延时。下表总结了指令类型的所有延时:l ALU32, CR, XTYPE, program flow: 零延时l Speculative jump with incorrect hint: 一个周期的延时l Speculative new-value jump with incorrect hint: 两个周期的延时l Load/store: 一般是零延时,如果发生了不命中,那么会产生两个周期延时.l Data prefetch: 零延时

数据访问

这一部分讨论对于内存访问指令的特定实现的思考

数据缓存

Hexagon处理器中有一个一级数据缓存,它有如下的特点:32 KB8-way set associative32-byte linesPLRU replacementpolicy流水线的设计可以保证发生了不命中的程序将会一直等待直到发生命中。为了最小化由于缓存丢失所导致的性能惩罚,我们可以使用如下的技巧:l 应用应该竭尽所能减少关键数据的结构,浙江减少缓存工作组的大小l 需要重度访问的数据在内存中应该紧凑放置。这将使得缓存可以带来更多有用的数据。同样的,数据结构应该尽可能的线性化。l 应该使用dcfetch以及l2fetch指令,用于提前取得数据。这些指令不会在流水线上发生不命中。而程序将会继续运行如果缓存中的行命中被解决。在某些情况下,如发生了异常,那么dcfetch指令会被硬件忽略。dcfetch指令应该要小心的使用。提前调用数据将会占用不必要的总线带宽。l dczeroa指令应该被用来在一级数据中开辟写空间l dccleaninva或dcinva指令应该被用于将那些不再使用的数据失真。这会为缓存提供一个可能的取代区域。l 如果需要,对延迟敏感的数据可以放在二级TCM内存中来最小化性能的退化

Bank冲突

数据缓存是伪双端口。在大多数情况下缓存可以支持双访问。偶尔的,一个bank冲突暂停会在缓存不支持双访问时发生。这种情况主要发生在如下情形:l Load/Store + Load: 如果位 [31:6]不匹配, 但 [5:3]可匹配,发生冲突l Load + Load: 如果 [31:3]匹配,那么不发生冲突 (same line dual-access).l Store + Load: 如果位 [31:3] 匹配,而指令重叠,发生冲突

页面交叉

下面的寻址模式将通过添加一个偏移量以及基地址来计算他们的有效地址l 绝对寄存器偏移寻址l 全局指针相对寻址l 间接偏移寻址l 间接寄存器寻址如果一个不同的内存页上基地址以及偏移地址相加要超过总值。在这种情况下将会发生一个周期的页面交叉暂停。注意到这个暂停只会在基地址加偏移地址模式时才会发生,其他的寻址模式不会发生这样的情况。

指令访问

指令缓存

Hexagon处理器中含有一个一级指令缓存,他有如下的性质:l 16 KB大小l 4路级联l 32位线路l PLRU替换原则l 硬件预取如果程序中发生了不命中,那么程序会一直等待直到命中发生为了最小化指令缓存不命中带来的性能惩罚,可以使用下面的技巧:需要经常访问的代码应该被分组到仪器。这样编译器的程序分析器可以根据内存将程序根据访问频率分类。需要马上被访问的代码例如中断句柄,可以放置在二级TCM内存中来减少缓存丢失延迟

数据取对齐

对于一个横跨了对齐的16个字节边界的指令包,流水线在分支发生时都会产生一个周期的暂停,如果这样一个包被用来在内循环中指令,那么累计起来的性能惩罚将会是非常可观的。对于这个问题,最好的解决方法是在接下来的包的空槽中通过加入一个NOP指令来使包对齐16位的边界。但是,这很难手动操作,因为这需要跟踪每个指令的对齐方式。为了简化这个流程,Hexagon汇编器提供了.falign指示。但写入汇编语言代码时,简单的将这个指示在跳转频繁的指令前插入,那么汇编器将会试着去防止上文提到的阻碍。下面的代码演示了如何使用.falign指示以及.p2align指示去防止对齐阻碍:
//// align function and loop on 16-byteboundaries//.text.p2align 4.globl freq_func.type freq_func, @function{insninsnloop0(.L5,#128)}.falign.L5:{insninsn} {insninsn}:endloop0

多线程

Hexagon处理器提供了多线程功能,对于程序员来说,它包含了三个全能的对称处理器核,使用了一致内存。处理器将会作为一个单一的物理处理器来实现,同时在三个虚拟核上共享,每一个都会被定义为一个线程。每个线程有完全的寄存器组来访问所有的硬件资源。互联线程的通讯通过共享内存来实现:当某个线程将数据存储至内存是,数据对其他线程也是一致的。多个线程的同步通过基于内存的原子操作来实现。线程可以使用软件互相中断。线程的通讯以及同步机制用来穿件软件线程。

为低功耗编程

小循环

那些在一个缓存列中的循环将会在低功耗下运行,这是由于标签决定的。重要的循环应该相应的彼此对齐。

矢量指令的使用技巧

矢量操作如比较两个标量是不需要太多能耗的如下面的代码:
R5 = add(R1,R3)R4 = add(R0,R2)
我们可以将其改为矢量指令
R5:4 = vaddw(R1:0,R3:2)
该指令比上述指令消耗更少的能耗
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: