ARM流水线关键技术分析与代码优化

2 三级流水线运行情况分析ARM7

    三级流水线在处理简单的寄存器操作指令时,吞吐率为平均每个时钟周期一条指令;但是在存在存储器访问指令、跳转指令的情况下会出现流水线阻断情况,导致流水线的性能下降。图1给出了流水线的最佳运行情况,图中的MOV、ADD、SUB指令为单周期指令。从T1开始,用3个时钟周期执行了3条指令,指令平均周期数(CPI)等于1个时钟周期。,而51的CPI=12


图1  ARM7单周期指令最佳流水线

流水线中阻断现象也十分普遍,下面就各种阻断情况下的流水线性能进行详细分析。

2.1 带有存储器访问指令的流水线

    对存储器的访问指令LDR就是非单周期指令,如图2所示。这类指令在执行阶段,首先要进行存储器的地址计算,占用控制信号线,而译码的过程同样需要占用控制信号线,所以下一条指令(第一个SUB)的译码被阻断,并且由于LDR访问存储器和回写寄存器的过程中需要继续占用执行单元,所以下一条(第一个SUB)的执行也被阻断。由于采用冯·诺伊曼体系结构,不能够同时访问数据存储器和指令存储器,当LDR处于访存周期的过程中时,MOV指令的取指被阻断。因此处理器用8个时钟周期执行了6条指令,指令平均周期数(CPI)=1.3个时钟周期。


图2  带有存储器访问指令的流水线

2.2 带有分支指令的流水线

    当指令序列中含有具有分支功能的指令(如BL等)时,流水线也会被阻断,如图3所示。分支指令在执行时,其后第1条指令被译码,其后第2条指令进行取指,但是这两步操作的指令并不被执行。因为分支指令执行完毕后,程序应该转到跳转的目标地址处执行,因此在流水线上需要丢弃这两条指令,同时程序计数器就会转移到新的位置接着进行取指、译码和执行。此外还有一些特殊的转移指令需要在跳转完成的同时进行写链接寄存器(RLpc-4)、程序计数寄存器,如BL执行过程中包括两个附加操作——写链接寄存器和调整程序指针。这两个操作仍然占用执行单元,这时处于译码和取指的流水线被阻断了。


图3  带有分支指令的流水线

2.3 中断流水线
    
处理器中断的发生具有不确定性,与当前所执行的指令没有任何关系。在中断发生时,处理器总是会执行完当前正被执行的指令,然后去响应中断。如图4所示,在Ox90000处的指令ADD执行期间IRQ中断发生,这时要等待ADD指令执行完毕,IRQ才获得执行单元,处理器开始处理IRQ中断,保存程序返回地址并调整程序指针指向Oxl8内存单元。在Oxl8处有IRO中断向量(也就是跳向IRQ中断服务的指令)(中断向量表中),接下来执行跳转指令转向中断服务程序,流水线又被阻断,执行0x18处指令的过程同带有分支指令的流水线


0X0000001C B HandlerFiQ

0X00000018 B HandlerIRQ
0X00000014 B .
0X00000010 B HandlerSWI
0X0000000C B HandlerPabort
0X00000008 B HandlerSWI
0X00000004 B HandlerUndef
0X00000000 B ResetHandler
这个中断向量表中的跳转指令为B,而不是BL,这是因此它不需要返回来执行下一条指令。如果为BL,则在IRQ中断完成后就会跳转到 0X00000014,处执行。HandlerIRQ为一个地址标号,所以中断函数中若为IRQ中断,我们要在中断函数前面加上这个标号,也就是内存中的某个地址,不是固定的。
	但也有些把中断向量表定位在存储空间的更高地址(从偏移量0xffff0000开始).
 
  
常向量也可以出现在高地址0xFFFF0000处,当今操作系统为了控制内存访问权限常向量也可以出现在高地址0xFFFF0000处,通常会开启虚拟内存,
开启了虚拟内存之后,内存的开始空间通常为内核进程空间,和页表空间,异常向量表不能再安装在0地址处了

图4  中断流水线

3 五级流水线技术

     五级流水线技术在多种RISC处理器中被广泛使用,被认为是经典的处理器设计方式。五级流水线中的存储器访问部件(访存)和寄存器回写部件,解决了三级流水线中存储器访问指令在指令执行阶段的延迟问题。图5为五级流水线的运行情况(五级流水线也存在阻断)。


图5  ARM9的五级最佳流水线

3.1 五级流水线互锁分析

    五级流水线只存在一种互锁,即寄存器冲突。读寄存器是在译码阶段,写寄存器是在回写阶段(因为CPU从存储器或Cache中取出指令后,把它放到译码寄存器中进行解析)。如果当前指令(A)的目的操作数寄存器和下一条指令(B)的源操作数寄存器一致,B指令就需要等A回写之后才能译码。这就是五级流水线中的寄存器冲突。如图6所示,LDR指令写R9是在回写阶段,而MOV中需要用到的R9正是LDR在回写阶段将会重新写入的寄存器值,MOV译码需要等待,直到LDR指令的寄存器回写操作完成。(注:现在处理器设计中,可以通过寄存器旁路技术对流水线进行优化,解决流水线的寄存器冲突问题。)


图6  ARM9的五级流水线互锁

 虽然流水线互锁会增加代码执行时间,但是为初期的设计者提供了巨大的方便,可以不必考虑使用的寄存器会不会造成冲突;而且编译器以及汇编程序员可以通过重新设计代码的顺序或者其他方法来减少互锁的数量。另外分支指令和中断的发生仍然会阻断五级流水线。
3.2 五级流水线优化
    
采用重新设计代码顺序在很多情况下可以很好地减少流水线的阻塞,使流水线的运行流畅。下面详细分析代码优化对流水线的优化和效率的提高。
    要实现把内存地址0x1000和Ox2000处的数据分别拷贝到0x8000和0x9000处。
    Oxl000处的内容:1,2,3,4,5,6,7,8,9,10
    Ox2000处的内容:H,e,l,l,o,W,o,r,l,d
    实现第一个拷贝过程的程序代码及指令的执行时空图如图7所示。


图7  未经优化的流水线

 全部拷贝过程由两个结构相同的循环各自独立完成,分别实现两块数据的拷贝,并且两个拷贝过程极为类似,分析其中一个即可。
    T1~T3是3个单独的时钟周期;T4~T11是一个循环,在时空图中描述了第一次循环的执行情况。在T12的时候写LR的同时,开始对循环的第一条语句进行取指,所以总的流水线周期数为3+10×10+2×9=121。整个拷贝过程需要121×2+2=244个时钟周期完成。
    考虑到通过减少流水线的冲突可以提高流水线的执行效率,而流水线的冲突主要来自寄存器冲突和分支指令,因此对代码作如下两方面调整:
    ①将两个循环合并成一个循环能够充分减少循环跳转的次数,减少跳转带来的流水线停滞;
    ②调整代码的顺序,将带有与临近指令不相关的寄存器插到带有相关寄存器的指令之间,能够充分地避免寄存器冲突导致的流水线阻塞。
    对代码调整和流水线的时空图如图8所示。


图8  优化后的流水线

 调整之后,T1~T5是5个单独的时钟周期,T6~T13是一个循环,同样在T14的时候BNE指令在写LR的同时,循环的第一条指令开始取指,所以总的指令周期数为5+10×10+2×9+2=125。
    通过两段代码的比较可看出:调整之前整个拷贝过程总共使用了244个时钟周期,调整了循环内指令的顺序后,总共使用了125个时钟周期就完成了同样的工作,时钟周期减少了119个,缩短了119/244=48.8%,效率提升十分明显。
    代码优化前后执行周期数对比的情况如表1所列。


http://www.you01.com/dzly/html/70/n-1270.html

你可能感兴趣的:(嵌入式硬件相关)